aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpi_amba.c122
-rw-r--r--drivers/acpi/acpi_apd.c1
-rw-r--r--drivers/acpi/acpi_platform.c21
-rw-r--r--drivers/acpi/acpi_processor.c17
-rw-r--r--drivers/acpi/acpi_video.c7
-rw-r--r--drivers/acpi/acpica/acglobal.h2
-rw-r--r--drivers/acpi/acpica/aclocal.h6
-rw-r--r--drivers/acpi/acpica/acnamesp.h2
-rw-r--r--drivers/acpi/acpica/acpredef.h2
-rw-r--r--drivers/acpi/acpica/dbcmds.c2
-rw-r--r--drivers/acpi/acpica/dbconvert.c5
-rw-r--r--drivers/acpi/acpica/dsmethod.c3
-rw-r--r--drivers/acpi/acpica/dsobject.c3
-rw-r--r--drivers/acpi/acpica/evgpeblk.c3
-rw-r--r--drivers/acpi/acpica/evgpeinit.c2
-rw-r--r--drivers/acpi/acpica/evregion.c2
-rw-r--r--drivers/acpi/acpica/exconfig.c4
-rw-r--r--drivers/acpi/acpica/exoparg3.c4
-rw-r--r--drivers/acpi/acpica/nseval.c3
-rw-r--r--drivers/acpi/acpica/nsinit.c137
-rw-r--r--drivers/acpi/acpica/psargs.c9
-rw-r--r--drivers/acpi/acpica/tbinstal.c5
-rw-r--r--drivers/acpi/acpica/tbprint.c7
-rw-r--r--drivers/acpi/acpica/tbutils.c4
-rw-r--r--drivers/acpi/acpica/tbxfload.c40
-rw-r--r--drivers/acpi/acpica/utcache.c2
-rw-r--r--drivers/acpi/acpica/utnonansi.c246
-rw-r--r--drivers/acpi/acpica/uttrack.c2
-rw-r--r--drivers/acpi/acpica/utxferror.c3
-rw-r--r--drivers/acpi/acpica/utxfinit.c67
-rw-r--r--drivers/acpi/apei/apei-base.c6
-rw-r--r--drivers/acpi/apei/einj.c15
-rw-r--r--drivers/acpi/apei/erst.c3
-rw-r--r--drivers/acpi/apei/ghes.c23
-rw-r--r--drivers/acpi/bgrt.c10
-rw-r--r--drivers/acpi/bus.c26
-rw-r--r--drivers/acpi/cppc_acpi.c237
-rw-r--r--drivers/acpi/ec_sys.c3
-rw-r--r--drivers/acpi/fan.c2
-rw-r--r--drivers/acpi/internal.h7
-rw-r--r--drivers/acpi/nfit.c861
-rw-r--r--drivers/acpi/nfit.h30
-rw-r--r--drivers/acpi/osl.c158
-rw-r--r--drivers/acpi/pci_irq.c46
-rw-r--r--drivers/acpi/pci_link.c128
-rw-r--r--drivers/acpi/pmic/intel_pmic_crc.c7
-rw-r--r--drivers/acpi/processor_driver.c2
-rw-r--r--drivers/acpi/processor_idle.c66
-rw-r--r--drivers/acpi/scan.c1
-rw-r--r--drivers/acpi/sleep.c35
-rw-r--r--drivers/acpi/tables.c12
-rw-r--r--drivers/acpi/utils.c4
-rw-r--r--drivers/android/binder.c28
-rw-r--r--drivers/ata/ahci.c49
-rw-r--r--drivers/ata/ahci.h5
-rw-r--r--drivers/ata/ahci_xgene.c85
-rw-r--r--drivers/ata/libahci.c63
-rw-r--r--drivers/ata/libata-scsi.c11
-rw-r--r--drivers/ata/pata_macio.c2
-rw-r--r--drivers/ata/pata_rb532_cf.c11
-rw-r--r--drivers/base/bus.c15
-rw-r--r--drivers/base/component.c2
-rw-r--r--drivers/base/dma-coherent.c28
-rw-r--r--drivers/base/firmware_class.c87
-rw-r--r--drivers/base/memory.c34
-rw-r--r--drivers/base/power/domain.c60
-rw-r--r--drivers/base/power/domain_governor.c64
-rw-r--r--drivers/base/power/opp/core.c1079
-rw-r--r--drivers/base/power/opp/cpu.c22
-rw-r--r--drivers/base/power/opp/debugfs.c85
-rw-r--r--drivers/base/power/opp/opp.h74
-rw-r--r--drivers/base/power/trace.c4
-rw-r--r--drivers/base/property.c25
-rw-r--r--drivers/base/regmap/internal.h16
-rw-r--r--drivers/base/regmap/regcache-flat.c20
-rw-r--r--drivers/base/regmap/regcache.c45
-rw-r--r--drivers/base/regmap/regmap-irq.c104
-rw-r--r--drivers/base/regmap/regmap-mmio.c259
-rw-r--r--drivers/base/regmap/regmap.c241
-rw-r--r--drivers/block/cryptoloop.c48
-rw-r--r--drivers/block/drbd/drbd_int.h16
-rw-r--r--drivers/block/drbd/drbd_main.c16
-rw-r--r--drivers/block/drbd/drbd_nl.c59
-rw-r--r--drivers/block/drbd/drbd_receiver.c56
-rw-r--r--drivers/block/drbd/drbd_worker.c43
-rw-r--r--drivers/block/floppy.c67
-rw-r--r--drivers/block/null_blk.c8
-rw-r--r--drivers/block/paride/pd.c4
-rw-r--r--drivers/block/paride/pt.c4
-rw-r--r--drivers/block/xen-blkfront.c74
-rw-r--r--drivers/char/Kconfig3
-rw-r--r--drivers/char/agp/uninorth-agp.c1
-rw-r--r--drivers/char/hpet.c2
-rw-r--r--drivers/char/hw_random/Kconfig15
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/bcm63xx-rng.c11
-rw-r--r--drivers/char/hw_random/exynos-rng.c10
-rw-r--r--drivers/char/hw_random/n2-drv.c10
-rw-r--r--drivers/char/hw_random/pic32-rng.c155
-rw-r--r--drivers/char/mem.c2
-rw-r--r--drivers/char/nvram.c12
-rw-r--r--drivers/char/nwbutton.c5
-rw-r--r--drivers/char/pcmcia/synclink_cs.c21
-rw-r--r--drivers/char/ppdev.c397
-rw-r--r--drivers/char/random.c22
-rw-r--r--drivers/char/raw.c4
-rw-r--r--drivers/char/tpm/tpm-chip.c19
-rw-r--r--drivers/char/tpm/tpm.h7
-rw-r--r--drivers/char/tpm/tpm2-cmd.c22
-rw-r--r--drivers/char/tpm/tpm_crb.c196
-rw-r--r--drivers/char/tpm/tpm_eventlog.c14
-rw-r--r--drivers/char/tpm/tpm_tis.c253
-rw-r--r--drivers/char/ttyprintk.c2
-rw-r--r--drivers/char/xillybus/xillybus_core.c4
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/clk-gpio.c2
-rw-r--r--drivers/clk/clk-scpi.c2
-rw-r--r--drivers/clk/mvebu/dove-divider.c2
-rw-r--r--drivers/clk/qcom/gcc-apq8084.c1
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c1
-rw-r--r--drivers/clk/qcom/gcc-msm8660.c1
-rw-r--r--drivers/clk/qcom/gcc-msm8916.c1
-rw-r--r--drivers/clk/qcom/gcc-msm8960.c2
-rw-r--r--drivers/clk/qcom/gcc-msm8974.c1
-rw-r--r--drivers/clk/qcom/lcc-ipq806x.c1
-rw-r--r--drivers/clk/qcom/lcc-msm8960.c1
-rw-r--r--drivers/clk/qcom/mmcc-apq8084.c1
-rw-r--r--drivers/clk/qcom/mmcc-msm8960.c2
-rw-r--r--drivers/clk/qcom/mmcc-msm8974.c1
-rw-r--r--drivers/clk/rockchip/clk-rk3036.c26
-rw-r--r--drivers/clk/rockchip/clk-rk3368.c26
-rw-r--r--drivers/clk/tegra/clk-emc.c6
-rw-r--r--drivers/clk/tegra/clk-id.h1
-rw-r--r--drivers/clk/tegra/clk-pll.c50
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c5
-rw-r--r--drivers/clk/tegra/clk-tegra-super-gen4.c6
-rw-r--r--drivers/clk/tegra/clk-tegra210.c132
-rw-r--r--drivers/clk/ti/dpll3xxx.c3
-rw-r--r--drivers/clk/versatile/clk-icst.c3
-rw-r--r--drivers/clocksource/Kconfig1
-rw-r--r--drivers/clocksource/arm_arch_timer.c136
-rw-r--r--drivers/clocksource/arm_global_timer.c18
-rw-r--r--drivers/clocksource/exynos_mct.c2
-rw-r--r--drivers/clocksource/rockchip_timer.c21
-rw-r--r--drivers/clocksource/time-lpc32xx.c66
-rw-r--r--drivers/cpufreq/Kconfig2
-rw-r--r--drivers/cpufreq/Kconfig.arm4
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c212
-rw-r--r--drivers/cpufreq/amd_freq_sensitivity.c8
-rw-r--r--drivers/cpufreq/cpufreq-dt.c300
-rw-r--r--drivers/cpufreq/cpufreq.c333
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c282
-rw-r--r--drivers/cpufreq/cpufreq_governor.c766
-rw-r--r--drivers/cpufreq/cpufreq_governor.h261
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c445
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.h30
-rw-r--r--drivers/cpufreq/cpufreq_performance.c18
-rw-r--r--drivers/cpufreq/cpufreq_powersave.c10
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c10
-rw-r--r--drivers/cpufreq/intel_pstate.c192
-rw-r--r--drivers/cpufreq/mt8173-cpufreq.c1
-rw-r--r--drivers/cpufreq/powernv-cpufreq.c152
-rw-r--r--drivers/cpuidle/governors/menu.c47
-rw-r--r--drivers/crypto/Kconfig7
-rw-r--r--drivers/crypto/atmel-aes.c10
-rw-r--r--drivers/crypto/atmel-sha-regs.h4
-rw-r--r--drivers/crypto/atmel-sha.c200
-rw-r--r--drivers/crypto/atmel-tdes.c4
-rw-r--r--drivers/crypto/caam/ctrl.c2
-rw-r--r--drivers/crypto/caam/jr.c2
-rw-r--r--drivers/crypto/caam/regs.h3
-rw-r--r--drivers/crypto/ccp/Makefile2
-rw-r--r--drivers/crypto/ccp/ccp-crypto-aes-cmac.c36
-rw-r--r--drivers/crypto/ccp/ccp-crypto-aes.c12
-rw-r--r--drivers/crypto/ccp/ccp-crypto-sha.c49
-rw-r--r--drivers/crypto/ccp/ccp-crypto.h22
-rw-r--r--drivers/crypto/ccp/ccp-dev-v3.c533
-rw-r--r--drivers/crypto/ccp/ccp-dev.c471
-rw-r--r--drivers/crypto/ccp/ccp-dev.h155
-rw-r--r--drivers/crypto/ccp/ccp-ops.c381
-rw-r--r--drivers/crypto/ccp/ccp-pci.c23
-rw-r--r--drivers/crypto/ccp/ccp-platform.c48
-rw-r--r--drivers/crypto/ixp4xx_crypto.c26
-rw-r--r--drivers/crypto/omap-aes.c97
-rw-r--r--drivers/crypto/qat/qat_common/adf_accel_devices.h4
-rw-r--r--drivers/crypto/qat/qat_common/adf_aer.c1
-rw-r--r--drivers/crypto/qat/qat_common/adf_cfg_user.h6
-rw-r--r--drivers/crypto/qat/qat_common/adf_hw_arbiter.c19
-rw-r--r--drivers/crypto/qat/qat_common/icp_qat_uclo.h42
-rw-r--r--drivers/crypto/qat/qat_common/qat_algs.c6
-rw-r--r--drivers/crypto/qat/qat_common/qat_asym_algs.c70
-rw-r--r--drivers/crypto/qat/qat_common/qat_uclo.c2
-rw-r--r--drivers/crypto/rockchip/Makefile1
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto.c28
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto.h56
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c20
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto_ahash.c404
-rw-r--r--drivers/crypto/s5p-sss.c12
-rw-r--r--drivers/crypto/sahara.c19
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss-cipher.c5
-rw-r--r--drivers/crypto/ux500/cryp/cryp_core.c4
-rw-r--r--drivers/crypto/ux500/hash/hash_core.c4
-rw-r--r--drivers/devfreq/tegra-devfreq.c2
-rw-r--r--drivers/dma/Kconfig16
-rw-r--r--drivers/dma/Makefile2
-rw-r--r--drivers/dma/acpi-dma.c2
-rw-r--r--drivers/dma/at_xdmac.c42
-rw-r--r--drivers/dma/dmaengine.c1
-rw-r--r--drivers/dma/dw/core.c15
-rw-r--r--drivers/dma/dw/pci.c4
-rw-r--r--drivers/dma/dw/regs.h2
-rw-r--r--drivers/dma/edma.c104
-rw-r--r--drivers/dma/ep93xx_dma.c28
-rw-r--r--drivers/dma/fsldma.c2
-rw-r--r--drivers/dma/idma64.c3
-rw-r--r--drivers/dma/idma64.h2
-rw-r--r--drivers/dma/ioat/dma.c302
-rw-r--r--drivers/dma/ioat/dma.h23
-rw-r--r--drivers/dma/ioat/hw.h2
-rw-r--r--drivers/dma/ioat/init.c49
-rw-r--r--drivers/dma/ioat/prep.c2
-rw-r--r--drivers/dma/iop-adma.c8
-rw-r--r--drivers/dma/mic_x100_dma.c2
-rw-r--r--drivers/dma/mv_xor.c4
-rw-r--r--drivers/dma/omap-dma.c8
-rw-r--r--drivers/dma/pl330.c101
-rw-r--r--drivers/dma/pxa_dma.c8
-rw-r--r--drivers/dma/qcom/Kconfig29
-rw-r--r--drivers/dma/qcom/Makefile3
-rw-r--r--drivers/dma/qcom/bam_dma.c (renamed from drivers/dma/qcom_bam_dma.c)37
-rw-r--r--drivers/dma/qcom/hidma.c706
-rw-r--r--drivers/dma/qcom/hidma.h160
-rw-r--r--drivers/dma/qcom/hidma_mgmt.c302
-rw-r--r--drivers/dma/qcom/hidma_mgmt.h39
-rw-r--r--drivers/dma/qcom/hidma_mgmt_sys.c295
-rw-r--r--drivers/dma/sh/Kconfig6
-rw-r--r--drivers/dma/sh/rcar-dmac.c2
-rw-r--r--drivers/dma/sh/shdmac.c2
-rw-r--r--drivers/dma/sirf-dma.c10
-rw-r--r--drivers/dma/sun4i-dma.c1
-rw-r--r--drivers/dma/tegra20-apb-dma.c47
-rw-r--r--drivers/dma/xilinx/xilinx_vdma.c204
-rw-r--r--drivers/edac/Kconfig26
-rw-r--r--drivers/edac/Makefile2
-rw-r--r--drivers/edac/altera_edac.c492
-rw-r--r--drivers/edac/amd64_edac.c2
-rw-r--r--drivers/edac/debugfs.c2
-rw-r--r--drivers/edac/edac_mc.c64
-rw-r--r--drivers/edac/edac_pci.c67
-rw-r--r--drivers/edac/mce_amd.c335
-rw-r--r--drivers/edac/mpc85xx_edac.c2
-rw-r--r--drivers/edac/sb_edac.c28
-rw-r--r--drivers/edac/xgene_edac.c70
-rw-r--r--drivers/extcon/extcon-arizona.c4
-rw-r--r--drivers/extcon/extcon-gpio.c2
-rw-r--r--drivers/extcon/extcon-max14577.c3
-rw-r--r--drivers/extcon/extcon-max77693.c12
-rw-r--r--drivers/extcon/extcon-max77843.c5
-rw-r--r--drivers/extcon/extcon-max8997.c3
-rw-r--r--drivers/extcon/extcon-palmas.c54
-rw-r--r--drivers/extcon/extcon-rt8973a.c8
-rw-r--r--drivers/extcon/extcon-sm5502.c8
-rw-r--r--drivers/firmware/Kconfig20
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/efi/efivars.c35
-rw-r--r--drivers/firmware/efi/vars.c144
-rw-r--r--drivers/firmware/iscsi_ibft.c4
-rw-r--r--drivers/firmware/qemu_fw_cfg.c751
-rw-r--r--drivers/gpio/gpio-rcar.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c35
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_dp.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_dpm.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c5
-rw-r--r--drivers/gpu/drm/amd/powerplay/amd_powerplay.c5
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c1
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c4
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c2
-rw-r--r--drivers/gpu/drm/ast/ast_main.c2
-rw-r--r--drivers/gpu/drm/bochs/bochs_drv.c4
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.c5
-rw-r--r--drivers/gpu/drm/drm_atomic.c44
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c2
-rw-r--r--drivers/gpu/drm/drm_crtc.c49
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c37
-rw-r--r--drivers/gpu/drm/drm_gem_cma_helper.c13
-rw-r--r--drivers/gpu/drm/drm_irq.c73
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c8
-rw-r--r--drivers/gpu/drm/exynos/Kconfig2
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c32
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_mic.c72
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c8
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c10
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c28
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h5
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c3
-rw-r--r--drivers/gpu/drm/i915/i915_gem_userptr.c3
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h17
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c4
-rw-r--r--drivers/gpu/drm/i915/intel_audio.c3
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c13
-rw-r--r--drivers/gpu/drm/i915/intel_csr.c2
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c116
-rw-r--r--drivers/gpu/drm/i915/intel_display.c86
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c33
-rw-r--r--drivers/gpu/drm/i915/intel_dp_link_training.c45
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h3
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.c13
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_panel_vbt.c21
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c16
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c8
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c14
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c21
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c153
-rw-r--r--drivers/gpu/drm/imx/ipuv3-crtc.c2
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_platform.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c40
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h6
-rw-r--r--drivers/gpu/drm/omapdrm/omap_dmm_tiler.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.c8
-rw-r--r--drivers/gpu/drm/qxl/qxl_ioctl.c3
-rw-r--r--drivers/gpu/drm/qxl/qxl_prime.c2
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c20
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c19
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c2
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c20
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c3
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c6
-rw-r--r--drivers/gpu/drm/tegra/gem.c11
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c21
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h13
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c65
-rw-r--r--drivers/gpu/drm/vc4/vc4_irq.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_render_cl.c22
-rw-r--r--drivers/gpu/drm/vc4/vc4_v3d.c48
-rw-r--r--drivers/gpu/drm/vc4/vc4_validate.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c2
-rw-r--r--drivers/gpu/host1x/bus.c2
-rw-r--r--drivers/gpu/host1x/cdma.c8
-rw-r--r--drivers/gpu/host1x/dev.c7
-rw-r--r--drivers/gpu/host1x/dev.h1
-rw-r--r--drivers/gpu/host1x/job.c10
-rw-r--r--drivers/gpu/ipu-v3/ipu-common.c31
-rw-r--r--drivers/hsi/clients/nokia-modem.c2
-rw-r--r--drivers/hsi/clients/ssi_protocol.c16
-rw-r--r--drivers/hv/channel.c36
-rw-r--r--drivers/hv/channel_mgmt.c262
-rw-r--r--drivers/hv/connection.c20
-rw-r--r--drivers/hv/hv.c36
-rw-r--r--drivers/hv/hv_fcopy.c2
-rw-r--r--drivers/hv/hv_kvp.c2
-rw-r--r--drivers/hv/hv_snapshot.c2
-rw-r--r--drivers/hv/hv_util.c1
-rw-r--r--drivers/hv/hv_utils_transport.c3
-rw-r--r--drivers/hv/hyperv_vmbus.h42
-rw-r--r--drivers/hv/ring_buffer.c31
-rw-r--r--drivers/hv/vmbus_drv.c117
-rw-r--r--drivers/hwmon/Kconfig31
-rw-r--r--drivers/hwmon/Makefile4
-rw-r--r--drivers/hwmon/ads1015.c2
-rw-r--r--drivers/hwmon/gpio-fan.c7
-rw-r--r--drivers/hwmon/iio_hwmon.c11
-rw-r--r--drivers/hwmon/ltc2990.c161
-rw-r--r--drivers/hwmon/nsa320-hwmon.c215
-rw-r--r--drivers/hwmon/ntc_thermistor.c44
-rw-r--r--drivers/hwmon/pmbus/Kconfig4
-rw-r--r--drivers/hwmon/pmbus/adm1275.c56
-rw-r--r--drivers/hwmon/vexpress-hwmon.c (renamed from drivers/hwmon/vexpress.c)0
-rw-r--r--drivers/hwtracing/coresight/Kconfig1
-rw-r--r--drivers/hwtracing/coresight/Makefile4
-rw-r--r--drivers/hwtracing/coresight/coresight-etb10.c293
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.c393
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.h32
-rw-r--r--drivers/hwtracing/coresight/coresight-etm.h142
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-sysfs.c1272
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x.c1687
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.c37
-rw-r--r--drivers/hwtracing/coresight/coresight-funnel.c21
-rw-r--r--drivers/hwtracing/coresight/coresight-priv.h15
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator-qcom.c19
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator.c25
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.c35
-rw-r--r--drivers/hwtracing/coresight/coresight-tpiu.c23
-rw-r--r--drivers/hwtracing/coresight/coresight.c388
-rw-r--r--drivers/hwtracing/coresight/of_coresight.c3
-rw-r--r--drivers/hwtracing/intel_th/Kconfig1
-rw-r--r--drivers/hwtracing/intel_th/core.c30
-rw-r--r--drivers/hwtracing/intel_th/gth.c32
-rw-r--r--drivers/hwtracing/intel_th/gth.h3
-rw-r--r--drivers/hwtracing/intel_th/intel_th.h41
-rw-r--r--drivers/hwtracing/intel_th/msu.c9
-rw-r--r--drivers/hwtracing/intel_th/pci.c12
-rw-r--r--drivers/hwtracing/intel_th/sth.c11
-rw-r--r--drivers/hwtracing/stm/Kconfig16
-rw-r--r--drivers/hwtracing/stm/Makefile2
-rw-r--r--drivers/hwtracing/stm/core.c175
-rw-r--r--drivers/hwtracing/stm/dummy_stm.c71
-rw-r--r--drivers/hwtracing/stm/heartbeat.c130
-rw-r--r--drivers/hwtracing/stm/policy.c25
-rw-r--r--drivers/hwtracing/stm/stm.h2
-rw-r--r--drivers/i2c/busses/i2c-brcmstb.c3
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c1
-rw-r--r--drivers/i2c/busses/i2c-i801.c2
-rw-r--r--drivers/i2c/busses/i2c-omap.c4
-rw-r--r--drivers/i2c/busses/i2c-uniphier-f.c2
-rw-r--r--drivers/i2c/busses/i2c-uniphier.c2
-rw-r--r--drivers/ide/pdc202xx_new.c1
-rw-r--r--drivers/ide/pmac.c1
-rw-r--r--drivers/infiniband/core/cma_configfs.c31
-rw-r--r--drivers/infiniband/core/device.c1
-rw-r--r--drivers/infiniband/core/sa_query.c2
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c9
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c63
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c7
-rw-r--r--drivers/infiniband/hw/mlx5/srq.c41
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma.h3
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c18
-rw-r--r--drivers/iommu/amd_iommu.c4
-rw-r--r--drivers/iommu/amd_iommu_init.c63
-rw-r--r--drivers/iommu/dmar.c7
-rw-r--r--drivers/iommu/intel-iommu.c4
-rw-r--r--drivers/iommu/intel-svm.c37
-rw-r--r--drivers/iommu/intel_irq_remapping.c2
-rw-r--r--drivers/irqchip/Kconfig28
-rw-r--r--drivers/irqchip/Makefile8
-rw-r--r--drivers/irqchip/irq-alpine-msi.c293
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c156
-rw-r--r--drivers/irqchip/irq-ath79-cpu.c97
-rw-r--r--drivers/irqchip/irq-ath79-misc.c189
-rw-r--r--drivers/irqchip/irq-atmel-aic-common.c14
-rw-r--r--drivers/irqchip/irq-atmel-aic-common.h7
-rw-r--r--drivers/irqchip/irq-atmel-aic.c9
-rw-r--r--drivers/irqchip/irq-atmel-aic5.c9
-rw-r--r--drivers/irqchip/irq-bcm2836.c1
-rw-r--r--drivers/irqchip/irq-bcm6345-l1.c364
-rw-r--r--drivers/irqchip/irq-gic-realview.c44
-rw-r--r--drivers/irqchip/irq-gic-v2m.c14
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c28
-rw-r--r--drivers/irqchip/irq-gic-v3.c349
-rw-r--r--drivers/irqchip/irq-gic.c2
-rw-r--r--drivers/irqchip/irq-mips-gic.c354
-rw-r--r--drivers/irqchip/irq-mvebu-odmi.c236
-rw-r--r--drivers/irqchip/irq-mxs.c2
-rw-r--r--drivers/irqchip/irq-sunxi-nmi.c4
-rw-r--r--drivers/irqchip/irq-tango.c232
-rw-r--r--drivers/irqchip/irq-ts4800.c2
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c9
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.c2
-rw-r--r--drivers/isdn/i4l/isdn_tty.c12
-rw-r--r--drivers/leds/Kconfig8
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/led-class.c2
-rw-r--r--drivers/leds/led-core.c45
-rw-r--r--drivers/leds/led-triggers.c13
-rw-r--r--drivers/leds/leds-88pm860x.c12
-rw-r--r--drivers/leds/leds-da903x.c12
-rw-r--r--drivers/leds/leds-gpio.c6
-rw-r--r--drivers/leds/leds-is31fl32xx.c508
-rw-r--r--drivers/leds/leds-lm3533.c12
-rw-r--r--drivers/leds/leds-lp3944.c7
-rw-r--r--drivers/leds/leds-lp8788.c14
-rw-r--r--drivers/leds/leds-max8997.c14
-rw-r--r--drivers/leds/leds-s3c24xx.c19
-rw-r--r--drivers/leds/leds-wm831x-status.c13
-rw-r--r--drivers/lightnvm/core.c25
-rw-r--r--drivers/lightnvm/rrpc.c4
-rw-r--r--drivers/lightnvm/rrpc.h5
-rw-r--r--drivers/macintosh/macio_asic.c1
-rw-r--r--drivers/mailbox/pcc.c111
-rw-r--r--drivers/md/Kconfig11
-rw-r--r--drivers/md/Makefile2
-rw-r--r--drivers/md/dm-cache-metadata.c98
-rw-r--r--drivers/md/dm-cache-metadata.h4
-rw-r--r--drivers/md/dm-cache-policy-mq.c1473
-rw-r--r--drivers/md/dm-cache-policy-smq.c92
-rw-r--r--drivers/md/dm-cache-target.c16
-rw-r--r--drivers/md/dm-crypt.c95
-rw-r--r--drivers/md/dm-delay.c2
-rw-r--r--drivers/md/dm-flakey.c2
-rw-r--r--drivers/md/dm-ioctl.c5
-rw-r--r--drivers/md/dm-log-writes.c2
-rw-r--r--drivers/md/dm-mpath.c216
-rw-r--r--drivers/md/dm-path-selector.h5
-rw-r--r--drivers/md/dm-queue-length.c37
-rw-r--r--drivers/md/dm-raid1.c2
-rw-r--r--drivers/md/dm-round-robin.c85
-rw-r--r--drivers/md/dm-service-time.c35
-rw-r--r--drivers/md/dm-snap.c11
-rw-r--r--drivers/md/dm-table.c66
-rw-r--r--drivers/md/dm-target.c3
-rw-r--r--drivers/md/dm-thin-metadata.c7
-rw-r--r--drivers/md/dm-thin.c23
-rw-r--r--drivers/md/dm-verity-fec.c2
-rw-r--r--drivers/md/dm-verity-target.c12
-rw-r--r--drivers/md/dm.c600
-rw-r--r--drivers/md/dm.h4
-rw-r--r--drivers/media/common/b2c2/flexcop-fe-tuner.c4
-rw-r--r--drivers/media/common/b2c2/flexcop.c4
-rw-r--r--drivers/media/common/cypress_firmware.c2
-rw-r--r--drivers/media/common/cypress_firmware.h2
-rw-r--r--drivers/media/common/siano/smscoreapi.c4
-rw-r--r--drivers/media/common/siano/smsdvb-main.c7
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h9
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c218
-rw-r--r--drivers/media/dvb-core/dvb_frontend.h3
-rw-r--r--drivers/media/dvb-core/dvbdev.c15
-rw-r--r--drivers/media/dvb-frontends/Kconfig8
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/af9013.c8
-rw-r--r--drivers/media/dvb-frontends/af9033.c7
-rw-r--r--drivers/media/dvb-frontends/as102_fe.c4
-rw-r--r--drivers/media/dvb-frontends/atbm8830.c4
-rw-r--r--drivers/media/dvb-frontends/au8522.h1
-rw-r--r--drivers/media/dvb-frontends/au8522_decoder.c7
-rw-r--r--drivers/media/dvb-frontends/au8522_dig.c4
-rw-r--r--drivers/media/dvb-frontends/au8522_priv.h11
-rw-r--r--drivers/media/dvb-frontends/bcm3510.c4
-rw-r--r--drivers/media/dvb-frontends/bcm3510.h2
-rw-r--r--drivers/media/dvb-frontends/bcm3510_priv.h2
-rw-r--r--drivers/media/dvb-frontends/cx22700.c4
-rw-r--r--drivers/media/dvb-frontends/cx22702.c4
-rw-r--r--drivers/media/dvb-frontends/cx24110.c4
-rw-r--r--drivers/media/dvb-frontends/cx24117.c4
-rw-r--r--drivers/media/dvb-frontends/cx24120.c8
-rw-r--r--drivers/media/dvb-frontends/cx24123.c4
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_c.c4
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_core.c20
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_priv.h9
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t.c4
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t2.c6
-rw-r--r--drivers/media/dvb-frontends/cxd2841er.c4
-rw-r--r--drivers/media/dvb-frontends/dib0070.c2
-rw-r--r--drivers/media/dvb-frontends/dib0090.c16
-rw-r--r--drivers/media/dvb-frontends/dib3000.h6
-rw-r--r--drivers/media/dvb-frontends/dib3000mb.c17
-rw-r--r--drivers/media/dvb-frontends/dib3000mb_priv.h2
-rw-r--r--drivers/media/dvb-frontends/dib3000mc.c10
-rw-r--r--drivers/media/dvb-frontends/dib3000mc.h2
-rw-r--r--drivers/media/dvb-frontends/dib7000m.c8
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c10
-rw-r--r--drivers/media/dvb-frontends/dib8000.c77
-rw-r--r--drivers/media/dvb-frontends/dib9000.c31
-rw-r--r--drivers/media/dvb-frontends/dibx000_common.c2
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c11
-rw-r--r--drivers/media/dvb-frontends/dvb_dummy_fe.c7
-rw-r--r--drivers/media/dvb-frontends/hd29l2.c4
-rw-r--r--drivers/media/dvb-frontends/l64781.c4
-rw-r--r--drivers/media/dvb-frontends/lg2160.c62
-rw-r--r--drivers/media/dvb-frontends/lgdt3305.c4
-rw-r--r--drivers/media/dvb-frontends/lgdt3306a.c4
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.c5
-rw-r--r--drivers/media/dvb-frontends/lgs8gl5.c5
-rw-r--r--drivers/media/dvb-frontends/lgs8gxx.c13
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c4
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.c5
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.c11
-rw-r--r--drivers/media/dvb-frontends/mn88473.c (renamed from drivers/staging/media/mn88473/mn88473.c)388
-rw-r--r--drivers/media/dvb-frontends/mn88473.h14
-rw-r--r--drivers/media/dvb-frontends/mn88473_priv.h (renamed from drivers/staging/media/mn88473/mn88473_priv.h)7
-rw-r--r--drivers/media/dvb-frontends/mt312.c4
-rw-r--r--drivers/media/dvb-frontends/mt352.c4
-rw-r--r--drivers/media/dvb-frontends/or51132.c4
-rw-r--r--drivers/media/dvb-frontends/rtl2830.c7
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c155
-rw-r--r--drivers/media/dvb-frontends/rtl2832.h4
-rw-r--r--drivers/media/dvb-frontends/rtl2832_priv.h1
-rw-r--r--drivers/media/dvb-frontends/s5h1409.c4
-rw-r--r--drivers/media/dvb-frontends/s5h1411.c4
-rw-r--r--drivers/media/dvb-frontends/s5h1420.c4
-rw-r--r--drivers/media/dvb-frontends/s921.c4
-rw-r--r--drivers/media/dvb-frontends/si2165.c28
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.c4
-rw-r--r--drivers/media/dvb-frontends/stb6100.c2
-rw-r--r--drivers/media/dvb-frontends/stv0297.c4
-rw-r--r--drivers/media/dvb-frontends/stv0299.c8
-rw-r--r--drivers/media/dvb-frontends/stv0367.c8
-rw-r--r--drivers/media/dvb-frontends/stv0900_core.c11
-rw-r--r--drivers/media/dvb-frontends/stv6110x.c4
-rw-r--r--drivers/media/dvb-frontends/stv6110x.h4
-rw-r--r--drivers/media/dvb-frontends/stv6110x_priv.h2
-rw-r--r--drivers/media/dvb-frontends/tc90522.c10
-rw-r--r--drivers/media/dvb-frontends/tda10021.c4
-rw-r--r--drivers/media/dvb-frontends/tda10023.c4
-rw-r--r--drivers/media/dvb-frontends/tda10048.c4
-rw-r--r--drivers/media/dvb-frontends/tda1004x.c4
-rw-r--r--drivers/media/dvb-frontends/tda10071.c4
-rw-r--r--drivers/media/dvb-frontends/tda10086.c4
-rw-r--r--drivers/media/dvb-frontends/tda8083.c4
-rw-r--r--drivers/media/dvb-frontends/ts2020.c4
-rw-r--r--drivers/media/dvb-frontends/ves1820.c4
-rw-r--r--drivers/media/dvb-frontends/ves1x93.c4
-rw-r--r--drivers/media/dvb-frontends/zl10353.c4
-rw-r--r--drivers/media/i2c/adp1653.c2
-rw-r--r--drivers/media/i2c/adv7511.c43
-rw-r--r--drivers/media/i2c/adv7604.c233
-rw-r--r--drivers/media/i2c/adv7842.c20
-rw-r--r--drivers/media/i2c/msp3400-driver.c14
-rw-r--r--drivers/media/i2c/msp3400-driver.h5
-rw-r--r--drivers/media/i2c/mt9v011.c15
-rw-r--r--drivers/media/i2c/mt9v032.c28
-rw-r--r--drivers/media/i2c/ov2659.c8
-rw-r--r--drivers/media/i2c/ov9650.c4
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c4
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-spi.c1
-rw-r--r--drivers/media/i2c/s5k5baf.c5
-rw-r--r--drivers/media/i2c/saa7115.c19
-rw-r--r--drivers/media/i2c/soc_camera/mt9m001.c2
-rw-r--r--drivers/media/i2c/soc_camera/mt9t031.c2
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c2
-rw-r--r--drivers/media/i2c/tc358743.c55
-rw-r--r--drivers/media/i2c/tvp514x.c6
-rw-r--r--drivers/media/i2c/tvp5150.c452
-rw-r--r--drivers/media/i2c/tvp7002.c6
-rw-r--r--drivers/media/i2c/vpx3220.c2
-rw-r--r--drivers/media/media-device.c168
-rw-r--r--drivers/media/media-devnode.c1
-rw-r--r--drivers/media/media-entity.c94
-rw-r--r--drivers/media/pci/b2c2/flexcop-pci.c2
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c53
-rw-r--r--drivers/media/pci/bt8xx/dst.c4
-rw-r--r--drivers/media/pci/bt8xx/dvb-bt8xx.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c19
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c3
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-queue.c2
-rw-r--r--drivers/media/pci/netup_unidvb/netup_unidvb_core.c7
-rw-r--r--drivers/media/pci/ngene/ngene-cards.c2
-rw-r--r--drivers/media/pci/pt3/pt3.c3
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c1851
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c195
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c9
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c3
-rw-r--r--drivers/media/pci/saa7134/saa7134-go7007.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-input.c21
-rw-r--r--drivers/media/pci/saa7134/saa7134-tvaudio.c13
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c108
-rw-r--r--drivers/media/pci/saa7134/saa7134.h46
-rw-r--r--drivers/media/pci/ttpci/av7110.c15
-rw-r--r--drivers/media/pci/ttpci/budget.c36
-rw-r--r--drivers/media/platform/Kconfig22
-rw-r--r--drivers/media/platform/Makefile3
-rw-r--r--drivers/media/platform/coda/coda-bit.c12
-rw-r--r--drivers/media/platform/coda/coda-common.c106
-rw-r--r--drivers/media/platform/coda/coda.h3
-rw-r--r--drivers/media/platform/davinci/dm644x_ccdc.c2
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c12
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c20
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c10
-rw-r--r--drivers/media/platform/omap3isp/isp.c226
-rw-r--r--drivers/media/platform/omap3isp/isp.h4
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c2
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c14
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c116
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.h1
-rw-r--r--drivers/media/platform/omap3isp/omap3isp.h8
-rw-r--r--drivers/media/platform/rcar_jpu.c1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c12
-rw-r--r--drivers/media/platform/soc_camera/Kconfig29
-rw-r--r--drivers/media/platform/soc_camera/Makefile3
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c4
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c478
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c41
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c14
-rw-r--r--drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c2
-rw-r--r--drivers/media/platform/ti-vpe/Makefile4
-rw-r--r--drivers/media/platform/ti-vpe/cal.c1947
-rw-r--r--drivers/media/platform/ti-vpe/cal_regs.h479
-rw-r--r--drivers/media/platform/vim2m.c2
-rw-r--r--drivers/media/platform/vivid/vivid-osd.c2
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.c32
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.h2
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c39
-rw-r--r--drivers/media/platform/vsp1/Makefile3
-rw-r--r--drivers/media/platform/vsp1/vsp1.h29
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.c33
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.h3
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.c305
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.h42
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.c597
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.h49
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c382
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c31
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.h14
-rw-r--r--drivers/media/platform/vsp1/vsp1_hsit.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.c11
-rw-r--r--drivers/media/platform/vsp1/vsp1_lut.c7
-rw-r--r--drivers/media/platform/vsp1/vsp1_pipe.c426
-rw-r--r--drivers/media/platform/vsp1/vsp1_pipe.h134
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h32
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c88
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h29
-rw-r--r--drivers/media/platform/vsp1/vsp1_sru.c9
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.c8
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c518
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.h111
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c98
-rw-r--r--drivers/media/radio/radio-si476x.c4
-rw-r--r--drivers/media/radio/tea575x.c21
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c2
-rw-r--r--drivers/media/rc/ati_remote.c47
-rw-r--r--drivers/media/rc/igorplugusb.c17
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-rm-ks.c56
-rw-r--r--drivers/media/rc/lirc_dev.c7
-rw-r--r--drivers/media/rc/mceusb.c5
-rw-r--r--drivers/media/rc/nuvoton-cir.c358
-rw-r--r--drivers/media/rc/nuvoton-cir.h15
-rw-r--r--drivers/media/rc/rc-core-priv.h6
-rw-r--r--drivers/media/rc/rc-ir-raw.c23
-rw-r--r--drivers/media/rc/rc-main.c48
-rw-r--r--drivers/media/rc/sunxi-cir.c1
-rw-r--r--drivers/media/tuners/m88rs6000t.c11
-rw-r--r--drivers/media/tuners/r820t.c2
-rw-r--r--drivers/media/tuners/si2157.c39
-rw-r--r--drivers/media/tuners/si2157.h5
-rw-r--r--drivers/media/tuners/si2157_priv.h8
-rw-r--r--drivers/media/tuners/tuner-xc2028.c6
-rw-r--r--drivers/media/tuners/xc4000.c2
-rw-r--r--drivers/media/usb/airspy/airspy.c11
-rw-r--r--drivers/media/usb/as102/as102_drv.h2
-rw-r--r--drivers/media/usb/as102/as102_usb_drv.c2
-rw-r--r--drivers/media/usb/au0828/au0828-core.c456
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c12
-rw-r--r--drivers/media/usb/au0828/au0828-video.c191
-rw-r--r--drivers/media/usb/au0828/au0828.h27
-rw-r--r--drivers/media/usb/b2c2/flexcop-usb.c2
-rw-r--r--drivers/media/usb/cpia2/cpia2_core.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c68
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c10
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c47
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h4
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.h3
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_common.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c15
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvbsky.c7
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h8
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c32
-rw-r--r--drivers/media/usb/dvb-usb-v2/usb_urb.c2
-rw-r--r--drivers/media/usb/dvb-usb/a800.c4
-rw-r--r--drivers/media/usb/dvb-usb/af9005-fe.c4
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c4
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_core.c2
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c77
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-common.c2
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-mb.c6
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-mc.c6
-rw-r--r--drivers/media/usb/dvb-usb/dibusb.h2
-rw-r--r--drivers/media/usb/dvb-usb/digitv.c4
-rw-r--r--drivers/media/usb/dvb-usb/dtt200u-fe.c7
-rw-r--r--drivers/media/usb/dvb-usb/dtt200u.c4
-rw-r--r--drivers/media/usb/dvb-usb/dtt200u.h2
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-common.h2
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-dvb.c13
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-firmware.c2
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-i2c.c2
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-init.c4
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-urb.c2
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb.h2
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c105
-rw-r--r--drivers/media/usb/dvb-usb/friio-fe.c27
-rw-r--r--drivers/media/usb/dvb-usb/nova-t-usb2.c4
-rw-r--r--drivers/media/usb/dvb-usb/technisat-usb2.c43
-rw-r--r--drivers/media/usb/dvb-usb/ttusb2.c2
-rw-r--r--drivers/media/usb/dvb-usb/umt-010.c4
-rw-r--r--drivers/media/usb/dvb-usb/usb-urb.c2
-rw-r--r--drivers/media/usb/dvb-usb/vp702x-fe.c2
-rw-r--r--drivers/media/usb/dvb-usb/vp702x.c4
-rw-r--r--drivers/media/usb/dvb-usb/vp7045-fe.c2
-rw-r--r--drivers/media/usb/dvb-usb/vp7045.c4
-rw-r--r--drivers/media/usb/dvb-usb/vp7045.h2
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c246
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c21
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c213
-rw-r--r--drivers/media/usb/em28xx/em28xx.h21
-rw-r--r--drivers/media/usb/go7007/go7007-priv.h2
-rw-r--r--drivers/media/usb/go7007/go7007-usb.c4
-rw-r--r--drivers/media/usb/gspca/ov519.c43
-rw-r--r--drivers/media/usb/gspca/touptek.c8
-rw-r--r--drivers/media/usb/gspca/w996Xcf.c8
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c2
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c6
-rw-r--r--drivers/media/usb/msi2500/msi2500.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c3
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.c2
-rw-r--r--drivers/media/usb/pwc/pwc-if.c6
-rw-r--r--drivers/media/usb/siano/smsusb.c30
-rw-r--r--drivers/media/usb/stk1160/stk1160-video.c1
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c37
-rw-r--r--drivers/media/usb/usbtv/usbtv.h1
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c29
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c20
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h12
-rw-r--r--drivers/media/v4l2-core/Kconfig1
-rw-r--r--drivers/media/v4l2-core/Makefile1
-rw-r--r--drivers/media/v4l2-core/tuner-core.c26
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c7
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c21
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c34
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c3
-rw-r--r--drivers/media/v4l2-core/v4l2-fh.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c36
-rw-r--r--drivers/media/v4l2-core/v4l2-mc.c403
-rw-r--r--drivers/media/v4l2-core/v4l2-of.c2
-rw-r--r--drivers/media/v4l2-core/videobuf-core.c10
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c5
-rw-r--r--drivers/media/v4l2-core/videobuf2-dvb.c13
-rw-r--r--drivers/message/fusion/mptbase.c42
-rw-r--r--drivers/mfd/max77686.c86
-rw-r--r--drivers/misc/Kconfig4
-rw-r--r--drivers/misc/ad525x_dpot.c4
-rw-r--r--drivers/misc/apds990x.c8
-rw-r--r--drivers/misc/arm-charlcd.c24
-rw-r--r--drivers/misc/bh1770glc.c8
-rw-r--r--drivers/misc/c2port/core.c8
-rw-r--r--drivers/misc/cxl/pci.c3
-rw-r--r--drivers/misc/cxl/sysfs.c5
-rw-r--r--drivers/misc/eeprom/Kconfig6
-rw-r--r--drivers/misc/eeprom/at24.c130
-rw-r--r--drivers/misc/eeprom/at25.c148
-rw-r--r--drivers/misc/eeprom/eeprom.c2
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c332
-rw-r--r--drivers/misc/genwqe/card_sysfs.c2
-rw-r--r--drivers/misc/ibmasm/ibmasm.h9
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d_i2c.c8
-rw-r--r--drivers/misc/lkdtm.c153
-rw-r--r--drivers/misc/mei/Kconfig6
-rw-r--r--drivers/misc/mei/Makefile1
-rw-r--r--drivers/misc/mei/amthif.c130
-rw-r--r--drivers/misc/mei/bus-fixup.c41
-rw-r--r--drivers/misc/mei/bus.c57
-rw-r--r--drivers/misc/mei/client.c189
-rw-r--r--drivers/misc/mei/client.h27
-rw-r--r--drivers/misc/mei/debugfs.c65
-rw-r--r--drivers/misc/mei/hbm.c24
-rw-r--r--drivers/misc/mei/hw-me-regs.h4
-rw-r--r--drivers/misc/mei/hw-me.c10
-rw-r--r--drivers/misc/mei/hw-txe.c10
-rw-r--r--drivers/misc/mei/hw.h32
-rw-r--r--drivers/misc/mei/init.c20
-rw-r--r--drivers/misc/mei/interrupt.c94
-rw-r--r--drivers/misc/mei/main.c106
-rw-r--r--drivers/misc/mei/mei-trace.c2
-rw-r--r--drivers/misc/mei/mei-trace.h40
-rw-r--r--drivers/misc/mei/mei_dev.h118
-rw-r--r--drivers/misc/mei/pci-me.c7
-rw-r--r--drivers/misc/mei/pci-txe.c4
-rw-r--r--drivers/misc/mei/wd.c391
-rw-r--r--drivers/misc/mic/Kconfig44
-rw-r--r--drivers/misc/mic/Makefile1
-rw-r--r--drivers/misc/mic/bus/Makefile1
-rw-r--r--drivers/misc/mic/bus/cosm_bus.h2
-rw-r--r--drivers/misc/mic/bus/vop_bus.c203
-rw-r--r--drivers/misc/mic/bus/vop_bus.h140
-rw-r--r--drivers/misc/mic/card/Makefile1
-rw-r--r--drivers/misc/mic/card/mic_device.c89
-rw-r--r--drivers/misc/mic/card/mic_device.h3
-rw-r--r--drivers/misc/mic/card/mic_virtio.c634
-rw-r--r--drivers/misc/mic/card/mic_virtio.h76
-rw-r--r--drivers/misc/mic/card/mic_x100.c1
-rw-r--r--drivers/misc/mic/cosm/cosm_main.c13
-rw-r--r--drivers/misc/mic/host/Makefile2
-rw-r--r--drivers/misc/mic/host/mic_boot.c125
-rw-r--r--drivers/misc/mic/host/mic_debugfs.c190
-rw-r--r--drivers/misc/mic/host/mic_device.h9
-rw-r--r--drivers/misc/mic/host/mic_fops.c222
-rw-r--r--drivers/misc/mic/host/mic_fops.h32
-rw-r--r--drivers/misc/mic/host/mic_main.c49
-rw-r--r--drivers/misc/mic/host/mic_virtio.c811
-rw-r--r--drivers/misc/mic/host/mic_x100.c19
-rw-r--r--drivers/misc/mic/scif/scif_dma.c41
-rw-r--r--drivers/misc/mic/scif/scif_rma.c7
-rw-r--r--drivers/misc/mic/vop/Makefile9
-rw-r--r--drivers/misc/mic/vop/vop_debugfs.c232
-rw-r--r--drivers/misc/mic/vop/vop_main.c755
-rw-r--r--drivers/misc/mic/vop/vop_main.h (renamed from drivers/misc/mic/host/mic_virtio.h)129
-rw-r--r--drivers/misc/mic/vop/vop_vringh.c1165
-rw-r--r--drivers/misc/pch_phub.c10
-rw-r--r--drivers/misc/ti-st/st_core.c1
-rw-r--r--drivers/misc/vmw_vmci/vmci_driver.c2
-rw-r--r--drivers/mmc/card/sdio_uart.c14
-rw-r--r--drivers/mmc/host/omap_hsmmc.c2
-rw-r--r--drivers/mtd/tests/mtd_nandecctest.c2
-rw-r--r--drivers/mtd/ubi/upd.c2
-rw-r--r--drivers/net/bonding/bond_main.c40
-rw-r--r--drivers/net/can/spi/mcp251x.c2
-rw-r--r--drivers/net/can/usb/ems_usb.c14
-rw-r--r--drivers/net/can/usb/gs_usb.c24
-rw-r--r--drivers/net/dsa/mv88e6352.c1
-rw-r--r--drivers/net/dsa/mv88e6xxx.c27
-rw-r--r--drivers/net/ethernet/3com/3c59x.c2
-rw-r--r--drivers/net/ethernet/8390/pcnet_cs.c1
-rw-r--r--drivers/net/ethernet/agere/et131x.c2
-rw-r--r--drivers/net/ethernet/altera/altera_tse_main.c1
-rw-r--r--drivers/net/ethernet/amd/am79c961a.c64
-rw-r--r--drivers/net/ethernet/amd/lance.c4
-rw-r--r--drivers/net/ethernet/arc/emac_main.c74
-rw-r--r--drivers/net/ethernet/aurora/nb8800.c14
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h36
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c299
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c22
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h6
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c12
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c6
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c72
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h15
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c46
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c3
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_tx_rx.c2
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_main.c4
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_droq.c2
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic.h9
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic_main.c6
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic_reg.h2
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_main.c18
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.c8
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.h3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/t3_hw.c34
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h1
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c34
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h1
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h9
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c20
-rw-r--r--drivers/net/ethernet/ethoc.c1
-rw-r--r--drivers/net/ethernet/freescale/fman/fman.c4
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c4
-rw-r--r--drivers/net/ethernet/fujitsu/fmvj18x_cs.c4
-rw-r--r--drivers/net/ethernet/hisilicon/Kconfig1
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c8
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c37
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h1
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h5
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_ethtool.c15
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c5
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c62
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.h4
-rw-r--r--drivers/net/ethernet/intel/Kconfig9
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h5
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c85
-rw-r--r--drivers/net/ethernet/intel/e1000e/regs.h4
-rw-r--r--drivers/net/ethernet/jme.c26
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c184
-rw-r--r--drivers/net/ethernet/marvell/mvpp2.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/catas.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cq.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_clock.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_port.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_resources.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c70
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/pd.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/port.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h18
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_clock.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c36
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c126
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c19
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/port.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/reg.h58
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c14
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c69
-rw-r--r--drivers/net/ethernet/moxa/moxart_ether.c4
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.c2
-rw-r--r--drivers/net/ethernet/realtek/r8169.c32
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c20
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c10
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c9
-rw-r--r--drivers/net/ethernet/sun/sungem.c1
-rw-r--r--drivers/net/ethernet/synopsys/dwc_eth_qos.c45
-rw-r--r--drivers/net/ethernet/ti/cpsw-phy-sel.c12
-rw-r--r--drivers/net/ethernet/ti/netcp_core.c105
-rw-r--r--drivers/net/ethernet/toshiba/spider_net.c1
-rw-r--r--drivers/net/geneve.c31
-rw-r--r--drivers/net/hyperv/netvsc_drv.c3
-rw-r--r--drivers/net/irda/irtty-sir.c10
-rw-r--r--drivers/net/phy/bcm7xxx.c43
-rw-r--r--drivers/net/phy/marvell.c15
-rw-r--r--drivers/net/phy/micrel.c28
-rw-r--r--drivers/net/phy/phy_device.c2
-rw-r--r--drivers/net/ppp/ppp_generic.c11
-rw-r--r--drivers/net/ppp/ppp_mppe.c99
-rw-r--r--drivers/net/ppp/pppoe.c2
-rw-r--r--drivers/net/usb/Kconfig10
-rw-r--r--drivers/net/usb/Makefile2
-rw-r--r--drivers/net/usb/ax88172a.c1
-rw-r--r--drivers/net/usb/cdc_ncm.c26
-rw-r--r--drivers/net/usb/qmi_wwan.c8
-rw-r--r--drivers/net/usb/usbnet.c7
-rw-r--r--drivers/net/vmxnet3/vmxnet3_defs.h2
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c73
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h4
-rw-r--r--drivers/net/vrf.c13
-rw-r--r--drivers/net/vxlan.c17
-rw-r--r--drivers/net/wan/dscc4.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/Kconfig1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-8000.c42
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/internal.h9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/rx.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c188
-rw-r--r--drivers/net/wireless/intersil/orinoco/mic.c29
-rw-r--r--drivers/net/wireless/intersil/orinoco/mic.h4
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco.h4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rc.c5
-rw-r--r--drivers/net/wireless/ti/wlcore/io.c8
-rw-r--r--drivers/net/wireless/ti/wlcore/io.h4
-rw-r--r--drivers/nfc/s3fwrn5/firmware.c36
-rw-r--r--drivers/nvdimm/blk.c18
-rw-r--r--drivers/nvdimm/btt.c19
-rw-r--r--drivers/nvdimm/bus.c151
-rw-r--r--drivers/nvdimm/core.c110
-rw-r--r--drivers/nvdimm/dimm_devs.c6
-rw-r--r--drivers/nvdimm/e820.c2
-rw-r--r--drivers/nvdimm/namespace_devs.c7
-rw-r--r--drivers/nvdimm/nd.h4
-rw-r--r--drivers/nvdimm/pfn.h23
-rw-r--r--drivers/nvdimm/pfn_devs.c61
-rw-r--r--drivers/nvdimm/pmem.c221
-rw-r--r--drivers/nvdimm/region.c12
-rw-r--r--drivers/nvme/host/Kconfig5
-rw-r--r--drivers/nvme/host/core.c112
-rw-r--r--drivers/nvme/host/lightnvm.c12
-rw-r--r--drivers/nvme/host/nvme.h12
-rw-r--r--drivers/nvme/host/pci.c160
-rw-r--r--drivers/nvmem/Kconfig24
-rw-r--r--drivers/nvmem/Makefile4
-rw-r--r--drivers/nvmem/core.c145
-rw-r--r--drivers/nvmem/imx-ocotp.c2
-rw-r--r--drivers/nvmem/lpc18xx_eeprom.c330
-rw-r--r--drivers/nvmem/mtk-efuse.c110
-rw-r--r--drivers/nvmem/rockchip-efuse.c90
-rw-r--r--drivers/nvmem/sunxi_sid.c9
-rw-r--r--drivers/of/fdt.c32
-rw-r--r--drivers/of/fdt_address.c11
-rw-r--r--drivers/of/irq.c9
-rw-r--r--drivers/of/of_mdio.c1
-rw-r--r--drivers/of/of_pci.c1
-rw-r--r--drivers/parisc/Kconfig2
-rw-r--r--drivers/parisc/eisa_enumerator.c4
-rw-r--r--drivers/pci/Kconfig10
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/access.c239
-rw-r--r--drivers/pci/bus.c7
-rw-r--r--drivers/pci/host/Kconfig47
-rw-r--r--drivers/pci/host/Makefile6
-rw-r--r--drivers/pci/host/pci-dra7xx.c11
-rw-r--r--drivers/pci/host/pci-exynos.c13
-rw-r--r--drivers/pci/host/pci-host-common.c194
-rw-r--r--drivers/pci/host/pci-host-common.h47
-rw-r--r--drivers/pci/host/pci-host-generic.c181
-rw-r--r--drivers/pci/host/pci-hyperv.c2346
-rw-r--r--drivers/pci/host/pci-imx6.c166
-rw-r--r--drivers/pci/host/pci-keystone-dw.c11
-rw-r--r--drivers/pci/host/pci-keystone.c13
-rw-r--r--drivers/pci/host/pci-layerscape.c22
-rw-r--r--drivers/pci/host/pci-tegra.c85
-rw-r--r--drivers/pci/host/pci-thunder-ecam.c403
-rw-r--r--drivers/pci/host/pci-thunder-pem.c346
-rw-r--r--drivers/pci/host/pcie-altera.c3
-rw-r--r--drivers/pci/host/pcie-designware-plat.c138
-rw-r--r--drivers/pci/host/pcie-designware.c44
-rw-r--r--drivers/pci/host/pcie-designware.h6
-rw-r--r--drivers/pci/host/pcie-qcom.c12
-rw-r--r--drivers/pci/host/pcie-rcar.c14
-rw-r--r--drivers/pci/host/pcie-spear13xx.c14
-rw-r--r--drivers/pci/host/pcie-xilinx-nwl.c881
-rw-r--r--drivers/pci/host/pcie-xilinx.c191
-rw-r--r--drivers/pci/hotplug/s390_pci_hpc.c8
-rw-r--r--drivers/pci/iov.c4
-rw-r--r--drivers/pci/pci-label.c2
-rw-r--r--drivers/pci/pci-sysfs.c94
-rw-r--r--drivers/pci/pci.c44
-rw-r--r--drivers/pci/pci.h16
-rw-r--r--drivers/pci/pcie/Kconfig7
-rw-r--r--drivers/pci/pcie/aer/aer_inject.c90
-rw-r--r--drivers/pci/pcie/pme.c11
-rw-r--r--drivers/pci/probe.c45
-rw-r--r--drivers/pci/quirks.c46
-rw-r--r--drivers/pci/remove.c5
-rw-r--r--drivers/pci/rom.c83
-rw-r--r--drivers/pci/setup-bus.c1
-rw-r--r--drivers/pci/setup-res.c6
-rw-r--r--drivers/pci/xen-pcifront.c10
-rw-r--r--drivers/phy/Kconfig16
-rw-r--r--drivers/phy/Makefile2
-rw-r--r--drivers/phy/phy-dm816x-usb.c4
-rw-r--r--drivers/phy/phy-rcar-gen3-usb2.c83
-rw-r--r--drivers/phy/phy-rockchip-dp.c151
-rw-r--r--drivers/phy/phy-rockchip-emmc.c229
-rw-r--r--drivers/phy/phy-rockchip-usb.c233
-rw-r--r--drivers/phy/phy-twl4030-usb.c4
-rw-r--r--drivers/pinctrl/Kconfig52
-rw-r--r--drivers/pinctrl/Makefile16
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm2835.c2
-rw-r--r--drivers/pinctrl/core.c35
-rw-r--r--drivers/pinctrl/core.h4
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.c36
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.h1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx50.c1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx53.c1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx6dl.c1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx6q.c1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx6sl.c1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx6sx.c1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx6ul.c1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx7d.c1
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c4
-rw-r--r--drivers/pinctrl/mediatek/Kconfig22
-rw-r--r--drivers/pinctrl/mediatek/Makefile12
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt2701.c585
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt6397.c10
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7623.c379
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8127.c8
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8135.c8
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8173.c8
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c57
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.h12
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h2323
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h1936
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.c143
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.h21
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson8.c137
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson8b.c182
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c9
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-abx500.c5
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c7
-rw-r--r--drivers/pinctrl/pinctrl-amd.c4
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c4
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c2
-rw-r--r--drivers/pinctrl/pinctrl-lpc18xx.c148
-rw-r--r--drivers/pinctrl/pinctrl-pic32.c2312
-rw-r--r--drivers/pinctrl/pinctrl-pic32.h141
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c369
-rw-r--r--drivers/pinctrl/pinctrl-single.c8
-rw-r--r--drivers/pinctrl/pinctrl-st.c1
-rw-r--r--drivers/pinctrl/pinctrl-zynq.c2
-rw-r--r--drivers/pinctrl/pxa/pinctrl-pxa2xx.c2
-rw-r--r--drivers/pinctrl/qcom/Kconfig8
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ipq4019.c453
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-mpp.c30
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.c48
-rw-r--r--drivers/pinctrl/sh-pfc/Kconfig56
-rw-r--r--drivers/pinctrl/sh-pfc/Makefile7
-rw-r--r--drivers/pinctrl/sh-pfc/core.c24
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7778.c690
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7779.c1136
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7790.c774
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7791.c624
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7794.c1405
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7795.c915
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7734.c412
-rw-r--r--drivers/pinctrl/sh-pfc/sh_pfc.h98
-rw-r--r--drivers/pinctrl/stm32/Kconfig16
-rw-r--r--drivers/pinctrl/stm32/Makefile5
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.c829
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.h51
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32f429.c1591
-rw-r--r--drivers/pinctrl/sunxi/Kconfig36
-rw-r--r--drivers/pinctrl/sunxi/Makefile4
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c601
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c32
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-h3-r.c106
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c1
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c9
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c7
-rw-r--r--drivers/pinctrl/tegra/Kconfig30
-rw-r--r--drivers/pinctrl/tegra/Makefile7
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra-xusb.c (renamed from drivers/pinctrl/pinctrl-tegra-xusb.c)4
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra.c (renamed from drivers/pinctrl/pinctrl-tegra.c)4
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra.h (renamed from drivers/pinctrl/pinctrl-tegra.h)0
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra114.c (renamed from drivers/pinctrl/pinctrl-tegra114.c)0
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra124.c (renamed from drivers/pinctrl/pinctrl-tegra124.c)0
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra20.c (renamed from drivers/pinctrl/pinctrl-tegra20.c)0
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra210.c (renamed from drivers/pinctrl/pinctrl-tegra210.c)0
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra30.c (renamed from drivers/pinctrl/pinctrl-tegra30.c)0
-rw-r--r--drivers/pinctrl/uniphier/Kconfig14
-rw-r--r--drivers/pinctrl/uniphier/Makefile14
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-ld4.c (renamed from drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c)0
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c (renamed from drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c)0
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c (renamed from drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c)0
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c (renamed from drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c)0
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-pxs2.c (renamed from drivers/pinctrl/uniphier/pinctrl-proxstream2.c)0
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-sld8.c (renamed from drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c)0
-rw-r--r--drivers/platform/Kconfig3
-rw-r--r--drivers/platform/goldfish/Kconfig19
-rw-r--r--drivers/platform/goldfish/Makefile2
-rw-r--r--drivers/platform/goldfish/goldfish_pipe.c169
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c4
-rw-r--r--drivers/power/88pm860x_charger.c2
-rw-r--r--drivers/power/Kconfig7
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/act8945a_charger.c359
-rw-r--r--drivers/power/bq2415x_charger.c22
-rw-r--r--drivers/power/bq24735-charger.c146
-rw-r--r--drivers/power/bq27xxx_battery.c12
-rw-r--r--drivers/power/bq27xxx_battery_i2c.c61
-rw-r--r--drivers/power/collie_battery.c3
-rw-r--r--drivers/power/goldfish_battery.c17
-rw-r--r--drivers/power/ipaq_micro_battery.c4
-rw-r--r--drivers/power/isp1704_charger.c19
-rw-r--r--drivers/power/jz4740-battery.c2
-rw-r--r--drivers/power/lp8788-charger.c2
-rw-r--r--drivers/power/pm2301_charger.c22
-rw-r--r--drivers/power/power_supply_sysfs.c3
-rw-r--r--drivers/power/reset/Kconfig2
-rw-r--r--drivers/power/reset/arm-versatile-reboot.c39
-rw-r--r--drivers/powercap/intel_rapl.c220
-rw-r--r--drivers/ptp/ptp_chardev.c27
-rw-r--r--drivers/rapidio/rio.c8
-rw-r--r--drivers/regulator/Kconfig26
-rw-r--r--drivers/regulator/Makefile9
-rw-r--r--drivers/regulator/act8865-regulator.c8
-rw-r--r--drivers/regulator/act8945a-regulator.c165
-rw-r--r--drivers/regulator/ad5398.c6
-rw-r--r--drivers/regulator/axp20x-regulator.c56
-rw-r--r--drivers/regulator/core.c75
-rw-r--r--drivers/regulator/da9210-regulator.c5
-rw-r--r--drivers/regulator/fan53555.c18
-rw-r--r--drivers/regulator/gpio-regulator.c6
-rw-r--r--drivers/regulator/helpers.c23
-rw-r--r--drivers/regulator/hi655x-regulator.c227
-rw-r--r--drivers/regulator/lp872x.c38
-rw-r--r--drivers/regulator/ltc3589.c15
-rw-r--r--drivers/regulator/max77620-regulator.c813
-rw-r--r--drivers/regulator/max77686-regulator.c (renamed from drivers/regulator/max77686.c)0
-rw-r--r--drivers/regulator/max77802-regulator.c (renamed from drivers/regulator/max77802.c)0
-rw-r--r--drivers/regulator/mt6397-regulator.c15
-rw-r--r--drivers/regulator/of_regulator.c21
-rw-r--r--drivers/regulator/pv88060-regulator.c8
-rw-r--r--drivers/regulator/pv88090-regulator.c8
-rw-r--r--drivers/regulator/pwm-regulator.c29
-rw-r--r--drivers/regulator/s2mps11.c43
-rw-r--r--drivers/regulator/s5m8767.c13
-rw-r--r--drivers/regulator/vexpress-regulator.c (renamed from drivers/regulator/vexpress.c)0
-rw-r--r--drivers/remoteproc/Kconfig9
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/remoteproc_core.c4
-rw-r--r--drivers/remoteproc/remoteproc_debugfs.c36
-rw-r--r--drivers/remoteproc/st_remoteproc.c297
-rw-r--r--drivers/remoteproc/wkup_m3_rproc.c1
-rw-r--r--drivers/rtc/Kconfig252
-rw-r--r--drivers/rtc/Makefile5
-rw-r--r--drivers/rtc/class.c13
-rw-r--r--drivers/rtc/interface.c54
-rw-r--r--drivers/rtc/rtc-as3722.c2
-rw-r--r--drivers/rtc/rtc-asm9260.c355
-rw-r--r--drivers/rtc/rtc-ds1305.c4
-rw-r--r--drivers/rtc/rtc-ds1307.c411
-rw-r--r--drivers/rtc/rtc-ds1685.c9
-rw-r--r--drivers/rtc/rtc-ds3232.c476
-rw-r--r--drivers/rtc/rtc-ds3234.c171
-rw-r--r--drivers/rtc/rtc-generic.c12
-rw-r--r--drivers/rtc/rtc-hym8563.c2
-rw-r--r--drivers/rtc/rtc-max77686.c565
-rw-r--r--drivers/rtc/rtc-max77802.c502
-rw-r--r--drivers/rtc/rtc-mt6397.c1
-rw-r--r--drivers/rtc/rtc-palmas.c3
-rw-r--r--drivers/rtc/rtc-pcf2123.c271
-rw-r--r--drivers/rtc/rtc-pcf2127.c335
-rw-r--r--drivers/rtc/rtc-pcf85063.c162
-rw-r--r--drivers/rtc/rtc-pcf8523.c25
-rw-r--r--drivers/rtc/rtc-pic32.c411
-rw-r--r--drivers/rtc/rtc-rv3029c2.c723
-rw-r--r--drivers/rtc/rtc-rv8803.c39
-rw-r--r--drivers/rtc/rtc-rx6110.c402
-rw-r--r--drivers/rtc/rtc-rx8025.c25
-rw-r--r--drivers/rtc/rtc-s5m.c8
-rw-r--r--drivers/rtc/rtc-sysfs.c35
-rw-r--r--drivers/rtc/rtc-tps6586x.c2
-rw-r--r--drivers/rtc/rtc-tps65910.c2
-rw-r--r--drivers/rtc/rtc-tps80031.c2
-rw-r--r--drivers/rtc/rtc-vr41xx.c13
-rw-r--r--drivers/s390/block/dasd.c1
-rw-r--r--drivers/s390/block/dasd_alias.c313
-rw-r--r--drivers/s390/block/dasd_devmap.c10
-rw-r--r--drivers/s390/block/dasd_diag.c78
-rw-r--r--drivers/s390/block/dasd_eckd.c311
-rw-r--r--drivers/s390/block/dasd_fba.c28
-rw-r--r--drivers/s390/block/dasd_genhd.c4
-rw-r--r--drivers/s390/block/dasd_int.h9
-rw-r--r--drivers/s390/block/dasd_ioctl.c38
-rw-r--r--drivers/s390/block/dasd_proc.c5
-rw-r--r--drivers/s390/block/dcssblk.c13
-rw-r--r--drivers/s390/char/con3215.c3
-rw-r--r--drivers/s390/char/monreader.c10
-rw-r--r--drivers/s390/char/sclp_cmd.c27
-rw-r--r--drivers/s390/char/sclp_cpi_sys.c6
-rw-r--r--drivers/s390/char/tape_core.c4
-rw-r--r--drivers/s390/char/vmlogrdr.c6
-rw-r--r--drivers/s390/cio/blacklist.c9
-rw-r--r--drivers/s390/cio/ccwreq.c13
-rw-r--r--drivers/s390/cio/cio.c2
-rw-r--r--drivers/s390/cio/device.c23
-rw-r--r--drivers/s390/net/lcs.c4
-rw-r--r--drivers/s390/net/qeth_l3_main.c2
-rw-r--r--drivers/scsi/Kconfig1
-rw-r--r--drivers/scsi/NCR5380.c133
-rw-r--r--drivers/scsi/aacraid/aachba.c27
-rw-r--r--drivers/scsi/aacraid/aacraid.h14
-rw-r--r--drivers/scsi/aacraid/commctrl.c13
-rw-r--r--drivers/scsi/aacraid/comminit.c6
-rw-r--r--drivers/scsi/aacraid/commsup.c69
-rw-r--r--drivers/scsi/aacraid/dpcsup.c2
-rw-r--r--drivers/scsi/aacraid/linit.c199
-rw-r--r--drivers/scsi/aacraid/src.c30
-rw-r--r--drivers/scsi/aha1542.c3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c1
-rw-r--r--drivers/scsi/arm/acornscsi.c3
-rw-r--r--drivers/scsi/arm/fas216.c2
-rw-r--r--drivers/scsi/atari_NCR5380.c133
-rw-r--r--drivers/scsi/be2iscsi/be.h20
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c867
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h148
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c62
-rw-r--r--drivers/scsi/be2iscsi/be_main.c313
-rw-r--r--drivers/scsi/be2iscsi/be_main.h25
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c573
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h2
-rw-r--r--drivers/scsi/bfa/bfa_core.c19
-rw-r--r--drivers/scsi/bfa/bfa_cs.h41
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c2
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c9
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c5
-rw-r--r--drivers/scsi/cxlflash/common.h8
-rw-r--r--drivers/scsi/cxlflash/main.c72
-rw-r--r--drivers/scsi/cxlflash/superpipe.c195
-rw-r--r--drivers/scsi/cxlflash/superpipe.h1
-rw-r--r--drivers/scsi/device_handler/Kconfig8
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c979
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c7
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c38
-rw-r--r--drivers/scsi/dpt_i2o.c3
-rw-r--r--drivers/scsi/esas2r/esas2r_ioctl.c5
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c3
-rw-r--r--drivers/scsi/fdomain.c2
-rw-r--r--drivers/scsi/gdth.c7
-rw-r--r--drivers/scsi/gdth_proc.c11
-rw-r--r--drivers/scsi/hisi_sas/Makefile2
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h43
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c136
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v1_hw.c100
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c2214
-rw-r--r--drivers/scsi/hosts.c22
-rw-r--r--drivers/scsi/hpsa.c52
-rw-r--r--drivers/scsi/hpsa.h3
-rw-r--r--drivers/scsi/hpsa_cmd.h5
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c3
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c122
-rw-r--r--drivers/scsi/ibmvscsi/viosrp.h26
-rw-r--r--drivers/scsi/imm.c7
-rw-r--r--drivers/scsi/ipr.c5
-rw-r--r--drivers/scsi/iscsi_boot_sysfs.c5
-rw-r--r--drivers/scsi/iscsi_tcp.c54
-rw-r--r--drivers/scsi/iscsi_tcp.h4
-rw-r--r--drivers/scsi/libiscsi_tcp.c29
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c17
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c43
-rw-r--r--drivers/scsi/mac53c94.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h351
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c1064
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c1287
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h136
-rw-r--r--drivers/scsi/mesh.c2
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2.h82
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h127
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_init.h22
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_ioc.h117
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_raid.h5
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_sas.h10
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_tool.h5
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_type.h5
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c153
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h47
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c37
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c272
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c25
-rw-r--r--drivers/scsi/mvumi.c4
-rw-r--r--drivers/scsi/osd/osd_initiator.c3
-rw-r--r--drivers/scsi/ppa.c46
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c22
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c201
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h34
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c146
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h56
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h14
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c119
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c27
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c10
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c70
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.c6
-rw-r--r--drivers/scsi/qlogicpti.c4
-rw-r--r--drivers/scsi/scsi_devinfo.c3
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/scsi_scan.c23
-rw-r--r--drivers/scsi/scsi_sysfs.c112
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c2
-rw-r--r--drivers/scsi/sd.c2
-rw-r--r--drivers/scsi/sg.c3
-rw-r--r--drivers/scsi/sim710.c3
-rw-r--r--drivers/scsi/snic/snic_ctl.c2
-rw-r--r--drivers/scsi/st.c122
-rw-r--r--drivers/scsi/stex.c153
-rw-r--r--drivers/scsi/storvsc_drv.c5
-rw-r--r--drivers/scsi/ufs/ufs.h2
-rw-r--r--drivers/scsi/ufs/ufshcd.c397
-rw-r--r--drivers/scsi/ufs/ufshcd.h6
-rw-r--r--drivers/sh/pm_runtime.c2
-rw-r--r--drivers/sh/superhyway/superhyway.c2
-rw-r--r--drivers/spi/Kconfig96
-rw-r--r--drivers/spi/Makefile5
-rw-r--r--drivers/spi/spi-atmel.c1
-rw-r--r--drivers/spi/spi-axi-spi-engine.c591
-rw-r--r--drivers/spi/spi-bcm2835.c5
-rw-r--r--drivers/spi/spi-bcm2835aux.c76
-rw-r--r--drivers/spi/spi-dw-mid.c4
-rw-r--r--drivers/spi/spi-dw-mmio.c5
-rw-r--r--drivers/spi/spi-fsl-espi.c4
-rw-r--r--drivers/spi/spi-imx.c352
-rw-r--r--drivers/spi/spi-loopback-test.c1
-rw-r--r--drivers/spi/spi-lp8841-rtc.c256
-rw-r--r--drivers/spi/spi-omap2-mcspi.c3
-rw-r--r--drivers/spi/spi-pl022.c7
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c8
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c13
-rw-r--r--drivers/spi/spi-pxa2xx.c151
-rw-r--r--drivers/spi/spi-pxa2xx.h37
-rw-r--r--drivers/spi/spi-rockchip.c71
-rw-r--r--drivers/spi/spi-ti-qspi.c139
-rw-r--r--drivers/spi/spi.c426
-rw-r--r--drivers/spmi/spmi-pmic-arb.c153
-rw-r--r--drivers/ssb/Kconfig1
-rw-r--r--drivers/staging/dgap/dgap.c36
-rw-r--r--drivers/staging/dgnc/dgnc_tty.c20
-rw-r--r--drivers/staging/goldfish/goldfish_audio.c8
-rw-r--r--drivers/staging/goldfish/goldfish_nand.c50
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c92
-rw-r--r--drivers/staging/media/Kconfig8
-rw-r--r--drivers/staging/media/Makefile5
-rw-r--r--drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h2
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c2
-rw-r--r--drivers/staging/media/lirc/lirc_parallel.c24
-rw-r--r--drivers/staging/media/lirc/lirc_zilog.c4
-rw-r--r--drivers/staging/media/mn88473/Kconfig7
-rw-r--r--drivers/staging/media/mn88473/Makefile5
-rw-r--r--drivers/staging/media/mn88473/TODO21
-rw-r--r--drivers/staging/media/mx2/Kconfig15
-rw-r--r--drivers/staging/media/mx2/Makefile3
-rw-r--r--drivers/staging/media/mx2/TODO10
-rw-r--r--drivers/staging/media/mx2/mx2_camera.c (renamed from drivers/media/platform/soc_camera/mx2_camera.c)0
-rw-r--r--drivers/staging/media/mx3/Kconfig15
-rw-r--r--drivers/staging/media/mx3/Makefile3
-rw-r--r--drivers/staging/media/mx3/TODO10
-rw-r--r--drivers/staging/media/mx3/mx3_camera.c (renamed from drivers/media/platform/soc_camera/mx3_camera.c)12
-rw-r--r--drivers/staging/media/omap1/Kconfig13
-rw-r--r--drivers/staging/media/omap1/Makefile3
-rw-r--r--drivers/staging/media/omap1/TODO8
-rw-r--r--drivers/staging/media/omap1/omap1_camera.c (renamed from drivers/media/platform/soc_camera/omap1_camera.c)0
-rw-r--r--drivers/staging/media/omap4iss/iss.c211
-rw-r--r--drivers/staging/media/omap4iss/iss.h6
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c15
-rw-r--r--drivers/staging/media/omap4iss/iss_video.h1
-rw-r--r--drivers/staging/media/timb/Kconfig11
-rw-r--r--drivers/staging/media/timb/Makefile1
-rw-r--r--drivers/staging/media/timb/timblogiw.c (renamed from drivers/media/platform/timblogiw.c)0
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_tkip.c99
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_wep.c48
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c92
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c46
-rw-r--r--drivers/target/iscsi/iscsi_target.c86
-rw-r--r--drivers/target/iscsi/iscsi_target_auth.c98
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c75
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c45
-rw-r--r--drivers/target/target_core_configfs.c203
-rw-r--r--drivers/target/target_core_fabric_configfs.c194
-rw-r--r--drivers/target/target_core_internal.h1
-rw-r--r--drivers/target/target_core_stat.c41
-rw-r--r--drivers/target/target_core_tmr.c1
-rw-r--r--drivers/tty/Kconfig2
-rw-r--r--drivers/tty/amiserial.c28
-rw-r--r--drivers/tty/cyclades.c22
-rw-r--r--drivers/tty/ehv_bytechan.c40
-rw-r--r--drivers/tty/goldfish.c42
-rw-r--r--drivers/tty/hvc/hvc_vio.c29
-rw-r--r--drivers/tty/hvc/hvc_xen.c6
-rw-r--r--drivers/tty/isicom.c3
-rw-r--r--drivers/tty/mxser.c21
-rw-r--r--drivers/tty/n_gsm.c22
-rw-r--r--drivers/tty/n_hdlc.c19
-rw-r--r--drivers/tty/n_tty.c117
-rw-r--r--drivers/tty/nozomi.c2
-rw-r--r--drivers/tty/pty.c30
-rw-r--r--drivers/tty/rocket.c18
-rw-r--r--drivers/tty/rocket_int.h1
-rw-r--r--drivers/tty/serial/68328serial.c1322
-rw-r--r--drivers/tty/serial/8250/8250.h14
-rw-r--r--drivers/tty/serial/8250/8250_accent.c13
-rw-r--r--drivers/tty/serial/8250/8250_acorn.c2
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c146
-rw-r--r--drivers/tty/serial/8250/8250_boca.c41
-rw-r--r--drivers/tty/serial/8250/8250_core.c30
-rw-r--r--drivers/tty/serial/8250/8250_dw.c137
-rw-r--r--drivers/tty/serial/8250/8250_early.c38
-rw-r--r--drivers/tty/serial/8250/8250_exar_st16c554.c17
-rw-r--r--drivers/tty/serial/8250/8250_fourport.c28
-rw-r--r--drivers/tty/serial/8250/8250_gsc.c7
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c27
-rw-r--r--drivers/tty/serial/8250/8250_hub6.c2
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c14
-rw-r--r--drivers/tty/serial/8250/8250_moxa.c157
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c51
-rw-r--r--drivers/tty/serial/8250/8250_of.c1
-rw-r--r--drivers/tty/serial/8250/8250_omap.c40
-rw-r--r--drivers/tty/serial/8250/8250_pci.c147
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c48
-rw-r--r--drivers/tty/serial/8250/8250_port.c462
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c2
-rw-r--r--drivers/tty/serial/8250/Kconfig51
-rw-r--r--drivers/tty/serial/8250/Makefile2
-rw-r--r--drivers/tty/serial/8250/serial_cs.c90
-rw-r--r--drivers/tty/serial/Kconfig42
-rw-r--r--drivers/tty/serial/Makefile2
-rw-r--r--drivers/tty/serial/amba-pl011.c24
-rw-r--r--drivers/tty/serial/arc_uart.c1
-rw-r--r--drivers/tty/serial/atmel_serial.c180
-rw-r--r--drivers/tty/serial/clps711x.c10
-rw-r--r--drivers/tty/serial/crisv10.c33
-rw-r--r--drivers/tty/serial/digicolor-usart.c9
-rw-r--r--drivers/tty/serial/earlycon.c118
-rw-r--r--drivers/tty/serial/ifx6x60.c3
-rw-r--r--drivers/tty/serial/imx.c5
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c13
-rw-r--r--drivers/tty/serial/m32r_sio.c134
-rw-r--r--drivers/tty/serial/m32r_sio.h49
-rw-r--r--drivers/tty/serial/meson_uart.c8
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c8
-rw-r--r--drivers/tty/serial/mpsc.c178
-rw-r--r--drivers/tty/serial/msm_serial.c2
-rw-r--r--drivers/tty/serial/mvebu-uart.c650
-rw-r--r--drivers/tty/serial/omap-serial.c2
-rw-r--r--drivers/tty/serial/samsung.c24
-rw-r--r--drivers/tty/serial/sc16is7xx.c24
-rw-r--r--drivers/tty/serial/serial_core.c125
-rw-r--r--drivers/tty/serial/serial_ks8695.c2
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c3
-rw-r--r--drivers/tty/serial/sh-sci.c178
-rw-r--r--drivers/tty/serial/sh-sci.h15
-rw-r--r--drivers/tty/serial/sprd_serial.c2
-rw-r--r--drivers/tty/serial/uartlite.c61
-rw-r--r--drivers/tty/serial/xilinx_uartps.c543
-rw-r--r--drivers/tty/serial/zs.c4
-rw-r--r--drivers/tty/synclink.c23
-rw-r--r--drivers/tty/synclink_gt.c19
-rw-r--r--drivers/tty/synclinkmp.c63
-rw-r--r--drivers/tty/tty_audit.c237
-rw-r--r--drivers/tty/tty_buffer.c39
-rw-r--r--drivers/tty/tty_io.c267
-rw-r--r--drivers/tty/tty_ioctl.c12
-rw-r--r--drivers/tty/tty_ldisc.c198
-rw-r--r--drivers/tty/tty_mutex.c8
-rw-r--r--drivers/tty/tty_port.c11
-rw-r--r--drivers/tty/vt/keyboard.c14
-rw-r--r--drivers/tty/vt/selection.c2
-rw-r--r--drivers/tty/vt/vt.c2
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/atm/cxacru.c2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c13
-rw-r--r--drivers/usb/chipidea/ci_hdrc_pci.c4
-rw-r--r--drivers/usb/chipidea/core.c3
-rw-r--r--drivers/usb/chipidea/debug.c8
-rw-r--r--drivers/usb/chipidea/otg.c2
-rw-r--r--drivers/usb/chipidea/otg_fsm.c29
-rw-r--r--drivers/usb/chipidea/otg_fsm.h2
-rw-r--r--drivers/usb/chipidea/udc.c4
-rw-r--r--drivers/usb/class/cdc-acm.c67
-rw-r--r--drivers/usb/class/cdc-acm.h1
-rw-r--r--drivers/usb/class/usbtmc.c331
-rw-r--r--drivers/usb/common/common.c1
-rw-r--r--drivers/usb/common/usb-otg-fsm.c87
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/buffer.c18
-rw-r--r--drivers/usb/core/config.c37
-rw-r--r--drivers/usb/core/devices.c26
-rw-r--r--drivers/usb/core/devio.c301
-rw-r--r--drivers/usb/core/file.c9
-rw-r--r--drivers/usb/core/hcd-pci.c3
-rw-r--r--drivers/usb/core/hcd.c114
-rw-r--r--drivers/usb/core/hub.c130
-rw-r--r--drivers/usb/core/hub.h7
-rw-r--r--drivers/usb/core/of.c47
-rw-r--r--drivers/usb/core/sysfs.c68
-rw-r--r--drivers/usb/core/urb.c3
-rw-r--r--drivers/usb/core/usb.c15
-rw-r--r--drivers/usb/core/usb.h2
-rw-r--r--drivers/usb/dwc2/Kconfig2
-rw-r--r--drivers/usb/dwc2/core.c1890
-rw-r--r--drivers/usb/dwc2/core.h151
-rw-r--r--drivers/usb/dwc2/gadget.c102
-rw-r--r--drivers/usb/dwc2/hcd.c2255
-rw-r--r--drivers/usb/dwc2/hcd.h134
-rw-r--r--drivers/usb/dwc2/hcd_ddma.c64
-rw-r--r--drivers/usb/dwc2/hcd_intr.c182
-rw-r--r--drivers/usb/dwc2/hcd_queue.c1941
-rw-r--r--drivers/usb/dwc2/platform.c38
-rw-r--r--drivers/usb/dwc3/core.c31
-rw-r--r--drivers/usb/dwc3/core.h12
-rw-r--r--drivers/usb/dwc3/ep0.c14
-rw-r--r--drivers/usb/dwc3/gadget.c100
-rw-r--r--drivers/usb/gadget/composite.c150
-rw-r--r--drivers/usb/gadget/config.c9
-rw-r--r--drivers/usb/gadget/configfs.c37
-rw-r--r--drivers/usb/gadget/function/f_acm.c6
-rw-r--r--drivers/usb/gadget/function/f_ecm.c2
-rw-r--r--drivers/usb/gadget/function/f_eem.c2
-rw-r--r--drivers/usb/gadget/function/f_fs.c155
-rw-r--r--drivers/usb/gadget/function/f_hid.c2
-rw-r--r--drivers/usb/gadget/function/f_loopback.c2
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c8
-rw-r--r--drivers/usb/gadget/function/f_midi.c200
-rw-r--r--drivers/usb/gadget/function/f_ncm.c2
-rw-r--r--drivers/usb/gadget/function/f_obex.c3
-rw-r--r--drivers/usb/gadget/function/f_phonet.c2
-rw-r--r--drivers/usb/gadget/function/f_printer.c2
-rw-r--r--drivers/usb/gadget/function/f_rndis.c7
-rw-r--r--drivers/usb/gadget/function/f_serial.c2
-rw-r--r--drivers/usb/gadget/function/f_sourcesink.c2
-rw-r--r--drivers/usb/gadget/function/f_subset.c2
-rw-r--r--drivers/usb/gadget/function/f_tcm.c2
-rw-r--r--drivers/usb/gadget/function/f_uac1.c3
-rw-r--r--drivers/usb/gadget/function/f_uac2.c3
-rw-r--r--drivers/usb/gadget/function/rndis.c20
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c198
-rw-r--r--drivers/usb/gadget/legacy/inode.c35
-rw-r--r--drivers/usb/gadget/udc/Kconfig7
-rw-r--r--drivers/usb/gadget/udc/amd5536udc.c2
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_udc.c5
-rw-r--r--drivers/usb/gadget/udc/fsl_qe_udc.c2
-rw-r--r--drivers/usb/gadget/udc/goku_udc.c2
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c103
-rw-r--r--drivers/usb/gadget/udc/net2280.c8
-rw-r--r--drivers/usb/gadget/udc/net2280.h15
-rw-r--r--drivers/usb/gadget/udc/pch_udc.c8
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.c530
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.h11
-rw-r--r--drivers/usb/gadget/udc/udc-core.c33
-rw-r--r--drivers/usb/host/Kconfig18
-rw-r--r--drivers/usb/host/Makefile3
-rw-r--r--drivers/usb/host/bcma-hcd.c83
-rw-r--r--drivers/usb/host/ehci-atmel.c6
-rw-r--r--drivers/usb/host/ehci-dbg.c477
-rw-r--r--drivers/usb/host/ehci-fsl.c24
-rw-r--r--drivers/usb/host/ehci-hcd.c22
-rw-r--r--drivers/usb/host/ehci-hub.c6
-rw-r--r--drivers/usb/host/ehci-msm.c66
-rw-r--r--drivers/usb/host/ehci-pci.c8
-rw-r--r--drivers/usb/host/ehci-platform.c6
-rw-r--r--drivers/usb/host/ehci-q.c104
-rw-r--r--drivers/usb/host/ehci-sched.c524
-rw-r--r--drivers/usb/host/ehci-st.c6
-rw-r--r--drivers/usb/host/ehci-timer.c5
-rw-r--r--drivers/usb/host/ehci.h99
-rw-r--r--drivers/usb/host/fotg210-hcd.c15
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c7
-rw-r--r--drivers/usb/host/max3421-hcd.c16
-rw-r--r--drivers/usb/host/ohci-at91.c8
-rw-r--r--drivers/usb/host/ohci-nxp.c87
-rw-r--r--drivers/usb/host/ohci-platform.c6
-rw-r--r--drivers/usb/host/ohci-pxa27x.c2
-rw-r--r--drivers/usb/host/ohci-st.c6
-rw-r--r--drivers/usb/host/ohci.h2
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c15
-rw-r--r--drivers/usb/host/pci-quirks.c3
-rw-r--r--drivers/usb/host/r8a66597-hcd.c11
-rw-r--r--drivers/usb/host/u132-hcd.c18
-rw-r--r--drivers/usb/host/xhci-hub.c27
-rw-r--r--drivers/usb/host/xhci-mem.c180
-rw-r--r--drivers/usb/host/xhci-mtk.c10
-rw-r--r--drivers/usb/host/xhci-plat.c6
-rw-r--r--drivers/usb/host/xhci-ring.c134
-rw-r--r--drivers/usb/host/xhci.c8
-rw-r--r--drivers/usb/host/xhci.h15
-rw-r--r--drivers/usb/misc/chaoskey.c122
-rw-r--r--drivers/usb/misc/idmouse.c2
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c1543
-rw-r--r--drivers/usb/mon/mon_main.c9
-rw-r--r--drivers/usb/musb/Kconfig2
-rw-r--r--drivers/usb/musb/musb_core.c2
-rw-r--r--drivers/usb/musb/musb_core.h2
-rw-r--r--drivers/usb/musb/musb_host.c8
-rw-r--r--drivers/usb/musb/musbhsdma.c8
-rw-r--r--drivers/usb/musb/sunxi.c1
-rw-r--r--drivers/usb/musb/tusb6010_omap.c4
-rw-r--r--drivers/usb/musb/ux500_dma.c3
-rw-r--r--drivers/usb/phy/phy-am335x.c1
-rw-r--r--drivers/usb/phy/phy-generic.c11
-rw-r--r--drivers/usb/phy/phy-isp1301-omap.c2
-rw-r--r--drivers/usb/phy/phy-msm-usb.c20
-rw-r--r--drivers/usb/renesas_usbhs/Kconfig2
-rw-r--r--drivers/usb/renesas_usbhs/Makefile2
-rw-r--r--drivers/usb/renesas_usbhs/common.c14
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c20
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h20
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c2
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c6
-rw-r--r--drivers/usb/renesas_usbhs/pipe.h2
-rw-r--r--drivers/usb/renesas_usbhs/rcar3.c54
-rw-r--r--drivers/usb/renesas_usbhs/rcar3.h3
-rw-r--r--drivers/usb/serial/Kconfig16
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/ch341.c2
-rw-r--r--drivers/usb/serial/console.c6
-rw-r--r--drivers/usb/serial/cp210x.c309
-rw-r--r--drivers/usb/serial/cyberjack.c3
-rw-r--r--drivers/usb/serial/cypress_m8.c3
-rw-r--r--drivers/usb/serial/digi_acceleport.c8
-rw-r--r--drivers/usb/serial/ftdi_sio.c10
-rw-r--r--drivers/usb/serial/ftdi_sio.h8
-rw-r--r--drivers/usb/serial/garmin_gps.c51
-rw-r--r--drivers/usb/serial/io_edgeport.c4
-rw-r--r--drivers/usb/serial/iuu_phoenix.c4
-rw-r--r--drivers/usb/serial/keyspan.c2
-rw-r--r--drivers/usb/serial/kl5kusb105.c3
-rw-r--r--drivers/usb/serial/mct_u232.c2
-rw-r--r--drivers/usb/serial/mos7720.c4
-rw-r--r--drivers/usb/serial/mos7840.c8
-rw-r--r--drivers/usb/serial/mxu11x0.c1006
-rw-r--r--drivers/usb/serial/option.c14
-rw-r--r--drivers/usb/serial/qcserial.c7
-rw-r--r--drivers/usb/serial/quatech2.c2
-rw-r--r--drivers/usb/serial/safe_serial.c11
-rw-r--r--drivers/usb/storage/debug.c12
-rw-r--r--drivers/usb/storage/debug.h3
-rw-r--r--drivers/usb/storage/ene_ub6250.c4
-rw-r--r--drivers/usb/storage/sddr09.c18
-rw-r--r--drivers/usb/storage/uas.c36
-rw-r--r--drivers/usb/usbip/usbip_event.c5
-rw-r--r--drivers/usb/usbip/usbip_protocol.txt358
-rw-r--r--drivers/usb/usbip/vhci_hcd.c88
-rw-r--r--drivers/usb/usbip/vhci_rx.c30
-rw-r--r--drivers/usb/usbip/vhci_sysfs.c19
-rw-r--r--drivers/usb/usbip/vhci_tx.c14
-rw-r--r--drivers/usb/wusbcore/crypto.c30
-rw-r--r--drivers/usb/wusbcore/wusbhc.h2
-rw-r--r--drivers/vfio/pci/Kconfig4
-rw-r--r--drivers/vfio/pci/Makefile1
-rw-r--r--drivers/vfio/pci/vfio_pci.c184
-rw-r--r--drivers/vfio/pci/vfio_pci_config.c45
-rw-r--r--drivers/vfio/pci/vfio_pci_igd.c280
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c17
-rw-r--r--drivers/vfio/pci/vfio_pci_private.h39
-rw-r--r--drivers/vfio/pci/vfio_pci_rdwr.c9
-rw-r--r--drivers/vfio/platform/vfio_platform_common.c9
-rw-r--r--drivers/vfio/vfio.c70
-rw-r--r--drivers/vfio/vfio_iommu_type1.c6
-rw-r--r--drivers/vhost/vhost.c15
-rw-r--r--drivers/video/console/fbcon.c2
-rw-r--r--drivers/video/fbdev/Kconfig7
-rw-r--r--drivers/video/fbdev/acornfb.c4
-rw-r--r--drivers/video/fbdev/amba-clcd-versatile.c14
-rw-r--r--drivers/video/fbdev/amba-clcd.c4
-rw-r--r--drivers/video/fbdev/atafb.c3
-rw-r--r--drivers/video/fbdev/atmel_lcdfb.c9
-rw-r--r--drivers/video/fbdev/aty/aty128fb.c1
-rw-r--r--drivers/video/fbdev/aty/radeon_base.c1
-rw-r--r--drivers/video/fbdev/au1100fb.c22
-rw-r--r--drivers/video/fbdev/bf537-lq035.c23
-rw-r--r--drivers/video/fbdev/bt431.h43
-rw-r--r--drivers/video/fbdev/bt455.h68
-rw-r--r--drivers/video/fbdev/da8xx-fb.c7
-rw-r--r--drivers/video/fbdev/ep93xx-fb.c8
-rw-r--r--drivers/video/fbdev/exynos/Kconfig6
-rw-r--r--drivers/video/fbdev/exynos/Makefile6
-rw-r--r--drivers/video/fbdev/exynos/exynos_mipi_dsi.c7
-rw-r--r--drivers/video/fbdev/gbefb.c8
-rw-r--r--drivers/video/fbdev/imsttfb.c1
-rw-r--r--drivers/video/fbdev/imxfb.c12
-rw-r--r--drivers/video/fbdev/intelfb/intelfbdrv.c2
-rw-r--r--drivers/video/fbdev/matrox/matroxfb_base.h1
-rw-r--r--drivers/video/fbdev/metronomefb.c6
-rw-r--r--drivers/video/fbdev/mx3fb.c9
-rw-r--r--drivers/video/fbdev/n411.c12
-rw-r--r--drivers/video/fbdev/nuc900fb.c8
-rw-r--r--drivers/video/fbdev/offb.c4
-rw-r--r--drivers/video/fbdev/omap/lcdc.c16
-rw-r--r--drivers/video/fbdev/omap/omapfb_main.c22
-rw-r--r--drivers/video/fbdev/pmag-aa-fb.c602
-rw-r--r--drivers/video/fbdev/pmag-ba-fb.c2
-rw-r--r--drivers/video/fbdev/pxa168fb.c8
-rw-r--r--drivers/video/fbdev/pxafb.c4
-rw-r--r--drivers/video/fbdev/s3c-fb.c7
-rw-r--r--drivers/video/fbdev/s3c2410fb.c8
-rw-r--r--drivers/video/fbdev/sa1100fb.c8
-rw-r--r--drivers/video/fbdev/sis/init301.c10
-rw-r--r--drivers/video/fbdev/skeletonfb.c17
-rw-r--r--drivers/video/fbdev/sunxvr1000.c42
-rw-r--r--drivers/video/fbdev/sunxvr2500.c39
-rw-r--r--drivers/video/fbdev/sunxvr500.c42
-rw-r--r--drivers/virtio/virtio_pci_common.c2
-rw-r--r--drivers/virtio/virtio_pci_modern.c2
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.c11
-rw-r--r--drivers/w1/masters/omap_hdq.c1
-rw-r--r--drivers/w1/w1.c1
-rw-r--r--drivers/watchdog/Kconfig26
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/mei_wdt.c724
-rw-r--r--drivers/watchdog/sun4v_wdt.c191
-rw-r--r--drivers/xen/Kconfig23
-rw-r--r--drivers/xen/balloon.c13
-rw-r--r--drivers/xen/events/events_2l.c5
-rw-r--r--drivers/xen/xen-pciback/pciback_ops.c9
-rw-r--r--drivers/xen/xen-scsiback.c80
-rw-r--r--drivers/xen/xenbus/xenbus_dev_frontend.c2
-rw-r--r--drivers/zorro/zorro-sysfs.c3
1865 files changed, 93160 insertions, 42478 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index cb648a49543a..edeb2d1d99be 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -43,6 +43,7 @@ acpi-y += pci_root.o pci_link.o pci_irq.o
acpi-y += acpi_lpss.o acpi_apd.o
acpi-y += acpi_platform.o
acpi-y += acpi_pnp.o
+acpi-$(CONFIG_ARM_AMBA) += acpi_amba.o
acpi-y += int340x_thermal.o
acpi-y += power.o
acpi-y += event.o
diff --git a/drivers/acpi/acpi_amba.c b/drivers/acpi/acpi_amba.c
new file mode 100644
index 000000000000..2a61b54ab968
--- /dev/null
+++ b/drivers/acpi/acpi_amba.c
@@ -0,0 +1,122 @@
+
+/*
+ * ACPI support for platform bus type.
+ *
+ * Copyright (C) 2015, Linaro Ltd
+ * Author: Graeme Gregory <graeme.gregory@linaro.org>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/amba/bus.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "internal.h"
+
+static const struct acpi_device_id amba_id_list[] = {
+ {"ARMH0061", 0}, /* PL061 GPIO Device */
+ {"", 0},
+};
+
+static void amba_register_dummy_clk(void)
+{
+ static struct clk *amba_dummy_clk;
+
+ /* If clock already registered */
+ if (amba_dummy_clk)
+ return;
+
+ amba_dummy_clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL,
+ CLK_IS_ROOT, 0);
+ clk_register_clkdev(amba_dummy_clk, "apb_pclk", NULL);
+}
+
+static int amba_handler_attach(struct acpi_device *adev,
+ const struct acpi_device_id *id)
+{
+ struct amba_device *dev;
+ struct resource_entry *rentry;
+ struct list_head resource_list;
+ bool address_found = false;
+ int irq_no = 0;
+ int ret;
+
+ /* If the ACPI node already has a physical device attached, skip it. */
+ if (adev->physical_node_count)
+ return 0;
+
+ dev = amba_device_alloc(dev_name(&adev->dev), 0, 0);
+ if (!dev) {
+ dev_err(&adev->dev, "%s(): amba_device_alloc() failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+ if (ret < 0)
+ goto err_free;
+
+ list_for_each_entry(rentry, &resource_list, node) {
+ switch (resource_type(rentry->res)) {
+ case IORESOURCE_MEM:
+ if (!address_found) {
+ dev->res = *rentry->res;
+ address_found = true;
+ }
+ break;
+ case IORESOURCE_IRQ:
+ if (irq_no < AMBA_NR_IRQS)
+ dev->irq[irq_no++] = rentry->res->start;
+ break;
+ default:
+ dev_warn(&adev->dev, "Invalid resource\n");
+ break;
+ }
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ /*
+ * If the ACPI node has a parent and that parent has a physical device
+ * attached to it, that physical device should be the parent of
+ * the amba device we are about to create.
+ */
+ if (adev->parent)
+ dev->dev.parent = acpi_get_first_physical_node(adev->parent);
+
+ ACPI_COMPANION_SET(&dev->dev, adev);
+
+ ret = amba_device_add(dev, &iomem_resource);
+ if (ret) {
+ dev_err(&adev->dev, "%s(): amba_device_add() failed (%d)\n",
+ __func__, ret);
+ goto err_free;
+ }
+
+ return 1;
+
+err_free:
+ amba_device_put(dev);
+ return ret;
+}
+
+static struct acpi_scan_handler amba_handler = {
+ .ids = amba_id_list,
+ .attach = amba_handler_attach,
+};
+
+void __init acpi_amba_init(void)
+{
+ amba_register_dummy_clk();
+ acpi_scan_add_handler(&amba_handler);
+}
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
index d507cf6deda0..d0aad06b3872 100644
--- a/drivers/acpi/acpi_apd.c
+++ b/drivers/acpi/acpi_apd.c
@@ -143,6 +143,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
/* Generic apd devices */
#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
{ "AMD0010", APD_ADDR(cz_i2c_desc) },
+ { "AMDI0010", APD_ADDR(cz_i2c_desc) },
{ "AMD0020", APD_ADDR(cz_uart_desc) },
{ "AMD0030", },
#endif
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 296b7a14893a..159f7f19abce 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -43,7 +43,6 @@ static const struct acpi_device_id forbidden_id_list[] = {
struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
{
struct platform_device *pdev = NULL;
- struct acpi_device *acpi_parent;
struct platform_device_info pdevinfo;
struct resource_entry *rentry;
struct list_head resource_list;
@@ -62,7 +61,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
if (count < 0) {
return NULL;
} else if (count > 0) {
- resources = kmalloc(count * sizeof(struct resource),
+ resources = kzalloc(count * sizeof(struct resource),
GFP_KERNEL);
if (!resources) {
dev_err(&adev->dev, "No memory for resources\n");
@@ -82,22 +81,8 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
* attached to it, that physical device should be the parent of the
* platform device we are about to create.
*/
- pdevinfo.parent = NULL;
- acpi_parent = adev->parent;
- if (acpi_parent) {
- struct acpi_device_physical_node *entry;
- struct list_head *list;
-
- mutex_lock(&acpi_parent->physical_node_lock);
- list = &acpi_parent->physical_node_list;
- if (!list_empty(list)) {
- entry = list_first_entry(list,
- struct acpi_device_physical_node,
- node);
- pdevinfo.parent = entry->dev;
- }
- mutex_unlock(&acpi_parent->physical_node_lock);
- }
+ pdevinfo.parent = adev->parent ?
+ acpi_get_first_physical_node(adev->parent) : NULL;
pdevinfo.name = dev_name(&adev->dev);
pdevinfo.id = -1;
pdevinfo.res = resources;
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 6979186dbd4b..b5e54f2da53d 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -514,7 +514,24 @@ static struct acpi_scan_handler processor_handler = {
},
};
+static int acpi_processor_container_attach(struct acpi_device *dev,
+ const struct acpi_device_id *id)
+{
+ return 1;
+}
+
+static const struct acpi_device_id processor_container_ids[] = {
+ { ACPI_PROCESSOR_CONTAINER_HID, },
+ { }
+};
+
+static struct acpi_scan_handler processor_container_handler = {
+ .ids = processor_container_ids,
+ .attach = acpi_processor_container_attach,
+};
+
void __init acpi_processor_init(void)
{
acpi_scan_add_handler_with_hotplug(&processor_handler, "processor");
+ acpi_scan_add_handler(&processor_container_handler);
}
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index a76f8be1bfe7..4361bc98ef4c 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -218,13 +218,6 @@ struct acpi_video_device {
struct thermal_cooling_device *cooling_dev;
};
-static const char device_decode[][30] = {
- "motherboard VGA device",
- "PCI VGA device",
- "AGP VGA device",
- "UNKNOWN",
-};
-
static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data);
static void acpi_video_device_rebind(struct acpi_video_bus *video);
static void acpi_video_device_bind(struct acpi_video_bus *video,
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 55c8197036f3..51b073b68f16 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -165,7 +165,7 @@ ACPI_GLOBAL(u8, acpi_gbl_next_owner_id_offset);
/* Initialization sequencing */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_reg_methods_enabled, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_namespace_initialized, FALSE);
/* Misc */
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index e4977fac9c1d..9562a10a1a18 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -85,7 +85,7 @@ union acpi_parse_object;
#define ACPI_MTX_MEMORY 5 /* Debug memory tracking lists */
#define ACPI_MAX_MUTEX 5
-#define ACPI_NUM_MUTEX ACPI_MAX_MUTEX+1
+#define ACPI_NUM_MUTEX (ACPI_MAX_MUTEX+1)
/* Lock structure for reader/writer interfaces */
@@ -103,11 +103,11 @@ struct acpi_rw_lock {
#define ACPI_LOCK_HARDWARE 1
#define ACPI_MAX_LOCK 1
-#define ACPI_NUM_LOCK ACPI_MAX_LOCK+1
+#define ACPI_NUM_LOCK (ACPI_MAX_LOCK+1)
/* This Thread ID means that the mutex is not in use (unlocked) */
-#define ACPI_MUTEX_NOT_ACQUIRED (acpi_thread_id) 0
+#define ACPI_MUTEX_NOT_ACQUIRED ((acpi_thread_id) 0)
/* This Thread ID means an invalid thread ID */
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 9684ed61284d..022d69cb345a 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -88,7 +88,7 @@
*/
acpi_status acpi_ns_initialize_objects(void);
-acpi_status acpi_ns_initialize_devices(void);
+acpi_status acpi_ns_initialize_devices(u32 flags);
/*
* nsload - Namespace loading
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 52f6bee52d47..5faeab41e302 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -1125,7 +1125,7 @@ const union acpi_predefined_info acpi_gbl_resource_names[] = {
PACKAGE_INFO(0, 0, 0, 0, 0, 0) /* Table terminator */
};
-static const union acpi_predefined_info acpi_gbl_scope_names[] = {
+const union acpi_predefined_info acpi_gbl_scope_names[] = {
{{"_GPE", 0, 0}},
{{"_PR_", 0, 0}},
{{"_SB_", 0, 0}},
diff --git a/drivers/acpi/acpica/dbcmds.c b/drivers/acpi/acpica/dbcmds.c
index 7ec62c461280..772178c96ccf 100644
--- a/drivers/acpi/acpica/dbcmds.c
+++ b/drivers/acpi/acpica/dbcmds.c
@@ -348,7 +348,7 @@ void acpi_db_display_table_info(char *table_arg)
} else {
/* If the pointer is null, the table has been unloaded */
- ACPI_INFO((AE_INFO, "%4.4s - Table has been unloaded",
+ ACPI_INFO(("%4.4s - Table has been unloaded",
table_desc->signature.ascii));
}
}
diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c
index 9fee88f1c654..68f4e0f4b095 100644
--- a/drivers/acpi/acpica/dbconvert.c
+++ b/drivers/acpi/acpica/dbconvert.c
@@ -408,7 +408,7 @@ void acpi_db_dump_pld_buffer(union acpi_object *obj_desc)
new_buffer = acpi_db_encode_pld_buffer(pld_info);
if (!new_buffer) {
- return;
+ goto exit;
}
/* The two bit-packed buffers should match */
@@ -479,6 +479,7 @@ void acpi_db_dump_pld_buffer(union acpi_object *obj_desc)
pld_info->horizontal_offset);
}
- ACPI_FREE(pld_info);
ACPI_FREE(new_buffer);
+exit:
+ ACPI_FREE(pld_info);
}
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 6a72047aae1c..1982310e6d83 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -809,8 +809,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
if (method_desc->method.
info_flags & ACPI_METHOD_SERIALIZED_PENDING) {
if (walk_state) {
- ACPI_INFO((AE_INFO,
- "Marking method %4.4s as Serialized "
+ ACPI_INFO(("Marking method %4.4s as Serialized "
"because of AE_ALREADY_EXISTS error",
walk_state->method_node->name.
ascii));
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index c303e9d9266f..a91de2b4603c 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -524,8 +524,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
arg = arg->common.next;
}
- ACPI_INFO((AE_INFO,
- "Actual Package length (%u) is larger than "
+ ACPI_INFO(("Actual Package length (%u) is larger than "
"NumElements field (%u), truncated",
i, element_count));
} else if (i < element_count) {
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 9275e626ed8d..447fa1cac64f 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -499,8 +499,7 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
}
if (gpe_enabled_count) {
- ACPI_INFO((AE_INFO,
- "Enabled %u GPEs in block %02X to %02X",
+ ACPI_INFO(("Enabled %u GPEs in block %02X to %02X",
gpe_enabled_count, (u32)gpe_block->block_base_number,
(u32)(gpe_block->block_base_number +
(gpe_block->gpe_count - 1))));
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 9fdd8d09141b..7dc75474c897 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -281,7 +281,7 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
}
if (walk_info.count) {
- ACPI_INFO((AE_INFO, "Enabled %u new GPEs", walk_info.count));
+ ACPI_INFO(("Enabled %u new GPEs", walk_info.count));
}
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 47092b4d633c..63924d1c737a 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -600,7 +600,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
if (region_obj2->extra.method_REG == NULL ||
region_obj->region.handler == NULL ||
- !acpi_gbl_reg_methods_enabled) {
+ !acpi_gbl_namespace_initialized) {
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 011df210b7b2..f74161301037 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -252,7 +252,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
status = acpi_get_table_by_index(table_index, &table);
if (ACPI_SUCCESS(status)) {
- ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:"));
+ ACPI_INFO(("Dynamic OEM Table Load:"));
acpi_tb_print_table_header(0, table);
}
@@ -472,7 +472,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Install the new table into the local data structures */
- ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:"));
+ ACPI_INFO(("Dynamic OEM Table Load:"));
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index 28eb861c44eb..5aa21c4eda1d 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -123,8 +123,10 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
* op is intended for use by disassemblers in order to properly
* disassemble control method invocations. The opcode or group of
* opcodes should be surrounded by an "if (0)" clause to ensure that
- * AML interpreters never see the opcode.
+ * AML interpreters never see the opcode. Thus, something is
+ * wrong if an external opcode ever gets here.
*/
+ ACPI_ERROR((AE_INFO, "Executed External Op"));
status = AE_OK;
goto cleanup;
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index 65d58bea4320..5d59cfcef6f4 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -378,8 +378,7 @@ void acpi_ns_exec_module_code_list(void)
acpi_ut_remove_reference(prev);
}
- ACPI_INFO((AE_INFO,
- "Executed %u blocks of module-level executable AML code",
+ ACPI_INFO(("Executed %u blocks of module-level executable AML code",
method_count));
ACPI_FREE(info);
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index bd75d46234a4..d4aa8b696ee9 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -46,6 +46,7 @@
#include "acnamesp.h"
#include "acdispat.h"
#include "acinterp.h"
+#include "acevents.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsinit")
@@ -83,6 +84,8 @@ acpi_status acpi_ns_initialize_objects(void)
ACPI_FUNCTION_TRACE(ns_initialize_objects);
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "[Init] Completing Initialization of ACPI Objects\n"));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
@@ -133,82 +136,108 @@ acpi_status acpi_ns_initialize_objects(void)
*
******************************************************************************/
-acpi_status acpi_ns_initialize_devices(void)
+acpi_status acpi_ns_initialize_devices(u32 flags)
{
- acpi_status status;
+ acpi_status status = AE_OK;
struct acpi_device_walk_info info;
ACPI_FUNCTION_TRACE(ns_initialize_devices);
- /* Init counters */
+ if (!(flags & ACPI_NO_DEVICE_INIT)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "[Init] Initializing ACPI Devices\n"));
- info.device_count = 0;
- info.num_STA = 0;
- info.num_INI = 0;
+ /* Init counters */
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "Initializing Device/Processor/Thermal objects "
- "and executing _INI/_STA methods:\n"));
+ info.device_count = 0;
+ info.num_STA = 0;
+ info.num_INI = 0;
- /* Tree analysis: find all subtrees that contain _INI methods */
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
+ "Initializing Device/Processor/Thermal objects "
+ "and executing _INI/_STA methods:\n"));
- status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, FALSE,
- acpi_ns_find_ini_methods, NULL, &info,
- NULL);
- if (ACPI_FAILURE(status)) {
- goto error_exit;
- }
+ /* Tree analysis: find all subtrees that contain _INI methods */
+
+ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, FALSE,
+ acpi_ns_find_ini_methods, NULL,
+ &info, NULL);
+ if (ACPI_FAILURE(status)) {
+ goto error_exit;
+ }
+
+ /* Allocate the evaluation information block */
- /* Allocate the evaluation information block */
+ info.evaluate_info =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info.evaluate_info) {
+ status = AE_NO_MEMORY;
+ goto error_exit;
+ }
- info.evaluate_info =
- ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
- if (!info.evaluate_info) {
- status = AE_NO_MEMORY;
- goto error_exit;
+ /*
+ * Execute the "global" _INI method that may appear at the root.
+ * This support is provided for Windows compatibility (Vista+) and
+ * is not part of the ACPI specification.
+ */
+ info.evaluate_info->prefix_node = acpi_gbl_root_node;
+ info.evaluate_info->relative_pathname = METHOD_NAME__INI;
+ info.evaluate_info->parameters = NULL;
+ info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE;
+
+ status = acpi_ns_evaluate(info.evaluate_info);
+ if (ACPI_SUCCESS(status)) {
+ info.num_INI++;
+ }
}
/*
- * Execute the "global" _INI method that may appear at the root. This
- * support is provided for Windows compatibility (Vista+) and is not
- * part of the ACPI specification.
+ * Run all _REG methods
+ *
+ * Note: Any objects accessed by the _REG methods will be automatically
+ * initialized, even if they contain executable AML (see the call to
+ * acpi_ns_initialize_objects below).
*/
- info.evaluate_info->prefix_node = acpi_gbl_root_node;
- info.evaluate_info->relative_pathname = METHOD_NAME__INI;
- info.evaluate_info->parameters = NULL;
- info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE;
+ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "[Init] Executing _REG OpRegion methods\n"));
- status = acpi_ns_evaluate(info.evaluate_info);
- if (ACPI_SUCCESS(status)) {
- info.num_INI++;
+ status = acpi_ev_initialize_op_regions();
+ if (ACPI_FAILURE(status)) {
+ goto error_exit;
+ }
}
- /* Walk namespace to execute all _INIs on present devices */
+ if (!(flags & ACPI_NO_DEVICE_INIT)) {
- status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, FALSE,
- acpi_ns_init_one_device, NULL, &info,
- NULL);
+ /* Walk namespace to execute all _INIs on present devices */
- /*
- * Any _OSI requests should be completed by now. If the BIOS has
- * requested any Windows OSI strings, we will always truncate
- * I/O addresses to 16 bits -- for Windows compatibility.
- */
- if (acpi_gbl_osi_data >= ACPI_OSI_WIN_2000) {
- acpi_gbl_truncate_io_addresses = TRUE;
- }
+ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, FALSE,
+ acpi_ns_init_one_device, NULL,
+ &info, NULL);
- ACPI_FREE(info.evaluate_info);
- if (ACPI_FAILURE(status)) {
- goto error_exit;
- }
+ /*
+ * Any _OSI requests should be completed by now. If the BIOS has
+ * requested any Windows OSI strings, we will always truncate
+ * I/O addresses to 16 bits -- for Windows compatibility.
+ */
+ if (acpi_gbl_osi_data >= ACPI_OSI_WIN_2000) {
+ acpi_gbl_truncate_io_addresses = TRUE;
+ }
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- " Executed %u _INI methods requiring %u _STA executions "
- "(examined %u objects)\n",
- info.num_INI, info.num_STA, info.device_count));
+ ACPI_FREE(info.evaluate_info);
+ if (ACPI_FAILURE(status)) {
+ goto error_exit;
+ }
+
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
+ " Executed %u _INI methods requiring %u _STA executions "
+ "(examined %u objects)\n",
+ info.num_INI, info.num_STA,
+ info.device_count));
+ }
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 305218539df2..d48cbed342c1 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -269,8 +269,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
*/
if (ACPI_SUCCESS(status) &&
possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
- if (GET_CURRENT_ARG_TYPE(walk_state->arg_types) ==
- ARGP_SUPERNAME) {
+ if (walk_state->opcode == AML_UNLOAD_OP) {
/*
* acpi_ps_get_next_namestring has increased the AML pointer,
* so we need to restore the saved AML pointer for method call.
@@ -697,7 +696,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
*
* PARAMETERS: walk_state - Current state
* parser_state - Current parser state object
- * arg_type - The parser argument type (ARGP_*)
+ * arg_type - The argument type (AML_*_ARG)
* return_arg - Where the next arg is returned
*
* RETURN: Status, and an op object containing the next argument.
@@ -817,9 +816,9 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NO_MEMORY);
}
- /* super_name allows argument to be a method call */
+ /* To support super_name arg of Unload */
- if (arg_type == ARGP_SUPERNAME) {
+ if (walk_state->opcode == AML_UNLOAD_OP) {
status =
acpi_ps_get_next_namepath(walk_state,
parser_state, arg,
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index b661a1e013fb..4dc6108de4ff 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -267,8 +267,7 @@ acpi_tb_install_standard_table(acpi_physical_address address,
if (!reload &&
acpi_gbl_disable_ssdt_table_install &&
ACPI_COMPARE_NAME(&new_table_desc.signature, ACPI_SIG_SSDT)) {
- ACPI_INFO((AE_INFO,
- "Ignoring installation of %4.4s at %8.8X%8.8X",
+ ACPI_INFO(("Ignoring installation of %4.4s at %8.8X%8.8X",
new_table_desc.signature.ascii,
ACPI_FORMAT_UINT64(address)));
goto release_and_exit;
@@ -432,7 +431,7 @@ finish_override:
return;
}
- ACPI_INFO((AE_INFO, "%4.4s 0x%8.8X%8.8X"
+ ACPI_INFO(("%4.4s 0x%8.8X%8.8X"
" %s table override, new table: 0x%8.8X%8.8X",
old_table_desc->signature.ascii,
ACPI_FORMAT_UINT64(old_table_desc->address),
diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c
index fd4146d4ff49..26d61dbace0a 100644
--- a/drivers/acpi/acpica/tbprint.c
+++ b/drivers/acpi/acpica/tbprint.c
@@ -132,7 +132,7 @@ acpi_tb_print_table_header(acpi_physical_address address,
/* FACS only has signature and length fields */
- ACPI_INFO((AE_INFO, "%-4.4s 0x%8.8X%8.8X %06X",
+ ACPI_INFO(("%-4.4s 0x%8.8X%8.8X %06X",
header->signature, ACPI_FORMAT_UINT64(address),
header->length));
} else if (ACPI_VALIDATE_RSDP_SIG(header->signature)) {
@@ -144,7 +144,7 @@ acpi_tb_print_table_header(acpi_physical_address address,
ACPI_OEM_ID_SIZE);
acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE);
- ACPI_INFO((AE_INFO, "RSDP 0x%8.8X%8.8X %06X (v%.2d %-6.6s)",
+ ACPI_INFO(("RSDP 0x%8.8X%8.8X %06X (v%.2d %-6.6s)",
ACPI_FORMAT_UINT64(address),
(ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
revision >
@@ -158,8 +158,7 @@ acpi_tb_print_table_header(acpi_physical_address address,
acpi_tb_cleanup_table_header(&local_header, header);
- ACPI_INFO((AE_INFO,
- "%-4.4s 0x%8.8X%8.8X"
+ ACPI_INFO(("%-4.4s 0x%8.8X%8.8X"
" %06X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)",
local_header.signature, ACPI_FORMAT_UINT64(address),
local_header.length, local_header.revision,
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 3269bef371d7..9240c76d2823 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -174,9 +174,7 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
new_table);
- ACPI_INFO((AE_INFO,
- "Forced DSDT copy: length 0x%05X copied locally, original unmapped",
- new_table->length));
+ ACPI_INFO(("Forced DSDT copy: length 0x%05X copied locally, original unmapped", new_table->length));
return (new_table);
}
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index 278666e39563..3151968c10d1 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -47,6 +47,7 @@
#include "accommon.h"
#include "acnamesp.h"
#include "actables.h"
+#include "acevents.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbxfload")
@@ -68,6 +69,25 @@ acpi_status __init acpi_load_tables(void)
ACPI_FUNCTION_TRACE(acpi_load_tables);
+ /*
+ * Install the default operation region handlers. These are the
+ * handlers that are defined by the ACPI specification to be
+ * "always accessible" -- namely, system_memory, system_IO, and
+ * PCI_Config. This also means that no _REG methods need to be
+ * run for these address spaces. We need to have these handlers
+ * installed before any AML code can be executed, especially any
+ * module-level code (11/2015).
+ * Note that we allow OSPMs to install their own region handlers
+ * between acpi_initialize_subsystem() and acpi_load_tables() to use
+ * their customized default region handlers.
+ */
+ status = acpi_ev_install_region_handlers();
+ if (ACPI_FAILURE(status) && status != AE_ALREADY_EXISTS) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During Region initialization"));
+ return_ACPI_STATUS(status);
+ }
+
/* Load the namespace from the tables */
status = acpi_tb_load_namespace();
@@ -83,6 +103,20 @@ acpi_status __init acpi_load_tables(void)
"While loading namespace from ACPI tables"));
}
+ if (!acpi_gbl_group_module_level_code) {
+ /*
+ * Initialize the objects that remain uninitialized. This
+ * runs the executable AML that may be part of the
+ * declaration of these objects:
+ * operation_regions, buffer_fields, Buffers, and Packages.
+ */
+ status = acpi_ns_initialize_objects();
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ acpi_gbl_namespace_initialized = TRUE;
return_ACPI_STATUS(status);
}
@@ -206,9 +240,7 @@ acpi_status acpi_tb_load_namespace(void)
}
if (!tables_failed) {
- ACPI_INFO((AE_INFO,
- "%u ACPI AML tables successfully acquired and loaded\n",
- tables_loaded));
+ ACPI_INFO(("%u ACPI AML tables successfully acquired and loaded\n", tables_loaded));
} else {
ACPI_ERROR((AE_INFO,
"%u table load failures, %u successful",
@@ -301,7 +333,7 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
/* Install the table and load it into the namespace */
- ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:"));
+ ACPI_INFO(("Host-directed Dynamic ACPI Table Load:"));
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),
diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c
index c9a720f2274a..f8e9978888e1 100644
--- a/drivers/acpi/acpica/utcache.c
+++ b/drivers/acpi/acpica/utcache.c
@@ -245,7 +245,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
acpi_status status;
void *object;
- ACPI_FUNCTION_NAME(os_acquire_object);
+ ACPI_FUNCTION_TRACE(os_acquire_object);
if (!cache) {
return_PTR(NULL);
diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c
index c427a5cda465..d5c3adf19bd0 100644
--- a/drivers/acpi/acpica/utnonansi.c
+++ b/drivers/acpi/acpica/utnonansi.c
@@ -140,6 +140,67 @@ int acpi_ut_stricmp(char *string1, char *string2)
return (c1 - c2);
}
+#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_safe_strcpy, acpi_ut_safe_strcat, acpi_ut_safe_strncat
+ *
+ * PARAMETERS: Adds a "DestSize" parameter to each of the standard string
+ * functions. This is the size of the Destination buffer.
+ *
+ * RETURN: TRUE if the operation would overflow the destination buffer.
+ *
+ * DESCRIPTION: Safe versions of standard Clib string functions. Ensure that
+ * the result of the operation will not overflow the output string
+ * buffer.
+ *
+ * NOTE: These functions are typically only helpful for processing
+ * user input and command lines. For most ACPICA code, the
+ * required buffer length is precisely calculated before buffer
+ * allocation, so the use of these functions is unnecessary.
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source)
+{
+
+ if (strlen(source) >= dest_size) {
+ return (TRUE);
+ }
+
+ strcpy(dest, source);
+ return (FALSE);
+}
+
+u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source)
+{
+
+ if ((strlen(dest) + strlen(source)) >= dest_size) {
+ return (TRUE);
+ }
+
+ strcat(dest, source);
+ return (FALSE);
+}
+
+u8
+acpi_ut_safe_strncat(char *dest,
+ acpi_size dest_size,
+ char *source, acpi_size max_transfer_length)
+{
+ acpi_size actual_transfer_length;
+
+ actual_transfer_length = ACPI_MIN(max_transfer_length, strlen(source));
+
+ if ((strlen(dest) + actual_transfer_length) >= dest_size) {
+ return (TRUE);
+ }
+
+ strncat(dest, source, max_transfer_length);
+ return (FALSE);
+}
+#endif
+
/*******************************************************************************
*
* FUNCTION: acpi_ut_strtoul64
@@ -155,7 +216,15 @@ int acpi_ut_stricmp(char *string1, char *string2)
* 32-bit or 64-bit conversion, depending on the current mode
* of the interpreter.
*
- * NOTE: Does not support Octal strings, not needed.
+ * NOTES: acpi_gbl_integer_byte_width should be set to the proper width.
+ * For the core ACPICA code, this width depends on the DSDT
+ * version. For iASL, the default byte width is always 8.
+ *
+ * Does not support Octal strings, not needed at this time.
+ *
+ * There is an earlier version of the function after this one,
+ * below. It is slightly different than this one, and the two
+ * may eventually may need to be merged. (01/2016).
*
******************************************************************************/
@@ -171,7 +240,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
u8 sign_of0x = 0;
u8 term = 0;
- ACPI_FUNCTION_TRACE_STR(ut_stroul64, string);
+ ACPI_FUNCTION_TRACE_STR(ut_strtoul64, string);
switch (base) {
case ACPI_ANY_BASE:
@@ -318,63 +387,162 @@ error_exit:
}
}
-#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION)
+#ifdef _OBSOLETE_FUNCTIONS
+/* TBD: use version in ACPICA main code base? */
+/* DONE: 01/2016 */
+
/*******************************************************************************
*
- * FUNCTION: acpi_ut_safe_strcpy, acpi_ut_safe_strcat, acpi_ut_safe_strncat
+ * FUNCTION: strtoul64
*
- * PARAMETERS: Adds a "DestSize" parameter to each of the standard string
- * functions. This is the size of the Destination buffer.
+ * PARAMETERS: string - Null terminated string
+ * terminater - Where a pointer to the terminating byte
+ * is returned
+ * base - Radix of the string
*
- * RETURN: TRUE if the operation would overflow the destination buffer.
+ * RETURN: Converted value
*
- * DESCRIPTION: Safe versions of standard Clib string functions. Ensure that
- * the result of the operation will not overflow the output string
- * buffer.
- *
- * NOTE: These functions are typically only helpful for processing
- * user input and command lines. For most ACPICA code, the
- * required buffer length is precisely calculated before buffer
- * allocation, so the use of these functions is unnecessary.
+ * DESCRIPTION: Convert a string into an unsigned value.
*
******************************************************************************/
-u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source)
+acpi_status strtoul64(char *string, u32 base, u64 *ret_integer)
{
+ u32 index;
+ u32 sign;
+ u64 return_value = 0;
+ acpi_status status = AE_OK;
- if (strlen(source) >= dest_size) {
- return (TRUE);
+ *ret_integer = 0;
+
+ switch (base) {
+ case 0:
+ case 8:
+ case 10:
+ case 16:
+
+ break;
+
+ default:
+ /*
+ * The specified Base parameter is not in the domain of
+ * this function:
+ */
+ return (AE_BAD_PARAMETER);
}
- strcpy(dest, source);
- return (FALSE);
-}
+ /* Skip over any white space in the buffer: */
-u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source)
-{
+ while (isspace((int)*string) || *string == '\t') {
+ ++string;
+ }
- if ((strlen(dest) + strlen(source)) >= dest_size) {
- return (TRUE);
+ /*
+ * The buffer may contain an optional plus or minus sign.
+ * If it does, then skip over it but remember what is was:
+ */
+ if (*string == '-') {
+ sign = ACPI_SIGN_NEGATIVE;
+ ++string;
+ } else if (*string == '+') {
+ ++string;
+ sign = ACPI_SIGN_POSITIVE;
+ } else {
+ sign = ACPI_SIGN_POSITIVE;
}
- strcat(dest, source);
- return (FALSE);
-}
+ /*
+ * If the input parameter Base is zero, then we need to
+ * determine if it is octal, decimal, or hexadecimal:
+ */
+ if (base == 0) {
+ if (*string == '0') {
+ if (tolower((int)*(++string)) == 'x') {
+ base = 16;
+ ++string;
+ } else {
+ base = 8;
+ }
+ } else {
+ base = 10;
+ }
+ }
-u8
-acpi_ut_safe_strncat(char *dest,
- acpi_size dest_size,
- char *source, acpi_size max_transfer_length)
-{
- acpi_size actual_transfer_length;
+ /*
+ * For octal and hexadecimal bases, skip over the leading
+ * 0 or 0x, if they are present.
+ */
+ if (base == 8 && *string == '0') {
+ string++;
+ }
- actual_transfer_length = ACPI_MIN(max_transfer_length, strlen(source));
+ if (base == 16 && *string == '0' && tolower((int)*(++string)) == 'x') {
+ string++;
+ }
- if ((strlen(dest) + actual_transfer_length) >= dest_size) {
- return (TRUE);
+ /* Main loop: convert the string to an unsigned long */
+
+ while (*string) {
+ if (isdigit((int)*string)) {
+ index = ((u8)*string) - '0';
+ } else {
+ index = (u8)toupper((int)*string);
+ if (isupper((int)index)) {
+ index = index - 'A' + 10;
+ } else {
+ goto error_exit;
+ }
+ }
+
+ if (index >= base) {
+ goto error_exit;
+ }
+
+ /* Check to see if value is out of range: */
+
+ if (return_value > ((ACPI_UINT64_MAX - (u64)index) / (u64)base)) {
+ goto error_exit;
+ } else {
+ return_value *= base;
+ return_value += index;
+ }
+
+ ++string;
}
- strncat(dest, source, max_transfer_length);
- return (FALSE);
+ /* If a minus sign was present, then "the conversion is negated": */
+
+ if (sign == ACPI_SIGN_NEGATIVE) {
+ return_value = (ACPI_UINT32_MAX - return_value) + 1;
+ }
+
+ *ret_integer = return_value;
+ return (status);
+
+error_exit:
+ switch (base) {
+ case 8:
+
+ status = AE_BAD_OCTAL_CONSTANT;
+ break;
+
+ case 10:
+
+ status = AE_BAD_DECIMAL_CONSTANT;
+ break;
+
+ case 16:
+
+ status = AE_BAD_HEX_CONSTANT;
+ break;
+
+ default:
+
+ /* Base validated above */
+
+ break;
+ }
+
+ return (status);
}
#endif
diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c
index c7c2bb8f3559..60c406a8efcb 100644
--- a/drivers/acpi/acpica/uttrack.c
+++ b/drivers/acpi/acpica/uttrack.c
@@ -712,7 +712,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
/* Print summary */
if (!num_outstanding) {
- ACPI_INFO((AE_INFO, "No outstanding allocations"));
+ ACPI_INFO(("No outstanding allocations"));
} else {
ACPI_ERROR((AE_INFO, "%u(0x%X) Outstanding allocations",
num_outstanding, num_outstanding));
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index 6fe59597b599..d9f15cbcd8a0 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -175,8 +175,7 @@ ACPI_EXPORT_SYMBOL(acpi_warning)
* TBD: module_name and line_number args are not needed, should be removed.
*
******************************************************************************/
-void ACPI_INTERNAL_VAR_XFACE
-acpi_info(const char *module_name, u32 line_number, const char *format, ...)
+void ACPI_INTERNAL_VAR_XFACE acpi_info(const char *format, ...)
{
va_list arg_list;
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index 721b87cce908..75b5f27da267 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -154,21 +154,6 @@ acpi_status __init acpi_enable_subsystem(u32 flags)
*/
acpi_gbl_early_initialization = FALSE;
- /*
- * Install the default operation region handlers. These are the
- * handlers that are defined by the ACPI specification to be
- * "always accessible" -- namely, system_memory, system_IO, and
- * PCI_Config. This also means that no _REG methods need to be
- * run for these address spaces. We need to have these handlers
- * installed before any AML code can be executed, especially any
- * module-level code (11/2015).
- */
- status = acpi_ev_install_region_handlers();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "During Region initialization"));
- return_ACPI_STATUS(status);
- }
#if (!ACPI_REDUCED_HARDWARE)
/* Enable ACPI mode */
@@ -260,23 +245,6 @@ acpi_status __init acpi_initialize_objects(u32 flags)
ACPI_FUNCTION_TRACE(acpi_initialize_objects);
- /*
- * Run all _REG methods
- *
- * Note: Any objects accessed by the _REG methods will be automatically
- * initialized, even if they contain executable AML (see the call to
- * acpi_ns_initialize_objects below).
- */
- acpi_gbl_reg_methods_enabled = TRUE;
- if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "[Init] Executing _REG OpRegion methods\n"));
-
- status = acpi_ev_initialize_op_regions();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
#ifdef ACPI_EXEC_APP
/*
* This call implements the "initialization file" option for acpi_exec.
@@ -299,32 +267,27 @@ acpi_status __init acpi_initialize_objects(u32 flags)
*/
if (acpi_gbl_group_module_level_code) {
acpi_ns_exec_module_code_list();
- }
-
- /*
- * Initialize the objects that remain uninitialized. This runs the
- * executable AML that may be part of the declaration of these objects:
- * operation_regions, buffer_fields, Buffers, and Packages.
- */
- if (!(flags & ACPI_NO_OBJECT_INIT)) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "[Init] Completing Initialization of ACPI Objects\n"));
- status = acpi_ns_initialize_objects();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /*
+ * Initialize the objects that remain uninitialized. This
+ * runs the executable AML that may be part of the
+ * declaration of these objects:
+ * operation_regions, buffer_fields, Buffers, and Packages.
+ */
+ if (!(flags & ACPI_NO_OBJECT_INIT)) {
+ status = acpi_ns_initialize_objects();
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
}
/*
- * Initialize all device objects in the namespace. This runs the device
- * _STA and _INI methods.
+ * Initialize all device/region objects in the namespace. This runs
+ * the device _STA and _INI methods and region _REG methods.
*/
- if (!(flags & ACPI_NO_DEVICE_INIT)) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "[Init] Initializing ACPI Devices\n"));
-
- status = acpi_ns_initialize_devices();
+ if (!(flags & (ACPI_NO_DEVICE_INIT | ACPI_NO_ADDRESS_SPACE_INIT))) {
+ status = acpi_ns_initialize_devices(flags);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index a2c8d7adb6eb..da370e1d31f4 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -536,7 +536,8 @@ int apei_resources_request(struct apei_resources *resources,
goto err_unmap_ioport;
}
- return 0;
+ goto arch_res_fini;
+
err_unmap_ioport:
list_for_each_entry(res, &resources->ioport, list) {
if (res == res_bak)
@@ -551,7 +552,8 @@ err_unmap_iomem:
release_mem_region(res->start, res->end - res->start);
}
arch_res_fini:
- apei_resources_fini(&arch_res);
+ if (arch_apei_filter_addr)
+ apei_resources_fini(&arch_res);
nvs_res_fini:
apei_resources_fini(&nvs_resources);
return rc;
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 0431883653be..559c1173de1c 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -519,7 +519,7 @@ static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
u64 param3, u64 param4)
{
int rc;
- unsigned long pfn;
+ u64 base_addr, size;
/* If user manually set "flags", make sure it is legal */
if (flags && (flags &
@@ -545,10 +545,17 @@ static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
/*
* Disallow crazy address masks that give BIOS leeway to pick
* injection address almost anywhere. Insist on page or
- * better granularity and that target address is normal RAM.
+ * better granularity and that target address is normal RAM or
+ * NVDIMM.
*/
- pfn = PFN_DOWN(param1 & param2);
- if (!page_is_ram(pfn) || ((param2 & PAGE_MASK) != PAGE_MASK))
+ base_addr = param1 & param2;
+ size = ~param2 + 1;
+
+ if (((param2 & PAGE_MASK) != PAGE_MASK) ||
+ ((region_intersects(base_addr, size, IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)
+ != REGION_INTERSECTS) &&
+ (region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY)
+ != REGION_INTERSECTS)))
return -EINVAL;
inject:
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 6e6bc1059301..006c3894c6ea 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -1207,6 +1207,9 @@ static int __init erst_init(void)
"Failed to allocate %lld bytes for persistent store error log.\n",
erst_erange.size);
+ /* Cleanup ERST Resources */
+ apei_resources_fini(&erst_resources);
+
return 0;
err_release_erange:
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 3dd9c462d22a..60746ef904e4 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -26,7 +26,7 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/io.h>
@@ -79,6 +79,11 @@
((struct acpi_hest_generic_status *) \
((struct ghes_estatus_node *)(estatus_node) + 1))
+/*
+ * This driver isn't really modular, however for the time being,
+ * continuing to use module_param is the easiest way to remain
+ * compatible with existing boot arg use cases.
+ */
bool ghes_disable;
module_param_named(disable, ghes_disable, bool, 0);
@@ -1148,18 +1153,4 @@ err_ioremap_exit:
err:
return rc;
}
-
-static void __exit ghes_exit(void)
-{
- platform_driver_unregister(&ghes_platform_driver);
- ghes_estatus_pool_exit();
- ghes_ioremap_exit();
-}
-
-module_init(ghes_init);
-module_exit(ghes_exit);
-
-MODULE_AUTHOR("Huang Ying");
-MODULE_DESCRIPTION("APEI Generic Hardware Error Source support");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:GHES");
+device_initcall(ghes_init);
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c
index a83e3c62c5a9..75f128e766a9 100644
--- a/drivers/acpi/bgrt.c
+++ b/drivers/acpi/bgrt.c
@@ -1,4 +1,6 @@
/*
+ * BGRT boot graphic support
+ * Authors: Matthew Garrett, Josh Triplett <josh@joshtriplett.org>
* Copyright 2012 Red Hat, Inc <mjg@redhat.com>
* Copyright 2012 Intel Corporation
*
@@ -8,7 +10,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/sysfs.h>
@@ -103,9 +104,4 @@ out_kobject:
kobject_put(bgrt_kobj);
return ret;
}
-
-module_init(bgrt_init);
-
-MODULE_AUTHOR("Matthew Garrett, Josh Triplett <josh@joshtriplett.org>");
-MODULE_DESCRIPTION("BGRT boot graphic support");
-MODULE_LICENSE("GPL");
+device_initcall(bgrt_init);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 891c42d1cd65..0e8567846f1a 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -479,24 +479,38 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device)
Device Matching
-------------------------------------------------------------------------- */
-static struct acpi_device *acpi_primary_dev_companion(struct acpi_device *adev,
- const struct device *dev)
+/**
+ * acpi_get_first_physical_node - Get first physical node of an ACPI device
+ * @adev: ACPI device in question
+ *
+ * Return: First physical node of ACPI device @adev
+ */
+struct device *acpi_get_first_physical_node(struct acpi_device *adev)
{
struct mutex *physical_node_lock = &adev->physical_node_lock;
+ struct device *phys_dev;
mutex_lock(physical_node_lock);
if (list_empty(&adev->physical_node_list)) {
- adev = NULL;
+ phys_dev = NULL;
} else {
const struct acpi_device_physical_node *node;
node = list_first_entry(&adev->physical_node_list,
struct acpi_device_physical_node, node);
- if (node->dev != dev)
- adev = NULL;
+
+ phys_dev = node->dev;
}
mutex_unlock(physical_node_lock);
- return adev;
+ return phys_dev;
+}
+
+static struct acpi_device *acpi_primary_dev_companion(struct acpi_device *adev,
+ const struct device *dev)
+{
+ const struct device *phys_dev = acpi_get_first_physical_node(adev);
+
+ return phys_dev && phys_dev == dev ? adev : NULL;
}
/**
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 6730f965b379..8adac69dba3d 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -39,6 +39,7 @@
#include <linux/cpufreq.h>
#include <linux/delay.h>
+#include <linux/ktime.h>
#include <acpi/cppc_acpi.h>
/*
@@ -63,58 +64,140 @@ static struct mbox_chan *pcc_channel;
static void __iomem *pcc_comm_addr;
static u64 comm_base_addr;
static int pcc_subspace_idx = -1;
-static u16 pcc_cmd_delay;
static bool pcc_channel_acquired;
+static ktime_t deadline;
+static unsigned int pcc_mpar, pcc_mrtt;
+
+/* pcc mapped address + header size + offset within PCC subspace */
+#define GET_PCC_VADDR(offs) (pcc_comm_addr + 0x8 + (offs))
/*
* Arbitrary Retries in case the remote processor is slow to respond
- * to PCC commands.
+ * to PCC commands. Keeping it high enough to cover emulators where
+ * the processors run painfully slow.
*/
#define NUM_RETRIES 500
+static int check_pcc_chan(void)
+{
+ int ret = -EIO;
+ struct acpi_pcct_shared_memory __iomem *generic_comm_base = pcc_comm_addr;
+ ktime_t next_deadline = ktime_add(ktime_get(), deadline);
+
+ /* Retry in case the remote processor was too slow to catch up. */
+ while (!ktime_after(ktime_get(), next_deadline)) {
+ /*
+ * Per spec, prior to boot the PCC space wil be initialized by
+ * platform and should have set the command completion bit when
+ * PCC can be used by OSPM
+ */
+ if (readw_relaxed(&generic_comm_base->status) & PCC_CMD_COMPLETE) {
+ ret = 0;
+ break;
+ }
+ /*
+ * Reducing the bus traffic in case this loop takes longer than
+ * a few retries.
+ */
+ udelay(3);
+ }
+
+ return ret;
+}
+
static int send_pcc_cmd(u16 cmd)
{
- int retries, result = -EIO;
- struct acpi_pcct_hw_reduced *pcct_ss = pcc_channel->con_priv;
+ int ret = -EIO;
struct acpi_pcct_shared_memory *generic_comm_base =
(struct acpi_pcct_shared_memory *) pcc_comm_addr;
- u32 cmd_latency = pcct_ss->latency;
+ static ktime_t last_cmd_cmpl_time, last_mpar_reset;
+ static int mpar_count;
+ unsigned int time_delta;
- /* Min time OS should wait before sending next command. */
- udelay(pcc_cmd_delay);
+ /*
+ * For CMD_WRITE we know for a fact the caller should have checked
+ * the channel before writing to PCC space
+ */
+ if (cmd == CMD_READ) {
+ ret = check_pcc_chan();
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Handle the Minimum Request Turnaround Time(MRTT)
+ * "The minimum amount of time that OSPM must wait after the completion
+ * of a command before issuing the next command, in microseconds"
+ */
+ if (pcc_mrtt) {
+ time_delta = ktime_us_delta(ktime_get(), last_cmd_cmpl_time);
+ if (pcc_mrtt > time_delta)
+ udelay(pcc_mrtt - time_delta);
+ }
+
+ /*
+ * Handle the non-zero Maximum Periodic Access Rate(MPAR)
+ * "The maximum number of periodic requests that the subspace channel can
+ * support, reported in commands per minute. 0 indicates no limitation."
+ *
+ * This parameter should be ideally zero or large enough so that it can
+ * handle maximum number of requests that all the cores in the system can
+ * collectively generate. If it is not, we will follow the spec and just
+ * not send the request to the platform after hitting the MPAR limit in
+ * any 60s window
+ */
+ if (pcc_mpar) {
+ if (mpar_count == 0) {
+ time_delta = ktime_ms_delta(ktime_get(), last_mpar_reset);
+ if (time_delta < 60 * MSEC_PER_SEC) {
+ pr_debug("PCC cmd not sent due to MPAR limit");
+ return -EIO;
+ }
+ last_mpar_reset = ktime_get();
+ mpar_count = pcc_mpar;
+ }
+ mpar_count--;
+ }
/* Write to the shared comm region. */
- writew(cmd, &generic_comm_base->command);
+ writew_relaxed(cmd, &generic_comm_base->command);
/* Flip CMD COMPLETE bit */
- writew(0, &generic_comm_base->status);
+ writew_relaxed(0, &generic_comm_base->status);
/* Ring doorbell */
- result = mbox_send_message(pcc_channel, &cmd);
- if (result < 0) {
+ ret = mbox_send_message(pcc_channel, &cmd);
+ if (ret < 0) {
pr_err("Err sending PCC mbox message. cmd:%d, ret:%d\n",
- cmd, result);
- return result;
+ cmd, ret);
+ return ret;
}
- /* Wait for a nominal time to let platform process command. */
- udelay(cmd_latency);
-
- /* Retry in case the remote processor was too slow to catch up. */
- for (retries = NUM_RETRIES; retries > 0; retries--) {
- if (readw_relaxed(&generic_comm_base->status) & PCC_CMD_COMPLETE) {
- result = 0;
- break;
- }
+ /*
+ * For READs we need to ensure the cmd completed to ensure
+ * the ensuing read()s can proceed. For WRITEs we dont care
+ * because the actual write()s are done before coming here
+ * and the next READ or WRITE will check if the channel
+ * is busy/free at the entry of this call.
+ *
+ * If Minimum Request Turnaround Time is non-zero, we need
+ * to record the completion time of both READ and WRITE
+ * command for proper handling of MRTT, so we need to check
+ * for pcc_mrtt in addition to CMD_READ
+ */
+ if (cmd == CMD_READ || pcc_mrtt) {
+ ret = check_pcc_chan();
+ if (pcc_mrtt)
+ last_cmd_cmpl_time = ktime_get();
}
- mbox_client_txdone(pcc_channel, result);
- return result;
+ mbox_client_txdone(pcc_channel, ret);
+ return ret;
}
static void cppc_chan_tx_done(struct mbox_client *cl, void *msg, int ret)
{
- if (ret)
+ if (ret < 0)
pr_debug("TX did not complete: CMD sent:%x, ret:%d\n",
*(u16 *)msg, ret);
else
@@ -306,6 +389,7 @@ static int register_pcc_channel(int pcc_subspace_idx)
{
struct acpi_pcct_hw_reduced *cppc_ss;
unsigned int len;
+ u64 usecs_lat;
if (pcc_subspace_idx >= 0) {
pcc_channel = pcc_mbox_request_channel(&cppc_mbox_cl,
@@ -335,7 +419,16 @@ static int register_pcc_channel(int pcc_subspace_idx)
*/
comm_base_addr = cppc_ss->base_address;
len = cppc_ss->length;
- pcc_cmd_delay = cppc_ss->min_turnaround_time;
+
+ /*
+ * cppc_ss->latency is just a Nominal value. In reality
+ * the remote processor could be much slower to reply.
+ * So add an arbitrary amount of wait on top of Nominal.
+ */
+ usecs_lat = NUM_RETRIES * cppc_ss->latency;
+ deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC);
+ pcc_mrtt = cppc_ss->min_turnaround_time;
+ pcc_mpar = cppc_ss->max_access_rate;
pcc_comm_addr = acpi_os_ioremap(comm_base_addr, len);
if (!pcc_comm_addr) {
@@ -546,29 +639,74 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
}
EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit);
-static u64 get_phys_addr(struct cpc_reg *reg)
-{
- /* PCC communication addr space begins at byte offset 0x8. */
- if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
- return (u64)comm_base_addr + 0x8 + reg->address;
- else
- return reg->address;
-}
+/*
+ * Since cpc_read and cpc_write are called while holding pcc_lock, it should be
+ * as fast as possible. We have already mapped the PCC subspace during init, so
+ * we can directly write to it.
+ */
-static void cpc_read(struct cpc_reg *reg, u64 *val)
+static int cpc_read(struct cpc_reg *reg, u64 *val)
{
- u64 addr = get_phys_addr(reg);
+ int ret_val = 0;
- acpi_os_read_memory((acpi_physical_address)addr,
- val, reg->bit_width);
+ *val = 0;
+ if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
+ void __iomem *vaddr = GET_PCC_VADDR(reg->address);
+
+ switch (reg->bit_width) {
+ case 8:
+ *val = readb_relaxed(vaddr);
+ break;
+ case 16:
+ *val = readw_relaxed(vaddr);
+ break;
+ case 32:
+ *val = readl_relaxed(vaddr);
+ break;
+ case 64:
+ *val = readq_relaxed(vaddr);
+ break;
+ default:
+ pr_debug("Error: Cannot read %u bit width from PCC\n",
+ reg->bit_width);
+ ret_val = -EFAULT;
+ }
+ } else
+ ret_val = acpi_os_read_memory((acpi_physical_address)reg->address,
+ val, reg->bit_width);
+ return ret_val;
}
-static void cpc_write(struct cpc_reg *reg, u64 val)
+static int cpc_write(struct cpc_reg *reg, u64 val)
{
- u64 addr = get_phys_addr(reg);
+ int ret_val = 0;
- acpi_os_write_memory((acpi_physical_address)addr,
- val, reg->bit_width);
+ if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
+ void __iomem *vaddr = GET_PCC_VADDR(reg->address);
+
+ switch (reg->bit_width) {
+ case 8:
+ writeb_relaxed(val, vaddr);
+ break;
+ case 16:
+ writew_relaxed(val, vaddr);
+ break;
+ case 32:
+ writel_relaxed(val, vaddr);
+ break;
+ case 64:
+ writeq_relaxed(val, vaddr);
+ break;
+ default:
+ pr_debug("Error: Cannot write %u bit width to PCC\n",
+ reg->bit_width);
+ ret_val = -EFAULT;
+ break;
+ }
+ } else
+ ret_val = acpi_os_write_memory((acpi_physical_address)reg->address,
+ val, reg->bit_width);
+ return ret_val;
}
/**
@@ -604,7 +742,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
(ref_perf->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
(nom_perf->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) {
/* Ring doorbell once to update PCC subspace */
- if (send_pcc_cmd(CMD_READ)) {
+ if (send_pcc_cmd(CMD_READ) < 0) {
ret = -EIO;
goto out_err;
}
@@ -662,7 +800,7 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
if ((delivered_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
(reference_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) {
/* Ring doorbell once to update PCC subspace */
- if (send_pcc_cmd(CMD_READ)) {
+ if (send_pcc_cmd(CMD_READ) < 0) {
ret = -EIO;
goto out_err;
}
@@ -713,6 +851,13 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
spin_lock(&pcc_lock);
+ /* If this is PCC reg, check if channel is free before writing */
+ if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
+ ret = check_pcc_chan();
+ if (ret)
+ goto busy_channel;
+ }
+
/*
* Skip writing MIN/MAX until Linux knows how to come up with
* useful values.
@@ -722,10 +867,10 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
/* Is this a PCC reg ?*/
if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
/* Ring doorbell so Remote can get our perf request. */
- if (send_pcc_cmd(CMD_WRITE))
+ if (send_pcc_cmd(CMD_WRITE) < 0)
ret = -EIO;
}
-
+busy_channel:
spin_unlock(&pcc_lock);
return ret;
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
index bea8e425a8de..6c7dd7af789e 100644
--- a/drivers/acpi/ec_sys.c
+++ b/drivers/acpi/ec_sys.c
@@ -73,6 +73,9 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
loff_t init_off = *off;
int err = 0;
+ if (!write_support)
+ return -EINVAL;
+
if (*off >= EC_SPACE_SIZE)
return 0;
if (*off + count >= EC_SPACE_SIZE) {
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 6322db64b4a4..384cfc3083e1 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -46,7 +46,7 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids);
#ifdef CONFIG_PM_SLEEP
static int acpi_fan_suspend(struct device *dev);
static int acpi_fan_resume(struct device *dev);
-static struct dev_pm_ops acpi_fan_pm = {
+static const struct dev_pm_ops acpi_fan_pm = {
.resume = acpi_fan_resume,
.freeze = acpi_fan_suspend,
.thaw = acpi_fan_resume,
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 1e6833a5cd44..a37508ef66c1 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -20,6 +20,7 @@
#define PREFIX "ACPI: "
+void acpi_initrd_initialize_tables(void);
acpi_status acpi_os_initialize1(void);
void init_acpi_device_notify(void);
int acpi_scan_init(void);
@@ -29,6 +30,11 @@ void acpi_processor_init(void);
void acpi_platform_init(void);
void acpi_pnp_init(void);
void acpi_int340x_thermal_init(void);
+#ifdef CONFIG_ARM_AMBA
+void acpi_amba_init(void);
+#else
+static inline void acpi_amba_init(void) {}
+#endif
int acpi_sysfs_init(void);
void acpi_container_init(void);
void acpi_memory_hotplug_init(void);
@@ -106,6 +112,7 @@ bool acpi_device_is_present(struct acpi_device *adev);
bool acpi_device_is_battery(struct acpi_device *adev);
bool acpi_device_is_first_physical_node(struct acpi_device *adev,
const struct device *dev);
+struct device *acpi_get_first_physical_node(struct acpi_device *adev);
/* --------------------------------------------------------------------------
Device Matching and Notification
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index ad6d8c6b777e..d0f35e63640b 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -21,6 +21,7 @@
#include <linux/sort.h>
#include <linux/pmem.h>
#include <linux/io.h>
+#include <linux/nd.h>
#include <asm/cacheflush.h>
#include "nfit.h"
@@ -34,6 +35,18 @@ static bool force_enable_dimms;
module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
+static unsigned int scrub_timeout = NFIT_ARS_TIMEOUT;
+module_param(scrub_timeout, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scrub_timeout, "Initial scrub timeout in seconds");
+
+/* after three payloads of overflow, it's dead jim */
+static unsigned int scrub_overflow_abort = 3;
+module_param(scrub_overflow_abort, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scrub_overflow_abort,
+ "Number of times we overflow ARS results before abort");
+
+static struct workqueue_struct *nfit_wq;
+
struct nfit_table_prev {
struct list_head spas;
struct list_head memdevs;
@@ -72,9 +85,90 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
return to_acpi_device(acpi_desc->dev);
}
+static int xlat_status(void *buf, unsigned int cmd)
+{
+ struct nd_cmd_clear_error *clear_err;
+ struct nd_cmd_ars_status *ars_status;
+ struct nd_cmd_ars_start *ars_start;
+ struct nd_cmd_ars_cap *ars_cap;
+ u16 flags;
+
+ switch (cmd) {
+ case ND_CMD_ARS_CAP:
+ ars_cap = buf;
+ if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE)
+ return -ENOTTY;
+
+ /* Command failed */
+ if (ars_cap->status & 0xffff)
+ return -EIO;
+
+ /* No supported scan types for this range */
+ flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
+ if ((ars_cap->status >> 16 & flags) == 0)
+ return -ENOTTY;
+ break;
+ case ND_CMD_ARS_START:
+ ars_start = buf;
+ /* ARS is in progress */
+ if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY)
+ return -EBUSY;
+
+ /* Command failed */
+ if (ars_start->status & 0xffff)
+ return -EIO;
+ break;
+ case ND_CMD_ARS_STATUS:
+ ars_status = buf;
+ /* Command failed */
+ if (ars_status->status & 0xffff)
+ return -EIO;
+ /* Check extended status (Upper two bytes) */
+ if (ars_status->status == NFIT_ARS_STATUS_DONE)
+ return 0;
+
+ /* ARS is in progress */
+ if (ars_status->status == NFIT_ARS_STATUS_BUSY)
+ return -EBUSY;
+
+ /* No ARS performed for the current boot */
+ if (ars_status->status == NFIT_ARS_STATUS_NONE)
+ return -EAGAIN;
+
+ /*
+ * ARS interrupted, either we overflowed or some other
+ * agent wants the scan to stop. If we didn't overflow
+ * then just continue with the returned results.
+ */
+ if (ars_status->status == NFIT_ARS_STATUS_INTR) {
+ if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
+ return -ENOSPC;
+ return 0;
+ }
+
+ /* Unknown status */
+ if (ars_status->status >> 16)
+ return -EIO;
+ break;
+ case ND_CMD_CLEAR_ERROR:
+ clear_err = buf;
+ if (clear_err->status & 0xffff)
+ return -EIO;
+ if (!clear_err->cleared)
+ return -EIO;
+ if (clear_err->length > clear_err->cleared)
+ return clear_err->cleared;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
- unsigned int buf_len)
+ unsigned int buf_len, int *cmd_rc)
{
struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
const struct nd_cmd_desc *desc = NULL;
@@ -185,6 +279,8 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
* unfilled in the output buffer
*/
rc = buf_len - offset - in_buf.buffer.length;
+ if (cmd_rc)
+ *cmd_rc = xlat_status(buf, cmd);
} else {
dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
__func__, dimm_name, cmd_name, buf_len,
@@ -469,37 +565,16 @@ static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc,
nfit_mem->bdw = NULL;
}
-static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
+static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc,
struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
{
u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
struct nfit_memdev *nfit_memdev;
struct nfit_flush *nfit_flush;
- struct nfit_dcr *nfit_dcr;
struct nfit_bdw *nfit_bdw;
struct nfit_idt *nfit_idt;
u16 idt_idx, range_index;
- list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
- if (nfit_dcr->dcr->region_index != dcr)
- continue;
- nfit_mem->dcr = nfit_dcr->dcr;
- break;
- }
-
- if (!nfit_mem->dcr) {
- dev_dbg(acpi_desc->dev, "SPA %d missing:%s%s\n",
- spa->range_index, __to_nfit_memdev(nfit_mem)
- ? "" : " MEMDEV", nfit_mem->dcr ? "" : " DCR");
- return -ENODEV;
- }
-
- /*
- * We've found enough to create an nvdimm, optionally
- * find an associated BDW
- */
- list_add(&nfit_mem->list, &acpi_desc->dimms);
-
list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
if (nfit_bdw->bdw->region_index != dcr)
continue;
@@ -508,12 +583,12 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
}
if (!nfit_mem->bdw)
- return 0;
+ return;
nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
if (!nfit_mem->spa_bdw)
- return 0;
+ return;
range_index = nfit_mem->spa_bdw->range_index;
list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
@@ -538,8 +613,6 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
}
break;
}
-
- return 0;
}
static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
@@ -548,7 +621,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
struct nfit_mem *nfit_mem, *found;
struct nfit_memdev *nfit_memdev;
int type = nfit_spa_type(spa);
- u16 dcr;
switch (type) {
case NFIT_SPA_DCR:
@@ -559,14 +631,18 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
}
list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
- int rc;
+ struct nfit_dcr *nfit_dcr;
+ u32 device_handle;
+ u16 dcr;
if (nfit_memdev->memdev->range_index != spa->range_index)
continue;
found = NULL;
dcr = nfit_memdev->memdev->region_index;
+ device_handle = nfit_memdev->memdev->device_handle;
list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
- if (__to_nfit_memdev(nfit_mem)->region_index == dcr) {
+ if (__to_nfit_memdev(nfit_mem)->device_handle
+ == device_handle) {
found = nfit_mem;
break;
}
@@ -579,6 +655,31 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
if (!nfit_mem)
return -ENOMEM;
INIT_LIST_HEAD(&nfit_mem->list);
+ list_add(&nfit_mem->list, &acpi_desc->dimms);
+ }
+
+ list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
+ if (nfit_dcr->dcr->region_index != dcr)
+ continue;
+ /*
+ * Record the control region for the dimm. For
+ * the ACPI 6.1 case, where there are separate
+ * control regions for the pmem vs blk
+ * interfaces, be sure to record the extended
+ * blk details.
+ */
+ if (!nfit_mem->dcr)
+ nfit_mem->dcr = nfit_dcr->dcr;
+ else if (nfit_mem->dcr->windows == 0
+ && nfit_dcr->dcr->windows)
+ nfit_mem->dcr = nfit_dcr->dcr;
+ break;
+ }
+
+ if (dcr && !nfit_mem->dcr) {
+ dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n",
+ spa->range_index, dcr);
+ return -ENODEV;
}
if (type == NFIT_SPA_DCR) {
@@ -595,6 +696,7 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
nfit_mem->idt_dcr = nfit_idt->idt;
break;
}
+ nfit_mem_init_bdw(acpi_desc, nfit_mem, spa);
} else {
/*
* A single dimm may belong to multiple SPA-PM
@@ -603,13 +705,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
*/
nfit_mem->memdev_pmem = nfit_memdev->memdev;
}
-
- if (found)
- continue;
-
- rc = nfit_mem_add(acpi_desc, nfit_mem, spa);
- if (rc)
- return rc;
}
return 0;
@@ -676,12 +771,11 @@ static struct attribute_group acpi_nfit_attribute_group = {
.attrs = acpi_nfit_attributes,
};
-const struct attribute_group *acpi_nfit_attribute_groups[] = {
+static const struct attribute_group *acpi_nfit_attribute_groups[] = {
&nvdimm_bus_attribute_group,
&acpi_nfit_attribute_group,
NULL,
};
-EXPORT_SYMBOL_GPL(acpi_nfit_attribute_groups);
static struct acpi_nfit_memory_map *to_nfit_memdev(struct device *dev)
{
@@ -918,7 +1012,7 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
if (!adev)
return;
- for (i = ND_CMD_ARS_CAP; i <= ND_CMD_ARS_STATUS; i++)
+ for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++)
if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i))
set_bit(i, &nd_desc->dsm_mask);
}
@@ -1106,7 +1200,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
writeq(cmd, mmio->addr.base + offset);
wmb_blk(nfit_blk);
- if (nfit_blk->dimm_flags & ND_BLK_DCR_LATCH)
+ if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
readq(mmio->addr.base + offset);
}
@@ -1142,7 +1236,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
memcpy_to_pmem(mmio->addr.aperture + offset,
iobuf + copied, c);
else {
- if (nfit_blk->dimm_flags & ND_BLK_READ_FLUSH)
+ if (nfit_blk->dimm_flags & NFIT_BLK_READ_FLUSH)
mmio_flush_range((void __force *)
mmio->addr.aperture + offset, c);
@@ -1329,13 +1423,13 @@ static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc,
memset(&flags, 0, sizeof(flags));
rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_DIMM_FLAGS, &flags,
- sizeof(flags));
+ sizeof(flags), NULL);
if (rc >= 0 && flags.status == 0)
nfit_blk->dimm_flags = flags.flags;
else if (rc == -ENOTTY) {
/* fall back to a conservative default */
- nfit_blk->dimm_flags = ND_BLK_DCR_LATCH | ND_BLK_READ_FLUSH;
+ nfit_blk->dimm_flags = NFIT_BLK_DCR_LATCH | NFIT_BLK_READ_FLUSH;
rc = 0;
} else
rc = -ENXIO;
@@ -1474,93 +1568,85 @@ static void acpi_nfit_blk_region_disable(struct nvdimm_bus *nvdimm_bus,
/* devm will free nfit_blk */
}
-static int ars_get_cap(struct nvdimm_bus_descriptor *nd_desc,
- struct nd_cmd_ars_cap *cmd, u64 addr, u64 length)
+static int ars_get_cap(struct acpi_nfit_desc *acpi_desc,
+ struct nd_cmd_ars_cap *cmd, struct nfit_spa *nfit_spa)
{
- cmd->address = addr;
- cmd->length = length;
+ struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+ struct acpi_nfit_system_address *spa = nfit_spa->spa;
+ int cmd_rc, rc;
- return nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, cmd,
- sizeof(*cmd));
+ cmd->address = spa->address;
+ cmd->length = spa->length;
+ rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, cmd,
+ sizeof(*cmd), &cmd_rc);
+ if (rc < 0)
+ return rc;
+ return cmd_rc;
}
-static int ars_do_start(struct nvdimm_bus_descriptor *nd_desc,
- struct nd_cmd_ars_start *cmd, u64 addr, u64 length)
+static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa)
{
int rc;
+ int cmd_rc;
+ struct nd_cmd_ars_start ars_start;
+ struct acpi_nfit_system_address *spa = nfit_spa->spa;
+ struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
- cmd->address = addr;
- cmd->length = length;
- cmd->type = ND_ARS_PERSISTENT;
+ memset(&ars_start, 0, sizeof(ars_start));
+ ars_start.address = spa->address;
+ ars_start.length = spa->length;
+ if (nfit_spa_type(spa) == NFIT_SPA_PM)
+ ars_start.type = ND_ARS_PERSISTENT;
+ else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE)
+ ars_start.type = ND_ARS_VOLATILE;
+ else
+ return -ENOTTY;
- while (1) {
- rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, cmd,
- sizeof(*cmd));
- if (rc)
- return rc;
- switch (cmd->status) {
- case 0:
- return 0;
- case 1:
- /* ARS unsupported, but we should never get here */
- return 0;
- case 2:
- return -EINVAL;
- case 3:
- /* ARS is in progress */
- msleep(1000);
- break;
- default:
- return -ENXIO;
- }
- }
+ rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
+ sizeof(ars_start), &cmd_rc);
+
+ if (rc < 0)
+ return rc;
+ return cmd_rc;
}
-static int ars_get_status(struct nvdimm_bus_descriptor *nd_desc,
- struct nd_cmd_ars_status *cmd)
+static int ars_continue(struct acpi_nfit_desc *acpi_desc)
{
- int rc;
+ int rc, cmd_rc;
+ struct nd_cmd_ars_start ars_start;
+ struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+ struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
+
+ memset(&ars_start, 0, sizeof(ars_start));
+ ars_start.address = ars_status->restart_address;
+ ars_start.length = ars_status->restart_length;
+ ars_start.type = ars_status->type;
+ rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
+ sizeof(ars_start), &cmd_rc);
+ if (rc < 0)
+ return rc;
+ return cmd_rc;
+}
- while (1) {
- rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, cmd,
- sizeof(*cmd));
- if (rc || cmd->status & 0xffff)
- return -ENXIO;
+static int ars_get_status(struct acpi_nfit_desc *acpi_desc)
+{
+ struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+ struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
+ int rc, cmd_rc;
- /* Check extended status (Upper two bytes) */
- switch (cmd->status >> 16) {
- case 0:
- return 0;
- case 1:
- /* ARS is in progress */
- msleep(1000);
- break;
- case 2:
- /* No ARS performed for the current boot */
- return 0;
- default:
- return -ENXIO;
- }
- }
+ rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, ars_status,
+ acpi_desc->ars_status_size, &cmd_rc);
+ if (rc < 0)
+ return rc;
+ return cmd_rc;
}
static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus,
- struct nd_cmd_ars_status *ars_status, u64 start)
+ struct nd_cmd_ars_status *ars_status)
{
int rc;
u32 i;
- /*
- * The address field returned by ars_status should be either
- * less than or equal to the address we last started ARS for.
- * The (start, length) returned by ars_status should also have
- * non-zero overlap with the range we started ARS for.
- * If this is not the case, bail.
- */
- if (ars_status->address > start ||
- (ars_status->address + ars_status->length < start))
- return -ENXIO;
-
for (i = 0; i < ars_status->num_records; i++) {
rc = nvdimm_bus_add_poison(nvdimm_bus,
ars_status->records[i].err_address,
@@ -1572,110 +1658,56 @@ static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus,
return 0;
}
-static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
- struct nd_region_desc *ndr_desc)
+static void acpi_nfit_remove_resource(void *data)
{
- struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
- struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus;
- struct nd_cmd_ars_status *ars_status = NULL;
- struct nd_cmd_ars_start *ars_start = NULL;
- struct nd_cmd_ars_cap *ars_cap = NULL;
- u64 start, len, cur, remaining;
- int rc;
+ struct resource *res = data;
- ars_cap = kzalloc(sizeof(*ars_cap), GFP_KERNEL);
- if (!ars_cap)
- return -ENOMEM;
-
- start = ndr_desc->res->start;
- len = ndr_desc->res->end - ndr_desc->res->start + 1;
-
- rc = ars_get_cap(nd_desc, ars_cap, start, len);
- if (rc)
- goto out;
-
- /*
- * If ARS is unsupported, or if the 'Persistent Memory Scrub' flag in
- * extended status is not set, skip this but continue initialization
- */
- if ((ars_cap->status & 0xffff) ||
- !(ars_cap->status >> 16 & ND_ARS_PERSISTENT)) {
- dev_warn(acpi_desc->dev,
- "ARS unsupported (status: 0x%x), won't create an error list\n",
- ars_cap->status);
- goto out;
- }
-
- /*
- * Check if a full-range ARS has been run. If so, use those results
- * without having to start a new ARS.
- */
- ars_status = kzalloc(ars_cap->max_ars_out + sizeof(*ars_status),
- GFP_KERNEL);
- if (!ars_status) {
- rc = -ENOMEM;
- goto out;
- }
+ remove_resource(res);
+}
- rc = ars_get_status(nd_desc, ars_status);
- if (rc)
- goto out;
+static int acpi_nfit_insert_resource(struct acpi_nfit_desc *acpi_desc,
+ struct nd_region_desc *ndr_desc)
+{
+ struct resource *res, *nd_res = ndr_desc->res;
+ int is_pmem, ret;
- if (ars_status->address <= start &&
- (ars_status->address + ars_status->length >= start + len)) {
- rc = ars_status_process_records(nvdimm_bus, ars_status, start);
- goto out;
- }
+ /* No operation if the region is already registered as PMEM */
+ is_pmem = region_intersects(nd_res->start, resource_size(nd_res),
+ IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY);
+ if (is_pmem == REGION_INTERSECTS)
+ return 0;
- /*
- * ARS_STATUS can overflow if the number of poison entries found is
- * greater than the maximum buffer size (ars_cap->max_ars_out)
- * To detect overflow, check if the length field of ars_status
- * is less than the length we supplied. If so, process the
- * error entries we got, adjust the start point, and start again
- */
- ars_start = kzalloc(sizeof(*ars_start), GFP_KERNEL);
- if (!ars_start)
+ res = devm_kzalloc(acpi_desc->dev, sizeof(*res), GFP_KERNEL);
+ if (!res)
return -ENOMEM;
- cur = start;
- remaining = len;
- do {
- u64 done, end;
+ res->name = "Persistent Memory";
+ res->start = nd_res->start;
+ res->end = nd_res->end;
+ res->flags = IORESOURCE_MEM;
+ res->desc = IORES_DESC_PERSISTENT_MEMORY;
- rc = ars_do_start(nd_desc, ars_start, cur, remaining);
- if (rc)
- goto out;
+ ret = insert_resource(&iomem_resource, res);
+ if (ret)
+ return ret;
- rc = ars_get_status(nd_desc, ars_status);
- if (rc)
- goto out;
-
- rc = ars_status_process_records(nvdimm_bus, ars_status, cur);
- if (rc)
- goto out;
-
- end = min(cur + remaining,
- ars_status->address + ars_status->length);
- done = end - cur;
- cur += done;
- remaining -= done;
- } while (remaining);
+ ret = devm_add_action(acpi_desc->dev, acpi_nfit_remove_resource, res);
+ if (ret) {
+ remove_resource(res);
+ return ret;
+ }
- out:
- kfree(ars_cap);
- kfree(ars_start);
- kfree(ars_status);
- return rc;
+ return 0;
}
static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
struct nd_mapping *nd_mapping, struct nd_region_desc *ndr_desc,
struct acpi_nfit_memory_map *memdev,
- struct acpi_nfit_system_address *spa)
+ struct nfit_spa *nfit_spa)
{
struct nvdimm *nvdimm = acpi_nfit_dimm_by_handle(acpi_desc,
memdev->device_handle);
+ struct acpi_nfit_system_address *spa = nfit_spa->spa;
struct nd_blk_region_desc *ndbr_desc;
struct nfit_mem *nfit_mem;
int blk_valid = 0;
@@ -1711,7 +1743,9 @@ static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
ndbr_desc->enable = acpi_nfit_blk_region_enable;
ndbr_desc->disable = acpi_nfit_blk_region_disable;
ndbr_desc->do_io = acpi_desc->blk_do_io;
- if (!nvdimm_blk_region_create(acpi_desc->nvdimm_bus, ndr_desc))
+ nfit_spa->nd_region = nvdimm_blk_region_create(acpi_desc->nvdimm_bus,
+ ndr_desc);
+ if (!nfit_spa->nd_region)
return -ENOMEM;
break;
}
@@ -1731,7 +1765,7 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
struct resource res;
int count = 0, rc;
- if (nfit_spa->is_registered)
+ if (nfit_spa->nd_region)
return 0;
if (spa->range_index == 0) {
@@ -1768,47 +1802,332 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
}
nd_mapping = &nd_mappings[count++];
rc = acpi_nfit_init_mapping(acpi_desc, nd_mapping, ndr_desc,
- memdev, spa);
+ memdev, nfit_spa);
if (rc)
- return rc;
+ goto out;
}
ndr_desc->nd_mapping = nd_mappings;
ndr_desc->num_mappings = count;
rc = acpi_nfit_init_interleave_set(acpi_desc, ndr_desc, spa);
if (rc)
- return rc;
+ goto out;
nvdimm_bus = acpi_desc->nvdimm_bus;
if (nfit_spa_type(spa) == NFIT_SPA_PM) {
- rc = acpi_nfit_find_poison(acpi_desc, ndr_desc);
+ rc = acpi_nfit_insert_resource(acpi_desc, ndr_desc);
if (rc) {
- dev_err(acpi_desc->dev,
- "error while performing ARS to find poison: %d\n",
+ dev_warn(acpi_desc->dev,
+ "failed to insert pmem resource to iomem: %d\n",
rc);
- return rc;
+ goto out;
}
- if (!nvdimm_pmem_region_create(nvdimm_bus, ndr_desc))
- return -ENOMEM;
+
+ nfit_spa->nd_region = nvdimm_pmem_region_create(nvdimm_bus,
+ ndr_desc);
+ if (!nfit_spa->nd_region)
+ rc = -ENOMEM;
} else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) {
- if (!nvdimm_volatile_region_create(nvdimm_bus, ndr_desc))
- return -ENOMEM;
+ nfit_spa->nd_region = nvdimm_volatile_region_create(nvdimm_bus,
+ ndr_desc);
+ if (!nfit_spa->nd_region)
+ rc = -ENOMEM;
+ }
+
+ out:
+ if (rc)
+ dev_err(acpi_desc->dev, "failed to register spa range %d\n",
+ nfit_spa->spa->range_index);
+ return rc;
+}
+
+static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc,
+ u32 max_ars)
+{
+ struct device *dev = acpi_desc->dev;
+ struct nd_cmd_ars_status *ars_status;
+
+ if (acpi_desc->ars_status && acpi_desc->ars_status_size >= max_ars) {
+ memset(acpi_desc->ars_status, 0, acpi_desc->ars_status_size);
+ return 0;
}
- nfit_spa->is_registered = 1;
+ if (acpi_desc->ars_status)
+ devm_kfree(dev, acpi_desc->ars_status);
+ acpi_desc->ars_status = NULL;
+ ars_status = devm_kzalloc(dev, max_ars, GFP_KERNEL);
+ if (!ars_status)
+ return -ENOMEM;
+ acpi_desc->ars_status = ars_status;
+ acpi_desc->ars_status_size = max_ars;
return 0;
}
-static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
+static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_spa *nfit_spa)
+{
+ struct acpi_nfit_system_address *spa = nfit_spa->spa;
+ int rc;
+
+ if (!nfit_spa->max_ars) {
+ struct nd_cmd_ars_cap ars_cap;
+
+ memset(&ars_cap, 0, sizeof(ars_cap));
+ rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa);
+ if (rc < 0)
+ return rc;
+ nfit_spa->max_ars = ars_cap.max_ars_out;
+ nfit_spa->clear_err_unit = ars_cap.clear_err_unit;
+ /* check that the supported scrub types match the spa type */
+ if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE &&
+ ((ars_cap.status >> 16) & ND_ARS_VOLATILE) == 0)
+ return -ENOTTY;
+ else if (nfit_spa_type(spa) == NFIT_SPA_PM &&
+ ((ars_cap.status >> 16) & ND_ARS_PERSISTENT) == 0)
+ return -ENOTTY;
+ }
+
+ if (ars_status_alloc(acpi_desc, nfit_spa->max_ars))
+ return -ENOMEM;
+
+ rc = ars_get_status(acpi_desc);
+ if (rc < 0 && rc != -ENOSPC)
+ return rc;
+
+ if (ars_status_process_records(acpi_desc->nvdimm_bus,
+ acpi_desc->ars_status))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void acpi_nfit_async_scrub(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_spa *nfit_spa)
+{
+ struct acpi_nfit_system_address *spa = nfit_spa->spa;
+ unsigned int overflow_retry = scrub_overflow_abort;
+ u64 init_ars_start = 0, init_ars_len = 0;
+ struct device *dev = acpi_desc->dev;
+ unsigned int tmo = scrub_timeout;
+ int rc;
+
+ if (nfit_spa->ars_done || !nfit_spa->nd_region)
+ return;
+
+ rc = ars_start(acpi_desc, nfit_spa);
+ /*
+ * If we timed out the initial scan we'll still be busy here,
+ * and will wait another timeout before giving up permanently.
+ */
+ if (rc < 0 && rc != -EBUSY)
+ return;
+
+ do {
+ u64 ars_start, ars_len;
+
+ if (acpi_desc->cancel)
+ break;
+ rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
+ if (rc == -ENOTTY)
+ break;
+ if (rc == -EBUSY && !tmo) {
+ dev_warn(dev, "range %d ars timeout, aborting\n",
+ spa->range_index);
+ break;
+ }
+
+ if (rc == -EBUSY) {
+ /*
+ * Note, entries may be appended to the list
+ * while the lock is dropped, but the workqueue
+ * being active prevents entries being deleted /
+ * freed.
+ */
+ mutex_unlock(&acpi_desc->init_mutex);
+ ssleep(1);
+ tmo--;
+ mutex_lock(&acpi_desc->init_mutex);
+ continue;
+ }
+
+ /* we got some results, but there are more pending... */
+ if (rc == -ENOSPC && overflow_retry--) {
+ if (!init_ars_len) {
+ init_ars_len = acpi_desc->ars_status->length;
+ init_ars_start = acpi_desc->ars_status->address;
+ }
+ rc = ars_continue(acpi_desc);
+ }
+
+ if (rc < 0) {
+ dev_warn(dev, "range %d ars continuation failed\n",
+ spa->range_index);
+ break;
+ }
+
+ if (init_ars_len) {
+ ars_start = init_ars_start;
+ ars_len = init_ars_len;
+ } else {
+ ars_start = acpi_desc->ars_status->address;
+ ars_len = acpi_desc->ars_status->length;
+ }
+ dev_dbg(dev, "spa range: %d ars from %#llx + %#llx complete\n",
+ spa->range_index, ars_start, ars_len);
+ /* notify the region about new poison entries */
+ nvdimm_region_notify(nfit_spa->nd_region,
+ NVDIMM_REVALIDATE_POISON);
+ break;
+ } while (1);
+}
+
+static void acpi_nfit_scrub(struct work_struct *work)
{
+ struct device *dev;
+ u64 init_scrub_length = 0;
struct nfit_spa *nfit_spa;
+ u64 init_scrub_address = 0;
+ bool init_ars_done = false;
+ struct acpi_nfit_desc *acpi_desc;
+ unsigned int tmo = scrub_timeout;
+ unsigned int overflow_retry = scrub_overflow_abort;
+ acpi_desc = container_of(work, typeof(*acpi_desc), work);
+ dev = acpi_desc->dev;
+
+ /*
+ * We scrub in 2 phases. The first phase waits for any platform
+ * firmware initiated scrubs to complete and then we go search for the
+ * affected spa regions to mark them scanned. In the second phase we
+ * initiate a directed scrub for every range that was not scrubbed in
+ * phase 1.
+ */
+
+ /* process platform firmware initiated scrubs */
+ retry:
+ mutex_lock(&acpi_desc->init_mutex);
list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
- int rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
+ struct nd_cmd_ars_status *ars_status;
+ struct acpi_nfit_system_address *spa;
+ u64 ars_start, ars_len;
+ int rc;
- if (rc)
- return rc;
+ if (acpi_desc->cancel)
+ break;
+
+ if (nfit_spa->nd_region)
+ continue;
+
+ if (init_ars_done) {
+ /*
+ * No need to re-query, we're now just
+ * reconciling all the ranges covered by the
+ * initial scrub
+ */
+ rc = 0;
+ } else
+ rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
+
+ if (rc == -ENOTTY) {
+ /* no ars capability, just register spa and move on */
+ acpi_nfit_register_region(acpi_desc, nfit_spa);
+ continue;
+ }
+
+ if (rc == -EBUSY && !tmo) {
+ /* fallthrough to directed scrub in phase 2 */
+ dev_warn(dev, "timeout awaiting ars results, continuing...\n");
+ break;
+ } else if (rc == -EBUSY) {
+ mutex_unlock(&acpi_desc->init_mutex);
+ ssleep(1);
+ tmo--;
+ goto retry;
+ }
+
+ /* we got some results, but there are more pending... */
+ if (rc == -ENOSPC && overflow_retry--) {
+ ars_status = acpi_desc->ars_status;
+ /*
+ * Record the original scrub range, so that we
+ * can recall all the ranges impacted by the
+ * initial scrub.
+ */
+ if (!init_scrub_length) {
+ init_scrub_length = ars_status->length;
+ init_scrub_address = ars_status->address;
+ }
+ rc = ars_continue(acpi_desc);
+ if (rc == 0) {
+ mutex_unlock(&acpi_desc->init_mutex);
+ goto retry;
+ }
+ }
+
+ if (rc < 0) {
+ /*
+ * Initial scrub failed, we'll give it one more
+ * try below...
+ */
+ break;
+ }
+
+ /* We got some final results, record completed ranges */
+ ars_status = acpi_desc->ars_status;
+ if (init_scrub_length) {
+ ars_start = init_scrub_address;
+ ars_len = ars_start + init_scrub_length;
+ } else {
+ ars_start = ars_status->address;
+ ars_len = ars_status->length;
+ }
+ spa = nfit_spa->spa;
+
+ if (!init_ars_done) {
+ init_ars_done = true;
+ dev_dbg(dev, "init scrub %#llx + %#llx complete\n",
+ ars_start, ars_len);
+ }
+ if (ars_start <= spa->address && ars_start + ars_len
+ >= spa->address + spa->length)
+ acpi_nfit_register_region(acpi_desc, nfit_spa);
}
+
+ /*
+ * For all the ranges not covered by an initial scrub we still
+ * want to see if there are errors, but it's ok to discover them
+ * asynchronously.
+ */
+ list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+ /*
+ * Flag all the ranges that still need scrubbing, but
+ * register them now to make data available.
+ */
+ if (nfit_spa->nd_region)
+ nfit_spa->ars_done = 1;
+ else
+ acpi_nfit_register_region(acpi_desc, nfit_spa);
+ }
+
+ list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
+ acpi_nfit_async_scrub(acpi_desc, nfit_spa);
+ mutex_unlock(&acpi_desc->init_mutex);
+}
+
+static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
+{
+ struct nfit_spa *nfit_spa;
+ int rc;
+
+ list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
+ if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) {
+ /* BLK regions don't need to wait for ars results */
+ rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
+ if (rc)
+ return rc;
+ }
+
+ queue_work(nfit_wq, &acpi_desc->work);
return 0;
}
@@ -1894,15 +2213,64 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
}
EXPORT_SYMBOL_GPL(acpi_nfit_init);
-static struct acpi_nfit_desc *acpi_nfit_desc_init(struct acpi_device *adev)
+struct acpi_nfit_flush_work {
+ struct work_struct work;
+ struct completion cmp;
+};
+
+static void flush_probe(struct work_struct *work)
{
- struct nvdimm_bus_descriptor *nd_desc;
- struct acpi_nfit_desc *acpi_desc;
- struct device *dev = &adev->dev;
+ struct acpi_nfit_flush_work *flush;
- acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
- if (!acpi_desc)
- return ERR_PTR(-ENOMEM);
+ flush = container_of(work, typeof(*flush), work);
+ complete(&flush->cmp);
+}
+
+static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
+{
+ struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
+ struct device *dev = acpi_desc->dev;
+ struct acpi_nfit_flush_work flush;
+
+ /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
+ device_lock(dev);
+ device_unlock(dev);
+
+ /*
+ * Scrub work could take 10s of seconds, userspace may give up so we
+ * need to be interruptible while waiting.
+ */
+ INIT_WORK_ONSTACK(&flush.work, flush_probe);
+ COMPLETION_INITIALIZER_ONSTACK(flush.cmp);
+ queue_work(nfit_wq, &flush.work);
+ return wait_for_completion_interruptible(&flush.cmp);
+}
+
+static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
+ struct nvdimm *nvdimm, unsigned int cmd)
+{
+ struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
+
+ if (nvdimm)
+ return 0;
+ if (cmd != ND_CMD_ARS_START)
+ return 0;
+
+ /*
+ * The kernel and userspace may race to initiate a scrub, but
+ * the scrub thread is prepared to lose that initial race. It
+ * just needs guarantees that any ars it initiates are not
+ * interrupted by any intervening start reqeusts from userspace.
+ */
+ if (work_busy(&acpi_desc->work))
+ return -EBUSY;
+
+ return 0;
+}
+
+void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
+{
+ struct nvdimm_bus_descriptor *nd_desc;
dev_set_drvdata(dev, acpi_desc);
acpi_desc->dev = dev;
@@ -1910,14 +2278,10 @@ static struct acpi_nfit_desc *acpi_nfit_desc_init(struct acpi_device *adev)
nd_desc = &acpi_desc->nd_desc;
nd_desc->provider_name = "ACPI.NFIT";
nd_desc->ndctl = acpi_nfit_ctl;
+ nd_desc->flush_probe = acpi_nfit_flush_probe;
+ nd_desc->clear_to_send = acpi_nfit_clear_to_send;
nd_desc->attr_groups = acpi_nfit_attribute_groups;
- acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, nd_desc);
- if (!acpi_desc->nvdimm_bus) {
- devm_kfree(dev, acpi_desc);
- return ERR_PTR(-ENXIO);
- }
-
INIT_LIST_HEAD(&acpi_desc->spa_maps);
INIT_LIST_HEAD(&acpi_desc->spas);
INIT_LIST_HEAD(&acpi_desc->dcrs);
@@ -1928,9 +2292,9 @@ static struct acpi_nfit_desc *acpi_nfit_desc_init(struct acpi_device *adev)
INIT_LIST_HEAD(&acpi_desc->dimms);
mutex_init(&acpi_desc->spa_map_mutex);
mutex_init(&acpi_desc->init_mutex);
-
- return acpi_desc;
+ INIT_WORK(&acpi_desc->work, acpi_nfit_scrub);
}
+EXPORT_SYMBOL_GPL(acpi_nfit_desc_init);
static int acpi_nfit_add(struct acpi_device *adev)
{
@@ -1949,12 +2313,13 @@ static int acpi_nfit_add(struct acpi_device *adev)
return 0;
}
- acpi_desc = acpi_nfit_desc_init(adev);
- if (IS_ERR(acpi_desc)) {
- dev_err(dev, "%s: error initializing acpi_desc: %ld\n",
- __func__, PTR_ERR(acpi_desc));
- return PTR_ERR(acpi_desc);
- }
+ acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
+ if (!acpi_desc)
+ return -ENOMEM;
+ acpi_nfit_desc_init(acpi_desc, &adev->dev);
+ acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, &acpi_desc->nd_desc);
+ if (!acpi_desc->nvdimm_bus)
+ return -ENOMEM;
/*
* Save the acpi header for later and then skip it,
@@ -1993,6 +2358,8 @@ static int acpi_nfit_remove(struct acpi_device *adev)
{
struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
+ acpi_desc->cancel = 1;
+ flush_workqueue(nfit_wq);
nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
return 0;
}
@@ -2017,12 +2384,19 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
}
if (!acpi_desc) {
- acpi_desc = acpi_nfit_desc_init(adev);
- if (IS_ERR(acpi_desc)) {
- dev_err(dev, "%s: error initializing acpi_desc: %ld\n",
- __func__, PTR_ERR(acpi_desc));
+ acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
+ if (!acpi_desc)
goto out_unlock;
- }
+ acpi_nfit_desc_init(acpi_desc, &adev->dev);
+ acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, &acpi_desc->nd_desc);
+ if (!acpi_desc->nvdimm_bus)
+ goto out_unlock;
+ } else {
+ /*
+ * Finish previous registration before considering new
+ * regions.
+ */
+ flush_workqueue(nfit_wq);
}
/* Evaluate _FIT */
@@ -2090,12 +2464,17 @@ static __init int nfit_init(void)
acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]);
acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]);
+ nfit_wq = create_singlethread_workqueue("nfit");
+ if (!nfit_wq)
+ return -ENOMEM;
+
return acpi_bus_register_driver(&acpi_nfit_driver);
}
static __exit void nfit_exit(void)
{
acpi_bus_unregister_driver(&acpi_nfit_driver);
+ destroy_workqueue(nfit_wq);
}
module_init(nfit_init);
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h
index 3d549a383659..c75576b2d50e 100644
--- a/drivers/acpi/nfit.h
+++ b/drivers/acpi/nfit.h
@@ -14,6 +14,7 @@
*/
#ifndef __NFIT_H__
#define __NFIT_H__
+#include <linux/workqueue.h>
#include <linux/libnvdimm.h>
#include <linux/types.h>
#include <linux/uuid.h>
@@ -40,15 +41,32 @@ enum nfit_uuids {
NFIT_UUID_MAX,
};
+enum nfit_fic {
+ NFIT_FIC_BYTE = 0x101, /* byte-addressable energy backed */
+ NFIT_FIC_BLK = 0x201, /* block-addressable non-energy backed */
+ NFIT_FIC_BYTEN = 0x301, /* byte-addressable non-energy backed */
+};
+
enum {
- ND_BLK_READ_FLUSH = 1,
- ND_BLK_DCR_LATCH = 2,
+ NFIT_BLK_READ_FLUSH = 1,
+ NFIT_BLK_DCR_LATCH = 2,
+ NFIT_ARS_STATUS_DONE = 0,
+ NFIT_ARS_STATUS_BUSY = 1 << 16,
+ NFIT_ARS_STATUS_NONE = 2 << 16,
+ NFIT_ARS_STATUS_INTR = 3 << 16,
+ NFIT_ARS_START_BUSY = 6,
+ NFIT_ARS_CAP_NONE = 1,
+ NFIT_ARS_F_OVERFLOW = 1,
+ NFIT_ARS_TIMEOUT = 90,
};
struct nfit_spa {
struct acpi_nfit_system_address *spa;
struct list_head list;
- int is_registered;
+ struct nd_region *nd_region;
+ unsigned int ars_done:1;
+ u32 clear_err_unit;
+ u32 max_ars;
};
struct nfit_dcr {
@@ -110,6 +128,10 @@ struct acpi_nfit_desc {
struct list_head idts;
struct nvdimm_bus *nvdimm_bus;
struct device *dev;
+ struct nd_cmd_ars_status *ars_status;
+ size_t ars_status_size;
+ struct work_struct work;
+ unsigned int cancel:1;
unsigned long dimm_dsm_force_en;
unsigned long bus_dsm_force_en;
int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
@@ -182,5 +204,5 @@ static inline struct acpi_nfit_desc *to_acpi_desc(
const u8 *to_nfit_uuid(enum nfit_uuids id);
int acpi_nfit_init(struct acpi_nfit_desc *nfit, acpi_size sz);
-extern const struct attribute_group *acpi_nfit_attribute_groups[];
+void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
#endif /* __NFIT_H__ */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 67da6fb72274..814d5f83b75e 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -602,6 +602,14 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
return AE_OK;
}
+static void acpi_table_taint(struct acpi_table_header *table)
+{
+ pr_warn(PREFIX
+ "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
+ table->signature, table->oem_table_id);
+ add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
+}
+
#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
#include <linux/earlycpio.h>
#include <linux/memblock.h>
@@ -636,6 +644,7 @@ static const char * const table_sigs[] = {
#define ACPI_OVERRIDE_TABLES 64
static struct cpio_data __initdata acpi_initrd_files[ACPI_OVERRIDE_TABLES];
+static DECLARE_BITMAP(acpi_initrd_installed, ACPI_OVERRIDE_TABLES);
#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT)
@@ -746,96 +755,125 @@ void __init acpi_initrd_override(void *data, size_t size)
}
}
}
-#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
-static void acpi_table_taint(struct acpi_table_header *table)
+acpi_status
+acpi_os_physical_table_override(struct acpi_table_header *existing_table,
+ acpi_physical_address *address, u32 *length)
{
- pr_warn(PREFIX
- "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
- table->signature, table->oem_table_id);
- add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
-}
+ int table_offset = 0;
+ int table_index = 0;
+ struct acpi_table_header *table;
+ u32 table_length;
+ *length = 0;
+ *address = 0;
+ if (!acpi_tables_addr)
+ return AE_OK;
-acpi_status
-acpi_os_table_override(struct acpi_table_header * existing_table,
- struct acpi_table_header ** new_table)
-{
- if (!existing_table || !new_table)
- return AE_BAD_PARAMETER;
+ while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
+ table = acpi_os_map_memory(acpi_tables_addr + table_offset,
+ ACPI_HEADER_SIZE);
+ if (table_offset + table->length > all_tables_size) {
+ acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+ WARN_ON(1);
+ return AE_OK;
+ }
- *new_table = NULL;
+ table_length = table->length;
-#ifdef CONFIG_ACPI_CUSTOM_DSDT
- if (strncmp(existing_table->signature, "DSDT", 4) == 0)
- *new_table = (struct acpi_table_header *)AmlCode;
-#endif
- if (*new_table != NULL)
+ /* Only override tables matched */
+ if (test_bit(table_index, acpi_initrd_installed) ||
+ memcmp(existing_table->signature, table->signature, 4) ||
+ memcmp(table->oem_table_id, existing_table->oem_table_id,
+ ACPI_OEM_TABLE_ID_SIZE)) {
+ acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+ goto next_table;
+ }
+
+ *length = table_length;
+ *address = acpi_tables_addr + table_offset;
acpi_table_taint(existing_table);
+ acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+ set_bit(table_index, acpi_initrd_installed);
+ break;
+
+next_table:
+ table_offset += table_length;
+ table_index++;
+ }
return AE_OK;
}
-acpi_status
-acpi_os_physical_table_override(struct acpi_table_header *existing_table,
- acpi_physical_address *address,
- u32 *table_length)
+void __init acpi_initrd_initialize_tables(void)
{
-#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
- *table_length = 0;
- *address = 0;
- return AE_OK;
-#else
int table_offset = 0;
+ int table_index = 0;
+ u32 table_length;
struct acpi_table_header *table;
- *table_length = 0;
- *address = 0;
-
if (!acpi_tables_addr)
- return AE_OK;
-
- do {
- if (table_offset + ACPI_HEADER_SIZE > all_tables_size) {
- WARN_ON(1);
- return AE_OK;
- }
+ return;
+ while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
table = acpi_os_map_memory(acpi_tables_addr + table_offset,
ACPI_HEADER_SIZE);
-
if (table_offset + table->length > all_tables_size) {
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
WARN_ON(1);
- return AE_OK;
+ return;
}
- table_offset += table->length;
+ table_length = table->length;
- if (memcmp(existing_table->signature, table->signature, 4)) {
- acpi_os_unmap_memory(table,
- ACPI_HEADER_SIZE);
- continue;
- }
-
- /* Only override tables with matching oem id */
- if (memcmp(table->oem_table_id, existing_table->oem_table_id,
- ACPI_OEM_TABLE_ID_SIZE)) {
- acpi_os_unmap_memory(table,
- ACPI_HEADER_SIZE);
- continue;
+ /* Skip RSDT/XSDT which should only be used for override */
+ if (test_bit(table_index, acpi_initrd_installed) ||
+ ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) ||
+ ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) {
+ acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+ goto next_table;
}
- table_offset -= table->length;
- *table_length = table->length;
+ acpi_table_taint(table);
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
- *address = acpi_tables_addr + table_offset;
- break;
- } while (table_offset + ACPI_HEADER_SIZE < all_tables_size);
+ acpi_install_table(acpi_tables_addr + table_offset, TRUE);
+ set_bit(table_index, acpi_initrd_installed);
+next_table:
+ table_offset += table_length;
+ table_index++;
+ }
+}
+#else
+acpi_status
+acpi_os_physical_table_override(struct acpi_table_header *existing_table,
+ acpi_physical_address *address,
+ u32 *table_length)
+{
+ *table_length = 0;
+ *address = 0;
+ return AE_OK;
+}
+
+void __init acpi_initrd_initialize_tables(void)
+{
+}
+#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
- if (*address != 0)
+acpi_status
+acpi_os_table_override(struct acpi_table_header *existing_table,
+ struct acpi_table_header **new_table)
+{
+ if (!existing_table || !new_table)
+ return AE_BAD_PARAMETER;
+
+ *new_table = NULL;
+
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
+ if (strncmp(existing_table->signature, "DSDT", 4) == 0)
+ *new_table = (struct acpi_table_header *)AmlCode;
+#endif
+ if (*new_table != NULL)
acpi_table_taint(existing_table);
return AE_OK;
-#endif
}
static irqreturn_t acpi_irq(int irq, void *dev_id)
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index d30184c7f3bc..2c45dd3acc17 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -33,6 +33,7 @@
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/slab.h>
+#include <linux/interrupt.h>
#define PREFIX "ACPI: "
@@ -387,6 +388,23 @@ static inline int acpi_isa_register_gsi(struct pci_dev *dev)
}
#endif
+static inline bool acpi_pci_irq_valid(struct pci_dev *dev, u8 pin)
+{
+#ifdef CONFIG_X86
+ /*
+ * On x86 irq line 0xff means "unknown" or "no connection"
+ * (PCI 3.0, Section 6.2.4, footnote on page 223).
+ */
+ if (dev->irq == 0xff) {
+ dev->irq = IRQ_NOTCONNECTED;
+ dev_warn(&dev->dev, "PCI INT %c: not connected\n",
+ pin_name(pin));
+ return false;
+ }
+#endif
+ return true;
+}
+
int acpi_pci_irq_enable(struct pci_dev *dev)
{
struct acpi_prt_entry *entry;
@@ -406,7 +424,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
return 0;
}
- if (pci_has_managed_irq(dev))
+ if (dev->irq_managed && dev->irq > 0)
return 0;
entry = acpi_pci_irq_lookup(dev, pin);
@@ -431,11 +449,14 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
} else
gsi = -1;
- /*
- * No IRQ known to the ACPI subsystem - maybe the BIOS /
- * driver reported one, then use it. Exit in any case.
- */
if (gsi < 0) {
+ /*
+ * No IRQ known to the ACPI subsystem - maybe the BIOS /
+ * driver reported one, then use it. Exit in any case.
+ */
+ if (!acpi_pci_irq_valid(dev, pin))
+ return 0;
+
if (acpi_isa_register_gsi(dev))
dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
pin_name(pin));
@@ -451,7 +472,8 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
kfree(entry);
return rc;
}
- pci_set_managed_irq(dev, rc);
+ dev->irq = rc;
+ dev->irq_managed = 1;
if (link)
snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link);
@@ -474,9 +496,17 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
u8 pin;
pin = dev->pin;
- if (!pin || !pci_has_managed_irq(dev))
+ if (!pin || !dev->irq_managed || dev->irq <= 0)
return;
+ /* Keep IOAPIC pin configuration when suspending */
+ if (dev->dev.power.is_prepared)
+ return;
+#ifdef CONFIG_PM
+ if (dev->dev.power.runtime_status == RPM_SUSPENDING)
+ return;
+#endif
+
entry = acpi_pci_irq_lookup(dev, pin);
if (!entry)
return;
@@ -496,6 +526,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
if (gsi >= 0) {
acpi_unregister_gsi(gsi);
- pci_reset_managed_irq(dev);
+ dev->irq_managed = 0;
}
}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index fa2863567eed..ededa909df2f 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -4,7 +4,6 @@
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2002 Dominik Brodowski <devel@brodo.de>
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -438,6 +437,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
* enabled system.
*/
+#define ACPI_MAX_IRQS 256
#define ACPI_MAX_ISA_IRQ 16
#define PIRQ_PENALTY_PCI_AVAILABLE (0)
@@ -447,7 +447,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16)
#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16)
-static int acpi_irq_isa_penalty[ACPI_MAX_ISA_IRQ] = {
+static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */
@@ -464,68 +464,9 @@ static int acpi_irq_isa_penalty[ACPI_MAX_ISA_IRQ] = {
PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */
PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */
PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */
+ /* >IRQ15 */
};
-struct irq_penalty_info {
- int irq;
- int penalty;
- struct list_head node;
-};
-
-static LIST_HEAD(acpi_irq_penalty_list);
-
-static int acpi_irq_get_penalty(int irq)
-{
- struct irq_penalty_info *irq_info;
-
- if (irq < ACPI_MAX_ISA_IRQ)
- return acpi_irq_isa_penalty[irq];
-
- list_for_each_entry(irq_info, &acpi_irq_penalty_list, node) {
- if (irq_info->irq == irq)
- return irq_info->penalty;
- }
-
- return 0;
-}
-
-static int acpi_irq_set_penalty(int irq, int new_penalty)
-{
- struct irq_penalty_info *irq_info;
-
- /* see if this is a ISA IRQ */
- if (irq < ACPI_MAX_ISA_IRQ) {
- acpi_irq_isa_penalty[irq] = new_penalty;
- return 0;
- }
-
- /* next, try to locate from the dynamic list */
- list_for_each_entry(irq_info, &acpi_irq_penalty_list, node) {
- if (irq_info->irq == irq) {
- irq_info->penalty = new_penalty;
- return 0;
- }
- }
-
- /* nope, let's allocate a slot for this IRQ */
- irq_info = kzalloc(sizeof(*irq_info), GFP_KERNEL);
- if (!irq_info)
- return -ENOMEM;
-
- irq_info->irq = irq;
- irq_info->penalty = new_penalty;
- list_add_tail(&irq_info->node, &acpi_irq_penalty_list);
-
- return 0;
-}
-
-static void acpi_irq_add_penalty(int irq, int penalty)
-{
- int curpen = acpi_irq_get_penalty(irq);
-
- acpi_irq_set_penalty(irq, curpen + penalty);
-}
-
int __init acpi_irq_penalty_init(void)
{
struct acpi_pci_link *link;
@@ -546,16 +487,15 @@ int __init acpi_irq_penalty_init(void)
link->irq.possible_count;
for (i = 0; i < link->irq.possible_count; i++) {
- if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) {
- int irqpos = link->irq.possible[i];
-
- acpi_irq_add_penalty(irqpos, penalty);
- }
+ if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
+ acpi_irq_penalty[link->irq.
+ possible[i]] +=
+ penalty;
}
} else if (link->irq.active) {
- acpi_irq_add_penalty(link->irq.active,
- PIRQ_PENALTY_PCI_POSSIBLE);
+ acpi_irq_penalty[link->irq.active] +=
+ PIRQ_PENALTY_PCI_POSSIBLE;
}
}
@@ -607,12 +547,12 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
* the use of IRQs 9, 10, 11, and >15.
*/
for (i = (link->irq.possible_count - 1); i >= 0; i--) {
- if (acpi_irq_get_penalty(irq) >
- acpi_irq_get_penalty(link->irq.possible[i]))
+ if (acpi_irq_penalty[irq] >
+ acpi_irq_penalty[link->irq.possible[i]])
irq = link->irq.possible[i];
}
}
- if (acpi_irq_get_penalty(irq) >= PIRQ_PENALTY_ISA_ALWAYS) {
+ if (acpi_irq_penalty[irq] >= PIRQ_PENALTY_ISA_ALWAYS) {
printk(KERN_ERR PREFIX "No IRQ available for %s [%s]. "
"Try pci=noacpi or acpi=off\n",
acpi_device_name(link->device),
@@ -628,8 +568,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
acpi_device_bid(link->device));
return -ENODEV;
} else {
- acpi_irq_add_penalty(link->irq.active, PIRQ_PENALTY_PCI_USING);
-
+ acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
acpi_device_name(link->device),
acpi_device_bid(link->device), link->irq.active);
@@ -839,7 +778,7 @@ static void acpi_pci_link_remove(struct acpi_device *device)
}
/*
- * modify penalty from cmdline
+ * modify acpi_irq_penalty[] from cmdline
*/
static int __init acpi_irq_penalty_update(char *str, int used)
{
@@ -857,10 +796,13 @@ static int __init acpi_irq_penalty_update(char *str, int used)
if (irq < 0)
continue;
+ if (irq >= ARRAY_SIZE(acpi_irq_penalty))
+ continue;
+
if (used)
- acpi_irq_add_penalty(irq, PIRQ_PENALTY_ISA_USED);
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
else
- acpi_irq_set_penalty(irq, PIRQ_PENALTY_PCI_AVAILABLE);
+ acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;
if (retval != 2) /* no next number */
break;
@@ -877,15 +819,18 @@ static int __init acpi_irq_penalty_update(char *str, int used)
*/
void acpi_penalize_isa_irq(int irq, int active)
{
- if (irq >= 0)
- acpi_irq_add_penalty(irq, active ?
- PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING);
+ if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
+ if (active)
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
+ else
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
+ }
}
bool acpi_isa_irq_available(int irq)
{
- return irq >= 0 &&
- (acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
+ return irq >= 0 && (irq >= ARRAY_SIZE(acpi_irq_penalty) ||
+ acpi_irq_penalty[irq] < PIRQ_PENALTY_ISA_ALWAYS);
}
/*
@@ -895,18 +840,13 @@ bool acpi_isa_irq_available(int irq)
*/
void acpi_penalize_sci_irq(int irq, int trigger, int polarity)
{
- int penalty;
-
- if (irq < 0)
- return;
-
- if (trigger != ACPI_MADT_TRIGGER_LEVEL ||
- polarity != ACPI_MADT_POLARITY_ACTIVE_LOW)
- penalty = PIRQ_PENALTY_ISA_ALWAYS;
- else
- penalty = PIRQ_PENALTY_PCI_USING;
-
- acpi_irq_add_penalty(irq, penalty);
+ if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
+ if (trigger != ACPI_MADT_TRIGGER_LEVEL ||
+ polarity != ACPI_MADT_POLARITY_ACTIVE_LOW)
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_ALWAYS;
+ else
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
+ }
}
/*
diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c
index 42df46a86c25..fcd1852dcdee 100644
--- a/drivers/acpi/pmic/intel_pmic_crc.c
+++ b/drivers/acpi/pmic/intel_pmic_crc.c
@@ -13,7 +13,7 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/regmap.h>
@@ -205,7 +205,4 @@ static int __init intel_crc_pmic_opregion_driver_init(void)
{
return platform_driver_register(&intel_crc_pmic_opregion_driver);
}
-module_init(intel_crc_pmic_opregion_driver_init);
-
-MODULE_DESCRIPTION("CrystalCove ACPI operation region driver");
-MODULE_LICENSE("GPL");
+device_initcall(intel_crc_pmic_opregion_driver_init);
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 11154a330f07..d2fa8cb82d2b 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -314,7 +314,6 @@ static int __init acpi_processor_driver_init(void)
if (result < 0)
return result;
- acpi_processor_syscore_init();
register_hotcpu_notifier(&acpi_cpu_notifier);
acpi_thermal_cpufreq_init();
acpi_processor_ppc_init();
@@ -330,7 +329,6 @@ static void __exit acpi_processor_driver_exit(void)
acpi_processor_ppc_exit();
acpi_thermal_cpufreq_exit();
unregister_hotcpu_notifier(&acpi_cpu_notifier);
- acpi_processor_syscore_exit();
driver_unregister(&acpi_processor_driver);
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 175c86bee3a9..444e3745c8b3 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -23,6 +23,7 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#define pr_fmt(fmt) "ACPI: " fmt
#include <linux/module.h>
#include <linux/acpi.h>
@@ -30,7 +31,6 @@
#include <linux/sched.h> /* need_resched() */
#include <linux/tick.h>
#include <linux/cpuidle.h>
-#include <linux/syscore_ops.h>
#include <acpi/processor.h>
/*
@@ -43,8 +43,6 @@
#include <asm/apic.h>
#endif
-#define PREFIX "ACPI: "
-
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_idle");
@@ -61,8 +59,8 @@ module_param(latency_factor, uint, 0644);
static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device);
-static DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX],
- acpi_cstate);
+static
+DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX], acpi_cstate);
static int disabled_by_idle_boot_param(void)
{
@@ -81,9 +79,9 @@ static int set_max_cstate(const struct dmi_system_id *id)
if (max_cstate > ACPI_PROCESSOR_MAX_POWER)
return 0;
- printk(KERN_NOTICE PREFIX "%s detected - limiting to C%ld max_cstate."
- " Override with \"processor.max_cstate=%d\"\n", id->ident,
- (long)id->driver_data, ACPI_PROCESSOR_MAX_POWER + 1);
+ pr_notice("%s detected - limiting to C%ld max_cstate."
+ " Override with \"processor.max_cstate=%d\"\n", id->ident,
+ (long)id->driver_data, ACPI_PROCESSOR_MAX_POWER + 1);
max_cstate = (long)id->driver_data;
@@ -194,42 +192,6 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
#endif
-#ifdef CONFIG_PM_SLEEP
-static u32 saved_bm_rld;
-
-static int acpi_processor_suspend(void)
-{
- acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);
- return 0;
-}
-
-static void acpi_processor_resume(void)
-{
- u32 resumed_bm_rld = 0;
-
- acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld);
- if (resumed_bm_rld == saved_bm_rld)
- return;
-
- acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
-}
-
-static struct syscore_ops acpi_processor_syscore_ops = {
- .suspend = acpi_processor_suspend,
- .resume = acpi_processor_resume,
-};
-
-void acpi_processor_syscore_init(void)
-{
- register_syscore_ops(&acpi_processor_syscore_ops);
-}
-
-void acpi_processor_syscore_exit(void)
-{
- unregister_syscore_ops(&acpi_processor_syscore_ops);
-}
-#endif /* CONFIG_PM_SLEEP */
-
#if defined(CONFIG_X86)
static void tsc_check_state(int state)
{
@@ -351,7 +313,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
/* There must be at least 2 elements */
if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
- printk(KERN_ERR PREFIX "not enough elements in _CST\n");
+ pr_err("not enough elements in _CST\n");
ret = -EFAULT;
goto end;
}
@@ -360,7 +322,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
/* Validate number of power states. */
if (count < 1 || count != cst->package.count - 1) {
- printk(KERN_ERR PREFIX "count given by _CST is not valid\n");
+ pr_err("count given by _CST is not valid\n");
ret = -EFAULT;
goto end;
}
@@ -469,11 +431,9 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
* (From 1 through ACPI_PROCESSOR_MAX_POWER - 1)
*/
if (current_count >= (ACPI_PROCESSOR_MAX_POWER - 1)) {
- printk(KERN_WARNING
- "Limiting number of power states to max (%d)\n",
- ACPI_PROCESSOR_MAX_POWER);
- printk(KERN_WARNING
- "Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n");
+ pr_warn("Limiting number of power states to max (%d)\n",
+ ACPI_PROCESSOR_MAX_POWER);
+ pr_warn("Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n");
break;
}
}
@@ -1097,8 +1057,8 @@ int acpi_processor_power_init(struct acpi_processor *pr)
retval = cpuidle_register_driver(&acpi_idle_driver);
if (retval)
return retval;
- printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
- acpi_idle_driver.name);
+ pr_debug("%s registered with cpuidle\n",
+ acpi_idle_driver.name);
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 407a3760e8de..5f28cf778349 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1930,6 +1930,7 @@ int __init acpi_scan_init(void)
acpi_memory_hotplug_init();
acpi_pnp_init();
acpi_int340x_thermal_init();
+ acpi_amba_init();
acpi_scan_add_handler(&generic_device_handler);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 9cb975200cac..fbfcce3b5227 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -19,6 +19,7 @@
#include <linux/reboot.h>
#include <linux/acpi.h>
#include <linux/module.h>
+#include <linux/syscore_ops.h>
#include <asm/io.h>
#include <trace/events/power.h>
@@ -677,6 +678,39 @@ static void acpi_sleep_suspend_setup(void)
static inline void acpi_sleep_suspend_setup(void) {}
#endif /* !CONFIG_SUSPEND */
+#ifdef CONFIG_PM_SLEEP
+static u32 saved_bm_rld;
+
+static int acpi_save_bm_rld(void)
+{
+ acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);
+ return 0;
+}
+
+static void acpi_restore_bm_rld(void)
+{
+ u32 resumed_bm_rld = 0;
+
+ acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld);
+ if (resumed_bm_rld == saved_bm_rld)
+ return;
+
+ acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
+}
+
+static struct syscore_ops acpi_sleep_syscore_ops = {
+ .suspend = acpi_save_bm_rld,
+ .resume = acpi_restore_bm_rld,
+};
+
+void acpi_sleep_syscore_init(void)
+{
+ register_syscore_ops(&acpi_sleep_syscore_ops);
+}
+#else
+static inline void acpi_sleep_syscore_init(void) {}
+#endif /* CONFIG_PM_SLEEP */
+
#ifdef CONFIG_HIBERNATION
static unsigned long s4_hardware_signature;
static struct acpi_table_facs *facs;
@@ -839,6 +873,7 @@ int __init acpi_sleep_init(void)
sleep_states[ACPI_STATE_S0] = 1;
+ acpi_sleep_syscore_init();
acpi_sleep_suspend_setup();
acpi_sleep_hibernate_setup();
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 6c0f0794aa82..f49c02442d65 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -32,6 +32,7 @@
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/bootmem.h>
+#include "internal.h"
#define ACPI_MAX_TABLES 128
@@ -456,6 +457,7 @@ int __init acpi_table_init(void)
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
if (ACPI_FAILURE(status))
return -EINVAL;
+ acpi_initrd_initialize_tables();
check_multiple_madt();
return 0;
@@ -484,3 +486,13 @@ static int __init acpi_force_table_verification_setup(char *s)
}
early_param("acpi_force_table_verification", acpi_force_table_verification_setup);
+
+static int __init acpi_force_32bit_fadt_addr(char *s)
+{
+ pr_info("Forcing 32 Bit FADT addresses\n");
+ acpi_gbl_use32_bit_fadt_addresses = TRUE;
+
+ return 0;
+}
+
+early_param("acpi_force_32bit_fadt_addr", acpi_force_32bit_fadt_addr);
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index f2f9873bb5c3..f12a72428aac 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -201,10 +201,6 @@ acpi_extract_package(union acpi_object *package,
u8 **pointer = NULL;
union acpi_object *element = &(package->package.elements[i]);
- if (!element) {
- return AE_BAD_DATA;
- }
-
switch (element->type) {
case ACPI_TYPE_INTEGER:
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index a39e85f9efa9..57f52a2afa35 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -1321,6 +1321,7 @@ static void binder_transaction(struct binder_proc *proc,
struct binder_transaction *t;
struct binder_work *tcomplete;
binder_size_t *offp, *off_end;
+ binder_size_t off_min;
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
@@ -1522,18 +1523,24 @@ static void binder_transaction(struct binder_proc *proc,
goto err_bad_offset;
}
off_end = (void *)offp + tr->offsets_size;
+ off_min = 0;
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
if (*offp > t->buffer->data_size - sizeof(*fp) ||
+ *offp < off_min ||
t->buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(u32))) {
- binder_user_error("%d:%d got transaction with invalid offset, %lld\n",
- proc->pid, thread->pid, (u64)*offp);
+ binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)\n",
+ proc->pid, thread->pid, (u64)*offp,
+ (u64)off_min,
+ (u64)(t->buffer->data_size -
+ sizeof(*fp)));
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
+ off_min = *offp + sizeof(struct flat_binder_object);
switch (fp->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
@@ -2074,7 +2081,7 @@ static int binder_thread_write(struct binder_proc *proc,
if (get_user(cookie, (binder_uintptr_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(cookie);
list_for_each_entry(w, &proc->delivered_death, entry) {
struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);
@@ -3593,13 +3600,24 @@ static int binder_transactions_show(struct seq_file *m, void *unused)
static int binder_proc_show(struct seq_file *m, void *unused)
{
+ struct binder_proc *itr;
struct binder_proc *proc = m->private;
int do_lock = !binder_debug_no_lock;
+ bool valid_proc = false;
if (do_lock)
binder_lock(__func__);
- seq_puts(m, "binder proc state:\n");
- print_binder_proc(m, proc, 1);
+
+ hlist_for_each_entry(itr, &binder_procs, proc_node) {
+ if (itr == proc) {
+ valid_proc = true;
+ break;
+ }
+ }
+ if (valid_proc) {
+ seq_puts(m, "binder proc state:\n");
+ print_binder_proc(m, proc, 1);
+ }
if (do_lock)
binder_unlock(__func__);
return 0;
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 546a3692774f..146dc0b8ec61 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -367,15 +367,21 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
{ PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
{ PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -1325,6 +1331,44 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{}
#endif
+#ifdef CONFIG_ARM64
+/*
+ * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently.
+ * Workaround is to make sure all pending IRQs are served before leaving
+ * handler.
+ */
+static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct ahci_host_priv *hpriv;
+ unsigned int rc = 0;
+ void __iomem *mmio;
+ u32 irq_stat, irq_masked;
+ unsigned int handled = 1;
+
+ VPRINTK("ENTER\n");
+ hpriv = host->private_data;
+ mmio = hpriv->mmio;
+ irq_stat = readl(mmio + HOST_IRQ_STAT);
+ if (!irq_stat)
+ return IRQ_NONE;
+
+ do {
+ irq_masked = irq_stat & hpriv->port_map;
+ spin_lock(&host->lock);
+ rc = ahci_handle_port_intr(host, irq_masked);
+ if (!rc)
+ handled = 0;
+ writel(irq_stat, mmio + HOST_IRQ_STAT);
+ irq_stat = readl(mmio + HOST_IRQ_STAT);
+ spin_unlock(&host->lock);
+ } while (irq_stat);
+ VPRINTK("EXIT\n");
+
+ return IRQ_RETVAL(handled);
+}
+#endif
+
/*
* ahci_init_msix() - optionally enable per-port MSI-X otherwise defer
* to single msi.
@@ -1560,6 +1604,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ahci_broken_devslp(pdev))
hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
+#ifdef CONFIG_ARM64
+ if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
+ hpriv->irq_handler = ahci_thunderx_irq_handler;
+#endif
+
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index a44c75d4c284..167ba7e3b92e 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -240,8 +240,7 @@ enum {
error-handling stage) */
AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */
AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
- AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as
- Edge Triggered */
+
#ifdef CONFIG_PCI_MSI
AHCI_HFLAG_MULTI_MSI = (1 << 20), /* multiple PCI MSIs */
AHCI_HFLAG_MULTI_MSIX = (1 << 21), /* per-port MSI-X */
@@ -361,6 +360,7 @@ struct ahci_host_priv {
* be overridden anytime before the host is activated.
*/
void (*start_engine)(struct ata_port *ap);
+ irqreturn_t (*irq_handler)(int irq, void *dev_instance);
};
#ifdef CONFIG_PCI_MSI
@@ -424,6 +424,7 @@ int ahci_reset_em(struct ata_host *host);
void ahci_print_info(struct ata_host *host, const char *scc_s);
int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht);
void ahci_error_handler(struct ata_port *ap);
+u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked);
static inline void __iomem *__ahci_port_base(struct ata_host *host,
unsigned int port_no)
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
index e2c6d9e0c5ac..8e3f7faf00d3 100644
--- a/drivers/ata/ahci_xgene.c
+++ b/drivers/ata/ahci_xgene.c
@@ -548,6 +548,88 @@ softreset_retry:
return rc;
}
+/**
+ * xgene_ahci_handle_broken_edge_irq - Handle the broken irq.
+ * @ata_host: Host that recieved the irq
+ * @irq_masked: HOST_IRQ_STAT value
+ *
+ * For hardware with broken edge trigger latch
+ * the HOST_IRQ_STAT register misses the edge interrupt
+ * when clearing of HOST_IRQ_STAT register and hardware
+ * reporting the PORT_IRQ_STAT register at the
+ * same clock cycle.
+ * As such, the algorithm below outlines the workaround.
+ *
+ * 1. Read HOST_IRQ_STAT register and save the state.
+ * 2. Clear the HOST_IRQ_STAT register.
+ * 3. Read back the HOST_IRQ_STAT register.
+ * 4. If HOST_IRQ_STAT register equals to zero, then
+ * traverse the rest of port's PORT_IRQ_STAT register
+ * to check if an interrupt is triggered at that point else
+ * go to step 6.
+ * 5. If PORT_IRQ_STAT register of rest ports is not equal to zero
+ * then update the state of HOST_IRQ_STAT saved in step 1.
+ * 6. Handle port interrupts.
+ * 7. Exit
+ */
+static int xgene_ahci_handle_broken_edge_irq(struct ata_host *host,
+ u32 irq_masked)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *port_mmio;
+ int i;
+
+ if (!readl(hpriv->mmio + HOST_IRQ_STAT)) {
+ for (i = 0; i < host->n_ports; i++) {
+ if (irq_masked & (1 << i))
+ continue;
+
+ port_mmio = ahci_port_base(host->ports[i]);
+ if (readl(port_mmio + PORT_IRQ_STAT))
+ irq_masked |= (1 << i);
+ }
+ }
+
+ return ahci_handle_port_intr(host, irq_masked);
+}
+
+static irqreturn_t xgene_ahci_irq_intr(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct ahci_host_priv *hpriv;
+ unsigned int rc = 0;
+ void __iomem *mmio;
+ u32 irq_stat, irq_masked;
+
+ VPRINTK("ENTER\n");
+
+ hpriv = host->private_data;
+ mmio = hpriv->mmio;
+
+ /* sigh. 0xffffffff is a valid return from h/w */
+ irq_stat = readl(mmio + HOST_IRQ_STAT);
+ if (!irq_stat)
+ return IRQ_NONE;
+
+ irq_masked = irq_stat & hpriv->port_map;
+
+ spin_lock(&host->lock);
+
+ /*
+ * HOST_IRQ_STAT behaves as edge triggered latch meaning that
+ * it should be cleared before all the port events are cleared.
+ */
+ writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+ rc = xgene_ahci_handle_broken_edge_irq(host, irq_masked);
+
+ spin_unlock(&host->lock);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_RETVAL(rc);
+}
+
static struct ata_port_operations xgene_ahci_v1_ops = {
.inherits = &ahci_ops,
.host_stop = xgene_ahci_host_stop,
@@ -779,7 +861,8 @@ skip_clk_phy:
hpriv->flags = AHCI_HFLAG_NO_NCQ;
break;
case XGENE_AHCI_V2:
- hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ;
+ hpriv->flags |= AHCI_HFLAG_YES_FBS;
+ hpriv->irq_handler = xgene_ahci_irq_intr;
break;
default:
break;
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 402967902cbe..85ea5142a095 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -113,6 +113,7 @@ static ssize_t ahci_store_em_buffer(struct device *dev,
const char *buf, size_t size);
static ssize_t ahci_show_em_supported(struct device *dev,
struct device_attribute *attr, char *buf);
+static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance);
static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
@@ -512,6 +513,9 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
if (!hpriv->start_engine)
hpriv->start_engine = ahci_start_engine;
+
+ if (!hpriv->irq_handler)
+ hpriv->irq_handler = ahci_single_level_irq_intr;
}
EXPORT_SYMBOL_GPL(ahci_save_initial_config);
@@ -1164,8 +1168,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap,
/* mark esata ports */
tmp = readl(port_mmio + PORT_CMD);
- if ((tmp & PORT_CMD_HPCP) ||
- ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)))
+ if ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS))
ap->pflags |= ATA_PFLAG_EXTERNAL;
}
@@ -1846,7 +1849,7 @@ static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance)
return IRQ_HANDLED;
}
-static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
+u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
{
unsigned int i, handled = 0;
@@ -1872,43 +1875,7 @@ static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
return handled;
}
-
-static irqreturn_t ahci_single_edge_irq_intr(int irq, void *dev_instance)
-{
- struct ata_host *host = dev_instance;
- struct ahci_host_priv *hpriv;
- unsigned int rc = 0;
- void __iomem *mmio;
- u32 irq_stat, irq_masked;
-
- VPRINTK("ENTER\n");
-
- hpriv = host->private_data;
- mmio = hpriv->mmio;
-
- /* sigh. 0xffffffff is a valid return from h/w */
- irq_stat = readl(mmio + HOST_IRQ_STAT);
- if (!irq_stat)
- return IRQ_NONE;
-
- irq_masked = irq_stat & hpriv->port_map;
-
- spin_lock(&host->lock);
-
- /*
- * HOST_IRQ_STAT behaves as edge triggered latch meaning that
- * it should be cleared before all the port events are cleared.
- */
- writel(irq_stat, mmio + HOST_IRQ_STAT);
-
- rc = ahci_handle_port_intr(host, irq_masked);
-
- spin_unlock(&host->lock);
-
- VPRINTK("EXIT\n");
-
- return IRQ_RETVAL(rc);
-}
+EXPORT_SYMBOL_GPL(ahci_handle_port_intr);
static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance)
{
@@ -2535,14 +2502,18 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
int irq = hpriv->irq;
int rc;
- if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX))
+ if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) {
+ if (hpriv->irq_handler)
+ dev_warn(host->dev, "both AHCI_HFLAG_MULTI_MSI flag set \
+ and custom irq handler implemented\n");
+
rc = ahci_host_activate_multi_irqs(host, sht);
- else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ)
- rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr,
- IRQF_SHARED, sht);
- else
- rc = ata_host_activate(host, irq, ahci_single_level_irq_intr,
+ } else {
+ rc = ata_host_activate(host, irq, hpriv->irq_handler,
IRQF_SHARED, sht);
+ }
+
+
return rc;
}
EXPORT_SYMBOL_GPL(ahci_host_activate);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 7e959f90c020..e417e1a1d02c 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -675,19 +675,18 @@ static int ata_ioc32(struct ata_port *ap)
int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
int cmd, void __user *arg)
{
- int val = -EINVAL, rc = -EINVAL;
+ unsigned long val;
+ int rc = -EINVAL;
unsigned long flags;
switch (cmd) {
- case ATA_IOC_GET_IO32:
+ case HDIO_GET_32BIT:
spin_lock_irqsave(ap->lock, flags);
val = ata_ioc32(ap);
spin_unlock_irqrestore(ap->lock, flags);
- if (copy_to_user(arg, &val, 1))
- return -EFAULT;
- return 0;
+ return put_user(val, (unsigned long __user *)arg);
- case ATA_IOC_SET_IO32:
+ case HDIO_SET_32BIT:
val = (unsigned long) arg;
rc = 0;
spin_lock_irqsave(ap->lock, flags);
diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c
index e3d4b059fcd1..e347e7acd8ed 100644
--- a/drivers/ata/pata_macio.c
+++ b/drivers/ata/pata_macio.c
@@ -22,6 +22,7 @@
#include <linux/scatterlist.h>
#include <linux/of.h>
#include <linux/gfp.h>
+#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -30,7 +31,6 @@
#include <asm/macio.h>
#include <asm/io.h>
#include <asm/dbdma.h>
-#include <asm/pci-bridge.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/mediabay.h>
diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c
index 12fe0f3bb7e9..c8b6a780a290 100644
--- a/drivers/ata/pata_rb532_cf.c
+++ b/drivers/ata/pata_rb532_cf.c
@@ -32,6 +32,8 @@
#include <linux/libata.h>
#include <scsi/scsi_host.h>
+#include <asm/mach-rc32434/rb.h>
+
#define DRV_NAME "pata-rb532-cf"
#define DRV_VERSION "0.1.0"
#define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash"
@@ -107,6 +109,7 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
int gpio;
struct resource *res;
struct ata_host *ah;
+ struct cf_device *pdata;
struct rb532_cf_info *info;
int ret;
@@ -122,7 +125,13 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
return -ENOENT;
}
- gpio = irq_to_gpio(irq);
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+
+ gpio = pdata->gpio_pin;
if (gpio < 0) {
dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq);
return -ENOENT;
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 500592486e88..6470eb8088f4 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -149,8 +149,7 @@ EXPORT_SYMBOL_GPL(bus_remove_file);
static void bus_release(struct kobject *kobj)
{
- struct subsys_private *priv =
- container_of(kobj, typeof(*priv), subsys.kobj);
+ struct subsys_private *priv = to_subsys_private(kobj);
struct bus_type *bus = priv->bus;
kfree(priv);
@@ -1019,13 +1018,11 @@ static void device_insertion_sort_klist(struct device *a, struct list_head *list
int (*compare)(const struct device *a,
const struct device *b))
{
- struct list_head *pos;
struct klist_node *n;
struct device_private *dev_prv;
struct device *b;
- list_for_each(pos, list) {
- n = container_of(pos, struct klist_node, n_node);
+ list_for_each_entry(n, list, n_node) {
dev_prv = to_device_private_bus(n);
b = dev_prv->device;
if (compare(a, b) <= 0) {
@@ -1042,8 +1039,7 @@ void bus_sort_breadthfirst(struct bus_type *bus,
const struct device *b))
{
LIST_HEAD(sorted_devices);
- struct list_head *pos, *tmp;
- struct klist_node *n;
+ struct klist_node *n, *tmp;
struct device_private *dev_prv;
struct device *dev;
struct klist *device_klist;
@@ -1051,8 +1047,7 @@ void bus_sort_breadthfirst(struct bus_type *bus,
device_klist = bus_get_device_klist(bus);
spin_lock(&device_klist->k_lock);
- list_for_each_safe(pos, tmp, &device_klist->k_list) {
- n = container_of(pos, struct klist_node, n_node);
+ list_for_each_entry_safe(n, tmp, &device_klist->k_list, n_node) {
dev_prv = to_device_private_bus(n);
dev = dev_prv->device;
device_insertion_sort_klist(dev, &sorted_devices, compare);
@@ -1107,7 +1102,7 @@ struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter)
knode = klist_next(&iter->ki);
if (!knode)
return NULL;
- dev = container_of(knode, struct device_private, knode_bus)->device;
+ dev = to_device_private_bus(knode)->device;
if (!iter->type || iter->type == dev->type)
return dev;
}
diff --git a/drivers/base/component.c b/drivers/base/component.c
index 04a1582e80bb..89b032f2ffd2 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -267,7 +267,7 @@ void component_match_add_release(struct device *master,
}
if (match->num == match->alloc) {
- size_t new_size = match ? match->alloc + 16 : 15;
+ size_t new_size = match->alloc + 16;
int ret;
ret = component_match_realloc(master, match, new_size);
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
index 55b83983a9c0..87b808374888 100644
--- a/drivers/base/dma-coherent.c
+++ b/drivers/base/dma-coherent.c
@@ -17,9 +17,9 @@ struct dma_coherent_mem {
spinlock_t spinlock;
};
-static int dma_init_coherent_memory(phys_addr_t phys_addr, dma_addr_t device_addr,
- size_t size, int flags,
- struct dma_coherent_mem **mem)
+static bool dma_init_coherent_memory(
+ phys_addr_t phys_addr, dma_addr_t device_addr, size_t size, int flags,
+ struct dma_coherent_mem **mem)
{
struct dma_coherent_mem *dma_mem = NULL;
void __iomem *mem_base = NULL;
@@ -50,17 +50,13 @@ static int dma_init_coherent_memory(phys_addr_t phys_addr, dma_addr_t device_add
spin_lock_init(&dma_mem->spinlock);
*mem = dma_mem;
-
- if (flags & DMA_MEMORY_MAP)
- return DMA_MEMORY_MAP;
-
- return DMA_MEMORY_IO;
+ return true;
out:
kfree(dma_mem);
if (mem_base)
iounmap(mem_base);
- return 0;
+ return false;
}
static void dma_release_coherent_memory(struct dma_coherent_mem *mem)
@@ -88,15 +84,13 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
dma_addr_t device_addr, size_t size, int flags)
{
struct dma_coherent_mem *mem;
- int ret;
- ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags,
- &mem);
- if (ret == 0)
+ if (!dma_init_coherent_memory(phys_addr, device_addr, size, flags,
+ &mem))
return 0;
if (dma_assign_coherent_memory(dev, mem) == 0)
- return ret;
+ return flags & DMA_MEMORY_MAP ? DMA_MEMORY_MAP : DMA_MEMORY_IO;
dma_release_coherent_memory(mem);
return 0;
@@ -281,9 +275,9 @@ static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
struct dma_coherent_mem *mem = rmem->priv;
if (!mem &&
- dma_init_coherent_memory(rmem->base, rmem->base, rmem->size,
- DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE,
- &mem) != DMA_MEMORY_MAP) {
+ !dma_init_coherent_memory(rmem->base, rmem->base, rmem->size,
+ DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE,
+ &mem)) {
pr_err("Reserved memory: failed to init DMA memory pool at %pa, size %ld MiB\n",
&rmem->base, (unsigned long)rmem->size / SZ_1M);
return -ENODEV;
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b9250e564ebf..773fc3099769 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -23,6 +23,7 @@
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/list.h>
+#include <linux/fs.h>
#include <linux/async.h>
#include <linux/pm.h>
#include <linux/suspend.h>
@@ -257,7 +258,7 @@ static void __fw_free_buf(struct kref *ref)
vunmap(buf->data);
for (i = 0; i < buf->nr_pages; i++)
__free_page(buf->pages[i]);
- kfree(buf->pages);
+ vfree(buf->pages);
} else
#endif
vfree(buf->data);
@@ -291,40 +292,19 @@ static const char * const fw_path[] = {
module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
-static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
+static void fw_finish_direct_load(struct device *device,
+ struct firmware_buf *buf)
{
- int size;
- char *buf;
- int rc;
-
- if (!S_ISREG(file_inode(file)->i_mode))
- return -EINVAL;
- size = i_size_read(file_inode(file));
- if (size <= 0)
- return -EINVAL;
- buf = vmalloc(size);
- if (!buf)
- return -ENOMEM;
- rc = kernel_read(file, 0, buf, size);
- if (rc != size) {
- if (rc > 0)
- rc = -EIO;
- goto fail;
- }
- rc = security_kernel_fw_from_file(file, buf, size);
- if (rc)
- goto fail;
- fw_buf->data = buf;
- fw_buf->size = size;
- return 0;
-fail:
- vfree(buf);
- return rc;
+ mutex_lock(&fw_lock);
+ set_bit(FW_STATUS_DONE, &buf->status);
+ complete_all(&buf->completion);
+ mutex_unlock(&fw_lock);
}
static int fw_get_filesystem_firmware(struct device *device,
struct firmware_buf *buf)
{
+ loff_t size;
int i, len;
int rc = -ENOENT;
char *path;
@@ -334,8 +314,6 @@ static int fw_get_filesystem_firmware(struct device *device,
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
- struct file *file;
-
/* skip the unset customized path */
if (!fw_path[i][0])
continue;
@@ -347,28 +325,25 @@ static int fw_get_filesystem_firmware(struct device *device,
break;
}
- file = filp_open(path, O_RDONLY, 0);
- if (IS_ERR(file))
+ buf->size = 0;
+ rc = kernel_read_file_from_path(path, &buf->data, &size,
+ INT_MAX, READING_FIRMWARE);
+ if (rc) {
+ if (rc == -ENOENT)
+ dev_dbg(device, "loading %s failed with error %d\n",
+ path, rc);
+ else
+ dev_warn(device, "loading %s failed with error %d\n",
+ path, rc);
continue;
- rc = fw_read_file_contents(file, buf);
- fput(file);
- if (rc)
- dev_warn(device, "firmware, attempted to load %s, but failed with error %d\n",
- path, rc);
- else
- break;
+ }
+ dev_dbg(device, "direct-loading %s\n", buf->fw_id);
+ buf->size = size;
+ fw_finish_direct_load(device, buf);
+ break;
}
__putname(path);
- if (!rc) {
- dev_dbg(device, "firmware: direct-loading firmware %s\n",
- buf->fw_id);
- mutex_lock(&fw_lock);
- set_bit(FW_STATUS_DONE, &buf->status);
- complete_all(&buf->completion);
- mutex_unlock(&fw_lock);
- }
-
return rc;
}
@@ -660,7 +635,7 @@ static ssize_t firmware_loading_store(struct device *dev,
if (!test_bit(FW_STATUS_DONE, &fw_buf->status)) {
for (i = 0; i < fw_buf->nr_pages; i++)
__free_page(fw_buf->pages[i]);
- kfree(fw_buf->pages);
+ vfree(fw_buf->pages);
fw_buf->pages = NULL;
fw_buf->page_array_size = 0;
fw_buf->nr_pages = 0;
@@ -685,8 +660,9 @@ static ssize_t firmware_loading_store(struct device *dev,
dev_err(dev, "%s: map pages failed\n",
__func__);
else
- rc = security_kernel_fw_from_file(NULL,
- fw_buf->data, fw_buf->size);
+ rc = security_kernel_post_read_file(NULL,
+ fw_buf->data, fw_buf->size,
+ READING_FIRMWARE);
/*
* Same logic as fw_load_abort, only the DONE bit
@@ -770,8 +746,7 @@ static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
buf->page_array_size * 2);
struct page **new_pages;
- new_pages = kmalloc(new_array_size * sizeof(void *),
- GFP_KERNEL);
+ new_pages = vmalloc(new_array_size * sizeof(void *));
if (!new_pages) {
fw_load_abort(fw_priv);
return -ENOMEM;
@@ -780,7 +755,7 @@ static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
buf->page_array_size * sizeof(void *));
memset(&new_pages[buf->page_array_size], 0, sizeof(void *) *
(new_array_size - buf->page_array_size));
- kfree(buf->pages);
+ vfree(buf->pages);
buf->pages = new_pages;
buf->page_array_size = new_array_size;
}
@@ -1051,7 +1026,7 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
}
if (fw_get_builtin_firmware(firmware, name)) {
- dev_dbg(device, "firmware: using built-in firmware %s\n", name);
+ dev_dbg(device, "using built-in %s\n", name);
return 0; /* assigned */
}
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 213456c2b123..f46dba8b7092 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -251,7 +251,7 @@ memory_block_action(unsigned long phys_index, unsigned long action, int online_t
return ret;
}
-static int memory_block_change_state(struct memory_block *mem,
+int memory_block_change_state(struct memory_block *mem,
unsigned long to_state, unsigned long from_state_req)
{
int ret = 0;
@@ -439,6 +439,37 @@ print_block_size(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(block_size_bytes, 0444, print_block_size, NULL);
/*
+ * Memory auto online policy.
+ */
+
+static ssize_t
+show_auto_online_blocks(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ if (memhp_auto_online)
+ return sprintf(buf, "online\n");
+ else
+ return sprintf(buf, "offline\n");
+}
+
+static ssize_t
+store_auto_online_blocks(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ if (sysfs_streq(buf, "online"))
+ memhp_auto_online = true;
+ else if (sysfs_streq(buf, "offline"))
+ memhp_auto_online = false;
+ else
+ return -EINVAL;
+
+ return count;
+}
+
+static DEVICE_ATTR(auto_online_blocks, 0644, show_auto_online_blocks,
+ store_auto_online_blocks);
+
+/*
* Some architectures will have custom drivers to do this, and
* will not need to do it from userspace. The fake hot-add code
* as well as ppc64 will do all of their discovery in userspace
@@ -746,6 +777,7 @@ static struct attribute *memory_root_attrs[] = {
#endif
&dev_attr_block_size_bytes.attr,
+ &dev_attr_auto_online_blocks.attr,
NULL
};
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 301b785f9f56..56705b52758e 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -104,6 +104,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
{
+ unsigned int state_idx = genpd->state_idx;
ktime_t time_start;
s64 elapsed_ns;
int ret;
@@ -120,10 +121,10 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
return ret;
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
- if (elapsed_ns <= genpd->power_on_latency_ns)
+ if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
return ret;
- genpd->power_on_latency_ns = elapsed_ns;
+ genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
genpd->max_off_time_changed = true;
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
genpd->name, "on", elapsed_ns);
@@ -133,6 +134,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
{
+ unsigned int state_idx = genpd->state_idx;
ktime_t time_start;
s64 elapsed_ns;
int ret;
@@ -149,10 +151,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
return ret;
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
- if (elapsed_ns <= genpd->power_off_latency_ns)
+ if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns)
return ret;
- genpd->power_off_latency_ns = elapsed_ns;
+ genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
genpd->max_off_time_changed = true;
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
genpd->name, "off", elapsed_ns);
@@ -485,8 +487,13 @@ static int pm_genpd_runtime_resume(struct device *dev)
if (timed && runtime_pm)
time_start = ktime_get();
- genpd_start_dev(genpd, dev);
- genpd_restore_dev(genpd, dev);
+ ret = genpd_start_dev(genpd, dev);
+ if (ret)
+ goto err_poweroff;
+
+ ret = genpd_restore_dev(genpd, dev);
+ if (ret)
+ goto err_stop;
/* Update resume latency value if the measured time exceeds it. */
if (timed && runtime_pm) {
@@ -501,6 +508,17 @@ static int pm_genpd_runtime_resume(struct device *dev)
}
return 0;
+
+err_stop:
+ genpd_stop_dev(genpd, dev);
+err_poweroff:
+ if (!dev->power.irq_safe) {
+ mutex_lock(&genpd->lock);
+ genpd_poweroff(genpd, 0);
+ mutex_unlock(&genpd->lock);
+ }
+
+ return ret;
}
static bool pd_ignore_unused;
@@ -585,6 +603,8 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
|| atomic_read(&genpd->sd_count) > 0)
return;
+ /* Choose the deepest state when suspending */
+ genpd->state_idx = genpd->state_count - 1;
genpd_power_off(genpd, timed);
genpd->status = GPD_STATE_POWER_OFF;
@@ -1378,7 +1398,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
mutex_lock(&subdomain->lock);
mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
- if (!list_empty(&subdomain->slave_links) || subdomain->device_count) {
+ if (!list_empty(&subdomain->master_links) || subdomain->device_count) {
pr_warn("%s: unable to remove subdomain %s\n", genpd->name,
subdomain->name);
ret = -EBUSY;
@@ -1508,6 +1528,20 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
genpd->dev_ops.start = pm_clk_resume;
}
+ if (genpd->state_idx >= GENPD_MAX_NUM_STATES) {
+ pr_warn("Initial state index out of bounds.\n");
+ genpd->state_idx = GENPD_MAX_NUM_STATES - 1;
+ }
+
+ if (genpd->state_count > GENPD_MAX_NUM_STATES) {
+ pr_warn("Limiting states to %d\n", GENPD_MAX_NUM_STATES);
+ genpd->state_count = GENPD_MAX_NUM_STATES;
+ }
+
+ /* Use only one "off" state if there were no states declared */
+ if (genpd->state_count == 0)
+ genpd->state_count = 1;
+
mutex_lock(&gpd_list_lock);
list_add(&genpd->gpd_list_node, &gpd_list);
mutex_unlock(&gpd_list_lock);
@@ -1668,6 +1702,9 @@ struct generic_pm_domain *of_genpd_get_from_provider(
struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
struct of_genpd_provider *provider;
+ if (!genpdspec)
+ return ERR_PTR(-EINVAL);
+
mutex_lock(&of_genpd_mutex);
/* Check if we have such a provider in our array */
@@ -1864,6 +1901,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
struct pm_domain_data *pm_data;
const char *kobj_path;
struct gpd_link *link;
+ char state[16];
int ret;
ret = mutex_lock_interruptible(&genpd->lock);
@@ -1872,7 +1910,13 @@ static int pm_genpd_summary_one(struct seq_file *s,
if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
goto exit;
- seq_printf(s, "%-30s %-15s ", genpd->name, status_lookup[genpd->status]);
+ if (genpd->status == GPD_STATE_POWER_OFF)
+ snprintf(state, sizeof(state), "%s-%u",
+ status_lookup[genpd->status], genpd->state_idx);
+ else
+ snprintf(state, sizeof(state), "%s",
+ status_lookup[genpd->status]);
+ seq_printf(s, "%-30s %-15s ", genpd->name, state);
/*
* Modifications on the list require holding locks on both
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 1e937ac5f456..00a5436dd44b 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -98,7 +98,8 @@ static bool default_stop_ok(struct device *dev)
*
* This routine must be executed under the PM domain's lock.
*/
-static bool default_power_down_ok(struct dev_pm_domain *pd)
+static bool __default_power_down_ok(struct dev_pm_domain *pd,
+ unsigned int state)
{
struct generic_pm_domain *genpd = pd_to_genpd(pd);
struct gpd_link *link;
@@ -106,27 +107,9 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
s64 min_off_time_ns;
s64 off_on_time_ns;
- if (genpd->max_off_time_changed) {
- struct gpd_link *link;
-
- /*
- * We have to invalidate the cached results for the masters, so
- * use the observation that default_power_down_ok() is not
- * going to be called for any master until this instance
- * returns.
- */
- list_for_each_entry(link, &genpd->slave_links, slave_node)
- link->master->max_off_time_changed = true;
-
- genpd->max_off_time_changed = false;
- genpd->cached_power_down_ok = false;
- genpd->max_off_time_ns = -1;
- } else {
- return genpd->cached_power_down_ok;
- }
+ off_on_time_ns = genpd->states[state].power_off_latency_ns +
+ genpd->states[state].power_on_latency_ns;
- off_on_time_ns = genpd->power_off_latency_ns +
- genpd->power_on_latency_ns;
min_off_time_ns = -1;
/*
@@ -186,8 +169,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
min_off_time_ns = constraint_ns;
}
- genpd->cached_power_down_ok = true;
-
/*
* If the computed minimum device off time is negative, there are no
* latency constraints, so the domain can spend arbitrary time in the
@@ -201,10 +182,45 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
* time and the time needed to turn the domain on is the maximum
* theoretical time this domain can spend in the "off" state.
*/
- genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
+ genpd->max_off_time_ns = min_off_time_ns -
+ genpd->states[state].power_on_latency_ns;
return true;
}
+static bool default_power_down_ok(struct dev_pm_domain *pd)
+{
+ struct generic_pm_domain *genpd = pd_to_genpd(pd);
+ struct gpd_link *link;
+
+ if (!genpd->max_off_time_changed)
+ return genpd->cached_power_down_ok;
+
+ /*
+ * We have to invalidate the cached results for the masters, so
+ * use the observation that default_power_down_ok() is not
+ * going to be called for any master until this instance
+ * returns.
+ */
+ list_for_each_entry(link, &genpd->slave_links, slave_node)
+ link->master->max_off_time_changed = true;
+
+ genpd->max_off_time_ns = -1;
+ genpd->max_off_time_changed = false;
+ genpd->cached_power_down_ok = true;
+ genpd->state_idx = genpd->state_count - 1;
+
+ /* Find a state to power down to, starting from the deepest. */
+ while (!__default_power_down_ok(pd, genpd->state_idx)) {
+ if (genpd->state_idx == 0) {
+ genpd->cached_power_down_ok = false;
+ break;
+ }
+ genpd->state_idx--;
+ }
+
+ return genpd->cached_power_down_ok;
+}
+
static bool always_on_power_down_ok(struct dev_pm_domain *domain)
{
return false;
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index cf351d3dab1c..433b60092972 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -13,50 +13,52 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/export.h>
+#include <linux/regulator/consumer.h>
#include "opp.h"
/*
- * The root of the list of all devices. All device_opp structures branch off
- * from here, with each device_opp containing the list of opp it supports in
+ * The root of the list of all opp-tables. All opp_table structures branch off
+ * from here, with each opp_table containing the list of opps it supports in
* various states of availability.
*/
-static LIST_HEAD(dev_opp_list);
+static LIST_HEAD(opp_tables);
/* Lock to allow exclusive modification to the device and opp lists */
-DEFINE_MUTEX(dev_opp_list_lock);
+DEFINE_MUTEX(opp_table_lock);
#define opp_rcu_lockdep_assert() \
do { \
RCU_LOCKDEP_WARN(!rcu_read_lock_held() && \
- !lockdep_is_held(&dev_opp_list_lock), \
- "Missing rcu_read_lock() or " \
- "dev_opp_list_lock protection"); \
+ !lockdep_is_held(&opp_table_lock), \
+ "Missing rcu_read_lock() or " \
+ "opp_table_lock protection"); \
} while (0)
-static struct device_list_opp *_find_list_dev(const struct device *dev,
- struct device_opp *dev_opp)
+static struct opp_device *_find_opp_dev(const struct device *dev,
+ struct opp_table *opp_table)
{
- struct device_list_opp *list_dev;
+ struct opp_device *opp_dev;
- list_for_each_entry(list_dev, &dev_opp->dev_list, node)
- if (list_dev->dev == dev)
- return list_dev;
+ list_for_each_entry(opp_dev, &opp_table->dev_list, node)
+ if (opp_dev->dev == dev)
+ return opp_dev;
return NULL;
}
-static struct device_opp *_managed_opp(const struct device_node *np)
+static struct opp_table *_managed_opp(const struct device_node *np)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
- list_for_each_entry_rcu(dev_opp, &dev_opp_list, node) {
- if (dev_opp->np == np) {
+ list_for_each_entry_rcu(opp_table, &opp_tables, node) {
+ if (opp_table->np == np) {
/*
* Multiple devices can point to the same OPP table and
* so will have same node-pointer, np.
@@ -64,7 +66,7 @@ static struct device_opp *_managed_opp(const struct device_node *np)
* But the OPPs will be considered as shared only if the
* OPP table contains a "opp-shared" property.
*/
- return dev_opp->shared_opp ? dev_opp : NULL;
+ return opp_table->shared_opp ? opp_table : NULL;
}
}
@@ -72,24 +74,24 @@ static struct device_opp *_managed_opp(const struct device_node *np)
}
/**
- * _find_device_opp() - find device_opp struct using device pointer
- * @dev: device pointer used to lookup device OPPs
+ * _find_opp_table() - find opp_table struct using device pointer
+ * @dev: device pointer used to lookup OPP table
*
- * Search list of device OPPs for one containing matching device. Does a RCU
- * reader operation to grab the pointer needed.
+ * Search OPP table for one containing matching device. Does a RCU reader
+ * operation to grab the pointer needed.
*
- * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or
+ * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or
* -EINVAL based on type of error.
*
* Locking: For readers, this function must be called under rcu_read_lock().
- * device_opp is a RCU protected pointer, which means that device_opp is valid
+ * opp_table is a RCU protected pointer, which means that opp_table is valid
* as long as we are under RCU lock.
*
- * For Writers, this function must be called with dev_opp_list_lock held.
+ * For Writers, this function must be called with opp_table_lock held.
*/
-struct device_opp *_find_device_opp(struct device *dev)
+struct opp_table *_find_opp_table(struct device *dev)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
opp_rcu_lockdep_assert();
@@ -98,9 +100,9 @@ struct device_opp *_find_device_opp(struct device *dev)
return ERR_PTR(-EINVAL);
}
- list_for_each_entry_rcu(dev_opp, &dev_opp_list, node)
- if (_find_list_dev(dev, dev_opp))
- return dev_opp;
+ list_for_each_entry_rcu(opp_table, &opp_tables, node)
+ if (_find_opp_dev(dev, opp_table))
+ return opp_table;
return ERR_PTR(-ENODEV);
}
@@ -213,16 +215,16 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo);
*/
unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
unsigned long clock_latency_ns;
rcu_read_lock();
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp))
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table))
clock_latency_ns = 0;
else
- clock_latency_ns = dev_opp->clock_latency_ns_max;
+ clock_latency_ns = opp_table->clock_latency_ns_max;
rcu_read_unlock();
return clock_latency_ns;
@@ -230,6 +232,82 @@ unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
/**
+ * dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
+ * @dev: device for which we do this operation
+ *
+ * Return: This function returns the max voltage latency in nanoseconds.
+ *
+ * Locking: This function takes rcu_read_lock().
+ */
+unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
+{
+ struct opp_table *opp_table;
+ struct dev_pm_opp *opp;
+ struct regulator *reg;
+ unsigned long latency_ns = 0;
+ unsigned long min_uV = ~0, max_uV = 0;
+ int ret;
+
+ rcu_read_lock();
+
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ reg = opp_table->regulator;
+ if (IS_ERR(reg)) {
+ /* Regulator may not be required for device */
+ if (reg)
+ dev_err(dev, "%s: Invalid regulator (%ld)\n", __func__,
+ PTR_ERR(reg));
+ rcu_read_unlock();
+ return 0;
+ }
+
+ list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
+ if (!opp->available)
+ continue;
+
+ if (opp->u_volt_min < min_uV)
+ min_uV = opp->u_volt_min;
+ if (opp->u_volt_max > max_uV)
+ max_uV = opp->u_volt_max;
+ }
+
+ rcu_read_unlock();
+
+ /*
+ * The caller needs to ensure that opp_table (and hence the regulator)
+ * isn't freed, while we are executing this routine.
+ */
+ ret = regulator_set_voltage_time(reg, min_uV, max_uV);
+ if (ret > 0)
+ latency_ns = ret * 1000;
+
+ return latency_ns;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_volt_latency);
+
+/**
+ * dev_pm_opp_get_max_transition_latency() - Get max transition latency in
+ * nanoseconds
+ * @dev: device for which we do this operation
+ *
+ * Return: This function returns the max transition latency, in nanoseconds, to
+ * switch from one OPP to other.
+ *
+ * Locking: This function takes rcu_read_lock().
+ */
+unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev)
+{
+ return dev_pm_opp_get_max_volt_latency(dev) +
+ dev_pm_opp_get_max_clock_latency(dev);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_transition_latency);
+
+/**
* dev_pm_opp_get_suspend_opp() - Get suspend opp
* @dev: device for which we do this operation
*
@@ -244,21 +322,21 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
*/
struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
opp_rcu_lockdep_assert();
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp) || !dev_opp->suspend_opp ||
- !dev_opp->suspend_opp->available)
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table) || !opp_table->suspend_opp ||
+ !opp_table->suspend_opp->available)
return NULL;
- return dev_opp->suspend_opp;
+ return opp_table->suspend_opp;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp);
/**
- * dev_pm_opp_get_opp_count() - Get number of opps available in the opp list
+ * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table
* @dev: device for which we do this operation
*
* Return: This function returns the number of available opps if there are any,
@@ -268,21 +346,21 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp);
*/
int dev_pm_opp_get_opp_count(struct device *dev)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
struct dev_pm_opp *temp_opp;
int count = 0;
rcu_read_lock();
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp)) {
- count = PTR_ERR(dev_opp);
- dev_err(dev, "%s: device OPP not found (%d)\n",
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ count = PTR_ERR(opp_table);
+ dev_err(dev, "%s: OPP table not found (%d)\n",
__func__, count);
goto out_unlock;
}
- list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+ list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
if (temp_opp->available)
count++;
}
@@ -299,7 +377,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
* @freq: frequency to search for
* @available: true/false - match for available opp
*
- * Return: Searches for exact match in the opp list and returns pointer to the
+ * Return: Searches for exact match in the opp table and returns pointer to the
* matching opp if found, else returns ERR_PTR in case of error and should
* be handled using IS_ERR. Error return values can be:
* EINVAL: for bad pointer
@@ -323,19 +401,20 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
unsigned long freq,
bool available)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
opp_rcu_lockdep_assert();
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp)) {
- int r = PTR_ERR(dev_opp);
- dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ int r = PTR_ERR(opp_table);
+
+ dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
return ERR_PTR(r);
}
- list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+ list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
if (temp_opp->available == available &&
temp_opp->rate == freq) {
opp = temp_opp;
@@ -371,7 +450,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
unsigned long *freq)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
opp_rcu_lockdep_assert();
@@ -381,11 +460,11 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
return ERR_PTR(-EINVAL);
}
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp))
- return ERR_CAST(dev_opp);
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table))
+ return ERR_CAST(opp_table);
- list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+ list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
if (temp_opp->available && temp_opp->rate >= *freq) {
opp = temp_opp;
*freq = opp->rate;
@@ -421,7 +500,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
unsigned long *freq)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
opp_rcu_lockdep_assert();
@@ -431,11 +510,11 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
return ERR_PTR(-EINVAL);
}
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp))
- return ERR_CAST(dev_opp);
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table))
+ return ERR_CAST(opp_table);
- list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+ list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
if (temp_opp->available) {
/* go to the next node, before choosing prev */
if (temp_opp->rate > *freq)
@@ -451,130 +530,343 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
-/* List-dev Helpers */
-static void _kfree_list_dev_rcu(struct rcu_head *head)
+/*
+ * The caller needs to ensure that opp_table (and hence the clk) isn't freed,
+ * while clk returned here is used.
+ */
+static struct clk *_get_opp_clk(struct device *dev)
+{
+ struct opp_table *opp_table;
+ struct clk *clk;
+
+ rcu_read_lock();
+
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ dev_err(dev, "%s: device opp doesn't exist\n", __func__);
+ clk = ERR_CAST(opp_table);
+ goto unlock;
+ }
+
+ clk = opp_table->clk;
+ if (IS_ERR(clk))
+ dev_err(dev, "%s: No clock available for the device\n",
+ __func__);
+
+unlock:
+ rcu_read_unlock();
+ return clk;
+}
+
+static int _set_opp_voltage(struct device *dev, struct regulator *reg,
+ unsigned long u_volt, unsigned long u_volt_min,
+ unsigned long u_volt_max)
+{
+ int ret;
+
+ /* Regulator not available for device */
+ if (IS_ERR(reg)) {
+ dev_dbg(dev, "%s: regulator not available: %ld\n", __func__,
+ PTR_ERR(reg));
+ return 0;
+ }
+
+ dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, u_volt_min,
+ u_volt, u_volt_max);
+
+ ret = regulator_set_voltage_triplet(reg, u_volt_min, u_volt,
+ u_volt_max);
+ if (ret)
+ dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n",
+ __func__, u_volt_min, u_volt, u_volt_max, ret);
+
+ return ret;
+}
+
+/**
+ * dev_pm_opp_set_rate() - Configure new OPP based on frequency
+ * @dev: device for which we do this operation
+ * @target_freq: frequency to achieve
+ *
+ * This configures the power-supplies and clock source to the levels specified
+ * by the OPP corresponding to the target_freq.
+ *
+ * Locking: This function takes rcu_read_lock().
+ */
+int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
+{
+ struct opp_table *opp_table;
+ struct dev_pm_opp *old_opp, *opp;
+ struct regulator *reg;
+ struct clk *clk;
+ unsigned long freq, old_freq;
+ unsigned long u_volt, u_volt_min, u_volt_max;
+ unsigned long ou_volt, ou_volt_min, ou_volt_max;
+ int ret;
+
+ if (unlikely(!target_freq)) {
+ dev_err(dev, "%s: Invalid target frequency %lu\n", __func__,
+ target_freq);
+ return -EINVAL;
+ }
+
+ clk = _get_opp_clk(dev);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ freq = clk_round_rate(clk, target_freq);
+ if ((long)freq <= 0)
+ freq = target_freq;
+
+ old_freq = clk_get_rate(clk);
+
+ /* Return early if nothing to do */
+ if (old_freq == freq) {
+ dev_dbg(dev, "%s: old/new frequencies (%lu Hz) are same, nothing to do\n",
+ __func__, freq);
+ return 0;
+ }
+
+ rcu_read_lock();
+
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ dev_err(dev, "%s: device opp doesn't exist\n", __func__);
+ rcu_read_unlock();
+ return PTR_ERR(opp_table);
+ }
+
+ old_opp = dev_pm_opp_find_freq_ceil(dev, &old_freq);
+ if (!IS_ERR(old_opp)) {
+ ou_volt = old_opp->u_volt;
+ ou_volt_min = old_opp->u_volt_min;
+ ou_volt_max = old_opp->u_volt_max;
+ } else {
+ dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)\n",
+ __func__, old_freq, PTR_ERR(old_opp));
+ }
+
+ opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+ if (IS_ERR(opp)) {
+ ret = PTR_ERR(opp);
+ dev_err(dev, "%s: failed to find OPP for freq %lu (%d)\n",
+ __func__, freq, ret);
+ rcu_read_unlock();
+ return ret;
+ }
+
+ u_volt = opp->u_volt;
+ u_volt_min = opp->u_volt_min;
+ u_volt_max = opp->u_volt_max;
+
+ reg = opp_table->regulator;
+
+ rcu_read_unlock();
+
+ /* Scaling up? Scale voltage before frequency */
+ if (freq > old_freq) {
+ ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
+ u_volt_max);
+ if (ret)
+ goto restore_voltage;
+ }
+
+ /* Change frequency */
+
+ dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
+ __func__, old_freq, freq);
+
+ ret = clk_set_rate(clk, freq);
+ if (ret) {
+ dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
+ ret);
+ goto restore_voltage;
+ }
+
+ /* Scaling down? Scale voltage after frequency */
+ if (freq < old_freq) {
+ ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
+ u_volt_max);
+ if (ret)
+ goto restore_freq;
+ }
+
+ return 0;
+
+restore_freq:
+ if (clk_set_rate(clk, old_freq))
+ dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
+ __func__, old_freq);
+restore_voltage:
+ /* This shouldn't harm even if the voltages weren't updated earlier */
+ if (!IS_ERR(old_opp))
+ _set_opp_voltage(dev, reg, ou_volt, ou_volt_min, ou_volt_max);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
+
+/* OPP-dev Helpers */
+static void _kfree_opp_dev_rcu(struct rcu_head *head)
{
- struct device_list_opp *list_dev;
+ struct opp_device *opp_dev;
- list_dev = container_of(head, struct device_list_opp, rcu_head);
- kfree_rcu(list_dev, rcu_head);
+ opp_dev = container_of(head, struct opp_device, rcu_head);
+ kfree_rcu(opp_dev, rcu_head);
}
-static void _remove_list_dev(struct device_list_opp *list_dev,
- struct device_opp *dev_opp)
+static void _remove_opp_dev(struct opp_device *opp_dev,
+ struct opp_table *opp_table)
{
- opp_debug_unregister(list_dev, dev_opp);
- list_del(&list_dev->node);
- call_srcu(&dev_opp->srcu_head.srcu, &list_dev->rcu_head,
- _kfree_list_dev_rcu);
+ opp_debug_unregister(opp_dev, opp_table);
+ list_del(&opp_dev->node);
+ call_srcu(&opp_table->srcu_head.srcu, &opp_dev->rcu_head,
+ _kfree_opp_dev_rcu);
}
-struct device_list_opp *_add_list_dev(const struct device *dev,
- struct device_opp *dev_opp)
+struct opp_device *_add_opp_dev(const struct device *dev,
+ struct opp_table *opp_table)
{
- struct device_list_opp *list_dev;
+ struct opp_device *opp_dev;
int ret;
- list_dev = kzalloc(sizeof(*list_dev), GFP_KERNEL);
- if (!list_dev)
+ opp_dev = kzalloc(sizeof(*opp_dev), GFP_KERNEL);
+ if (!opp_dev)
return NULL;
- /* Initialize list-dev */
- list_dev->dev = dev;
- list_add_rcu(&list_dev->node, &dev_opp->dev_list);
+ /* Initialize opp-dev */
+ opp_dev->dev = dev;
+ list_add_rcu(&opp_dev->node, &opp_table->dev_list);
- /* Create debugfs entries for the dev_opp */
- ret = opp_debug_register(list_dev, dev_opp);
+ /* Create debugfs entries for the opp_table */
+ ret = opp_debug_register(opp_dev, opp_table);
if (ret)
dev_err(dev, "%s: Failed to register opp debugfs (%d)\n",
__func__, ret);
- return list_dev;
+ return opp_dev;
}
/**
- * _add_device_opp() - Find device OPP table or allocate a new one
+ * _add_opp_table() - Find OPP table or allocate a new one
* @dev: device for which we do this operation
*
* It tries to find an existing table first, if it couldn't find one, it
* allocates a new OPP table and returns that.
*
- * Return: valid device_opp pointer if success, else NULL.
+ * Return: valid opp_table pointer if success, else NULL.
*/
-static struct device_opp *_add_device_opp(struct device *dev)
+static struct opp_table *_add_opp_table(struct device *dev)
{
- struct device_opp *dev_opp;
- struct device_list_opp *list_dev;
+ struct opp_table *opp_table;
+ struct opp_device *opp_dev;
+ struct device_node *np;
+ int ret;
- /* Check for existing list for 'dev' first */
- dev_opp = _find_device_opp(dev);
- if (!IS_ERR(dev_opp))
- return dev_opp;
+ /* Check for existing table for 'dev' first */
+ opp_table = _find_opp_table(dev);
+ if (!IS_ERR(opp_table))
+ return opp_table;
/*
- * Allocate a new device OPP table. In the infrequent case where a new
+ * Allocate a new OPP table. In the infrequent case where a new
* device is needed to be added, we pay this penalty.
*/
- dev_opp = kzalloc(sizeof(*dev_opp), GFP_KERNEL);
- if (!dev_opp)
+ opp_table = kzalloc(sizeof(*opp_table), GFP_KERNEL);
+ if (!opp_table)
return NULL;
- INIT_LIST_HEAD(&dev_opp->dev_list);
+ INIT_LIST_HEAD(&opp_table->dev_list);
- list_dev = _add_list_dev(dev, dev_opp);
- if (!list_dev) {
- kfree(dev_opp);
+ opp_dev = _add_opp_dev(dev, opp_table);
+ if (!opp_dev) {
+ kfree(opp_table);
return NULL;
}
- srcu_init_notifier_head(&dev_opp->srcu_head);
- INIT_LIST_HEAD(&dev_opp->opp_list);
+ /*
+ * Only required for backward compatibility with v1 bindings, but isn't
+ * harmful for other cases. And so we do it unconditionally.
+ */
+ np = of_node_get(dev->of_node);
+ if (np) {
+ u32 val;
+
+ if (!of_property_read_u32(np, "clock-latency", &val))
+ opp_table->clock_latency_ns_max = val;
+ of_property_read_u32(np, "voltage-tolerance",
+ &opp_table->voltage_tolerance_v1);
+ of_node_put(np);
+ }
+
+ /* Set regulator to a non-NULL error value */
+ opp_table->regulator = ERR_PTR(-ENXIO);
+
+ /* Find clk for the device */
+ opp_table->clk = clk_get(dev, NULL);
+ if (IS_ERR(opp_table->clk)) {
+ ret = PTR_ERR(opp_table->clk);
+ if (ret != -EPROBE_DEFER)
+ dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__,
+ ret);
+ }
- /* Secure the device list modification */
- list_add_rcu(&dev_opp->node, &dev_opp_list);
- return dev_opp;
+ srcu_init_notifier_head(&opp_table->srcu_head);
+ INIT_LIST_HEAD(&opp_table->opp_list);
+
+ /* Secure the device table modification */
+ list_add_rcu(&opp_table->node, &opp_tables);
+ return opp_table;
}
/**
- * _kfree_device_rcu() - Free device_opp RCU handler
+ * _kfree_device_rcu() - Free opp_table RCU handler
* @head: RCU head
*/
static void _kfree_device_rcu(struct rcu_head *head)
{
- struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head);
+ struct opp_table *opp_table = container_of(head, struct opp_table,
+ rcu_head);
- kfree_rcu(device_opp, rcu_head);
+ kfree_rcu(opp_table, rcu_head);
}
/**
- * _remove_device_opp() - Removes a device OPP table
- * @dev_opp: device OPP table to be removed.
+ * _remove_opp_table() - Removes a OPP table
+ * @opp_table: OPP table to be removed.
*
- * Removes/frees device OPP table it it doesn't contain any OPPs.
+ * Removes/frees OPP table if it doesn't contain any OPPs.
*/
-static void _remove_device_opp(struct device_opp *dev_opp)
+static void _remove_opp_table(struct opp_table *opp_table)
{
- struct device_list_opp *list_dev;
+ struct opp_device *opp_dev;
+
+ if (!list_empty(&opp_table->opp_list))
+ return;
- if (!list_empty(&dev_opp->opp_list))
+ if (opp_table->supported_hw)
return;
- if (dev_opp->supported_hw)
+ if (opp_table->prop_name)
return;
- if (dev_opp->prop_name)
+ if (!IS_ERR(opp_table->regulator))
return;
- list_dev = list_first_entry(&dev_opp->dev_list, struct device_list_opp,
- node);
+ /* Release clk */
+ if (!IS_ERR(opp_table->clk))
+ clk_put(opp_table->clk);
- _remove_list_dev(list_dev, dev_opp);
+ opp_dev = list_first_entry(&opp_table->dev_list, struct opp_device,
+ node);
+
+ _remove_opp_dev(opp_dev, opp_table);
/* dev_list must be empty now */
- WARN_ON(!list_empty(&dev_opp->dev_list));
+ WARN_ON(!list_empty(&opp_table->dev_list));
- list_del_rcu(&dev_opp->node);
- call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head,
+ list_del_rcu(&opp_table->node);
+ call_srcu(&opp_table->srcu_head.srcu, &opp_table->rcu_head,
_kfree_device_rcu);
}
@@ -591,17 +883,17 @@ static void _kfree_opp_rcu(struct rcu_head *head)
/**
* _opp_remove() - Remove an OPP from a table definition
- * @dev_opp: points back to the device_opp struct this opp belongs to
+ * @opp_table: points back to the opp_table struct this opp belongs to
* @opp: pointer to the OPP to remove
* @notify: OPP_EVENT_REMOVE notification should be sent or not
*
- * This function removes an opp definition from the opp list.
+ * This function removes an opp definition from the opp table.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* It is assumed that the caller holds required mutex for an RCU updater
* strategy.
*/
-static void _opp_remove(struct device_opp *dev_opp,
+static void _opp_remove(struct opp_table *opp_table,
struct dev_pm_opp *opp, bool notify)
{
/*
@@ -609,22 +901,23 @@ static void _opp_remove(struct device_opp *dev_opp,
* frequency/voltage list.
*/
if (notify)
- srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp);
+ srcu_notifier_call_chain(&opp_table->srcu_head,
+ OPP_EVENT_REMOVE, opp);
opp_debug_remove_one(opp);
list_del_rcu(&opp->node);
- call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
+ call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
- _remove_device_opp(dev_opp);
+ _remove_opp_table(opp_table);
}
/**
- * dev_pm_opp_remove() - Remove an OPP from OPP list
+ * dev_pm_opp_remove() - Remove an OPP from OPP table
* @dev: device for which we do this operation
* @freq: OPP to remove with matching 'freq'
*
- * This function removes an opp from the opp list.
+ * This function removes an opp from the opp table.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -633,17 +926,17 @@ static void _opp_remove(struct device_opp *dev_opp,
void dev_pm_opp_remove(struct device *dev, unsigned long freq)
{
struct dev_pm_opp *opp;
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
bool found = false;
- /* Hold our list modification lock here */
- mutex_lock(&dev_opp_list_lock);
+ /* Hold our table modification lock here */
+ mutex_lock(&opp_table_lock);
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp))
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table))
goto unlock;
- list_for_each_entry(opp, &dev_opp->opp_list, node) {
+ list_for_each_entry(opp, &opp_table->opp_list, node) {
if (opp->rate == freq) {
found = true;
break;
@@ -656,14 +949,14 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
goto unlock;
}
- _opp_remove(dev_opp, opp, true);
+ _opp_remove(opp_table, opp, true);
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
static struct dev_pm_opp *_allocate_opp(struct device *dev,
- struct device_opp **dev_opp)
+ struct opp_table **opp_table)
{
struct dev_pm_opp *opp;
@@ -674,8 +967,8 @@ static struct dev_pm_opp *_allocate_opp(struct device *dev,
INIT_LIST_HEAD(&opp->node);
- *dev_opp = _add_device_opp(dev);
- if (!*dev_opp) {
+ *opp_table = _add_opp_table(dev);
+ if (!*opp_table) {
kfree(opp);
return NULL;
}
@@ -683,22 +976,38 @@ static struct dev_pm_opp *_allocate_opp(struct device *dev,
return opp;
}
+static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
+ struct opp_table *opp_table)
+{
+ struct regulator *reg = opp_table->regulator;
+
+ if (!IS_ERR(reg) &&
+ !regulator_is_supported_voltage(reg, opp->u_volt_min,
+ opp->u_volt_max)) {
+ pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
+ __func__, opp->u_volt_min, opp->u_volt_max);
+ return false;
+ }
+
+ return true;
+}
+
static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
- struct device_opp *dev_opp)
+ struct opp_table *opp_table)
{
struct dev_pm_opp *opp;
- struct list_head *head = &dev_opp->opp_list;
+ struct list_head *head = &opp_table->opp_list;
int ret;
/*
* Insert new OPP in order of increasing frequency and discard if
* already present.
*
- * Need to use &dev_opp->opp_list in the condition part of the 'for'
+ * Need to use &opp_table->opp_list in the condition part of the 'for'
* loop, don't replace it with head otherwise it will become an infinite
* loop.
*/
- list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) {
+ list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
if (new_opp->rate > opp->rate) {
head = &opp->node;
continue;
@@ -716,14 +1025,20 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
0 : -EEXIST;
}
- new_opp->dev_opp = dev_opp;
+ new_opp->opp_table = opp_table;
list_add_rcu(&new_opp->node, head);
- ret = opp_debug_create_one(new_opp, dev_opp);
+ ret = opp_debug_create_one(new_opp, opp_table);
if (ret)
dev_err(dev, "%s: Failed to register opp to debugfs (%d)\n",
__func__, ret);
+ if (!_opp_supported_by_regulators(new_opp, opp_table)) {
+ new_opp->available = false;
+ dev_warn(dev, "%s: OPP not supported by regulators (%lu)\n",
+ __func__, new_opp->rate);
+ }
+
return 0;
}
@@ -734,14 +1049,14 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
* @u_volt: Voltage in uVolts for this OPP
* @dynamic: Dynamically added OPPs.
*
- * This function adds an opp definition to the opp list and returns status.
+ * This function adds an opp definition to the opp table and returns status.
* The opp is made available by default and it can be controlled using
* dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove.
*
* NOTE: "dynamic" parameter impacts OPPs added by the dev_pm_opp_of_add_table
* and freed by dev_pm_opp_of_remove_table.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -757,14 +1072,15 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
static int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
bool dynamic)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
struct dev_pm_opp *new_opp;
+ unsigned long tol;
int ret;
- /* Hold our list modification lock here */
- mutex_lock(&dev_opp_list_lock);
+ /* Hold our table modification lock here */
+ mutex_lock(&opp_table_lock);
- new_opp = _allocate_opp(dev, &dev_opp);
+ new_opp = _allocate_opp(dev, &opp_table);
if (!new_opp) {
ret = -ENOMEM;
goto unlock;
@@ -772,33 +1088,36 @@ static int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
/* populate the opp table */
new_opp->rate = freq;
+ tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
new_opp->u_volt = u_volt;
+ new_opp->u_volt_min = u_volt - tol;
+ new_opp->u_volt_max = u_volt + tol;
new_opp->available = true;
new_opp->dynamic = dynamic;
- ret = _opp_add(dev, new_opp, dev_opp);
+ ret = _opp_add(dev, new_opp, opp_table);
if (ret)
goto free_opp;
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
/*
* Notify the changes in the availability of the operable
* frequency/voltage list.
*/
- srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp);
+ srcu_notifier_call_chain(&opp_table->srcu_head, OPP_EVENT_ADD, new_opp);
return 0;
free_opp:
- _opp_remove(dev_opp, new_opp, false);
+ _opp_remove(opp_table, new_opp, false);
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
return ret;
}
/* TODO: Support multiple regulators */
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
- struct device_opp *dev_opp)
+ struct opp_table *opp_table)
{
u32 microvolt[3] = {0};
u32 val;
@@ -807,9 +1126,9 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
char name[NAME_MAX];
/* Search for "opp-microvolt-<name>" */
- if (dev_opp->prop_name) {
+ if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microvolt-%s",
- dev_opp->prop_name);
+ opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
}
@@ -844,14 +1163,20 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
}
opp->u_volt = microvolt[0];
- opp->u_volt_min = microvolt[1];
- opp->u_volt_max = microvolt[2];
+
+ if (count == 1) {
+ opp->u_volt_min = opp->u_volt;
+ opp->u_volt_max = opp->u_volt;
+ } else {
+ opp->u_volt_min = microvolt[1];
+ opp->u_volt_max = microvolt[2];
+ }
/* Search for "opp-microamp-<name>" */
prop = NULL;
- if (dev_opp->prop_name) {
+ if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microamp-%s",
- dev_opp->prop_name);
+ opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
}
@@ -878,7 +1203,7 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
* OPPs, which are available for those versions, based on its 'opp-supported-hw'
* property.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -887,44 +1212,44 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
unsigned int count)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
int ret = 0;
- /* Hold our list modification lock here */
- mutex_lock(&dev_opp_list_lock);
+ /* Hold our table modification lock here */
+ mutex_lock(&opp_table_lock);
- dev_opp = _add_device_opp(dev);
- if (!dev_opp) {
+ opp_table = _add_opp_table(dev);
+ if (!opp_table) {
ret = -ENOMEM;
goto unlock;
}
- /* Make sure there are no concurrent readers while updating dev_opp */
- WARN_ON(!list_empty(&dev_opp->opp_list));
+ /* Make sure there are no concurrent readers while updating opp_table */
+ WARN_ON(!list_empty(&opp_table->opp_list));
- /* Do we already have a version hierarchy associated with dev_opp? */
- if (dev_opp->supported_hw) {
+ /* Do we already have a version hierarchy associated with opp_table? */
+ if (opp_table->supported_hw) {
dev_err(dev, "%s: Already have supported hardware list\n",
__func__);
ret = -EBUSY;
goto err;
}
- dev_opp->supported_hw = kmemdup(versions, count * sizeof(*versions),
+ opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions),
GFP_KERNEL);
- if (!dev_opp->supported_hw) {
+ if (!opp_table->supported_hw) {
ret = -ENOMEM;
goto err;
}
- dev_opp->supported_hw_count = count;
- mutex_unlock(&dev_opp_list_lock);
+ opp_table->supported_hw_count = count;
+ mutex_unlock(&opp_table_lock);
return 0;
err:
- _remove_device_opp(dev_opp);
+ _remove_opp_table(opp_table);
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
return ret;
}
@@ -932,13 +1257,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw);
/**
* dev_pm_opp_put_supported_hw() - Releases resources blocked for supported hw
- * @dev: Device for which supported-hw has to be set.
+ * @dev: Device for which supported-hw has to be put.
*
* This is required only for the V2 bindings, and is called for a matching
- * dev_pm_opp_set_supported_hw(). Until this is called, the device_opp structure
+ * dev_pm_opp_set_supported_hw(). Until this is called, the opp_table structure
* will not be freed.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -946,42 +1271,43 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw);
*/
void dev_pm_opp_put_supported_hw(struct device *dev)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
- /* Hold our list modification lock here */
- mutex_lock(&dev_opp_list_lock);
+ /* Hold our table modification lock here */
+ mutex_lock(&opp_table_lock);
- /* Check for existing list for 'dev' first */
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp)) {
- dev_err(dev, "Failed to find dev_opp: %ld\n", PTR_ERR(dev_opp));
+ /* Check for existing table for 'dev' first */
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ dev_err(dev, "Failed to find opp_table: %ld\n",
+ PTR_ERR(opp_table));
goto unlock;
}
- /* Make sure there are no concurrent readers while updating dev_opp */
- WARN_ON(!list_empty(&dev_opp->opp_list));
+ /* Make sure there are no concurrent readers while updating opp_table */
+ WARN_ON(!list_empty(&opp_table->opp_list));
- if (!dev_opp->supported_hw) {
+ if (!opp_table->supported_hw) {
dev_err(dev, "%s: Doesn't have supported hardware list\n",
__func__);
goto unlock;
}
- kfree(dev_opp->supported_hw);
- dev_opp->supported_hw = NULL;
- dev_opp->supported_hw_count = 0;
+ kfree(opp_table->supported_hw);
+ opp_table->supported_hw = NULL;
+ opp_table->supported_hw_count = 0;
- /* Try freeing device_opp if this was the last blocking resource */
- _remove_device_opp(dev_opp);
+ /* Try freeing opp_table if this was the last blocking resource */
+ _remove_opp_table(opp_table);
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
/**
* dev_pm_opp_set_prop_name() - Set prop-extn name
- * @dev: Device for which the regulator has to be set.
+ * @dev: Device for which the prop-name has to be set.
* @name: name to postfix to properties.
*
* This is required only for the V2 bindings, and it enables a platform to
@@ -989,7 +1315,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
* which the extension will apply are opp-microvolt and opp-microamp. OPP core
* should postfix the property name with -<name> while looking for them.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -997,42 +1323,42 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
*/
int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
int ret = 0;
- /* Hold our list modification lock here */
- mutex_lock(&dev_opp_list_lock);
+ /* Hold our table modification lock here */
+ mutex_lock(&opp_table_lock);
- dev_opp = _add_device_opp(dev);
- if (!dev_opp) {
+ opp_table = _add_opp_table(dev);
+ if (!opp_table) {
ret = -ENOMEM;
goto unlock;
}
- /* Make sure there are no concurrent readers while updating dev_opp */
- WARN_ON(!list_empty(&dev_opp->opp_list));
+ /* Make sure there are no concurrent readers while updating opp_table */
+ WARN_ON(!list_empty(&opp_table->opp_list));
- /* Do we already have a prop-name associated with dev_opp? */
- if (dev_opp->prop_name) {
+ /* Do we already have a prop-name associated with opp_table? */
+ if (opp_table->prop_name) {
dev_err(dev, "%s: Already have prop-name %s\n", __func__,
- dev_opp->prop_name);
+ opp_table->prop_name);
ret = -EBUSY;
goto err;
}
- dev_opp->prop_name = kstrdup(name, GFP_KERNEL);
- if (!dev_opp->prop_name) {
+ opp_table->prop_name = kstrdup(name, GFP_KERNEL);
+ if (!opp_table->prop_name) {
ret = -ENOMEM;
goto err;
}
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
return 0;
err:
- _remove_device_opp(dev_opp);
+ _remove_opp_table(opp_table);
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
return ret;
}
@@ -1040,13 +1366,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name);
/**
* dev_pm_opp_put_prop_name() - Releases resources blocked for prop-name
- * @dev: Device for which the regulator has to be set.
+ * @dev: Device for which the prop-name has to be put.
*
* This is required only for the V2 bindings, and is called for a matching
- * dev_pm_opp_set_prop_name(). Until this is called, the device_opp structure
+ * dev_pm_opp_set_prop_name(). Until this is called, the opp_table structure
* will not be freed.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -1054,45 +1380,154 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name);
*/
void dev_pm_opp_put_prop_name(struct device *dev)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
- /* Hold our list modification lock here */
- mutex_lock(&dev_opp_list_lock);
+ /* Hold our table modification lock here */
+ mutex_lock(&opp_table_lock);
- /* Check for existing list for 'dev' first */
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp)) {
- dev_err(dev, "Failed to find dev_opp: %ld\n", PTR_ERR(dev_opp));
+ /* Check for existing table for 'dev' first */
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ dev_err(dev, "Failed to find opp_table: %ld\n",
+ PTR_ERR(opp_table));
goto unlock;
}
- /* Make sure there are no concurrent readers while updating dev_opp */
- WARN_ON(!list_empty(&dev_opp->opp_list));
+ /* Make sure there are no concurrent readers while updating opp_table */
+ WARN_ON(!list_empty(&opp_table->opp_list));
- if (!dev_opp->prop_name) {
+ if (!opp_table->prop_name) {
dev_err(dev, "%s: Doesn't have a prop-name\n", __func__);
goto unlock;
}
- kfree(dev_opp->prop_name);
- dev_opp->prop_name = NULL;
+ kfree(opp_table->prop_name);
+ opp_table->prop_name = NULL;
- /* Try freeing device_opp if this was the last blocking resource */
- _remove_device_opp(dev_opp);
+ /* Try freeing opp_table if this was the last blocking resource */
+ _remove_opp_table(opp_table);
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
-static bool _opp_is_supported(struct device *dev, struct device_opp *dev_opp,
+/**
+ * dev_pm_opp_set_regulator() - Set regulator name for the device
+ * @dev: Device for which regulator name is being set.
+ * @name: Name of the regulator.
+ *
+ * In order to support OPP switching, OPP layer needs to know the name of the
+ * device's regulator, as the core would be required to switch voltages as well.
+ *
+ * This must be called before any OPPs are initialized for the device.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+int dev_pm_opp_set_regulator(struct device *dev, const char *name)
+{
+ struct opp_table *opp_table;
+ struct regulator *reg;
+ int ret;
+
+ mutex_lock(&opp_table_lock);
+
+ opp_table = _add_opp_table(dev);
+ if (!opp_table) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ /* This should be called before OPPs are initialized */
+ if (WARN_ON(!list_empty(&opp_table->opp_list))) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ /* Already have a regulator set */
+ if (WARN_ON(!IS_ERR(opp_table->regulator))) {
+ ret = -EBUSY;
+ goto err;
+ }
+ /* Allocate the regulator */
+ reg = regulator_get_optional(dev, name);
+ if (IS_ERR(reg)) {
+ ret = PTR_ERR(reg);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "%s: no regulator (%s) found: %d\n",
+ __func__, name, ret);
+ goto err;
+ }
+
+ opp_table->regulator = reg;
+
+ mutex_unlock(&opp_table_lock);
+ return 0;
+
+err:
+ _remove_opp_table(opp_table);
+unlock:
+ mutex_unlock(&opp_table_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
+
+/**
+ * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
+ * @dev: Device for which regulator was set.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+void dev_pm_opp_put_regulator(struct device *dev)
+{
+ struct opp_table *opp_table;
+
+ mutex_lock(&opp_table_lock);
+
+ /* Check for existing table for 'dev' first */
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ dev_err(dev, "Failed to find opp_table: %ld\n",
+ PTR_ERR(opp_table));
+ goto unlock;
+ }
+
+ if (IS_ERR(opp_table->regulator)) {
+ dev_err(dev, "%s: Doesn't have regulator set\n", __func__);
+ goto unlock;
+ }
+
+ /* Make sure there are no concurrent readers while updating opp_table */
+ WARN_ON(!list_empty(&opp_table->opp_list));
+
+ regulator_put(opp_table->regulator);
+ opp_table->regulator = ERR_PTR(-ENXIO);
+
+ /* Try freeing opp_table if this was the last blocking resource */
+ _remove_opp_table(opp_table);
+
+unlock:
+ mutex_unlock(&opp_table_lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulator);
+
+static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
struct device_node *np)
{
- unsigned int count = dev_opp->supported_hw_count;
+ unsigned int count = opp_table->supported_hw_count;
u32 version;
int ret;
- if (!dev_opp->supported_hw)
+ if (!opp_table->supported_hw)
return true;
while (count--) {
@@ -1105,7 +1540,7 @@ static bool _opp_is_supported(struct device *dev, struct device_opp *dev_opp,
}
/* Both of these are bitwise masks of the versions */
- if (!(version & dev_opp->supported_hw[count]))
+ if (!(version & opp_table->supported_hw[count]))
return false;
}
@@ -1117,11 +1552,11 @@ static bool _opp_is_supported(struct device *dev, struct device_opp *dev_opp,
* @dev: device for which we do this operation
* @np: device node
*
- * This function adds an opp definition to the opp list and returns status. The
+ * This function adds an opp definition to the opp table and returns status. The
* opp can be controlled using dev_pm_opp_enable/disable functions and may be
* removed by dev_pm_opp_remove.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -1137,16 +1572,16 @@ static bool _opp_is_supported(struct device *dev, struct device_opp *dev_opp,
*/
static int _opp_add_static_v2(struct device *dev, struct device_node *np)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
struct dev_pm_opp *new_opp;
u64 rate;
u32 val;
int ret;
- /* Hold our list modification lock here */
- mutex_lock(&dev_opp_list_lock);
+ /* Hold our table modification lock here */
+ mutex_lock(&opp_table_lock);
- new_opp = _allocate_opp(dev, &dev_opp);
+ new_opp = _allocate_opp(dev, &opp_table);
if (!new_opp) {
ret = -ENOMEM;
goto unlock;
@@ -1159,7 +1594,7 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
}
/* Check if the OPP supports hardware's hierarchy of versions or not */
- if (!_opp_is_supported(dev, dev_opp, np)) {
+ if (!_opp_is_supported(dev, opp_table, np)) {
dev_dbg(dev, "OPP not supported by hardware: %llu\n", rate);
goto free_opp;
}
@@ -1179,30 +1614,30 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
if (!of_property_read_u32(np, "clock-latency-ns", &val))
new_opp->clock_latency_ns = val;
- ret = opp_parse_supplies(new_opp, dev, dev_opp);
+ ret = opp_parse_supplies(new_opp, dev, opp_table);
if (ret)
goto free_opp;
- ret = _opp_add(dev, new_opp, dev_opp);
+ ret = _opp_add(dev, new_opp, opp_table);
if (ret)
goto free_opp;
/* OPP to select on device suspend */
if (of_property_read_bool(np, "opp-suspend")) {
- if (dev_opp->suspend_opp) {
+ if (opp_table->suspend_opp) {
dev_warn(dev, "%s: Multiple suspend OPPs found (%lu %lu)\n",
- __func__, dev_opp->suspend_opp->rate,
+ __func__, opp_table->suspend_opp->rate,
new_opp->rate);
} else {
new_opp->suspend = true;
- dev_opp->suspend_opp = new_opp;
+ opp_table->suspend_opp = new_opp;
}
}
- if (new_opp->clock_latency_ns > dev_opp->clock_latency_ns_max)
- dev_opp->clock_latency_ns_max = new_opp->clock_latency_ns;
+ if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max)
+ opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n",
__func__, new_opp->turbo, new_opp->rate, new_opp->u_volt,
@@ -1213,13 +1648,13 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
* Notify the changes in the availability of the operable
* frequency/voltage list.
*/
- srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp);
+ srcu_notifier_call_chain(&opp_table->srcu_head, OPP_EVENT_ADD, new_opp);
return 0;
free_opp:
- _opp_remove(dev_opp, new_opp, false);
+ _opp_remove(opp_table, new_opp, false);
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
return ret;
}
@@ -1229,11 +1664,11 @@ unlock:
* @freq: Frequency in Hz for this OPP
* @u_volt: Voltage in uVolts for this OPP
*
- * This function adds an opp definition to the opp list and returns status.
+ * This function adds an opp definition to the opp table and returns status.
* The opp is made available by default and it can be controlled using
* dev_pm_opp_enable/disable functions.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -1265,7 +1700,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_add);
* copy operation, returns 0 if no modification was done OR modification was
* successful.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks to
* keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -1274,7 +1709,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_add);
static int _opp_set_availability(struct device *dev, unsigned long freq,
bool availability_req)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV);
int r = 0;
@@ -1283,18 +1718,18 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
if (!new_opp)
return -ENOMEM;
- mutex_lock(&dev_opp_list_lock);
+ mutex_lock(&opp_table_lock);
- /* Find the device_opp */
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp)) {
- r = PTR_ERR(dev_opp);
+ /* Find the opp_table */
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ r = PTR_ERR(opp_table);
dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
goto unlock;
}
/* Do we have the frequency? */
- list_for_each_entry(tmp_opp, &dev_opp->opp_list, node) {
+ list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
if (tmp_opp->rate == freq) {
opp = tmp_opp;
break;
@@ -1315,21 +1750,21 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
new_opp->available = availability_req;
list_replace_rcu(&opp->node, &new_opp->node);
- mutex_unlock(&dev_opp_list_lock);
- call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
+ mutex_unlock(&opp_table_lock);
+ call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
/* Notify the change of the OPP availability */
if (availability_req)
- srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ENABLE,
- new_opp);
+ srcu_notifier_call_chain(&opp_table->srcu_head,
+ OPP_EVENT_ENABLE, new_opp);
else
- srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_DISABLE,
- new_opp);
+ srcu_notifier_call_chain(&opp_table->srcu_head,
+ OPP_EVENT_DISABLE, new_opp);
return 0;
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
kfree(new_opp);
return r;
}
@@ -1343,7 +1778,7 @@ unlock:
* corresponding error value. It is meant to be used for users an OPP available
* after being temporarily made unavailable with dev_pm_opp_disable.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function indirectly uses RCU and mutex locks to keep the
* integrity of the internal data structures. Callers should ensure that
* this function is *NOT* called under RCU protection or in contexts where
@@ -1369,7 +1804,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_enable);
* control by users to make this OPP not available until the circumstances are
* right to make it available again (with a call to dev_pm_opp_enable).
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function indirectly uses RCU and mutex locks to keep the
* integrity of the internal data structures. Callers should ensure that
* this function is *NOT* called under RCU protection or in contexts where
@@ -1387,26 +1822,26 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
/**
* dev_pm_opp_get_notifier() - find notifier_head of the device with opp
- * @dev: device pointer used to lookup device OPPs.
+ * @dev: device pointer used to lookup OPP table.
*
* Return: pointer to notifier head if found, otherwise -ENODEV or
* -EINVAL based on type of error casted as pointer. value must be checked
* with IS_ERR to determine valid pointer or error result.
*
- * Locking: This function must be called under rcu_read_lock(). dev_opp is a RCU
- * protected pointer. The reason for the same is that the opp pointer which is
- * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * Locking: This function must be called under rcu_read_lock(). opp_table is a
+ * RCU protected pointer. The reason for the same is that the opp pointer which
+ * is returned will remain valid for use with opp_get_{voltage, freq} only while
* under the locked area. The pointer returned must be used prior to unlocking
* with rcu_read_unlock() to maintain the integrity of the pointer.
*/
struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
{
- struct device_opp *dev_opp = _find_device_opp(dev);
+ struct opp_table *opp_table = _find_opp_table(dev);
- if (IS_ERR(dev_opp))
- return ERR_CAST(dev_opp); /* matching type */
+ if (IS_ERR(opp_table))
+ return ERR_CAST(opp_table); /* matching type */
- return &dev_opp->srcu_head;
+ return &opp_table->srcu_head;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
@@ -1414,11 +1849,11 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
/**
* dev_pm_opp_of_remove_table() - Free OPP table entries created from static DT
* entries
- * @dev: device pointer used to lookup device OPPs.
+ * @dev: device pointer used to lookup OPP table.
*
* Free OPPs created using static entries present in DT.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function indirectly uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
@@ -1426,38 +1861,38 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
*/
void dev_pm_opp_of_remove_table(struct device *dev)
{
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
struct dev_pm_opp *opp, *tmp;
- /* Hold our list modification lock here */
- mutex_lock(&dev_opp_list_lock);
+ /* Hold our table modification lock here */
+ mutex_lock(&opp_table_lock);
- /* Check for existing list for 'dev' */
- dev_opp = _find_device_opp(dev);
- if (IS_ERR(dev_opp)) {
- int error = PTR_ERR(dev_opp);
+ /* Check for existing table for 'dev' */
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ int error = PTR_ERR(opp_table);
if (error != -ENODEV)
- WARN(1, "%s: dev_opp: %d\n",
+ WARN(1, "%s: opp_table: %d\n",
IS_ERR_OR_NULL(dev) ?
"Invalid device" : dev_name(dev),
error);
goto unlock;
}
- /* Find if dev_opp manages a single device */
- if (list_is_singular(&dev_opp->dev_list)) {
+ /* Find if opp_table manages a single device */
+ if (list_is_singular(&opp_table->dev_list)) {
/* Free static OPPs */
- list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) {
+ list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
if (!opp->dynamic)
- _opp_remove(dev_opp, opp, true);
+ _opp_remove(opp_table, opp, true);
}
} else {
- _remove_list_dev(_find_list_dev(dev, dev_opp), dev_opp);
+ _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table);
}
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
@@ -1478,22 +1913,22 @@ struct device_node *_of_get_opp_desc_node(struct device *dev)
static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
{
struct device_node *np;
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
int ret = 0, count = 0;
- mutex_lock(&dev_opp_list_lock);
+ mutex_lock(&opp_table_lock);
- dev_opp = _managed_opp(opp_np);
- if (dev_opp) {
+ opp_table = _managed_opp(opp_np);
+ if (opp_table) {
/* OPPs are already managed */
- if (!_add_list_dev(dev, dev_opp))
+ if (!_add_opp_dev(dev, opp_table))
ret = -ENOMEM;
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
return ret;
}
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
- /* We have opp-list node now, iterate over it and add OPPs */
+ /* We have opp-table node now, iterate over it and add OPPs */
for_each_available_child_of_node(opp_np, np) {
count++;
@@ -1509,19 +1944,19 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
if (WARN_ON(!count))
return -ENOENT;
- mutex_lock(&dev_opp_list_lock);
+ mutex_lock(&opp_table_lock);
- dev_opp = _find_device_opp(dev);
- if (WARN_ON(IS_ERR(dev_opp))) {
- ret = PTR_ERR(dev_opp);
- mutex_unlock(&dev_opp_list_lock);
+ opp_table = _find_opp_table(dev);
+ if (WARN_ON(IS_ERR(opp_table))) {
+ ret = PTR_ERR(opp_table);
+ mutex_unlock(&opp_table_lock);
goto free_table;
}
- dev_opp->np = opp_np;
- dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared");
+ opp_table->np = opp_np;
+ opp_table->shared_opp = of_property_read_bool(opp_np, "opp-shared");
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
return 0;
@@ -1550,7 +1985,7 @@ static int _of_add_opp_table_v1(struct device *dev)
*/
nr = prop->length / sizeof(u32);
if (nr % 2) {
- dev_err(dev, "%s: Invalid OPP list\n", __func__);
+ dev_err(dev, "%s: Invalid OPP table\n", __func__);
return -EINVAL;
}
@@ -1570,11 +2005,11 @@ static int _of_add_opp_table_v1(struct device *dev)
/**
* dev_pm_opp_of_add_table() - Initialize opp table from device tree
- * @dev: device pointer used to lookup device OPPs.
+ * @dev: device pointer used to lookup OPP table.
*
* Register the initial OPP table with the OPP library for given device.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function indirectly uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c
index 9f0c15570f64..ba2bdbd932ef 100644
--- a/drivers/base/power/opp/cpu.c
+++ b/drivers/base/power/opp/cpu.c
@@ -31,7 +31,7 @@
* @table: Cpufreq table returned back to caller
*
* Generate a cpufreq table for a provided device- this assumes that the
- * opp list is already initialized and ready for usage.
+ * opp table is already initialized and ready for usage.
*
* This function allocates required memory for the cpufreq table. It is
* expected that the caller does the required maintenance such as freeing
@@ -44,7 +44,7 @@
* WARNING: It is important for the callers to ensure refreshing their copy of
* the table if any of the mentioned functions have been invoked in the interim.
*
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
* Since we just use the regular accessor functions to access the internal data
* structures, we use RCU read lock inside this function. As a result, users of
* this function DONOT need to use explicit locks for invoking.
@@ -122,15 +122,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
/* Required only for V1 bindings, as v2 can manage it from DT itself */
int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
{
- struct device_list_opp *list_dev;
- struct device_opp *dev_opp;
+ struct opp_device *opp_dev;
+ struct opp_table *opp_table;
struct device *dev;
int cpu, ret = 0;
- mutex_lock(&dev_opp_list_lock);
+ mutex_lock(&opp_table_lock);
- dev_opp = _find_device_opp(cpu_dev);
- if (IS_ERR(dev_opp)) {
+ opp_table = _find_opp_table(cpu_dev);
+ if (IS_ERR(opp_table)) {
ret = -EINVAL;
goto unlock;
}
@@ -146,15 +146,15 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
continue;
}
- list_dev = _add_list_dev(dev, dev_opp);
- if (!list_dev) {
- dev_err(dev, "%s: failed to add list-dev for cpu%d device\n",
+ opp_dev = _add_opp_dev(dev, opp_table);
+ if (!opp_dev) {
+ dev_err(dev, "%s: failed to add opp-dev for cpu%d device\n",
__func__, cpu);
continue;
}
}
unlock:
- mutex_unlock(&dev_opp_list_lock);
+ mutex_unlock(&opp_table_lock);
return ret;
}
diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c
index ddfe4773e922..ef1ae6b52042 100644
--- a/drivers/base/power/opp/debugfs.c
+++ b/drivers/base/power/opp/debugfs.c
@@ -34,9 +34,9 @@ void opp_debug_remove_one(struct dev_pm_opp *opp)
debugfs_remove_recursive(opp->dentry);
}
-int opp_debug_create_one(struct dev_pm_opp *opp, struct device_opp *dev_opp)
+int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
{
- struct dentry *pdentry = dev_opp->dentry;
+ struct dentry *pdentry = opp_table->dentry;
struct dentry *d;
char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */
@@ -83,52 +83,52 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct device_opp *dev_opp)
return 0;
}
-static int device_opp_debug_create_dir(struct device_list_opp *list_dev,
- struct device_opp *dev_opp)
+static int opp_list_debug_create_dir(struct opp_device *opp_dev,
+ struct opp_table *opp_table)
{
- const struct device *dev = list_dev->dev;
+ const struct device *dev = opp_dev->dev;
struct dentry *d;
- opp_set_dev_name(dev, dev_opp->dentry_name);
+ opp_set_dev_name(dev, opp_table->dentry_name);
/* Create device specific directory */
- d = debugfs_create_dir(dev_opp->dentry_name, rootdir);
+ d = debugfs_create_dir(opp_table->dentry_name, rootdir);
if (!d) {
dev_err(dev, "%s: Failed to create debugfs dir\n", __func__);
return -ENOMEM;
}
- list_dev->dentry = d;
- dev_opp->dentry = d;
+ opp_dev->dentry = d;
+ opp_table->dentry = d;
return 0;
}
-static int device_opp_debug_create_link(struct device_list_opp *list_dev,
- struct device_opp *dev_opp)
+static int opp_list_debug_create_link(struct opp_device *opp_dev,
+ struct opp_table *opp_table)
{
- const struct device *dev = list_dev->dev;
+ const struct device *dev = opp_dev->dev;
char name[NAME_MAX];
struct dentry *d;
- opp_set_dev_name(list_dev->dev, name);
+ opp_set_dev_name(opp_dev->dev, name);
/* Create device specific directory link */
- d = debugfs_create_symlink(name, rootdir, dev_opp->dentry_name);
+ d = debugfs_create_symlink(name, rootdir, opp_table->dentry_name);
if (!d) {
dev_err(dev, "%s: Failed to create link\n", __func__);
return -ENOMEM;
}
- list_dev->dentry = d;
+ opp_dev->dentry = d;
return 0;
}
/**
* opp_debug_register - add a device opp node to the debugfs 'opp' directory
- * @list_dev: list-dev pointer for device
- * @dev_opp: the device-opp being added
+ * @opp_dev: opp-dev pointer for device
+ * @opp_table: the device-opp being added
*
* Dynamically adds device specific directory in debugfs 'opp' directory. If the
* device-opp is shared with other devices, then links will be created for all
@@ -136,73 +136,72 @@ static int device_opp_debug_create_link(struct device_list_opp *list_dev,
*
* Return: 0 on success, otherwise negative error.
*/
-int opp_debug_register(struct device_list_opp *list_dev,
- struct device_opp *dev_opp)
+int opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table)
{
if (!rootdir) {
pr_debug("%s: Uninitialized rootdir\n", __func__);
return -EINVAL;
}
- if (dev_opp->dentry)
- return device_opp_debug_create_link(list_dev, dev_opp);
+ if (opp_table->dentry)
+ return opp_list_debug_create_link(opp_dev, opp_table);
- return device_opp_debug_create_dir(list_dev, dev_opp);
+ return opp_list_debug_create_dir(opp_dev, opp_table);
}
-static void opp_migrate_dentry(struct device_list_opp *list_dev,
- struct device_opp *dev_opp)
+static void opp_migrate_dentry(struct opp_device *opp_dev,
+ struct opp_table *opp_table)
{
- struct device_list_opp *new_dev;
+ struct opp_device *new_dev;
const struct device *dev;
struct dentry *dentry;
- /* Look for next list-dev */
- list_for_each_entry(new_dev, &dev_opp->dev_list, node)
- if (new_dev != list_dev)
+ /* Look for next opp-dev */
+ list_for_each_entry(new_dev, &opp_table->dev_list, node)
+ if (new_dev != opp_dev)
break;
/* new_dev is guaranteed to be valid here */
dev = new_dev->dev;
debugfs_remove_recursive(new_dev->dentry);
- opp_set_dev_name(dev, dev_opp->dentry_name);
+ opp_set_dev_name(dev, opp_table->dentry_name);
- dentry = debugfs_rename(rootdir, list_dev->dentry, rootdir,
- dev_opp->dentry_name);
+ dentry = debugfs_rename(rootdir, opp_dev->dentry, rootdir,
+ opp_table->dentry_name);
if (!dentry) {
dev_err(dev, "%s: Failed to rename link from: %s to %s\n",
- __func__, dev_name(list_dev->dev), dev_name(dev));
+ __func__, dev_name(opp_dev->dev), dev_name(dev));
return;
}
new_dev->dentry = dentry;
- dev_opp->dentry = dentry;
+ opp_table->dentry = dentry;
}
/**
* opp_debug_unregister - remove a device opp node from debugfs opp directory
- * @list_dev: list-dev pointer for device
- * @dev_opp: the device-opp being removed
+ * @opp_dev: opp-dev pointer for device
+ * @opp_table: the device-opp being removed
*
* Dynamically removes device specific directory from debugfs 'opp' directory.
*/
-void opp_debug_unregister(struct device_list_opp *list_dev,
- struct device_opp *dev_opp)
+void opp_debug_unregister(struct opp_device *opp_dev,
+ struct opp_table *opp_table)
{
- if (list_dev->dentry == dev_opp->dentry) {
+ if (opp_dev->dentry == opp_table->dentry) {
/* Move the real dentry object under another device */
- if (!list_is_singular(&dev_opp->dev_list)) {
- opp_migrate_dentry(list_dev, dev_opp);
+ if (!list_is_singular(&opp_table->dev_list)) {
+ opp_migrate_dentry(opp_dev, opp_table);
goto out;
}
- dev_opp->dentry = NULL;
+ opp_table->dentry = NULL;
}
- debugfs_remove_recursive(list_dev->dentry);
+ debugfs_remove_recursive(opp_dev->dentry);
out:
- list_dev->dentry = NULL;
+ opp_dev->dentry = NULL;
}
static int __init opp_debug_init(void)
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index 690638ef36ee..f67f806fcf3a 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -22,13 +22,16 @@
#include <linux/rculist.h>
#include <linux/rcupdate.h>
+struct clk;
+struct regulator;
+
/* Lock to allow exclusive modification to the device and opp lists */
-extern struct mutex dev_opp_list_lock;
+extern struct mutex opp_table_lock;
/*
* Internal data structure organization with the OPP layer library is as
* follows:
- * dev_opp_list (root)
+ * opp_tables (root)
* |- device 1 (represents voltage domain 1)
* | |- opp 1 (availability, freq, voltage)
* | |- opp 2 ..
@@ -37,18 +40,18 @@ extern struct mutex dev_opp_list_lock;
* |- device 2 (represents the next voltage domain)
* ...
* `- device m (represents mth voltage domain)
- * device 1, 2.. are represented by dev_opp structure while each opp
+ * device 1, 2.. are represented by opp_table structure while each opp
* is represented by the opp structure.
*/
/**
* struct dev_pm_opp - Generic OPP description structure
- * @node: opp list node. The nodes are maintained throughout the lifetime
+ * @node: opp table node. The nodes are maintained throughout the lifetime
* of boot. It is expected only an optimal set of OPPs are
* added to the library by the SoC framework.
- * RCU usage: opp list is traversed with RCU locks. node
+ * RCU usage: opp table is traversed with RCU locks. node
* modification is possible realtime, hence the modifications
- * are protected by the dev_opp_list_lock for integrity.
+ * are protected by the opp_table_lock for integrity.
* IMPORTANT: the opp nodes should be maintained in increasing
* order.
* @available: true/false - marks if this OPP as available or not
@@ -62,7 +65,7 @@ extern struct mutex dev_opp_list_lock;
* @u_amp: Maximum current drawn by the device in microamperes
* @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
* frequency from any other OPP's frequency.
- * @dev_opp: points back to the device_opp struct this opp belongs to
+ * @opp_table: points back to the opp_table struct this opp belongs to
* @rcu_head: RCU callback head used for deferred freeing
* @np: OPP's device node.
* @dentry: debugfs dentry pointer (per opp)
@@ -84,7 +87,7 @@ struct dev_pm_opp {
unsigned long u_amp;
unsigned long clock_latency_ns;
- struct device_opp *dev_opp;
+ struct opp_table *opp_table;
struct rcu_head rcu_head;
struct device_node *np;
@@ -95,16 +98,16 @@ struct dev_pm_opp {
};
/**
- * struct device_list_opp - devices managed by 'struct device_opp'
+ * struct opp_device - devices managed by 'struct opp_table'
* @node: list node
* @dev: device to which the struct object belongs
* @rcu_head: RCU callback head used for deferred freeing
* @dentry: debugfs dentry pointer (per device)
*
- * This is an internal data structure maintaining the list of devices that are
- * managed by 'struct device_opp'.
+ * This is an internal data structure maintaining the devices that are managed
+ * by 'struct opp_table'.
*/
-struct device_list_opp {
+struct opp_device {
struct list_head node;
const struct device *dev;
struct rcu_head rcu_head;
@@ -115,16 +118,16 @@ struct device_list_opp {
};
/**
- * struct device_opp - Device opp structure
- * @node: list node - contains the devices with OPPs that
+ * struct opp_table - Device opp structure
+ * @node: table node - contains the devices with OPPs that
* have been registered. Nodes once added are not modified in this
- * list.
- * RCU usage: nodes are not modified in the list of device_opp,
- * however addition is possible and is secured by dev_opp_list_lock
+ * table.
+ * RCU usage: nodes are not modified in the table of opp_table,
+ * however addition is possible and is secured by opp_table_lock
* @srcu_head: notifier head to notify the OPP availability changes.
* @rcu_head: RCU callback head used for deferred freeing
* @dev_list: list of devices that share these OPPs
- * @opp_list: list of opps
+ * @opp_list: table of opps
* @np: struct device_node pointer for opp's DT node.
* @clock_latency_ns_max: Max clock latency in nanoseconds.
* @shared_opp: OPP is shared between multiple devices.
@@ -132,9 +135,13 @@ struct device_list_opp {
* @supported_hw: Array of version number to support.
* @supported_hw_count: Number of elements in supported_hw array.
* @prop_name: A name to postfix to many DT properties, while parsing them.
+ * @clk: Device's clock handle
+ * @regulator: Supply regulator
* @dentry: debugfs dentry pointer of the real device directory (not links).
* @dentry_name: Name of the real dentry.
*
+ * @voltage_tolerance_v1: In percentage, for v1 bindings only.
+ *
* This is an internal data structure maintaining the link to opps attached to
* a device. This structure is not meant to be shared to users as it is
* meant for book keeping and private to OPP library.
@@ -143,7 +150,7 @@ struct device_list_opp {
* need to wait for the grace period of both of them before freeing any
* resources. And so we have used kfree_rcu() from within call_srcu() handlers.
*/
-struct device_opp {
+struct opp_table {
struct list_head node;
struct srcu_notifier_head srcu_head;
@@ -153,12 +160,18 @@ struct device_opp {
struct device_node *np;
unsigned long clock_latency_ns_max;
+
+ /* For backward compatibility with v1 bindings */
+ unsigned int voltage_tolerance_v1;
+
bool shared_opp;
struct dev_pm_opp *suspend_opp;
unsigned int *supported_hw;
unsigned int supported_hw_count;
const char *prop_name;
+ struct clk *clk;
+ struct regulator *regulator;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
@@ -167,30 +180,27 @@ struct device_opp {
};
/* Routines internal to opp core */
-struct device_opp *_find_device_opp(struct device *dev);
-struct device_list_opp *_add_list_dev(const struct device *dev,
- struct device_opp *dev_opp);
+struct opp_table *_find_opp_table(struct device *dev);
+struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
struct device_node *_of_get_opp_desc_node(struct device *dev);
#ifdef CONFIG_DEBUG_FS
void opp_debug_remove_one(struct dev_pm_opp *opp);
-int opp_debug_create_one(struct dev_pm_opp *opp, struct device_opp *dev_opp);
-int opp_debug_register(struct device_list_opp *list_dev,
- struct device_opp *dev_opp);
-void opp_debug_unregister(struct device_list_opp *list_dev,
- struct device_opp *dev_opp);
+int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table);
+int opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table);
+void opp_debug_unregister(struct opp_device *opp_dev, struct opp_table *opp_table);
#else
static inline void opp_debug_remove_one(struct dev_pm_opp *opp) {}
static inline int opp_debug_create_one(struct dev_pm_opp *opp,
- struct device_opp *dev_opp)
+ struct opp_table *opp_table)
{ return 0; }
-static inline int opp_debug_register(struct device_list_opp *list_dev,
- struct device_opp *dev_opp)
+static inline int opp_debug_register(struct opp_device *opp_dev,
+ struct opp_table *opp_table)
{ return 0; }
-static inline void opp_debug_unregister(struct device_list_opp *list_dev,
- struct device_opp *dev_opp)
+static inline void opp_debug_unregister(struct opp_device *opp_dev,
+ struct opp_table *opp_table)
{ }
#endif /* DEBUG_FS */
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
index a311cfa4c5bd..a6975795e7f3 100644
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -166,14 +166,14 @@ void generate_pm_trace(const void *tracedata, unsigned int user)
}
EXPORT_SYMBOL(generate_pm_trace);
-extern char __tracedata_start, __tracedata_end;
+extern char __tracedata_start[], __tracedata_end[];
static int show_file_hash(unsigned int value)
{
int match;
char *tracedata;
match = 0;
- for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ;
+ for (tracedata = __tracedata_start ; tracedata < __tracedata_end ;
tracedata += 2 + sizeof(unsigned long)) {
unsigned short lineno = *(unsigned short *)tracedata;
const char *file = *(const char **)(tracedata + 2);
diff --git a/drivers/base/property.c b/drivers/base/property.c
index c359351d50f1..76628a7b45f1 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -218,7 +218,8 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
bool ret;
ret = __fwnode_property_present(fwnode, propname);
- if (ret == false && fwnode && fwnode->secondary)
+ if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
+ !IS_ERR_OR_NULL(fwnode->secondary))
ret = __fwnode_property_present(fwnode->secondary, propname);
return ret;
}
@@ -423,7 +424,8 @@ EXPORT_SYMBOL_GPL(device_property_match_string);
int _ret_; \
_ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \
_val_, _nval_); \
- if (_ret_ == -EINVAL && _fwnode_ && _fwnode_->secondary) \
+ if (_ret_ == -EINVAL && !IS_ERR_OR_NULL(_fwnode_) && \
+ !IS_ERR_OR_NULL(_fwnode_->secondary)) \
_ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \
_proptype_, _val_, _nval_); \
_ret_; \
@@ -593,7 +595,8 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
int ret;
ret = __fwnode_property_read_string_array(fwnode, propname, val, nval);
- if (ret == -EINVAL && fwnode && fwnode->secondary)
+ if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
+ !IS_ERR_OR_NULL(fwnode->secondary))
ret = __fwnode_property_read_string_array(fwnode->secondary,
propname, val, nval);
return ret;
@@ -621,7 +624,8 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode,
int ret;
ret = __fwnode_property_read_string(fwnode, propname, val);
- if (ret == -EINVAL && fwnode && fwnode->secondary)
+ if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
+ !IS_ERR_OR_NULL(fwnode->secondary))
ret = __fwnode_property_read_string(fwnode->secondary,
propname, val);
return ret;
@@ -820,11 +824,16 @@ void device_remove_property_set(struct device *dev)
* the pset. If there is no real firmware node (ACPI/DT) primary
* will hold the pset.
*/
- if (!is_pset_node(fwnode))
- fwnode = fwnode->secondary;
- if (!IS_ERR(fwnode) && is_pset_node(fwnode))
+ if (is_pset_node(fwnode)) {
+ set_primary_fwnode(dev, NULL);
pset_free_set(to_pset_node(fwnode));
- set_secondary_fwnode(dev, NULL);
+ } else {
+ fwnode = fwnode->secondary;
+ if (!IS_ERR(fwnode) && is_pset_node(fwnode)) {
+ set_secondary_fwnode(dev, NULL);
+ pset_free_set(to_pset_node(fwnode));
+ }
+ }
}
EXPORT_SYMBOL_GPL(device_remove_property_set);
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 3df977054781..5c79526245c2 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -110,6 +110,7 @@ struct regmap {
/* number of bits to (left) shift the reg value when formatting*/
int reg_shift;
int reg_stride;
+ int reg_stride_order;
/* regcache specific members */
const struct regcache_ops *cache_ops;
@@ -263,4 +264,19 @@ static inline const char *regmap_name(const struct regmap *map)
return map->name;
}
+static inline unsigned int regmap_get_offset(const struct regmap *map,
+ unsigned int index)
+{
+ if (map->reg_stride_order >= 0)
+ return index << map->reg_stride_order;
+ else
+ return index * map->reg_stride;
+}
+
+static inline unsigned int regcache_get_index_by_order(const struct regmap *map,
+ unsigned int reg)
+{
+ return reg >> map->reg_stride_order;
+}
+
#endif
diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c
index 686c9e0b930e..3ee72550b1e3 100644
--- a/drivers/base/regmap/regcache-flat.c
+++ b/drivers/base/regmap/regcache-flat.c
@@ -16,20 +16,30 @@
#include "internal.h"
+static inline unsigned int regcache_flat_get_index(const struct regmap *map,
+ unsigned int reg)
+{
+ return regcache_get_index_by_order(map, reg);
+}
+
static int regcache_flat_init(struct regmap *map)
{
int i;
unsigned int *cache;
- map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int),
- GFP_KERNEL);
+ if (!map || map->reg_stride_order < 0)
+ return -EINVAL;
+
+ map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
+ + 1, sizeof(unsigned int), GFP_KERNEL);
if (!map->cache)
return -ENOMEM;
cache = map->cache;
for (i = 0; i < map->num_reg_defaults; i++)
- cache[map->reg_defaults[i].reg] = map->reg_defaults[i].def;
+ cache[regcache_flat_get_index(map, map->reg_defaults[i].reg)] =
+ map->reg_defaults[i].def;
return 0;
}
@@ -47,7 +57,7 @@ static int regcache_flat_read(struct regmap *map,
{
unsigned int *cache = map->cache;
- *value = cache[reg];
+ *value = cache[regcache_flat_get_index(map, reg)];
return 0;
}
@@ -57,7 +67,7 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg,
{
unsigned int *cache = map->cache;
- cache[reg] = value;
+ cache[regcache_flat_get_index(map, reg)] = value;
return 0;
}
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 348be3a35410..4170b7d95276 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -30,7 +30,7 @@ static int regcache_hw_init(struct regmap *map)
int i, j;
int ret;
int count;
- unsigned int val;
+ unsigned int reg, val;
void *tmp_buf;
if (!map->num_reg_defaults_raw)
@@ -57,7 +57,7 @@ static int regcache_hw_init(struct regmap *map)
bool cache_bypass = map->cache_bypass;
dev_warn(map->dev, "No cache defaults, reading back from HW\n");
- /* Bypass the cache access till data read from HW*/
+ /* Bypass the cache access till data read from HW */
map->cache_bypass = true;
tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
if (!tmp_buf) {
@@ -65,29 +65,48 @@ static int regcache_hw_init(struct regmap *map)
goto err_free;
}
ret = regmap_raw_read(map, 0, tmp_buf,
- map->num_reg_defaults_raw);
+ map->cache_size_raw);
map->cache_bypass = cache_bypass;
- if (ret < 0)
- goto err_cache_free;
-
- map->reg_defaults_raw = tmp_buf;
- map->cache_free = 1;
+ if (ret == 0) {
+ map->reg_defaults_raw = tmp_buf;
+ map->cache_free = 1;
+ } else {
+ kfree(tmp_buf);
+ }
}
/* fill the reg_defaults */
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
- if (regmap_volatile(map, i * map->reg_stride))
+ reg = i * map->reg_stride;
+
+ if (!regmap_readable(map, reg))
continue;
- val = regcache_get_val(map, map->reg_defaults_raw, i);
- map->reg_defaults[j].reg = i * map->reg_stride;
+
+ if (regmap_volatile(map, reg))
+ continue;
+
+ if (map->reg_defaults_raw) {
+ val = regcache_get_val(map, map->reg_defaults_raw, i);
+ } else {
+ bool cache_bypass = map->cache_bypass;
+
+ map->cache_bypass = true;
+ ret = regmap_read(map, reg, &val);
+ map->cache_bypass = cache_bypass;
+ if (ret != 0) {
+ dev_err(map->dev, "Failed to read %d: %d\n",
+ reg, ret);
+ goto err_free;
+ }
+ }
+
+ map->reg_defaults[j].reg = reg;
map->reg_defaults[j].def = val;
j++;
}
return 0;
-err_cache_free:
- kfree(tmp_buf);
err_free:
kfree(map->reg_defaults);
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 9b0d202414d0..26f799e71c82 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -379,6 +379,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
irq_set_chip_data(virq, data);
irq_set_chip(virq, &data->irq_chip);
irq_set_nested_thread(virq, 1);
+ irq_set_parent(virq, data->irq);
irq_set_noprobe(virq);
return 0;
@@ -655,13 +656,34 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
*
* @irq: Primary IRQ for the device
* @d: regmap_irq_chip_data allocated by regmap_add_irq_chip()
+ *
+ * This function also dispose all mapped irq on chip.
*/
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
{
+ unsigned int virq;
+ int hwirq;
+
if (!d)
return;
free_irq(irq, d);
+
+ /* Dispose all virtual irq from irq domain before removing it */
+ for (hwirq = 0; hwirq < d->chip->num_irqs; hwirq++) {
+ /* Ignore hwirq if holes in the IRQ list */
+ if (!d->chip->irqs[hwirq].mask)
+ continue;
+
+ /*
+ * Find the virtual irq of hwirq on chip and if it is
+ * there then dispose it
+ */
+ virq = irq_find_mapping(d->domain, hwirq);
+ if (virq)
+ irq_dispose_mapping(virq);
+ }
+
irq_domain_remove(d->domain);
kfree(d->type_buf);
kfree(d->type_buf_def);
@@ -674,6 +696,88 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
}
EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
+static void devm_regmap_irq_chip_release(struct device *dev, void *res)
+{
+ struct regmap_irq_chip_data *d = *(struct regmap_irq_chip_data **)res;
+
+ regmap_del_irq_chip(d->irq, d);
+}
+
+static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data)
+
+{
+ struct regmap_irq_chip_data **r = res;
+
+ if (!r || !*r) {
+ WARN_ON(!r || !*r);
+ return 0;
+ }
+ return *r == data;
+}
+
+/**
+ * devm_regmap_add_irq_chip(): Resource manager regmap_add_irq_chip()
+ *
+ * @dev: The device pointer on which irq_chip belongs to.
+ * @map: The regmap for the device.
+ * @irq: The IRQ the device uses to signal interrupts
+ * @irq_flags: The IRQF_ flags to use for the primary interrupt.
+ * @chip: Configuration for the interrupt controller.
+ * @data: Runtime data structure for the controller, allocated on success
+ *
+ * Returns 0 on success or an errno on failure.
+ *
+ * The regmap_irq_chip data automatically be released when the device is
+ * unbound.
+ */
+int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
+ int irq_flags, int irq_base,
+ const struct regmap_irq_chip *chip,
+ struct regmap_irq_chip_data **data)
+{
+ struct regmap_irq_chip_data **ptr, *d;
+ int ret;
+
+ ptr = devres_alloc(devm_regmap_irq_chip_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = regmap_add_irq_chip(map, irq, irq_flags, irq_base,
+ chip, &d);
+ if (ret < 0) {
+ devres_free(ptr);
+ return ret;
+ }
+
+ *ptr = d;
+ devres_add(dev, ptr);
+ *data = d;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip);
+
+/**
+ * devm_regmap_del_irq_chip(): Resource managed regmap_del_irq_chip()
+ *
+ * @dev: Device for which which resource was allocated.
+ * @irq: Primary IRQ for the device
+ * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip()
+ */
+void devm_regmap_del_irq_chip(struct device *dev, int irq,
+ struct regmap_irq_chip_data *data)
+{
+ int rc;
+
+ WARN_ON(irq != data->irq);
+ rc = devres_release(dev, devm_regmap_irq_chip_release,
+ devm_regmap_irq_chip_match, data);
+
+ if (rc != 0)
+ WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_del_irq_chip);
+
/**
* regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip
*
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index eea51569f0eb..7526906ca080 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -25,26 +25,14 @@
struct regmap_mmio_context {
void __iomem *regs;
- unsigned reg_bytes;
unsigned val_bytes;
- unsigned pad_bytes;
struct clk *clk;
-};
-static inline void regmap_mmio_regsize_check(size_t reg_size)
-{
- switch (reg_size) {
- case 1:
- case 2:
- case 4:
-#ifdef CONFIG_64BIT
- case 8:
-#endif
- break;
- default:
- BUG();
- }
-}
+ void (*reg_write)(struct regmap_mmio_context *ctx,
+ unsigned int reg, unsigned int val);
+ unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
+ unsigned int reg);
+};
static int regmap_mmio_regbits_check(size_t reg_bits)
{
@@ -88,72 +76,62 @@ static int regmap_mmio_get_min_stride(size_t val_bits)
return min_stride;
}
-static inline void regmap_mmio_count_check(size_t count, u32 offset)
+static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
+ unsigned int reg,
+ unsigned int val)
+{
+ writeb(val, ctx->regs + reg);
+}
+
+static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
+ unsigned int reg,
+ unsigned int val)
{
- BUG_ON(count <= offset);
+ writew(val, ctx->regs + reg);
}
-static inline unsigned int
-regmap_mmio_get_offset(const void *reg, size_t reg_size)
+static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
+ unsigned int reg,
+ unsigned int val)
{
- switch (reg_size) {
- case 1:
- return *(u8 *)reg;
- case 2:
- return *(u16 *)reg;
- case 4:
- return *(u32 *)reg;
+ iowrite16be(val, ctx->regs + reg);
+}
+
+static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
+ unsigned int reg,
+ unsigned int val)
+{
+ writel(val, ctx->regs + reg);
+}
+
+static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
+ unsigned int reg,
+ unsigned int val)
+{
+ iowrite32be(val, ctx->regs + reg);
+}
+
#ifdef CONFIG_64BIT
- case 8:
- return *(u64 *)reg;
-#endif
- default:
- BUG();
- }
+static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
+ unsigned int reg,
+ unsigned int val)
+{
+ writeq(val, ctx->regs + reg);
}
+#endif
-static int regmap_mmio_gather_write(void *context,
- const void *reg, size_t reg_size,
- const void *val, size_t val_size)
+static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
{
struct regmap_mmio_context *ctx = context;
- unsigned int offset;
int ret;
- regmap_mmio_regsize_check(reg_size);
-
if (!IS_ERR(ctx->clk)) {
ret = clk_enable(ctx->clk);
if (ret < 0)
return ret;
}
- offset = regmap_mmio_get_offset(reg, reg_size);
-
- while (val_size) {
- switch (ctx->val_bytes) {
- case 1:
- writeb(*(u8 *)val, ctx->regs + offset);
- break;
- case 2:
- writew(*(u16 *)val, ctx->regs + offset);
- break;
- case 4:
- writel(*(u32 *)val, ctx->regs + offset);
- break;
-#ifdef CONFIG_64BIT
- case 8:
- writeq(*(u64 *)val, ctx->regs + offset);
- break;
-#endif
- default:
- /* Should be caught by regmap_mmio_check_config */
- BUG();
- }
- val_size -= ctx->val_bytes;
- val += ctx->val_bytes;
- offset += ctx->val_bytes;
- }
+ ctx->reg_write(ctx, reg, val);
if (!IS_ERR(ctx->clk))
clk_disable(ctx->clk);
@@ -161,59 +139,56 @@ static int regmap_mmio_gather_write(void *context,
return 0;
}
-static int regmap_mmio_write(void *context, const void *data, size_t count)
+static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
+ unsigned int reg)
{
- struct regmap_mmio_context *ctx = context;
- unsigned int offset = ctx->reg_bytes + ctx->pad_bytes;
+ return readb(ctx->regs + reg);
+}
+
+static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
+ unsigned int reg)
+{
+ return readw(ctx->regs + reg);
+}
+
+static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
+ unsigned int reg)
+{
+ return ioread16be(ctx->regs + reg);
+}
+
+static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
+ unsigned int reg)
+{
+ return readl(ctx->regs + reg);
+}
- regmap_mmio_count_check(count, offset);
+static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
+ unsigned int reg)
+{
+ return ioread32be(ctx->regs + reg);
+}
- return regmap_mmio_gather_write(context, data, ctx->reg_bytes,
- data + offset, count - offset);
+#ifdef CONFIG_64BIT
+static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
+ unsigned int reg)
+{
+ return readq(ctx->regs + reg);
}
+#endif
-static int regmap_mmio_read(void *context,
- const void *reg, size_t reg_size,
- void *val, size_t val_size)
+static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
{
struct regmap_mmio_context *ctx = context;
- unsigned int offset;
int ret;
- regmap_mmio_regsize_check(reg_size);
-
if (!IS_ERR(ctx->clk)) {
ret = clk_enable(ctx->clk);
if (ret < 0)
return ret;
}
- offset = regmap_mmio_get_offset(reg, reg_size);
-
- while (val_size) {
- switch (ctx->val_bytes) {
- case 1:
- *(u8 *)val = readb(ctx->regs + offset);
- break;
- case 2:
- *(u16 *)val = readw(ctx->regs + offset);
- break;
- case 4:
- *(u32 *)val = readl(ctx->regs + offset);
- break;
-#ifdef CONFIG_64BIT
- case 8:
- *(u64 *)val = readq(ctx->regs + offset);
- break;
-#endif
- default:
- /* Should be caught by regmap_mmio_check_config */
- BUG();
- }
- val_size -= ctx->val_bytes;
- val += ctx->val_bytes;
- offset += ctx->val_bytes;
- }
+ *val = ctx->reg_read(ctx, reg);
if (!IS_ERR(ctx->clk))
clk_disable(ctx->clk);
@@ -232,14 +207,11 @@ static void regmap_mmio_free_context(void *context)
kfree(context);
}
-static struct regmap_bus regmap_mmio = {
+static const struct regmap_bus regmap_mmio = {
.fast_io = true,
- .write = regmap_mmio_write,
- .gather_write = regmap_mmio_gather_write,
- .read = regmap_mmio_read,
+ .reg_write = regmap_mmio_write,
+ .reg_read = regmap_mmio_read,
.free_context = regmap_mmio_free_context,
- .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
- .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
@@ -265,24 +237,71 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
if (config->reg_stride < min_stride)
return ERR_PTR(-EINVAL);
- switch (config->reg_format_endian) {
- case REGMAP_ENDIAN_DEFAULT:
- case REGMAP_ENDIAN_NATIVE:
- break;
- default:
- return ERR_PTR(-EINVAL);
- }
-
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return ERR_PTR(-ENOMEM);
ctx->regs = regs;
ctx->val_bytes = config->val_bits / 8;
- ctx->reg_bytes = config->reg_bits / 8;
- ctx->pad_bytes = config->pad_bits / 8;
ctx->clk = ERR_PTR(-ENODEV);
+ switch (config->reg_format_endian) {
+ case REGMAP_ENDIAN_DEFAULT:
+ case REGMAP_ENDIAN_LITTLE:
+#ifdef __LITTLE_ENDIAN
+ case REGMAP_ENDIAN_NATIVE:
+#endif
+ switch (config->val_bits) {
+ case 8:
+ ctx->reg_read = regmap_mmio_read8;
+ ctx->reg_write = regmap_mmio_write8;
+ break;
+ case 16:
+ ctx->reg_read = regmap_mmio_read16le;
+ ctx->reg_write = regmap_mmio_write16le;
+ break;
+ case 32:
+ ctx->reg_read = regmap_mmio_read32le;
+ ctx->reg_write = regmap_mmio_write32le;
+ break;
+#ifdef CONFIG_64BIT
+ case 64:
+ ctx->reg_read = regmap_mmio_read64le;
+ ctx->reg_write = regmap_mmio_write64le;
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ goto err_free;
+ }
+ break;
+ case REGMAP_ENDIAN_BIG:
+#ifdef __BIG_ENDIAN
+ case REGMAP_ENDIAN_NATIVE:
+#endif
+ switch (config->val_bits) {
+ case 8:
+ ctx->reg_read = regmap_mmio_read8;
+ ctx->reg_write = regmap_mmio_write8;
+ break;
+ case 16:
+ ctx->reg_read = regmap_mmio_read16be;
+ ctx->reg_write = regmap_mmio_write16be;
+ break;
+ case 32:
+ ctx->reg_read = regmap_mmio_read32be;
+ ctx->reg_write = regmap_mmio_write32be;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_free;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_free;
+ }
+
if (clk_id == NULL)
return ctx;
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index ee54e841de4a..df2d2ef5d6b3 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -19,6 +19,7 @@
#include <linux/rbtree.h>
#include <linux/sched.h>
#include <linux/delay.h>
+#include <linux/log2.h>
#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -557,6 +558,8 @@ enum regmap_endian regmap_get_val_endian(struct device *dev,
endian = REGMAP_ENDIAN_BIG;
else if (of_property_read_bool(np, "little-endian"))
endian = REGMAP_ENDIAN_LITTLE;
+ else if (of_property_read_bool(np, "native-endian"))
+ endian = REGMAP_ENDIAN_NATIVE;
/* If the endianness was specified in DT, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
@@ -638,6 +641,10 @@ struct regmap *__regmap_init(struct device *dev,
map->reg_stride = config->reg_stride;
else
map->reg_stride = 1;
+ if (is_power_of_2(map->reg_stride))
+ map->reg_stride_order = ilog2(map->reg_stride);
+ else
+ map->reg_stride_order = -1;
map->use_single_read = config->use_single_rw || !bus || !bus->read;
map->use_single_write = config->use_single_rw || !bus || !bus->write;
map->can_multi_write = config->can_multi_write && bus && bus->write;
@@ -1308,7 +1315,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
if (map->writeable_reg)
for (i = 0; i < val_len / map->format.val_bytes; i++)
if (!map->writeable_reg(map->dev,
- reg + (i * map->reg_stride)))
+ reg + regmap_get_offset(map, i)))
return -EINVAL;
if (!map->cache_bypass && map->format.parse_val) {
@@ -1316,7 +1323,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
int val_bytes = map->format.val_bytes;
for (i = 0; i < val_len / val_bytes; i++) {
ival = map->format.parse_val(val + (i * val_bytes));
- ret = regcache_write(map, reg + (i * map->reg_stride),
+ ret = regcache_write(map,
+ reg + regmap_get_offset(map, i),
ival);
if (ret) {
dev_err(map->dev,
@@ -1690,100 +1698,63 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
EXPORT_SYMBOL_GPL(regmap_raw_write);
/**
- * regmap_field_write(): Write a value to a single register field
- *
- * @field: Register field to write to
- * @val: Value to be written
- *
- * A value of zero will be returned on success, a negative errno will
- * be returned in error cases.
- */
-int regmap_field_write(struct regmap_field *field, unsigned int val)
-{
- return regmap_update_bits(field->regmap, field->reg,
- field->mask, val << field->shift);
-}
-EXPORT_SYMBOL_GPL(regmap_field_write);
-
-/**
- * regmap_field_update_bits(): Perform a read/modify/write cycle
- * on the register field
+ * regmap_field_update_bits_base():
+ * Perform a read/modify/write cycle on the register field
+ * with change, async, force option
*
* @field: Register field to write to
* @mask: Bitmask to change
* @val: Value to be written
+ * @change: Boolean indicating if a write was done
+ * @async: Boolean indicating asynchronously
+ * @force: Boolean indicating use force update
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
-int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val)
+int regmap_field_update_bits_base(struct regmap_field *field,
+ unsigned int mask, unsigned int val,
+ bool *change, bool async, bool force)
{
mask = (mask << field->shift) & field->mask;
- return regmap_update_bits(field->regmap, field->reg,
- mask, val << field->shift);
+ return regmap_update_bits_base(field->regmap, field->reg,
+ mask, val << field->shift,
+ change, async, force);
}
-EXPORT_SYMBOL_GPL(regmap_field_update_bits);
+EXPORT_SYMBOL_GPL(regmap_field_update_bits_base);
/**
- * regmap_fields_write(): Write a value to a single register field with port ID
- *
- * @field: Register field to write to
- * @id: port ID
- * @val: Value to be written
- *
- * A value of zero will be returned on success, a negative errno will
- * be returned in error cases.
- */
-int regmap_fields_write(struct regmap_field *field, unsigned int id,
- unsigned int val)
-{
- if (id >= field->id_size)
- return -EINVAL;
-
- return regmap_update_bits(field->regmap,
- field->reg + (field->id_offset * id),
- field->mask, val << field->shift);
-}
-EXPORT_SYMBOL_GPL(regmap_fields_write);
-
-int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
- unsigned int val)
-{
- if (id >= field->id_size)
- return -EINVAL;
-
- return regmap_write_bits(field->regmap,
- field->reg + (field->id_offset * id),
- field->mask, val << field->shift);
-}
-EXPORT_SYMBOL_GPL(regmap_fields_force_write);
-
-/**
- * regmap_fields_update_bits(): Perform a read/modify/write cycle
- * on the register field
+ * regmap_fields_update_bits_base():
+ * Perform a read/modify/write cycle on the register field
+ * with change, async, force option
*
* @field: Register field to write to
* @id: port ID
* @mask: Bitmask to change
* @val: Value to be written
+ * @change: Boolean indicating if a write was done
+ * @async: Boolean indicating asynchronously
+ * @force: Boolean indicating use force update
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
-int regmap_fields_update_bits(struct regmap_field *field, unsigned int id,
- unsigned int mask, unsigned int val)
+int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id,
+ unsigned int mask, unsigned int val,
+ bool *change, bool async, bool force)
{
if (id >= field->id_size)
return -EINVAL;
mask = (mask << field->shift) & field->mask;
- return regmap_update_bits(field->regmap,
- field->reg + (field->id_offset * id),
- mask, val << field->shift);
+ return regmap_update_bits_base(field->regmap,
+ field->reg + (field->id_offset * id),
+ mask, val << field->shift,
+ change, async, force);
}
-EXPORT_SYMBOL_GPL(regmap_fields_update_bits);
+EXPORT_SYMBOL_GPL(regmap_fields_update_bits_base);
/*
* regmap_bulk_write(): Write multiple registers to the device
@@ -1846,8 +1817,9 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
goto out;
}
- ret = _regmap_write(map, reg + (i * map->reg_stride),
- ival);
+ ret = _regmap_write(map,
+ reg + regmap_get_offset(map, i),
+ ival);
if (ret != 0)
goto out;
}
@@ -2253,6 +2225,9 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
WARN_ON(!map->bus);
+ if (!map->bus || !map->bus->read)
+ return -EINVAL;
+
range = _regmap_range_lookup(map, reg);
if (range) {
ret = _regmap_select_page(map, &reg, range,
@@ -2416,7 +2391,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
* cost as we expect to hit the cache.
*/
for (i = 0; i < val_count; i++) {
- ret = _regmap_read(map, reg + (i * map->reg_stride),
+ ret = _regmap_read(map, reg + regmap_get_offset(map, i),
&v);
if (ret != 0)
goto out;
@@ -2568,7 +2543,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
} else {
for (i = 0; i < val_count; i++) {
unsigned int ival;
- ret = regmap_read(map, reg + (i * map->reg_stride),
+ ret = regmap_read(map, reg + regmap_get_offset(map, i),
&ival);
if (ret != 0)
return ret;
@@ -2648,138 +2623,36 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
}
/**
- * regmap_update_bits: Perform a read/modify/write cycle on the register map
- *
- * @map: Register map to update
- * @reg: Register to update
- * @mask: Bitmask to change
- * @val: New value for bitmask
- *
- * Returns zero for success, a negative number on error.
- */
-int regmap_update_bits(struct regmap *map, unsigned int reg,
- unsigned int mask, unsigned int val)
-{
- int ret;
-
- map->lock(map->lock_arg);
- ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
- map->unlock(map->lock_arg);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(regmap_update_bits);
-
-/**
- * regmap_write_bits: Perform a read/modify/write cycle on the register map
- *
- * @map: Register map to update
- * @reg: Register to update
- * @mask: Bitmask to change
- * @val: New value for bitmask
- *
- * Returns zero for success, a negative number on error.
- */
-int regmap_write_bits(struct regmap *map, unsigned int reg,
- unsigned int mask, unsigned int val)
-{
- int ret;
-
- map->lock(map->lock_arg);
- ret = _regmap_update_bits(map, reg, mask, val, NULL, true);
- map->unlock(map->lock_arg);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(regmap_write_bits);
-
-/**
- * regmap_update_bits_async: Perform a read/modify/write cycle on the register
- * map asynchronously
- *
- * @map: Register map to update
- * @reg: Register to update
- * @mask: Bitmask to change
- * @val: New value for bitmask
- *
- * With most buses the read must be done synchronously so this is most
- * useful for devices with a cache which do not need to interact with
- * the hardware to determine the current register value.
- *
- * Returns zero for success, a negative number on error.
- */
-int regmap_update_bits_async(struct regmap *map, unsigned int reg,
- unsigned int mask, unsigned int val)
-{
- int ret;
-
- map->lock(map->lock_arg);
-
- map->async = true;
-
- ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
-
- map->async = false;
-
- map->unlock(map->lock_arg);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(regmap_update_bits_async);
-
-/**
- * regmap_update_bits_check: Perform a read/modify/write cycle on the
- * register map and report if updated
- *
- * @map: Register map to update
- * @reg: Register to update
- * @mask: Bitmask to change
- * @val: New value for bitmask
- * @change: Boolean indicating if a write was done
- *
- * Returns zero for success, a negative number on error.
- */
-int regmap_update_bits_check(struct regmap *map, unsigned int reg,
- unsigned int mask, unsigned int val,
- bool *change)
-{
- int ret;
-
- map->lock(map->lock_arg);
- ret = _regmap_update_bits(map, reg, mask, val, change, false);
- map->unlock(map->lock_arg);
- return ret;
-}
-EXPORT_SYMBOL_GPL(regmap_update_bits_check);
-
-/**
- * regmap_update_bits_check_async: Perform a read/modify/write cycle on the
- * register map asynchronously and report if
- * updated
+ * regmap_update_bits_base:
+ * Perform a read/modify/write cycle on the
+ * register map with change, async, force option
*
* @map: Register map to update
* @reg: Register to update
* @mask: Bitmask to change
* @val: New value for bitmask
* @change: Boolean indicating if a write was done
+ * @async: Boolean indicating asynchronously
+ * @force: Boolean indicating use force update
*
+ * if async was true,
* With most buses the read must be done synchronously so this is most
* useful for devices with a cache which do not need to interact with
* the hardware to determine the current register value.
*
* Returns zero for success, a negative number on error.
*/
-int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
- unsigned int mask, unsigned int val,
- bool *change)
+int regmap_update_bits_base(struct regmap *map, unsigned int reg,
+ unsigned int mask, unsigned int val,
+ bool *change, bool async, bool force)
{
int ret;
map->lock(map->lock_arg);
- map->async = true;
+ map->async = async;
- ret = _regmap_update_bits(map, reg, mask, val, change, false);
+ ret = _regmap_update_bits(map, reg, mask, val, change, force);
map->async = false;
@@ -2787,7 +2660,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
return ret;
}
-EXPORT_SYMBOL_GPL(regmap_update_bits_check_async);
+EXPORT_SYMBOL_GPL(regmap_update_bits_base);
void regmap_async_complete_cb(struct regmap_async *async, int ret)
{
diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c
index 99e773cb70d0..3d31761c0ed0 100644
--- a/drivers/block/cryptoloop.c
+++ b/drivers/block/cryptoloop.c
@@ -21,9 +21,9 @@
#include <linux/module.h>
+#include <crypto/skcipher.h>
#include <linux/init.h>
#include <linux/string.h>
-#include <linux/crypto.h>
#include <linux/blkdev.h>
#include <linux/scatterlist.h>
#include <asm/uaccess.h>
@@ -46,7 +46,7 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
char *cipher;
char *mode;
char *cmsp = cms; /* c-m string pointer */
- struct crypto_blkcipher *tfm;
+ struct crypto_skcipher *tfm;
/* encryption breaks for non sector aligned offsets */
@@ -82,12 +82,12 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
*cmsp++ = ')';
*cmsp = 0;
- tfm = crypto_alloc_blkcipher(cms, 0, CRYPTO_ALG_ASYNC);
+ tfm = crypto_alloc_skcipher(cms, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
- err = crypto_blkcipher_setkey(tfm, info->lo_encrypt_key,
- info->lo_encrypt_key_size);
+ err = crypto_skcipher_setkey(tfm, info->lo_encrypt_key,
+ info->lo_encrypt_key_size);
if (err != 0)
goto out_free_tfm;
@@ -96,17 +96,14 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
return 0;
out_free_tfm:
- crypto_free_blkcipher(tfm);
+ crypto_free_skcipher(tfm);
out:
return err;
}
-typedef int (*encdec_cbc_t)(struct blkcipher_desc *desc,
- struct scatterlist *sg_out,
- struct scatterlist *sg_in,
- unsigned int nsg);
+typedef int (*encdec_cbc_t)(struct skcipher_request *req);
static int
cryptoloop_transfer(struct loop_device *lo, int cmd,
@@ -114,11 +111,8 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
struct page *loop_page, unsigned loop_off,
int size, sector_t IV)
{
- struct crypto_blkcipher *tfm = lo->key_data;
- struct blkcipher_desc desc = {
- .tfm = tfm,
- .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
- };
+ struct crypto_skcipher *tfm = lo->key_data;
+ SKCIPHER_REQUEST_ON_STACK(req, tfm);
struct scatterlist sg_out;
struct scatterlist sg_in;
@@ -127,6 +121,10 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
unsigned in_offs, out_offs;
int err;
+ skcipher_request_set_tfm(req, tfm);
+ skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
+ NULL, NULL);
+
sg_init_table(&sg_out, 1);
sg_init_table(&sg_in, 1);
@@ -135,13 +133,13 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
in_offs = raw_off;
out_page = loop_page;
out_offs = loop_off;
- encdecfunc = crypto_blkcipher_crt(tfm)->decrypt;
+ encdecfunc = crypto_skcipher_decrypt;
} else {
in_page = loop_page;
in_offs = loop_off;
out_page = raw_page;
out_offs = raw_off;
- encdecfunc = crypto_blkcipher_crt(tfm)->encrypt;
+ encdecfunc = crypto_skcipher_encrypt;
}
while (size > 0) {
@@ -152,10 +150,10 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
sg_set_page(&sg_in, in_page, sz, in_offs);
sg_set_page(&sg_out, out_page, sz, out_offs);
- desc.info = iv;
- err = encdecfunc(&desc, &sg_out, &sg_in, sz);
+ skcipher_request_set_crypt(req, &sg_in, &sg_out, sz, iv);
+ err = encdecfunc(req);
if (err)
- return err;
+ goto out;
IV++;
size -= sz;
@@ -163,7 +161,11 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
out_offs += sz;
}
- return 0;
+ err = 0;
+
+out:
+ skcipher_request_zero(req);
+ return err;
}
static int
@@ -175,9 +177,9 @@ cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
static int
cryptoloop_release(struct loop_device *lo)
{
- struct crypto_blkcipher *tfm = lo->key_data;
+ struct crypto_skcipher *tfm = lo->key_data;
if (tfm != NULL) {
- crypto_free_blkcipher(tfm);
+ crypto_free_skcipher(tfm);
lo->key_data = NULL;
return 0;
}
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 34bc84efc29e..c227fd4cad75 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -26,13 +26,13 @@
#ifndef _DRBD_INT_H
#define _DRBD_INT_H
+#include <crypto/hash.h>
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/bitops.h>
#include <linux/slab.h>
-#include <linux/crypto.h>
#include <linux/ratelimit.h>
#include <linux/tcp.h>
#include <linux/mutex.h>
@@ -724,11 +724,11 @@ struct drbd_connection {
struct list_head transfer_log; /* all requests not yet fully processed */
- struct crypto_hash *cram_hmac_tfm;
- struct crypto_hash *integrity_tfm; /* checksums we compute, updates protected by connection->data->mutex */
- struct crypto_hash *peer_integrity_tfm; /* checksums we verify, only accessed from receiver thread */
- struct crypto_hash *csums_tfm;
- struct crypto_hash *verify_tfm;
+ struct crypto_shash *cram_hmac_tfm;
+ struct crypto_ahash *integrity_tfm; /* checksums we compute, updates protected by connection->data->mutex */
+ struct crypto_ahash *peer_integrity_tfm; /* checksums we verify, only accessed from receiver thread */
+ struct crypto_ahash *csums_tfm;
+ struct crypto_ahash *verify_tfm;
void *int_dig_in;
void *int_dig_vv;
@@ -1524,8 +1524,8 @@ static inline void ov_out_of_sync_print(struct drbd_device *device)
}
-extern void drbd_csum_bio(struct crypto_hash *, struct bio *, void *);
-extern void drbd_csum_ee(struct crypto_hash *, struct drbd_peer_request *, void *);
+extern void drbd_csum_bio(struct crypto_ahash *, struct bio *, void *);
+extern void drbd_csum_ee(struct crypto_ahash *, struct drbd_peer_request *, void *);
/* worker callbacks */
extern int w_e_end_data_req(struct drbd_work *, int);
extern int w_e_end_rsdata_req(struct drbd_work *, int);
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 5b43dfb79819..fa209773d494 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -1340,7 +1340,7 @@ void drbd_send_ack_dp(struct drbd_peer_device *peer_device, enum drbd_packet cmd
struct p_data *dp, int data_size)
{
if (peer_device->connection->peer_integrity_tfm)
- data_size -= crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
+ data_size -= crypto_ahash_digestsize(peer_device->connection->peer_integrity_tfm);
_drbd_send_ack(peer_device, cmd, dp->sector, cpu_to_be32(data_size),
dp->block_id);
}
@@ -1629,7 +1629,7 @@ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *
sock = &peer_device->connection->data;
p = drbd_prepare_command(peer_device, sock);
digest_size = peer_device->connection->integrity_tfm ?
- crypto_hash_digestsize(peer_device->connection->integrity_tfm) : 0;
+ crypto_ahash_digestsize(peer_device->connection->integrity_tfm) : 0;
if (!p)
return -EIO;
@@ -1718,7 +1718,7 @@ int drbd_send_block(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
p = drbd_prepare_command(peer_device, sock);
digest_size = peer_device->connection->integrity_tfm ?
- crypto_hash_digestsize(peer_device->connection->integrity_tfm) : 0;
+ crypto_ahash_digestsize(peer_device->connection->integrity_tfm) : 0;
if (!p)
return -EIO;
@@ -2498,11 +2498,11 @@ void conn_free_crypto(struct drbd_connection *connection)
{
drbd_free_sock(connection);
- crypto_free_hash(connection->csums_tfm);
- crypto_free_hash(connection->verify_tfm);
- crypto_free_hash(connection->cram_hmac_tfm);
- crypto_free_hash(connection->integrity_tfm);
- crypto_free_hash(connection->peer_integrity_tfm);
+ crypto_free_ahash(connection->csums_tfm);
+ crypto_free_ahash(connection->verify_tfm);
+ crypto_free_shash(connection->cram_hmac_tfm);
+ crypto_free_ahash(connection->integrity_tfm);
+ crypto_free_ahash(connection->peer_integrity_tfm);
kfree(connection->int_dig_in);
kfree(connection->int_dig_vv);
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index c055c5e12f24..226eb0c9f0fb 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -2160,19 +2160,34 @@ check_net_options(struct drbd_connection *connection, struct net_conf *new_net_c
}
struct crypto {
- struct crypto_hash *verify_tfm;
- struct crypto_hash *csums_tfm;
- struct crypto_hash *cram_hmac_tfm;
- struct crypto_hash *integrity_tfm;
+ struct crypto_ahash *verify_tfm;
+ struct crypto_ahash *csums_tfm;
+ struct crypto_shash *cram_hmac_tfm;
+ struct crypto_ahash *integrity_tfm;
};
static int
-alloc_hash(struct crypto_hash **tfm, char *tfm_name, int err_alg)
+alloc_shash(struct crypto_shash **tfm, char *tfm_name, int err_alg)
{
if (!tfm_name[0])
return NO_ERROR;
- *tfm = crypto_alloc_hash(tfm_name, 0, CRYPTO_ALG_ASYNC);
+ *tfm = crypto_alloc_shash(tfm_name, 0, 0);
+ if (IS_ERR(*tfm)) {
+ *tfm = NULL;
+ return err_alg;
+ }
+
+ return NO_ERROR;
+}
+
+static int
+alloc_ahash(struct crypto_ahash **tfm, char *tfm_name, int err_alg)
+{
+ if (!tfm_name[0])
+ return NO_ERROR;
+
+ *tfm = crypto_alloc_ahash(tfm_name, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(*tfm)) {
*tfm = NULL;
return err_alg;
@@ -2187,24 +2202,24 @@ alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf)
char hmac_name[CRYPTO_MAX_ALG_NAME];
enum drbd_ret_code rv;
- rv = alloc_hash(&crypto->csums_tfm, new_net_conf->csums_alg,
- ERR_CSUMS_ALG);
+ rv = alloc_ahash(&crypto->csums_tfm, new_net_conf->csums_alg,
+ ERR_CSUMS_ALG);
if (rv != NO_ERROR)
return rv;
- rv = alloc_hash(&crypto->verify_tfm, new_net_conf->verify_alg,
- ERR_VERIFY_ALG);
+ rv = alloc_ahash(&crypto->verify_tfm, new_net_conf->verify_alg,
+ ERR_VERIFY_ALG);
if (rv != NO_ERROR)
return rv;
- rv = alloc_hash(&crypto->integrity_tfm, new_net_conf->integrity_alg,
- ERR_INTEGRITY_ALG);
+ rv = alloc_ahash(&crypto->integrity_tfm, new_net_conf->integrity_alg,
+ ERR_INTEGRITY_ALG);
if (rv != NO_ERROR)
return rv;
if (new_net_conf->cram_hmac_alg[0] != 0) {
snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)",
new_net_conf->cram_hmac_alg);
- rv = alloc_hash(&crypto->cram_hmac_tfm, hmac_name,
- ERR_AUTH_ALG);
+ rv = alloc_shash(&crypto->cram_hmac_tfm, hmac_name,
+ ERR_AUTH_ALG);
}
return rv;
@@ -2212,10 +2227,10 @@ alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf)
static void free_crypto(struct crypto *crypto)
{
- crypto_free_hash(crypto->cram_hmac_tfm);
- crypto_free_hash(crypto->integrity_tfm);
- crypto_free_hash(crypto->csums_tfm);
- crypto_free_hash(crypto->verify_tfm);
+ crypto_free_shash(crypto->cram_hmac_tfm);
+ crypto_free_ahash(crypto->integrity_tfm);
+ crypto_free_ahash(crypto->csums_tfm);
+ crypto_free_ahash(crypto->verify_tfm);
}
int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
@@ -2292,23 +2307,23 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
rcu_assign_pointer(connection->net_conf, new_net_conf);
if (!rsr) {
- crypto_free_hash(connection->csums_tfm);
+ crypto_free_ahash(connection->csums_tfm);
connection->csums_tfm = crypto.csums_tfm;
crypto.csums_tfm = NULL;
}
if (!ovr) {
- crypto_free_hash(connection->verify_tfm);
+ crypto_free_ahash(connection->verify_tfm);
connection->verify_tfm = crypto.verify_tfm;
crypto.verify_tfm = NULL;
}
- crypto_free_hash(connection->integrity_tfm);
+ crypto_free_ahash(connection->integrity_tfm);
connection->integrity_tfm = crypto.integrity_tfm;
if (connection->cstate >= C_WF_REPORT_PARAMS && connection->agreed_pro_version >= 100)
/* Do this without trying to take connection->data.mutex again. */
__drbd_send_protocol(connection, P_PROTOCOL_UPDATE);
- crypto_free_hash(connection->cram_hmac_tfm);
+ crypto_free_shash(connection->cram_hmac_tfm);
connection->cram_hmac_tfm = crypto.cram_hmac_tfm;
mutex_unlock(&connection->resource->conf_update);
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 1957fe8601dc..050aaa1c0350 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -1627,7 +1627,7 @@ read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
digest_size = 0;
if (!trim && peer_device->connection->peer_integrity_tfm) {
- digest_size = crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
+ digest_size = crypto_ahash_digestsize(peer_device->connection->peer_integrity_tfm);
/*
* FIXME: Receive the incoming digest into the receive buffer
* here, together with its struct p_data?
@@ -1741,7 +1741,7 @@ static int recv_dless_read(struct drbd_peer_device *peer_device, struct drbd_req
digest_size = 0;
if (peer_device->connection->peer_integrity_tfm) {
- digest_size = crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
+ digest_size = crypto_ahash_digestsize(peer_device->connection->peer_integrity_tfm);
err = drbd_recv_all_warn(peer_device->connection, dig_in, digest_size);
if (err)
return err;
@@ -3321,7 +3321,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
int p_proto, p_discard_my_data, p_two_primaries, cf;
struct net_conf *nc, *old_net_conf, *new_net_conf = NULL;
char integrity_alg[SHARED_SECRET_MAX] = "";
- struct crypto_hash *peer_integrity_tfm = NULL;
+ struct crypto_ahash *peer_integrity_tfm = NULL;
void *int_dig_in = NULL, *int_dig_vv = NULL;
p_proto = be32_to_cpu(p->protocol);
@@ -3402,14 +3402,14 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
* change.
*/
- peer_integrity_tfm = crypto_alloc_hash(integrity_alg, 0, CRYPTO_ALG_ASYNC);
+ peer_integrity_tfm = crypto_alloc_ahash(integrity_alg, 0, CRYPTO_ALG_ASYNC);
if (!peer_integrity_tfm) {
drbd_err(connection, "peer data-integrity-alg %s not supported\n",
integrity_alg);
goto disconnect;
}
- hash_size = crypto_hash_digestsize(peer_integrity_tfm);
+ hash_size = crypto_ahash_digestsize(peer_integrity_tfm);
int_dig_in = kmalloc(hash_size, GFP_KERNEL);
int_dig_vv = kmalloc(hash_size, GFP_KERNEL);
if (!(int_dig_in && int_dig_vv)) {
@@ -3439,7 +3439,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
mutex_unlock(&connection->resource->conf_update);
mutex_unlock(&connection->data.mutex);
- crypto_free_hash(connection->peer_integrity_tfm);
+ crypto_free_ahash(connection->peer_integrity_tfm);
kfree(connection->int_dig_in);
kfree(connection->int_dig_vv);
connection->peer_integrity_tfm = peer_integrity_tfm;
@@ -3457,7 +3457,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
disconnect_rcu_unlock:
rcu_read_unlock();
disconnect:
- crypto_free_hash(peer_integrity_tfm);
+ crypto_free_ahash(peer_integrity_tfm);
kfree(int_dig_in);
kfree(int_dig_vv);
conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
@@ -3469,15 +3469,15 @@ disconnect:
* return: NULL (alg name was "")
* ERR_PTR(error) if something goes wrong
* or the crypto hash ptr, if it worked out ok. */
-static struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_device *device,
+static struct crypto_ahash *drbd_crypto_alloc_digest_safe(const struct drbd_device *device,
const char *alg, const char *name)
{
- struct crypto_hash *tfm;
+ struct crypto_ahash *tfm;
if (!alg[0])
return NULL;
- tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC);
+ tfm = crypto_alloc_ahash(alg, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm)) {
drbd_err(device, "Can not allocate \"%s\" as %s (reason: %ld)\n",
alg, name, PTR_ERR(tfm));
@@ -3530,8 +3530,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i
struct drbd_device *device;
struct p_rs_param_95 *p;
unsigned int header_size, data_size, exp_max_sz;
- struct crypto_hash *verify_tfm = NULL;
- struct crypto_hash *csums_tfm = NULL;
+ struct crypto_ahash *verify_tfm = NULL;
+ struct crypto_ahash *csums_tfm = NULL;
struct net_conf *old_net_conf, *new_net_conf = NULL;
struct disk_conf *old_disk_conf = NULL, *new_disk_conf = NULL;
const int apv = connection->agreed_pro_version;
@@ -3678,14 +3678,14 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i
if (verify_tfm) {
strcpy(new_net_conf->verify_alg, p->verify_alg);
new_net_conf->verify_alg_len = strlen(p->verify_alg) + 1;
- crypto_free_hash(peer_device->connection->verify_tfm);
+ crypto_free_ahash(peer_device->connection->verify_tfm);
peer_device->connection->verify_tfm = verify_tfm;
drbd_info(device, "using verify-alg: \"%s\"\n", p->verify_alg);
}
if (csums_tfm) {
strcpy(new_net_conf->csums_alg, p->csums_alg);
new_net_conf->csums_alg_len = strlen(p->csums_alg) + 1;
- crypto_free_hash(peer_device->connection->csums_tfm);
+ crypto_free_ahash(peer_device->connection->csums_tfm);
peer_device->connection->csums_tfm = csums_tfm;
drbd_info(device, "using csums-alg: \"%s\"\n", p->csums_alg);
}
@@ -3729,9 +3729,9 @@ disconnect:
mutex_unlock(&connection->resource->conf_update);
/* just for completeness: actually not needed,
* as this is not reached if csums_tfm was ok. */
- crypto_free_hash(csums_tfm);
+ crypto_free_ahash(csums_tfm);
/* but free the verify_tfm again, if csums_tfm did not work out */
- crypto_free_hash(verify_tfm);
+ crypto_free_ahash(verify_tfm);
conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
@@ -4925,14 +4925,13 @@ static int drbd_do_auth(struct drbd_connection *connection)
{
struct drbd_socket *sock;
char my_challenge[CHALLENGE_LEN]; /* 64 Bytes... */
- struct scatterlist sg;
char *response = NULL;
char *right_response = NULL;
char *peers_ch = NULL;
unsigned int key_len;
char secret[SHARED_SECRET_MAX]; /* 64 byte */
unsigned int resp_size;
- struct hash_desc desc;
+ SHASH_DESC_ON_STACK(desc, connection->cram_hmac_tfm);
struct packet_info pi;
struct net_conf *nc;
int err, rv;
@@ -4945,12 +4944,12 @@ static int drbd_do_auth(struct drbd_connection *connection)
memcpy(secret, nc->shared_secret, key_len);
rcu_read_unlock();
- desc.tfm = connection->cram_hmac_tfm;
- desc.flags = 0;
+ desc->tfm = connection->cram_hmac_tfm;
+ desc->flags = 0;
- rv = crypto_hash_setkey(connection->cram_hmac_tfm, (u8 *)secret, key_len);
+ rv = crypto_shash_setkey(connection->cram_hmac_tfm, (u8 *)secret, key_len);
if (rv) {
- drbd_err(connection, "crypto_hash_setkey() failed with %d\n", rv);
+ drbd_err(connection, "crypto_shash_setkey() failed with %d\n", rv);
rv = -1;
goto fail;
}
@@ -5011,7 +5010,7 @@ static int drbd_do_auth(struct drbd_connection *connection)
goto fail;
}
- resp_size = crypto_hash_digestsize(connection->cram_hmac_tfm);
+ resp_size = crypto_shash_digestsize(connection->cram_hmac_tfm);
response = kmalloc(resp_size, GFP_NOIO);
if (response == NULL) {
drbd_err(connection, "kmalloc of response failed\n");
@@ -5019,10 +5018,7 @@ static int drbd_do_auth(struct drbd_connection *connection)
goto fail;
}
- sg_init_table(&sg, 1);
- sg_set_buf(&sg, peers_ch, pi.size);
-
- rv = crypto_hash_digest(&desc, &sg, sg.length, response);
+ rv = crypto_shash_digest(desc, peers_ch, pi.size, response);
if (rv) {
drbd_err(connection, "crypto_hash_digest() failed with %d\n", rv);
rv = -1;
@@ -5070,9 +5066,8 @@ static int drbd_do_auth(struct drbd_connection *connection)
goto fail;
}
- sg_set_buf(&sg, my_challenge, CHALLENGE_LEN);
-
- rv = crypto_hash_digest(&desc, &sg, sg.length, right_response);
+ rv = crypto_shash_digest(desc, my_challenge, CHALLENGE_LEN,
+ right_response);
if (rv) {
drbd_err(connection, "crypto_hash_digest() failed with %d\n", rv);
rv = -1;
@@ -5091,6 +5086,7 @@ static int drbd_do_auth(struct drbd_connection *connection)
kfree(peers_ch);
kfree(response);
kfree(right_response);
+ shash_desc_zero(desc);
return rv;
}
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index eff716c27b1f..4d87499f0d54 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -274,51 +274,56 @@ void drbd_request_endio(struct bio *bio)
complete_master_bio(device, &m);
}
-void drbd_csum_ee(struct crypto_hash *tfm, struct drbd_peer_request *peer_req, void *digest)
+void drbd_csum_ee(struct crypto_ahash *tfm, struct drbd_peer_request *peer_req, void *digest)
{
- struct hash_desc desc;
+ AHASH_REQUEST_ON_STACK(req, tfm);
struct scatterlist sg;
struct page *page = peer_req->pages;
struct page *tmp;
unsigned len;
- desc.tfm = tfm;
- desc.flags = 0;
+ ahash_request_set_tfm(req, tfm);
+ ahash_request_set_callback(req, 0, NULL, NULL);
sg_init_table(&sg, 1);
- crypto_hash_init(&desc);
+ crypto_ahash_init(req);
while ((tmp = page_chain_next(page))) {
/* all but the last page will be fully used */
sg_set_page(&sg, page, PAGE_SIZE, 0);
- crypto_hash_update(&desc, &sg, sg.length);
+ ahash_request_set_crypt(req, &sg, NULL, sg.length);
+ crypto_ahash_update(req);
page = tmp;
}
/* and now the last, possibly only partially used page */
len = peer_req->i.size & (PAGE_SIZE - 1);
sg_set_page(&sg, page, len ?: PAGE_SIZE, 0);
- crypto_hash_update(&desc, &sg, sg.length);
- crypto_hash_final(&desc, digest);
+ ahash_request_set_crypt(req, &sg, digest, sg.length);
+ crypto_ahash_finup(req);
+ ahash_request_zero(req);
}
-void drbd_csum_bio(struct crypto_hash *tfm, struct bio *bio, void *digest)
+void drbd_csum_bio(struct crypto_ahash *tfm, struct bio *bio, void *digest)
{
- struct hash_desc desc;
+ AHASH_REQUEST_ON_STACK(req, tfm);
struct scatterlist sg;
struct bio_vec bvec;
struct bvec_iter iter;
- desc.tfm = tfm;
- desc.flags = 0;
+ ahash_request_set_tfm(req, tfm);
+ ahash_request_set_callback(req, 0, NULL, NULL);
sg_init_table(&sg, 1);
- crypto_hash_init(&desc);
+ crypto_ahash_init(req);
bio_for_each_segment(bvec, bio, iter) {
sg_set_page(&sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset);
- crypto_hash_update(&desc, &sg, sg.length);
+ ahash_request_set_crypt(req, &sg, NULL, sg.length);
+ crypto_ahash_update(req);
}
- crypto_hash_final(&desc, digest);
+ ahash_request_set_crypt(req, NULL, digest, 0);
+ crypto_ahash_final(req);
+ ahash_request_zero(req);
}
/* MAYBE merge common code with w_e_end_ov_req */
@@ -337,7 +342,7 @@ static int w_e_send_csum(struct drbd_work *w, int cancel)
if (unlikely((peer_req->flags & EE_WAS_ERROR) != 0))
goto out;
- digest_size = crypto_hash_digestsize(peer_device->connection->csums_tfm);
+ digest_size = crypto_ahash_digestsize(peer_device->connection->csums_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (digest) {
sector_t sector = peer_req->i.sector;
@@ -1113,7 +1118,7 @@ int w_e_end_csum_rs_req(struct drbd_work *w, int cancel)
* a real fix would be much more involved,
* introducing more locking mechanisms */
if (peer_device->connection->csums_tfm) {
- digest_size = crypto_hash_digestsize(peer_device->connection->csums_tfm);
+ digest_size = crypto_ahash_digestsize(peer_device->connection->csums_tfm);
D_ASSERT(device, digest_size == di->digest_size);
digest = kmalloc(digest_size, GFP_NOIO);
}
@@ -1163,7 +1168,7 @@ int w_e_end_ov_req(struct drbd_work *w, int cancel)
if (unlikely(cancel))
goto out;
- digest_size = crypto_hash_digestsize(peer_device->connection->verify_tfm);
+ digest_size = crypto_ahash_digestsize(peer_device->connection->verify_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (!digest) {
err = 1; /* terminate the connection in case the allocation failed */
@@ -1235,7 +1240,7 @@ int w_e_end_ov_reply(struct drbd_work *w, int cancel)
di = peer_req->digest;
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- digest_size = crypto_hash_digestsize(peer_device->connection->verify_tfm);
+ digest_size = crypto_ahash_digestsize(peer_device->connection->verify_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (digest) {
drbd_csum_ee(peer_device->connection->verify_tfm, peer_req, digest);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 9e251201dd48..84708a5f8c52 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -866,7 +866,7 @@ static void set_fdc(int drive)
}
/* locks the driver */
-static int lock_fdc(int drive, bool interruptible)
+static int lock_fdc(int drive)
{
if (WARN(atomic_read(&usage_count) == 0,
"Trying to lock fdc while usage count=0\n"))
@@ -2173,7 +2173,7 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
{
int ret;
- if (lock_fdc(drive, true))
+ if (lock_fdc(drive))
return -EINTR;
set_floppy(drive);
@@ -2960,7 +2960,7 @@ static int user_reset_fdc(int drive, int arg, bool interruptible)
{
int ret;
- if (lock_fdc(drive, interruptible))
+ if (lock_fdc(drive))
return -EINTR;
if (arg == FD_RESET_ALWAYS)
@@ -3243,7 +3243,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
mutex_lock(&open_lock);
- if (lock_fdc(drive, true)) {
+ if (lock_fdc(drive)) {
mutex_unlock(&open_lock);
return -EINTR;
}
@@ -3263,7 +3263,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
} else {
int oldStretch;
- if (lock_fdc(drive, true))
+ if (lock_fdc(drive))
return -EINTR;
if (cmd != FDDEFPRM) {
/* notice a disk change immediately, else
@@ -3349,7 +3349,7 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
if (type)
*g = &floppy_type[type];
else {
- if (lock_fdc(drive, false))
+ if (lock_fdc(drive))
return -EINTR;
if (poll_drive(false, 0) == -EINTR)
return -EINTR;
@@ -3433,7 +3433,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
if (UDRS->fd_ref != 1)
/* somebody else has this drive open */
return -EBUSY;
- if (lock_fdc(drive, true))
+ if (lock_fdc(drive))
return -EINTR;
/* do the actual eject. Fails on
@@ -3445,7 +3445,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
process_fd_request();
return ret;
case FDCLRPRM:
- if (lock_fdc(drive, true))
+ if (lock_fdc(drive))
return -EINTR;
current_type[drive] = NULL;
floppy_sizes[drive] = MAX_DISK_SIZE << 1;
@@ -3467,7 +3467,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
UDP->flags &= ~FTD_MSG;
return 0;
case FDFMTBEG:
- if (lock_fdc(drive, true))
+ if (lock_fdc(drive))
return -EINTR;
if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
return -EINTR;
@@ -3484,7 +3484,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
return do_format(drive, &inparam.f);
case FDFMTEND:
case FDFLUSH:
- if (lock_fdc(drive, true))
+ if (lock_fdc(drive))
return -EINTR;
return invalidate_drive(bdev);
case FDSETEMSGTRESH:
@@ -3507,7 +3507,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
outparam = UDP;
break;
case FDPOLLDRVSTAT:
- if (lock_fdc(drive, true))
+ if (lock_fdc(drive))
return -EINTR;
if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
return -EINTR;
@@ -3530,7 +3530,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
case FDRAWCMD:
if (type)
return -EINVAL;
- if (lock_fdc(drive, true))
+ if (lock_fdc(drive))
return -EINTR;
set_floppy(drive);
i = raw_cmd_ioctl(cmd, (void __user *)param);
@@ -3539,7 +3539,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
process_fd_request();
return i;
case FDTWADDLE:
- if (lock_fdc(drive, true))
+ if (lock_fdc(drive))
return -EINTR;
twaddle();
process_fd_request();
@@ -3663,6 +3663,11 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
opened_bdev[drive] = bdev;
+ if (!(mode & (FMODE_READ|FMODE_WRITE))) {
+ res = -EINVAL;
+ goto out;
+ }
+
res = -ENXIO;
if (!floppy_track_buffer) {
@@ -3706,21 +3711,20 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
if (UFDCS->rawcmd == 1)
UFDCS->rawcmd = 2;
- if (!(mode & FMODE_NDELAY)) {
- if (mode & (FMODE_READ|FMODE_WRITE)) {
- UDRS->last_checked = 0;
- clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
- check_disk_change(bdev);
- if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
- goto out;
- if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
- goto out;
- }
- res = -EROFS;
- if ((mode & FMODE_WRITE) &&
- !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
- goto out;
- }
+ UDRS->last_checked = 0;
+ clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
+ check_disk_change(bdev);
+ if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
+ goto out;
+ if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
+ goto out;
+
+ res = -EROFS;
+
+ if ((mode & FMODE_WRITE) &&
+ !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
+ goto out;
+
mutex_unlock(&open_lock);
mutex_unlock(&floppy_mutex);
return 0;
@@ -3748,7 +3752,8 @@ static unsigned int floppy_check_events(struct gendisk *disk,
return DISK_EVENT_MEDIA_CHANGE;
if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
- lock_fdc(drive, false);
+ if (lock_fdc(drive))
+ return -EINTR;
poll_drive(false, 0);
process_fd_request();
}
@@ -3847,7 +3852,9 @@ static int floppy_revalidate(struct gendisk *disk)
"VFS: revalidate called on non-open device.\n"))
return -EFAULT;
- lock_fdc(drive, false);
+ res = lock_fdc(drive);
+ if (res)
+ return res;
cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
test_bit(FD_VERIFY_BIT, &UDRS->flags));
if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
index 8ba1e97d573c..64a7b5971b57 100644
--- a/drivers/block/null_blk.c
+++ b/drivers/block/null_blk.c
@@ -478,7 +478,7 @@ static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id)
id->ver_id = 0x1;
id->vmnt = 0;
id->cgrps = 1;
- id->cap = 0x3;
+ id->cap = 0x2;
id->dom = 0x1;
id->ppaf.blk_offset = 0;
@@ -707,9 +707,7 @@ static int null_add_dev(void)
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, nullb->q);
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, nullb->q);
-
mutex_lock(&lock);
- list_add_tail(&nullb->list, &nullb_list);
nullb->index = nullb_indexes++;
mutex_unlock(&lock);
@@ -743,6 +741,10 @@ static int null_add_dev(void)
strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
add_disk(disk);
+
+ mutex_lock(&lock);
+ list_add_tail(&nullb->list, &nullb_list);
+ mutex_unlock(&lock);
done:
return 0;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 562b5a4ca7b7..78a39f736c64 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -126,7 +126,7 @@
*/
#include <linux/types.h>
-static bool verbose = 0;
+static int verbose = 0;
static int major = PD_MAJOR;
static char *name = PD_NAME;
static int cluster = 64;
@@ -161,7 +161,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV};
static DEFINE_MUTEX(pd_mutex);
static DEFINE_SPINLOCK(pd_lock);
-module_param(verbose, bool, 0);
+module_param(verbose, int, 0);
module_param(major, int, 0);
module_param(name, charp, 0);
module_param(cluster, int, 0);
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 1740d75e8a32..216a94fed5b4 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -117,7 +117,7 @@
*/
-static bool verbose = 0;
+static int verbose = 0;
static int major = PT_MAJOR;
static char *name = PT_NAME;
static int disable = 0;
@@ -152,7 +152,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
#include <asm/uaccess.h>
-module_param(verbose, bool, 0);
+module_param(verbose, int, 0);
module_param(major, int, 0);
module_param(name, charp, 0);
module_param_array(drive0, int, NULL, 0);
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 8a8dc91c39f7..83eb9e6bf8b0 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -1873,6 +1873,43 @@ again:
return err;
}
+static int negotiate_mq(struct blkfront_info *info)
+{
+ unsigned int backend_max_queues = 0;
+ int err;
+ unsigned int i;
+
+ BUG_ON(info->nr_rings);
+
+ /* Check if backend supports multiple queues. */
+ err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+ "multi-queue-max-queues", "%u", &backend_max_queues);
+ if (err < 0)
+ backend_max_queues = 1;
+
+ info->nr_rings = min(backend_max_queues, xen_blkif_max_queues);
+ /* We need at least one ring. */
+ if (!info->nr_rings)
+ info->nr_rings = 1;
+
+ info->rinfo = kzalloc(sizeof(struct blkfront_ring_info) * info->nr_rings, GFP_KERNEL);
+ if (!info->rinfo) {
+ xenbus_dev_fatal(info->xbdev, -ENOMEM, "allocating ring_info structure");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < info->nr_rings; i++) {
+ struct blkfront_ring_info *rinfo;
+
+ rinfo = &info->rinfo[i];
+ INIT_LIST_HEAD(&rinfo->indirect_pages);
+ INIT_LIST_HEAD(&rinfo->grants);
+ rinfo->dev_info = info;
+ INIT_WORK(&rinfo->work, blkif_restart_queue);
+ spin_lock_init(&rinfo->ring_lock);
+ }
+ return 0;
+}
/**
* Entry point to this code when a new device is created. Allocate the basic
* structures and the ring buffer for communication with the backend, and
@@ -1883,9 +1920,7 @@ static int blkfront_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
{
int err, vdevice;
- unsigned int r_index;
struct blkfront_info *info;
- unsigned int backend_max_queues = 0;
/* FIXME: Use dynamic device id if this is not set. */
err = xenbus_scanf(XBT_NIL, dev->nodename,
@@ -1936,33 +1971,10 @@ static int blkfront_probe(struct xenbus_device *dev,
}
info->xbdev = dev;
- /* Check if backend supports multiple queues. */
- err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
- "multi-queue-max-queues", "%u", &backend_max_queues);
- if (err < 0)
- backend_max_queues = 1;
-
- info->nr_rings = min(backend_max_queues, xen_blkif_max_queues);
- /* We need at least one ring. */
- if (!info->nr_rings)
- info->nr_rings = 1;
-
- info->rinfo = kzalloc(sizeof(struct blkfront_ring_info) * info->nr_rings, GFP_KERNEL);
- if (!info->rinfo) {
- xenbus_dev_fatal(dev, -ENOMEM, "allocating ring_info structure");
+ err = negotiate_mq(info);
+ if (err) {
kfree(info);
- return -ENOMEM;
- }
-
- for (r_index = 0; r_index < info->nr_rings; r_index++) {
- struct blkfront_ring_info *rinfo;
-
- rinfo = &info->rinfo[r_index];
- INIT_LIST_HEAD(&rinfo->indirect_pages);
- INIT_LIST_HEAD(&rinfo->grants);
- rinfo->dev_info = info;
- INIT_WORK(&rinfo->work, blkif_restart_queue);
- spin_lock_init(&rinfo->ring_lock);
+ return err;
}
mutex_init(&info->mutex);
@@ -2123,12 +2135,16 @@ static int blkif_recover(struct blkfront_info *info)
static int blkfront_resume(struct xenbus_device *dev)
{
struct blkfront_info *info = dev_get_drvdata(&dev->dev);
- int err;
+ int err = 0;
dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
+ err = negotiate_mq(info);
+ if (err)
+ return err;
+
err = talk_to_blkback(dev, info);
/*
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index a043107da2af..3ec0766ed5e9 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -328,7 +328,8 @@ config JS_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32 && !BLACKFIN && !UML
+ depends on RTC!=y
+ depends on ALPHA || M68K || MN10300 || PARISC || PPC || X86
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 05755441250c..fdced547ad59 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -10,7 +10,6 @@
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <asm/uninorth.h>
-#include <asm/pci-bridge.h>
#include <asm/prom.h>
#include <asm/pmac_feature.h>
#include "agp.h"
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 240b6cf1d97c..be54e5331a45 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -42,7 +42,7 @@
/*
* The High Precision Event Timer driver.
* This driver is closely modelled after the rtc.c driver.
- * http://www.intel.com/hardwaredesign/hpetspec_1.pdf
+ * See HPET spec revision 1.
*/
#define HPET_USER_FREQ (64)
#define HPET_DRIFT (500)
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index ff00331bff49..67ee8b08ab53 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -77,7 +77,7 @@ config HW_RANDOM_ATMEL
config HW_RANDOM_BCM63XX
tristate "Broadcom BCM63xx Random Number Generator support"
- depends on BCM63XX
+ depends on BCM63XX || BMIPS_GENERIC
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -382,6 +382,19 @@ config HW_RANDOM_STM32
If unsure, say N.
+config HW_RANDOM_PIC32
+ tristate "Microchip PIC32 Random Number Generator support"
+ depends on HW_RANDOM && MACH_PIC32
+ default y
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on a PIC32.
+
+ To compile this driver as a module, choose M here. the
+ module will be called pic32-rng.
+
+ If unsure, say Y.
+
endif # HW_RANDOM
config UML_RANDOM
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 5ad397635128..f5a6fa7690e7 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -33,3 +33,4 @@ obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o
obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o
+obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o
diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c
index 4b31f1387f37..ca9c40309757 100644
--- a/drivers/char/hw_random/bcm63xx-rng.c
+++ b/drivers/char/hw_random/bcm63xx-rng.c
@@ -79,10 +79,8 @@ static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data)
static int bcm63xx_rng_probe(struct platform_device *pdev)
{
struct resource *r;
- struct clk *clk;
int ret;
struct bcm63xx_rng_priv *priv;
- struct hwrng *rng;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
@@ -132,10 +130,19 @@ static int bcm63xx_rng_probe(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id bcm63xx_rng_of_match[] = {
+ { .compatible = "brcm,bcm6368-rng", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm63xx_rng_of_match);
+#endif
+
static struct platform_driver bcm63xx_rng_driver = {
.probe = bcm63xx_rng_probe,
.driver = {
.name = "bcm63xx-rng",
+ .of_match_table = of_match_ptr(bcm63xx_rng_of_match),
},
};
diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c
index 30cf4623184f..ada081232528 100644
--- a/drivers/char/hw_random/exynos-rng.c
+++ b/drivers/char/hw_random/exynos-rng.c
@@ -144,8 +144,7 @@ static int exynos_rng_probe(struct platform_device *pdev)
return devm_hwrng_register(&pdev->dev, &exynos_rng->rng);
}
-#ifdef CONFIG_PM
-static int exynos_rng_runtime_suspend(struct device *dev)
+static int __maybe_unused exynos_rng_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
@@ -155,7 +154,7 @@ static int exynos_rng_runtime_suspend(struct device *dev)
return 0;
}
-static int exynos_rng_runtime_resume(struct device *dev)
+static int __maybe_unused exynos_rng_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
@@ -163,12 +162,12 @@ static int exynos_rng_runtime_resume(struct device *dev)
return clk_prepare_enable(exynos_rng->clk);
}
-static int exynos_rng_suspend(struct device *dev)
+static int __maybe_unused exynos_rng_suspend(struct device *dev)
{
return pm_runtime_force_suspend(dev);
}
-static int exynos_rng_resume(struct device *dev)
+static int __maybe_unused exynos_rng_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
@@ -180,7 +179,6 @@ static int exynos_rng_resume(struct device *dev)
return exynos_rng_configure(exynos_rng);
}
-#endif
static const struct dev_pm_ops exynos_rng_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(exynos_rng_suspend, exynos_rng_resume)
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 843d6f6aee7a..3b06c1d6cfb2 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -743,6 +743,16 @@ static const struct of_device_id n2rng_match[] = {
.compatible = "SUNW,kt-rng",
.data = (void *) 1,
},
+ {
+ .name = "random-number-generator",
+ .compatible = "ORCL,m4-rng",
+ .data = (void *) 1,
+ },
+ {
+ .name = "random-number-generator",
+ .compatible = "ORCL,m7-rng",
+ .data = (void *) 1,
+ },
{},
};
MODULE_DEVICE_TABLE(of, n2rng_match);
diff --git a/drivers/char/hw_random/pic32-rng.c b/drivers/char/hw_random/pic32-rng.c
new file mode 100644
index 000000000000..108897bea2d0
--- /dev/null
+++ b/drivers/char/hw_random/pic32-rng.c
@@ -0,0 +1,155 @@
+/*
+ * PIC32 RNG driver
+ *
+ * Joshua Henderson <joshua.henderson@microchip.com>
+ * Copyright (C) 2016 Microchip Technology Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define RNGCON 0x04
+#define TRNGEN BIT(8)
+#define PRNGEN BIT(9)
+#define PRNGCONT BIT(10)
+#define TRNGMOD BIT(11)
+#define SEEDLOAD BIT(12)
+#define RNGPOLY1 0x08
+#define RNGPOLY2 0x0C
+#define RNGNUMGEN1 0x10
+#define RNGNUMGEN2 0x14
+#define RNGSEED1 0x18
+#define RNGSEED2 0x1C
+#define RNGRCNT 0x20
+#define RCNT_MASK 0x7F
+
+struct pic32_rng {
+ void __iomem *base;
+ struct hwrng rng;
+ struct clk *clk;
+};
+
+/*
+ * The TRNG can generate up to 24Mbps. This is a timeout that should be safe
+ * enough given the instructions in the loop and that the TRNG may not always
+ * be at maximum rate.
+ */
+#define RNG_TIMEOUT 500
+
+static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max,
+ bool wait)
+{
+ struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng);
+ u64 *data = buf;
+ u32 t;
+ unsigned int timeout = RNG_TIMEOUT;
+
+ if (max < 8)
+ return 0;
+
+ do {
+ t = readl(priv->base + RNGRCNT) & RCNT_MASK;
+ if (t == 64) {
+ /* TRNG value comes through the seed registers */
+ *data = ((u64)readl(priv->base + RNGSEED2) << 32) +
+ readl(priv->base + RNGSEED1);
+ return 8;
+ }
+ } while (wait && --timeout);
+
+ return -EIO;
+}
+
+static int pic32_rng_probe(struct platform_device *pdev)
+{
+ struct pic32_rng *priv;
+ struct resource *res;
+ u32 v;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ /* enable TRNG in enhanced mode */
+ v = TRNGEN | TRNGMOD;
+ writel(v, priv->base + RNGCON);
+
+ priv->rng.name = pdev->name;
+ priv->rng.read = pic32_rng_read;
+
+ ret = hwrng_register(&priv->rng);
+ if (ret)
+ goto err_register;
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+
+err_register:
+ clk_disable_unprepare(priv->clk);
+ return ret;
+}
+
+static int pic32_rng_remove(struct platform_device *pdev)
+{
+ struct pic32_rng *rng = platform_get_drvdata(pdev);
+
+ hwrng_unregister(&rng->rng);
+ writel(0, rng->base + RNGCON);
+ clk_disable_unprepare(rng->clk);
+ return 0;
+}
+
+static const struct of_device_id pic32_rng_of_match[] = {
+ { .compatible = "microchip,pic32mzda-rng", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pic32_rng_of_match);
+
+static struct platform_driver pic32_rng_driver = {
+ .probe = pic32_rng_probe,
+ .remove = pic32_rng_remove,
+ .driver = {
+ .name = "pic32-rng",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pic32_rng_of_match),
+ },
+};
+
+module_platform_driver(pic32_rng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>");
+MODULE_DESCRIPTION("Microchip PIC32 RNG Driver");
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 4f6f94c43412..71025c2f6bbb 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -695,7 +695,7 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
offset += file->f_pos;
case SEEK_SET:
/* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */
- if (IS_ERR_VALUE((unsigned long long)offset)) {
+ if ((unsigned long long)offset >= -MAX_ERRNO) {
ret = -EOVERFLOW;
break;
}
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 01292328a456..678fa97e41fb 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -496,12 +496,12 @@ static void pc_set_checksum(void)
#ifdef CONFIG_PROC_FS
-static char *floppy_types[] = {
+static const char * const floppy_types[] = {
"none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M",
"3.5'' 2.88M", "3.5'' 2.88M"
};
-static char *gfx_types[] = {
+static const char * const gfx_types[] = {
"EGA, VGA, ... (with BIOS)",
"CGA (40 cols)",
"CGA (80 cols)",
@@ -602,7 +602,7 @@ static void atari_set_checksum(void)
static struct {
unsigned char val;
- char *name;
+ const char *name;
} boot_prefs[] = {
{ 0x80, "TOS" },
{ 0x40, "ASV" },
@@ -611,7 +611,7 @@ static struct {
{ 0x00, "unspecified" }
};
-static char *languages[] = {
+static const char * const languages[] = {
"English (US)",
"German",
"French",
@@ -623,7 +623,7 @@ static char *languages[] = {
"Swiss (German)"
};
-static char *dateformat[] = {
+static const char * const dateformat[] = {
"MM%cDD%cYY",
"DD%cMM%cYY",
"YY%cMM%cDD",
@@ -634,7 +634,7 @@ static char *dateformat[] = {
"7 (undefined)"
};
-static char *colors[] = {
+static const char * const colors[] = {
"2", "4", "16", "256", "65536", "??", "??", "??"
};
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
index 76c490fa0511..0e184426db98 100644
--- a/drivers/char/nwbutton.c
+++ b/drivers/char/nwbutton.c
@@ -129,10 +129,9 @@ static void button_consume_callbacks (int bpcount)
static void button_sequence_finished (unsigned long parameters)
{
-#ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */
- if (button_press_count == reboot_count)
+ if (IS_ENABLED(CONFIG_NWBUTTON_REBOOT) &&
+ button_press_count == reboot_count)
kill_cad_pid(SIGINT, 1); /* Ask init to reboot us */
-#endif /* CONFIG_NWBUTTON_REBOOT */
button_consume_callbacks (button_press_count);
bcount = sprintf (button_output_buffer, "%d\n", button_press_count);
button_press_count = 0; /* Reset the button press counter */
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 45df4bf914f8..22c27652e46a 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1349,7 +1349,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
/* TODO:disable interrupts instead of reset to preserve signal states */
reset_device(info);
- if (!tty || tty->termios.c_cflag & HUPCL) {
+ if (!tty || C_HUPCL(tty)) {
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
set_signals(info);
}
@@ -1390,7 +1390,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
get_signals(info);
- if (info->netcount || (tty && (tty->termios.c_cflag & CREAD)))
+ if (info->netcount || (tty && C_CREAD(tty)))
rx_start(info);
spin_unlock_irqrestore(&info->lock, flags);
@@ -1733,7 +1733,7 @@ static void mgslpc_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
mgslpc_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock, flags);
info->serial_signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1762,7 +1762,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
mgslpc_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock, flags);
info->serial_signals |= SerialSignal_RTS;
set_signals(info);
@@ -2306,8 +2306,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
mgslpc_change_params(info, tty);
/* Handle transition to B0 status */
- if (old_termios->c_cflag & CBAUD &&
- !(tty->termios.c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
spin_lock_irqsave(&info->lock, flags);
set_signals(info);
@@ -2315,21 +2314,17 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios.c_cflag & CBAUD) {
+ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
info->serial_signals |= SerialSignal_RTS;
- }
spin_lock_irqsave(&info->lock, flags);
set_signals(info);
spin_unlock_irqrestore(&info->lock, flags);
}
/* Handle turning off CRTSCTS */
- if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
tx_release(tty);
}
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index ae0b42b66e55..d23368874710 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -69,12 +69,13 @@
#include <linux/ppdev.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
+#include <linux/compat.h>
#define PP_VERSION "ppdev: user-space parallel port driver"
#define CHRDEV "ppdev"
struct pp_struct {
- struct pardevice * pdev;
+ struct pardevice *pdev;
wait_queue_head_t irq_wait;
atomic_t irqc;
unsigned int flags;
@@ -98,18 +99,26 @@ struct pp_struct {
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
static DEFINE_MUTEX(pp_do_mutex);
-static inline void pp_enable_irq (struct pp_struct *pp)
+
+/* define fixed sized ioctl cmd for y2038 migration */
+#define PPGETTIME32 _IOR(PP_IOCTL, 0x95, s32[2])
+#define PPSETTIME32 _IOW(PP_IOCTL, 0x96, s32[2])
+#define PPGETTIME64 _IOR(PP_IOCTL, 0x95, s64[2])
+#define PPSETTIME64 _IOW(PP_IOCTL, 0x96, s64[2])
+
+static inline void pp_enable_irq(struct pp_struct *pp)
{
struct parport *port = pp->pdev->port;
- port->ops->enable_irq (port);
+
+ port->ops->enable_irq(port);
}
-static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
- loff_t * ppos)
+static ssize_t pp_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
{
unsigned int minor = iminor(file_inode(file));
struct pp_struct *pp = file->private_data;
- char * kbuffer;
+ char *kbuffer;
ssize_t bytes_read = 0;
struct parport *pport;
int mode;
@@ -125,16 +134,15 @@ static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
return 0;
kbuffer = kmalloc(min_t(size_t, count, PP_BUFFER_SIZE), GFP_KERNEL);
- if (!kbuffer) {
+ if (!kbuffer)
return -ENOMEM;
- }
pport = pp->pdev->port;
mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
- parport_set_timeout (pp->pdev,
- (file->f_flags & O_NONBLOCK) ?
- PARPORT_INACTIVITY_O_NONBLOCK :
- pp->default_inactivity);
+ parport_set_timeout(pp->pdev,
+ (file->f_flags & O_NONBLOCK) ?
+ PARPORT_INACTIVITY_O_NONBLOCK :
+ pp->default_inactivity);
while (bytes_read == 0) {
ssize_t need = min_t(unsigned long, count, PP_BUFFER_SIZE);
@@ -144,20 +152,17 @@ static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
int flags = 0;
size_t (*fn)(struct parport *, void *, size_t, int);
- if (pp->flags & PP_W91284PIC) {
+ if (pp->flags & PP_W91284PIC)
flags |= PARPORT_W91284PIC;
- }
- if (pp->flags & PP_FASTREAD) {
+ if (pp->flags & PP_FASTREAD)
flags |= PARPORT_EPP_FAST;
- }
- if (pport->ieee1284.mode & IEEE1284_ADDR) {
+ if (pport->ieee1284.mode & IEEE1284_ADDR)
fn = pport->ops->epp_read_addr;
- } else {
+ else
fn = pport->ops->epp_read_data;
- }
bytes_read = (*fn)(pport, kbuffer, need, flags);
} else {
- bytes_read = parport_read (pport, kbuffer, need);
+ bytes_read = parport_read(pport, kbuffer, need);
}
if (bytes_read != 0)
@@ -168,7 +173,7 @@ static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
break;
}
- if (signal_pending (current)) {
+ if (signal_pending(current)) {
bytes_read = -ERESTARTSYS;
break;
}
@@ -176,22 +181,22 @@ static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
cond_resched();
}
- parport_set_timeout (pp->pdev, pp->default_inactivity);
+ parport_set_timeout(pp->pdev, pp->default_inactivity);
- if (bytes_read > 0 && copy_to_user (buf, kbuffer, bytes_read))
+ if (bytes_read > 0 && copy_to_user(buf, kbuffer, bytes_read))
bytes_read = -EFAULT;
- kfree (kbuffer);
- pp_enable_irq (pp);
+ kfree(kbuffer);
+ pp_enable_irq(pp);
return bytes_read;
}
-static ssize_t pp_write (struct file * file, const char __user * buf,
- size_t count, loff_t * ppos)
+static ssize_t pp_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
{
unsigned int minor = iminor(file_inode(file));
struct pp_struct *pp = file->private_data;
- char * kbuffer;
+ char *kbuffer;
ssize_t bytes_written = 0;
ssize_t wrote;
int mode;
@@ -204,21 +209,21 @@ static ssize_t pp_write (struct file * file, const char __user * buf,
}
kbuffer = kmalloc(min_t(size_t, count, PP_BUFFER_SIZE), GFP_KERNEL);
- if (!kbuffer) {
+ if (!kbuffer)
return -ENOMEM;
- }
+
pport = pp->pdev->port;
mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
- parport_set_timeout (pp->pdev,
- (file->f_flags & O_NONBLOCK) ?
- PARPORT_INACTIVITY_O_NONBLOCK :
- pp->default_inactivity);
+ parport_set_timeout(pp->pdev,
+ (file->f_flags & O_NONBLOCK) ?
+ PARPORT_INACTIVITY_O_NONBLOCK :
+ pp->default_inactivity);
while (bytes_written < count) {
ssize_t n = min_t(unsigned long, count - bytes_written, PP_BUFFER_SIZE);
- if (copy_from_user (kbuffer, buf + bytes_written, n)) {
+ if (copy_from_user(kbuffer, buf + bytes_written, n)) {
bytes_written = -EFAULT;
break;
}
@@ -226,20 +231,19 @@ static ssize_t pp_write (struct file * file, const char __user * buf,
if ((pp->flags & PP_FASTWRITE) && (mode == IEEE1284_MODE_EPP)) {
/* do a fast EPP write */
if (pport->ieee1284.mode & IEEE1284_ADDR) {
- wrote = pport->ops->epp_write_addr (pport,
+ wrote = pport->ops->epp_write_addr(pport,
kbuffer, n, PARPORT_EPP_FAST);
} else {
- wrote = pport->ops->epp_write_data (pport,
+ wrote = pport->ops->epp_write_data(pport,
kbuffer, n, PARPORT_EPP_FAST);
}
} else {
- wrote = parport_write (pp->pdev->port, kbuffer, n);
+ wrote = parport_write(pp->pdev->port, kbuffer, n);
}
if (wrote <= 0) {
- if (!bytes_written) {
+ if (!bytes_written)
bytes_written = wrote;
- }
break;
}
@@ -251,67 +255,69 @@ static ssize_t pp_write (struct file * file, const char __user * buf,
break;
}
- if (signal_pending (current))
+ if (signal_pending(current))
break;
cond_resched();
}
- parport_set_timeout (pp->pdev, pp->default_inactivity);
+ parport_set_timeout(pp->pdev, pp->default_inactivity);
- kfree (kbuffer);
- pp_enable_irq (pp);
+ kfree(kbuffer);
+ pp_enable_irq(pp);
return bytes_written;
}
-static void pp_irq (void *private)
+static void pp_irq(void *private)
{
struct pp_struct *pp = private;
if (pp->irqresponse) {
- parport_write_control (pp->pdev->port, pp->irqctl);
+ parport_write_control(pp->pdev->port, pp->irqctl);
pp->irqresponse = 0;
}
- atomic_inc (&pp->irqc);
- wake_up_interruptible (&pp->irq_wait);
+ atomic_inc(&pp->irqc);
+ wake_up_interruptible(&pp->irq_wait);
}
-static int register_device (int minor, struct pp_struct *pp)
+static int register_device(int minor, struct pp_struct *pp)
{
struct parport *port;
- struct pardevice * pdev = NULL;
+ struct pardevice *pdev = NULL;
char *name;
- int fl;
+ struct pardev_cb ppdev_cb;
name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor);
if (name == NULL)
return -ENOMEM;
- port = parport_find_number (minor);
+ port = parport_find_number(minor);
if (!port) {
- printk (KERN_WARNING "%s: no associated port!\n", name);
- kfree (name);
+ printk(KERN_WARNING "%s: no associated port!\n", name);
+ kfree(name);
return -ENXIO;
}
- fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
- pdev = parport_register_device (port, name, NULL,
- NULL, pp_irq, fl, pp);
- parport_put_port (port);
+ memset(&ppdev_cb, 0, sizeof(ppdev_cb));
+ ppdev_cb.irq_func = pp_irq;
+ ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+ ppdev_cb.private = pp;
+ pdev = parport_register_dev_model(port, name, &ppdev_cb, minor);
+ parport_put_port(port);
if (!pdev) {
- printk (KERN_WARNING "%s: failed to register device!\n", name);
- kfree (name);
+ printk(KERN_WARNING "%s: failed to register device!\n", name);
+ kfree(name);
return -ENXIO;
}
pp->pdev = pdev;
- pr_debug("%s: registered pardevice\n", name);
+ dev_dbg(&pdev->dev, "registered pardevice\n");
return 0;
}
-static enum ieee1284_phase init_phase (int mode)
+static enum ieee1284_phase init_phase(int mode)
{
switch (mode & ~(IEEE1284_DEVICEID
| IEEE1284_ADDR)) {
@@ -322,11 +328,27 @@ static enum ieee1284_phase init_phase (int mode)
return IEEE1284_PH_FWD_IDLE;
}
+static int pp_set_timeout(struct pardevice *pdev, long tv_sec, int tv_usec)
+{
+ long to_jiffies;
+
+ if ((tv_sec < 0) || (tv_usec < 0))
+ return -EINVAL;
+
+ to_jiffies = usecs_to_jiffies(tv_usec);
+ to_jiffies += tv_sec * HZ;
+ if (to_jiffies <= 0)
+ return -EINVAL;
+
+ pdev->timeout = to_jiffies;
+ return 0;
+}
+
static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned int minor = iminor(file_inode(file));
struct pp_struct *pp = file->private_data;
- struct parport * port;
+ struct parport *port;
void __user *argp = (void __user *)arg;
/* First handle the cases that don't take arguments. */
@@ -337,19 +359,19 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int ret;
if (pp->flags & PP_CLAIMED) {
- pr_debug(CHRDEV "%x: you've already got it!\n", minor);
+ dev_dbg(&pp->pdev->dev, "you've already got it!\n");
return -EINVAL;
}
/* Deferred device registration. */
if (!pp->pdev) {
- int err = register_device (minor, pp);
- if (err) {
+ int err = register_device(minor, pp);
+
+ if (err)
return err;
- }
}
- ret = parport_claim_or_block (pp->pdev);
+ ret = parport_claim_or_block(pp->pdev);
if (ret < 0)
return ret;
@@ -357,7 +379,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
/* For interrupt-reporting to work, we need to be
* informed of each interrupt. */
- pp_enable_irq (pp);
+ pp_enable_irq(pp);
/* We may need to fix up the state machine. */
info = &pp->pdev->port->ieee1284;
@@ -365,15 +387,15 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
pp->saved_state.phase = info->phase;
info->mode = pp->state.mode;
info->phase = pp->state.phase;
- pp->default_inactivity = parport_set_timeout (pp->pdev, 0);
- parport_set_timeout (pp->pdev, pp->default_inactivity);
+ pp->default_inactivity = parport_set_timeout(pp->pdev, 0);
+ parport_set_timeout(pp->pdev, pp->default_inactivity);
return 0;
}
case PPEXCL:
if (pp->pdev) {
- pr_debug(CHRDEV "%x: too late for PPEXCL; "
- "already registered\n", minor);
+ dev_dbg(&pp->pdev->dev,
+ "too late for PPEXCL; already registered\n");
if (pp->flags & PP_EXCL)
/* But it's not really an error. */
return 0;
@@ -388,11 +410,12 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PPSETMODE:
{
int mode;
- if (copy_from_user (&mode, argp, sizeof (mode)))
+
+ if (copy_from_user(&mode, argp, sizeof(mode)))
return -EFAULT;
/* FIXME: validate mode */
pp->state.mode = mode;
- pp->state.phase = init_phase (mode);
+ pp->state.phase = init_phase(mode);
if (pp->flags & PP_CLAIMED) {
pp->pdev->port->ieee1284.mode = mode;
@@ -405,28 +428,27 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int mode;
- if (pp->flags & PP_CLAIMED) {
+ if (pp->flags & PP_CLAIMED)
mode = pp->pdev->port->ieee1284.mode;
- } else {
+ else
mode = pp->state.mode;
- }
- if (copy_to_user (argp, &mode, sizeof (mode))) {
+
+ if (copy_to_user(argp, &mode, sizeof(mode)))
return -EFAULT;
- }
return 0;
}
case PPSETPHASE:
{
int phase;
- if (copy_from_user (&phase, argp, sizeof (phase))) {
+
+ if (copy_from_user(&phase, argp, sizeof(phase)))
return -EFAULT;
- }
+
/* FIXME: validate phase */
pp->state.phase = phase;
- if (pp->flags & PP_CLAIMED) {
+ if (pp->flags & PP_CLAIMED)
pp->pdev->port->ieee1284.phase = phase;
- }
return 0;
}
@@ -434,38 +456,34 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int phase;
- if (pp->flags & PP_CLAIMED) {
+ if (pp->flags & PP_CLAIMED)
phase = pp->pdev->port->ieee1284.phase;
- } else {
+ else
phase = pp->state.phase;
- }
- if (copy_to_user (argp, &phase, sizeof (phase))) {
+ if (copy_to_user(argp, &phase, sizeof(phase)))
return -EFAULT;
- }
return 0;
}
case PPGETMODES:
{
unsigned int modes;
- port = parport_find_number (minor);
+ port = parport_find_number(minor);
if (!port)
return -ENODEV;
modes = port->modes;
parport_put_port(port);
- if (copy_to_user (argp, &modes, sizeof (modes))) {
+ if (copy_to_user(argp, &modes, sizeof(modes)))
return -EFAULT;
- }
return 0;
}
case PPSETFLAGS:
{
int uflags;
- if (copy_from_user (&uflags, argp, sizeof (uflags))) {
+ if (copy_from_user(&uflags, argp, sizeof(uflags)))
return -EFAULT;
- }
pp->flags &= ~PP_FLAGMASK;
pp->flags |= (uflags & PP_FLAGMASK);
return 0;
@@ -475,9 +493,8 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int uflags;
uflags = pp->flags & PP_FLAGMASK;
- if (copy_to_user (argp, &uflags, sizeof (uflags))) {
+ if (copy_to_user(argp, &uflags, sizeof(uflags)))
return -EFAULT;
- }
return 0;
}
} /* end switch() */
@@ -495,27 +512,28 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned char reg;
unsigned char mask;
int mode;
+ s32 time32[2];
+ s64 time64[2];
+ struct timespec64 ts;
int ret;
- struct timeval par_timeout;
- long to_jiffies;
case PPRSTATUS:
- reg = parport_read_status (port);
- if (copy_to_user (argp, &reg, sizeof (reg)))
+ reg = parport_read_status(port);
+ if (copy_to_user(argp, &reg, sizeof(reg)))
return -EFAULT;
return 0;
case PPRDATA:
- reg = parport_read_data (port);
- if (copy_to_user (argp, &reg, sizeof (reg)))
+ reg = parport_read_data(port);
+ if (copy_to_user(argp, &reg, sizeof(reg)))
return -EFAULT;
return 0;
case PPRCONTROL:
- reg = parport_read_control (port);
- if (copy_to_user (argp, &reg, sizeof (reg)))
+ reg = parport_read_control(port);
+ if (copy_to_user(argp, &reg, sizeof(reg)))
return -EFAULT;
return 0;
case PPYIELD:
- parport_yield_blocking (pp->pdev);
+ parport_yield_blocking(pp->pdev);
return 0;
case PPRELEASE:
@@ -525,45 +543,45 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
pp->state.phase = info->phase;
info->mode = pp->saved_state.mode;
info->phase = pp->saved_state.phase;
- parport_release (pp->pdev);
+ parport_release(pp->pdev);
pp->flags &= ~PP_CLAIMED;
return 0;
case PPWCONTROL:
- if (copy_from_user (&reg, argp, sizeof (reg)))
+ if (copy_from_user(&reg, argp, sizeof(reg)))
return -EFAULT;
- parport_write_control (port, reg);
+ parport_write_control(port, reg);
return 0;
case PPWDATA:
- if (copy_from_user (&reg, argp, sizeof (reg)))
+ if (copy_from_user(&reg, argp, sizeof(reg)))
return -EFAULT;
- parport_write_data (port, reg);
+ parport_write_data(port, reg);
return 0;
case PPFCONTROL:
- if (copy_from_user (&mask, argp,
- sizeof (mask)))
+ if (copy_from_user(&mask, argp,
+ sizeof(mask)))
return -EFAULT;
- if (copy_from_user (&reg, 1 + (unsigned char __user *) arg,
- sizeof (reg)))
+ if (copy_from_user(&reg, 1 + (unsigned char __user *) arg,
+ sizeof(reg)))
return -EFAULT;
- parport_frob_control (port, mask, reg);
+ parport_frob_control(port, mask, reg);
return 0;
case PPDATADIR:
- if (copy_from_user (&mode, argp, sizeof (mode)))
+ if (copy_from_user(&mode, argp, sizeof(mode)))
return -EFAULT;
if (mode)
- port->ops->data_reverse (port);
+ port->ops->data_reverse(port);
else
- port->ops->data_forward (port);
+ port->ops->data_forward(port);
return 0;
case PPNEGOT:
- if (copy_from_user (&mode, argp, sizeof (mode)))
+ if (copy_from_user(&mode, argp, sizeof(mode)))
return -EFAULT;
- switch ((ret = parport_negotiate (port, mode))) {
+ switch ((ret = parport_negotiate(port, mode))) {
case 0: break;
case -1: /* handshake failed, peripheral not IEEE 1284 */
ret = -EIO;
@@ -572,11 +590,11 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = -ENXIO;
break;
}
- pp_enable_irq (pp);
+ pp_enable_irq(pp);
return ret;
case PPWCTLONIRQ:
- if (copy_from_user (&reg, argp, sizeof (reg)))
+ if (copy_from_user(&reg, argp, sizeof(reg)))
return -EFAULT;
/* Remember what to set the control lines to, for next
@@ -586,39 +604,50 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return 0;
case PPCLRIRQ:
- ret = atomic_read (&pp->irqc);
- if (copy_to_user (argp, &ret, sizeof (ret)))
+ ret = atomic_read(&pp->irqc);
+ if (copy_to_user(argp, &ret, sizeof(ret)))
return -EFAULT;
- atomic_sub (ret, &pp->irqc);
+ atomic_sub(ret, &pp->irqc);
return 0;
- case PPSETTIME:
- if (copy_from_user (&par_timeout, argp, sizeof(struct timeval))) {
+ case PPSETTIME32:
+ if (copy_from_user(time32, argp, sizeof(time32)))
return -EFAULT;
- }
- /* Convert to jiffies, place in pp->pdev->timeout */
- if ((par_timeout.tv_sec < 0) || (par_timeout.tv_usec < 0)) {
- return -EINVAL;
- }
- to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
- to_jiffies += par_timeout.tv_sec * (long)HZ;
- if (to_jiffies <= 0) {
+
+ return pp_set_timeout(pp->pdev, time32[0], time32[1]);
+
+ case PPSETTIME64:
+ if (copy_from_user(time64, argp, sizeof(time64)))
+ return -EFAULT;
+
+ return pp_set_timeout(pp->pdev, time64[0], time64[1]);
+
+ case PPGETTIME32:
+ jiffies_to_timespec64(pp->pdev->timeout, &ts);
+ time32[0] = ts.tv_sec;
+ time32[1] = ts.tv_nsec / NSEC_PER_USEC;
+ if ((time32[0] < 0) || (time32[1] < 0))
return -EINVAL;
- }
- pp->pdev->timeout = to_jiffies;
+
+ if (copy_to_user(argp, time32, sizeof(time32)))
+ return -EFAULT;
+
return 0;
- case PPGETTIME:
- to_jiffies = pp->pdev->timeout;
- memset(&par_timeout, 0, sizeof(par_timeout));
- par_timeout.tv_sec = to_jiffies / HZ;
- par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ);
- if (copy_to_user (argp, &par_timeout, sizeof(struct timeval)))
+ case PPGETTIME64:
+ jiffies_to_timespec64(pp->pdev->timeout, &ts);
+ time64[0] = ts.tv_sec;
+ time64[1] = ts.tv_nsec / NSEC_PER_USEC;
+ if ((time64[0] < 0) || (time64[1] < 0))
+ return -EINVAL;
+
+ if (copy_to_user(argp, time64, sizeof(time64)))
return -EFAULT;
+
return 0;
default:
- pr_debug(CHRDEV "%x: What? (cmd=0x%x)\n", minor, cmd);
+ dev_dbg(&pp->pdev->dev, "What? (cmd=0x%x)\n", cmd);
return -EINVAL;
}
@@ -629,13 +658,22 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static long pp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
+
mutex_lock(&pp_do_mutex);
ret = pp_do_ioctl(file, cmd, arg);
mutex_unlock(&pp_do_mutex);
return ret;
}
-static int pp_open (struct inode * inode, struct file * file)
+#ifdef CONFIG_COMPAT
+static long pp_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return pp_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static int pp_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct pp_struct *pp;
@@ -643,16 +681,16 @@ static int pp_open (struct inode * inode, struct file * file)
if (minor >= PARPORT_MAX)
return -ENXIO;
- pp = kmalloc (sizeof (struct pp_struct), GFP_KERNEL);
+ pp = kmalloc(sizeof(struct pp_struct), GFP_KERNEL);
if (!pp)
return -ENOMEM;
pp->state.mode = IEEE1284_MODE_COMPAT;
- pp->state.phase = init_phase (pp->state.mode);
+ pp->state.phase = init_phase(pp->state.mode);
pp->flags = 0;
pp->irqresponse = 0;
- atomic_set (&pp->irqc, 0);
- init_waitqueue_head (&pp->irq_wait);
+ atomic_set(&pp->irqc, 0);
+ init_waitqueue_head(&pp->irq_wait);
/* Defer the actual device registration until the first claim.
* That way, we know whether or not the driver wants to have
@@ -664,7 +702,7 @@ static int pp_open (struct inode * inode, struct file * file)
return 0;
}
-static int pp_release (struct inode * inode, struct file * file)
+static int pp_release(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct pp_struct *pp = file->private_data;
@@ -673,10 +711,10 @@ static int pp_release (struct inode * inode, struct file * file)
compat_negot = 0;
if (!(pp->flags & PP_CLAIMED) && pp->pdev &&
(pp->state.mode != IEEE1284_MODE_COMPAT)) {
- struct ieee1284_info *info;
+ struct ieee1284_info *info;
/* parport released, but not in compatibility mode */
- parport_claim_or_block (pp->pdev);
+ parport_claim_or_block(pp->pdev);
pp->flags |= PP_CLAIMED;
info = &pp->pdev->port->ieee1284;
pp->saved_state.mode = info->mode;
@@ -689,9 +727,9 @@ static int pp_release (struct inode * inode, struct file * file)
compat_negot = 2;
}
if (compat_negot) {
- parport_negotiate (pp->pdev->port, IEEE1284_MODE_COMPAT);
- pr_debug(CHRDEV "%x: negotiated back to compatibility "
- "mode because user-space forgot\n", minor);
+ parport_negotiate(pp->pdev->port, IEEE1284_MODE_COMPAT);
+ dev_dbg(&pp->pdev->dev,
+ "negotiated back to compatibility mode because user-space forgot\n");
}
if (pp->flags & PP_CLAIMED) {
@@ -702,7 +740,7 @@ static int pp_release (struct inode * inode, struct file * file)
pp->state.phase = info->phase;
info->mode = pp->saved_state.mode;
info->phase = pp->saved_state.phase;
- parport_release (pp->pdev);
+ parport_release(pp->pdev);
if (compat_negot != 1) {
pr_debug(CHRDEV "%x: released pardevice "
"because user-space forgot\n", minor);
@@ -711,25 +749,26 @@ static int pp_release (struct inode * inode, struct file * file)
if (pp->pdev) {
const char *name = pp->pdev->name;
- parport_unregister_device (pp->pdev);
- kfree (name);
+
+ parport_unregister_device(pp->pdev);
+ kfree(name);
pp->pdev = NULL;
pr_debug(CHRDEV "%x: unregistered pardevice\n", minor);
}
- kfree (pp);
+ kfree(pp);
return 0;
}
/* No kernel lock held - fine */
-static unsigned int pp_poll (struct file * file, poll_table * wait)
+static unsigned int pp_poll(struct file *file, poll_table *wait)
{
struct pp_struct *pp = file->private_data;
unsigned int mask = 0;
- poll_wait (file, &pp->irq_wait, wait);
- if (atomic_read (&pp->irqc))
+ poll_wait(file, &pp->irq_wait, wait);
+ if (atomic_read(&pp->irqc))
mask |= POLLIN | POLLRDNORM;
return mask;
@@ -744,6 +783,9 @@ static const struct file_operations pp_fops = {
.write = pp_write,
.poll = pp_poll,
.unlocked_ioctl = pp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = pp_compat_ioctl,
+#endif
.open = pp_open,
.release = pp_release,
};
@@ -759,19 +801,32 @@ static void pp_detach(struct parport *port)
device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number));
}
+static int pp_probe(struct pardevice *par_dev)
+{
+ struct device_driver *drv = par_dev->dev.driver;
+ int len = strlen(drv->name);
+
+ if (strncmp(par_dev->name, drv->name, len))
+ return -ENODEV;
+
+ return 0;
+}
+
static struct parport_driver pp_driver = {
.name = CHRDEV,
- .attach = pp_attach,
+ .probe = pp_probe,
+ .match_port = pp_attach,
.detach = pp_detach,
+ .devmodel = true,
};
-static int __init ppdev_init (void)
+static int __init ppdev_init(void)
{
int err = 0;
- if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
- printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
- PP_MAJOR);
+ if (register_chrdev(PP_MAJOR, CHRDEV, &pp_fops)) {
+ printk(KERN_WARNING CHRDEV ": unable to get major %d\n",
+ PP_MAJOR);
return -EIO;
}
ppdev_class = class_create(THIS_MODULE, CHRDEV);
@@ -781,11 +836,11 @@ static int __init ppdev_init (void)
}
err = parport_register_driver(&pp_driver);
if (err < 0) {
- printk (KERN_WARNING CHRDEV ": unable to register with parport\n");
+ printk(KERN_WARNING CHRDEV ": unable to register with parport\n");
goto out_class;
}
- printk (KERN_INFO PP_VERSION "\n");
+ printk(KERN_INFO PP_VERSION "\n");
goto out;
out_class:
@@ -796,12 +851,12 @@ out:
return err;
}
-static void __exit ppdev_cleanup (void)
+static void __exit ppdev_cleanup(void)
{
/* Clean up all parport stuff */
parport_unregister_driver(&pp_driver);
class_destroy(ppdev_class);
- unregister_chrdev (PP_MAJOR, CHRDEV);
+ unregister_chrdev(PP_MAJOR, CHRDEV);
}
module_init(ppdev_init);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index d0da5d852d41..b583e5336630 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1819,6 +1819,28 @@ unsigned int get_random_int(void)
EXPORT_SYMBOL(get_random_int);
/*
+ * Same as get_random_int(), but returns unsigned long.
+ */
+unsigned long get_random_long(void)
+{
+ __u32 *hash;
+ unsigned long ret;
+
+ if (arch_get_random_long(&ret))
+ return ret;
+
+ hash = get_cpu_var(get_random_int_hash);
+
+ hash[0] += current->pid + jiffies + random_get_entropy();
+ md5_transform(hash, random_int_secret);
+ ret = *(unsigned long *)hash;
+ put_cpu_var(get_random_int_hash);
+
+ return ret;
+}
+EXPORT_SYMBOL(get_random_long);
+
+/*
* randomize_range() returns a start address such that
*
* [...... <range> .....]
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 9b9809b709a5..e83b2adc014a 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -334,10 +334,8 @@ static int __init raw_init(void)
cdev_init(&raw_cdev, &raw_fops);
ret = cdev_add(&raw_cdev, dev, max_raw_minors);
- if (ret) {
+ if (ret)
goto error_region;
- }
-
raw_class = class_create(THIS_MODULE, "raw");
if (IS_ERR(raw_class)) {
printk(KERN_ERR "Error creating raw class.\n");
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 45cc39aabeee..274dd0123237 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -88,6 +88,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
const struct tpm_class_ops *ops)
{
struct tpm_chip *chip;
+ int rc;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
@@ -136,11 +137,17 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
chip->cdev.owner = chip->pdev->driver->owner;
chip->cdev.kobj.parent = &chip->dev.kobj;
+ rc = devm_add_action(dev, (void (*)(void *)) put_device, &chip->dev);
+ if (rc) {
+ put_device(&chip->dev);
+ return ERR_PTR(rc);
+ }
+
return chip;
}
EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
-static int tpm_dev_add_device(struct tpm_chip *chip)
+static int tpm_add_char_device(struct tpm_chip *chip)
{
int rc;
@@ -151,7 +158,6 @@ static int tpm_dev_add_device(struct tpm_chip *chip)
chip->devname, MAJOR(chip->dev.devt),
MINOR(chip->dev.devt), rc);
- device_unregister(&chip->dev);
return rc;
}
@@ -162,16 +168,17 @@ static int tpm_dev_add_device(struct tpm_chip *chip)
chip->devname, MAJOR(chip->dev.devt),
MINOR(chip->dev.devt), rc);
+ cdev_del(&chip->cdev);
return rc;
}
return rc;
}
-static void tpm_dev_del_device(struct tpm_chip *chip)
+static void tpm_del_char_device(struct tpm_chip *chip)
{
cdev_del(&chip->cdev);
- device_unregister(&chip->dev);
+ device_del(&chip->dev);
}
static int tpm1_chip_register(struct tpm_chip *chip)
@@ -222,7 +229,7 @@ int tpm_chip_register(struct tpm_chip *chip)
tpm_add_ppi(chip);
- rc = tpm_dev_add_device(chip);
+ rc = tpm_add_char_device(chip);
if (rc)
goto out_err;
@@ -274,6 +281,6 @@ void tpm_chip_unregister(struct tpm_chip *chip)
sysfs_remove_link(&chip->pdev->kobj, "ppi");
tpm1_chip_unregister(chip);
- tpm_dev_del_device(chip);
+ tpm_del_char_device(chip);
}
EXPORT_SYMBOL_GPL(tpm_chip_unregister);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 542a80cbfd9c..28b477e8da6a 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -128,13 +128,6 @@ enum tpm2_startup_types {
TPM2_SU_STATE = 0x0001,
};
-enum tpm2_start_method {
- TPM2_START_ACPI = 2,
- TPM2_START_FIFO = 6,
- TPM2_START_CRB = 7,
- TPM2_START_CRB_WITH_ACPI = 8,
-};
-
struct tpm_chip;
struct tpm_vendor_specific {
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 45a634016f95..b28e4da3d2cf 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -20,7 +20,11 @@
#include <keys/trusted-type.h>
enum tpm2_object_attributes {
- TPM2_ATTR_USER_WITH_AUTH = BIT(6),
+ TPM2_OA_USER_WITH_AUTH = BIT(6),
+};
+
+enum tpm2_session_attributes {
+ TPM2_SA_CONTINUE_SESSION = BIT(0),
};
struct tpm2_startup_in {
@@ -478,22 +482,18 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
tpm_buf_append_u8(&buf, payload->migratable);
/* public */
- if (options->policydigest)
- tpm_buf_append_u16(&buf, 14 + options->digest_len);
- else
- tpm_buf_append_u16(&buf, 14);
-
+ tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
tpm_buf_append_u16(&buf, hash);
/* policy */
- if (options->policydigest) {
+ if (options->policydigest_len) {
tpm_buf_append_u32(&buf, 0);
- tpm_buf_append_u16(&buf, options->digest_len);
+ tpm_buf_append_u16(&buf, options->policydigest_len);
tpm_buf_append(&buf, options->policydigest,
- options->digest_len);
+ options->policydigest_len);
} else {
- tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
+ tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH);
tpm_buf_append_u16(&buf, 0);
}
@@ -631,7 +631,7 @@ static int tpm2_unseal(struct tpm_chip *chip,
options->policyhandle ?
options->policyhandle : TPM2_RS_PW,
NULL /* nonce */, 0,
- 0 /* session_attributes */,
+ TPM2_SA_CONTINUE_SESSION,
options->blobauth /* hmac */,
TPM_DIGEST_SIZE);
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 8342cf51ffdc..a12b31940344 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -34,14 +34,6 @@ enum crb_defaults {
CRB_ACPI_START_INDEX = 1,
};
-struct acpi_tpm2 {
- struct acpi_table_header hdr;
- u16 platform_class;
- u16 reserved;
- u64 control_area_pa;
- u32 start_method;
-} __packed;
-
enum crb_ca_request {
CRB_CA_REQ_GO_IDLE = BIT(0),
CRB_CA_REQ_CMD_READY = BIT(1),
@@ -85,6 +77,8 @@ enum crb_flags {
struct crb_priv {
unsigned int flags;
+ struct resource res;
+ void __iomem *iobase;
struct crb_control_area __iomem *cca;
u8 __iomem *cmd;
u8 __iomem *rsp;
@@ -97,7 +91,7 @@ static u8 crb_status(struct tpm_chip *chip)
struct crb_priv *priv = chip->vendor.priv;
u8 sts = 0;
- if ((le32_to_cpu(ioread32(&priv->cca->start)) & CRB_START_INVOKE) !=
+ if ((ioread32(&priv->cca->start) & CRB_START_INVOKE) !=
CRB_START_INVOKE)
sts |= CRB_STS_COMPLETE;
@@ -113,7 +107,7 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
if (count < 6)
return -EIO;
- if (le32_to_cpu(ioread32(&priv->cca->sts)) & CRB_CA_STS_ERROR)
+ if (ioread32(&priv->cca->sts) & CRB_CA_STS_ERROR)
return -EIO;
memcpy_fromio(buf, priv->rsp, 6);
@@ -149,11 +143,11 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
struct crb_priv *priv = chip->vendor.priv;
int rc = 0;
- if (len > le32_to_cpu(ioread32(&priv->cca->cmd_size))) {
+ if (len > ioread32(&priv->cca->cmd_size)) {
dev_err(&chip->dev,
"invalid command count value %x %zx\n",
(unsigned int) len,
- (size_t) le32_to_cpu(ioread32(&priv->cca->cmd_size)));
+ (size_t) ioread32(&priv->cca->cmd_size));
return -E2BIG;
}
@@ -189,7 +183,7 @@ static void crb_cancel(struct tpm_chip *chip)
static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
{
struct crb_priv *priv = chip->vendor.priv;
- u32 cancel = le32_to_cpu(ioread32(&priv->cca->cancel));
+ u32 cancel = ioread32(&priv->cca->cancel);
return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE;
}
@@ -204,97 +198,145 @@ static const struct tpm_class_ops tpm_crb = {
.req_complete_val = CRB_STS_COMPLETE,
};
-static int crb_acpi_add(struct acpi_device *device)
+static int crb_init(struct acpi_device *device, struct crb_priv *priv)
{
struct tpm_chip *chip;
- struct acpi_tpm2 *buf;
+ int rc;
+
+ chip = tpmm_chip_alloc(&device->dev, &tpm_crb);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ chip->vendor.priv = priv;
+ chip->acpi_dev_handle = device->handle;
+ chip->flags = TPM_CHIP_FLAG_TPM2;
+
+ rc = tpm_get_timeouts(chip);
+ if (rc)
+ return rc;
+
+ rc = tpm2_do_selftest(chip);
+ if (rc)
+ return rc;
+
+ return tpm_chip_register(chip);
+}
+
+static int crb_check_resource(struct acpi_resource *ares, void *data)
+{
+ struct crb_priv *priv = data;
+ struct resource res;
+
+ if (acpi_dev_resource_memory(ares, &res)) {
+ priv->res = res;
+ priv->res.name = NULL;
+ }
+
+ return 1;
+}
+
+static void __iomem *crb_map_res(struct device *dev, struct crb_priv *priv,
+ u64 start, u32 size)
+{
+ struct resource new_res = {
+ .start = start,
+ .end = start + size - 1,
+ .flags = IORESOURCE_MEM,
+ };
+
+ /* Detect a 64 bit address on a 32 bit system */
+ if (start != new_res.start)
+ return ERR_PTR(-EINVAL);
+
+ if (!resource_contains(&priv->res, &new_res))
+ return devm_ioremap_resource(dev, &new_res);
+
+ return priv->iobase + (new_res.start - priv->res.start);
+}
+
+static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
+ struct acpi_table_tpm2 *buf)
+{
+ struct list_head resources;
+ struct device *dev = &device->dev;
+ u64 pa;
+ int ret;
+
+ INIT_LIST_HEAD(&resources);
+ ret = acpi_dev_get_resources(device, &resources, crb_check_resource,
+ priv);
+ if (ret < 0)
+ return ret;
+ acpi_dev_free_resource_list(&resources);
+
+ if (resource_type(&priv->res) != IORESOURCE_MEM) {
+ dev_err(dev,
+ FW_BUG "TPM2 ACPI table does not define a memory resource\n");
+ return -EINVAL;
+ }
+
+ priv->iobase = devm_ioremap_resource(dev, &priv->res);
+ if (IS_ERR(priv->iobase))
+ return PTR_ERR(priv->iobase);
+
+ priv->cca = crb_map_res(dev, priv, buf->control_address, 0x1000);
+ if (IS_ERR(priv->cca))
+ return PTR_ERR(priv->cca);
+
+ pa = ((u64) ioread32(&priv->cca->cmd_pa_high) << 32) |
+ (u64) ioread32(&priv->cca->cmd_pa_low);
+ priv->cmd = crb_map_res(dev, priv, pa, ioread32(&priv->cca->cmd_size));
+ if (IS_ERR(priv->cmd))
+ return PTR_ERR(priv->cmd);
+
+ memcpy_fromio(&pa, &priv->cca->rsp_pa, 8);
+ pa = le64_to_cpu(pa);
+ priv->rsp = crb_map_res(dev, priv, pa, ioread32(&priv->cca->rsp_size));
+ return PTR_ERR_OR_ZERO(priv->rsp);
+}
+
+static int crb_acpi_add(struct acpi_device *device)
+{
+ struct acpi_table_tpm2 *buf;
struct crb_priv *priv;
struct device *dev = &device->dev;
acpi_status status;
u32 sm;
- u64 pa;
int rc;
status = acpi_get_table(ACPI_SIG_TPM2, 1,
(struct acpi_table_header **) &buf);
- if (ACPI_FAILURE(status)) {
- dev_err(dev, "failed to get TPM2 ACPI table\n");
- return -ENODEV;
+ if (ACPI_FAILURE(status) || buf->header.length < sizeof(*buf)) {
+ dev_err(dev, FW_BUG "failed to get TPM2 ACPI table\n");
+ return -EINVAL;
}
/* Should the FIFO driver handle this? */
- if (buf->start_method == TPM2_START_FIFO)
+ sm = buf->start_method;
+ if (sm == ACPI_TPM2_MEMORY_MAPPED)
return -ENODEV;
- chip = tpmm_chip_alloc(dev, &tpm_crb);
- if (IS_ERR(chip))
- return PTR_ERR(chip);
-
- chip->flags = TPM_CHIP_FLAG_TPM2;
-
- if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
- dev_err(dev, "TPM2 ACPI table has wrong size");
- return -EINVAL;
- }
-
- priv = (struct crb_priv *) devm_kzalloc(dev, sizeof(struct crb_priv),
- GFP_KERNEL);
- if (!priv) {
- dev_err(dev, "failed to devm_kzalloc for private data\n");
+ priv = devm_kzalloc(dev, sizeof(struct crb_priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- }
-
- sm = le32_to_cpu(buf->start_method);
/* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
* report only ACPI start but in practice seems to require both
* ACPI start and CRB start.
*/
- if (sm == TPM2_START_CRB || sm == TPM2_START_FIFO ||
+ if (sm == ACPI_TPM2_COMMAND_BUFFER || sm == ACPI_TPM2_MEMORY_MAPPED ||
!strcmp(acpi_device_hid(device), "MSFT0101"))
priv->flags |= CRB_FL_CRB_START;
- if (sm == TPM2_START_ACPI || sm == TPM2_START_CRB_WITH_ACPI)
+ if (sm == ACPI_TPM2_START_METHOD ||
+ sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)
priv->flags |= CRB_FL_ACPI_START;
- priv->cca = (struct crb_control_area __iomem *)
- devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
- if (!priv->cca) {
- dev_err(dev, "ioremap of the control area failed\n");
- return -ENOMEM;
- }
-
- pa = ((u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_high)) << 32) |
- (u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_low));
- priv->cmd = devm_ioremap_nocache(dev, pa,
- ioread32(&priv->cca->cmd_size));
- if (!priv->cmd) {
- dev_err(dev, "ioremap of the command buffer failed\n");
- return -ENOMEM;
- }
-
- memcpy_fromio(&pa, &priv->cca->rsp_pa, 8);
- pa = le64_to_cpu(pa);
- priv->rsp = devm_ioremap_nocache(dev, pa,
- ioread32(&priv->cca->rsp_size));
- if (!priv->rsp) {
- dev_err(dev, "ioremap of the response buffer failed\n");
- return -ENOMEM;
- }
-
- chip->vendor.priv = priv;
-
- rc = tpm_get_timeouts(chip);
+ rc = crb_map_io(device, priv, buf);
if (rc)
return rc;
- chip->acpi_dev_handle = device->handle;
-
- rc = tpm2_do_selftest(chip);
- if (rc)
- return rc;
-
- return tpm_chip_register(chip);
+ return crb_init(device, priv);
}
static int crb_acpi_remove(struct acpi_device *device)
@@ -302,11 +344,11 @@ static int crb_acpi_remove(struct acpi_device *device)
struct device *dev = &device->dev;
struct tpm_chip *chip = dev_get_drvdata(dev);
- tpm_chip_unregister(chip);
-
if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_shutdown(chip, TPM2_SU_CLEAR);
+ tpm_chip_unregister(chip);
+
return 0;
}
diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c
index bd72fb04225e..4e6940acf639 100644
--- a/drivers/char/tpm/tpm_eventlog.c
+++ b/drivers/char/tpm/tpm_eventlog.c
@@ -232,7 +232,7 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
{
struct tcpa_event *event = v;
struct tcpa_event temp_event;
- char *tempPtr;
+ char *temp_ptr;
int i;
memcpy(&temp_event, event, sizeof(struct tcpa_event));
@@ -242,10 +242,16 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
temp_event.event_type = do_endian_conversion(event->event_type);
temp_event.event_size = do_endian_conversion(event->event_size);
- tempPtr = (char *)&temp_event;
+ temp_ptr = (char *) &temp_event;
- for (i = 0; i < sizeof(struct tcpa_event) + temp_event.event_size; i++)
- seq_putc(m, tempPtr[i]);
+ for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
+ seq_putc(m, temp_ptr[i]);
+
+ temp_ptr = (char *) v;
+
+ for (i = (sizeof(struct tcpa_event) - 1);
+ i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
+ seq_putc(m, temp_ptr[i]);
return 0;
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 8a3509cb10da..a507006728e0 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -28,7 +28,6 @@
#include <linux/wait.h>
#include <linux/acpi.h>
#include <linux/freezer.h>
-#include <acpi/actbl2.h>
#include "tpm.h"
enum tis_access {
@@ -60,22 +59,18 @@ enum tis_int_flags {
};
enum tis_defaults {
- TIS_MEM_BASE = 0xFED40000,
TIS_MEM_LEN = 0x5000,
TIS_SHORT_TIMEOUT = 750, /* ms */
TIS_LONG_TIMEOUT = 2000, /* 2 sec */
};
struct tpm_info {
- unsigned long start;
- unsigned long len;
- unsigned int irq;
-};
-
-static struct tpm_info tis_default_info = {
- .start = TIS_MEM_BASE,
- .len = TIS_MEM_LEN,
- .irq = 0,
+ struct resource res;
+ /* irq > 0 means: use irq $irq;
+ * irq = 0 means: autoprobe for an irq;
+ * irq = -1 means: no irq support
+ */
+ int irq;
};
/* Some timeout values are needed before it is known whether the chip is
@@ -118,39 +113,11 @@ static inline int is_itpm(struct acpi_device *dev)
{
return has_hid(dev, "INTC0102");
}
-
-static inline int is_fifo(struct acpi_device *dev)
-{
- struct acpi_table_tpm2 *tbl;
- acpi_status st;
-
- /* TPM 1.2 FIFO */
- if (!has_hid(dev, "MSFT0101"))
- return 1;
-
- st = acpi_get_table(ACPI_SIG_TPM2, 1,
- (struct acpi_table_header **) &tbl);
- if (ACPI_FAILURE(st)) {
- dev_err(&dev->dev, "failed to get TPM2 ACPI table\n");
- return 0;
- }
-
- if (le32_to_cpu(tbl->start_method) != TPM2_START_FIFO)
- return 0;
-
- /* TPM 2.0 FIFO */
- return 1;
-}
#else
static inline int is_itpm(struct acpi_device *dev)
{
return 0;
}
-
-static inline int is_fifo(struct acpi_device *dev)
-{
- return 1;
-}
#endif
/* Before we attempt to access the TPM we must see that the valid bit is set.
@@ -716,9 +683,9 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
chip->acpi_dev_handle = acpi_dev_handle;
#endif
- chip->vendor.iobase = devm_ioremap(dev, tpm_info->start, tpm_info->len);
- if (!chip->vendor.iobase)
- return -EIO;
+ chip->vendor.iobase = devm_ioremap_resource(dev, &tpm_info->res);
+ if (IS_ERR(chip->vendor.iobase))
+ return PTR_ERR(chip->vendor.iobase);
/* Maximum timeouts */
chip->vendor.timeout_a = TIS_TIMEOUT_A_MAX;
@@ -807,7 +774,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
/* INTERRUPT Setup */
init_waitqueue_head(&chip->vendor.read_queue);
init_waitqueue_head(&chip->vendor.int_queue);
- if (interrupts) {
+ if (interrupts && tpm_info->irq != -1) {
if (tpm_info->irq) {
tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
tpm_info->irq);
@@ -893,29 +860,29 @@ static int tpm_tis_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
-#ifdef CONFIG_PNP
static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
- const struct pnp_device_id *pnp_id)
+ const struct pnp_device_id *pnp_id)
{
- struct tpm_info tpm_info = tis_default_info;
+ struct tpm_info tpm_info = {};
acpi_handle acpi_dev_handle = NULL;
+ struct resource *res;
- tpm_info.start = pnp_mem_start(pnp_dev, 0);
- tpm_info.len = pnp_mem_len(pnp_dev, 0);
+ res = pnp_get_resource(pnp_dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ tpm_info.res = *res;
if (pnp_irq_valid(pnp_dev, 0))
tpm_info.irq = pnp_irq(pnp_dev, 0);
else
- interrupts = false;
+ tpm_info.irq = -1;
-#ifdef CONFIG_ACPI
if (pnp_acpi_device(pnp_dev)) {
if (is_itpm(pnp_acpi_device(pnp_dev)))
itpm = true;
- acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
+ acpi_dev_handle = ACPI_HANDLE(&pnp_dev->dev);
}
-#endif
return tpm_tis_init(&pnp_dev->dev, &tpm_info, acpi_dev_handle);
}
@@ -956,7 +923,6 @@ static struct pnp_driver tis_pnp_driver = {
module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
-#endif
#ifdef CONFIG_ACPI
static int tpm_check_resource(struct acpi_resource *ares, void *data)
@@ -964,11 +930,11 @@ static int tpm_check_resource(struct acpi_resource *ares, void *data)
struct tpm_info *tpm_info = (struct tpm_info *) data;
struct resource res;
- if (acpi_dev_resource_interrupt(ares, 0, &res)) {
+ if (acpi_dev_resource_interrupt(ares, 0, &res))
tpm_info->irq = res.start;
- } else if (acpi_dev_resource_memory(ares, &res)) {
- tpm_info->start = res.start;
- tpm_info->len = resource_size(&res);
+ else if (acpi_dev_resource_memory(ares, &res)) {
+ tpm_info->res = res;
+ tpm_info->res.name = NULL;
}
return 1;
@@ -976,14 +942,25 @@ static int tpm_check_resource(struct acpi_resource *ares, void *data)
static int tpm_tis_acpi_init(struct acpi_device *acpi_dev)
{
+ struct acpi_table_tpm2 *tbl;
+ acpi_status st;
struct list_head resources;
- struct tpm_info tpm_info = tis_default_info;
+ struct tpm_info tpm_info = {};
int ret;
- if (!is_fifo(acpi_dev))
+ st = acpi_get_table(ACPI_SIG_TPM2, 1,
+ (struct acpi_table_header **) &tbl);
+ if (ACPI_FAILURE(st) || tbl->header.length < sizeof(*tbl)) {
+ dev_err(&acpi_dev->dev,
+ FW_BUG "failed to get TPM2 ACPI table\n");
+ return -EINVAL;
+ }
+
+ if (tbl->start_method != ACPI_TPM2_MEMORY_MAPPED)
return -ENODEV;
INIT_LIST_HEAD(&resources);
+ tpm_info.irq = -1;
ret = acpi_dev_get_resources(acpi_dev, &resources, tpm_check_resource,
&tpm_info);
if (ret < 0)
@@ -991,8 +968,11 @@ static int tpm_tis_acpi_init(struct acpi_device *acpi_dev)
acpi_dev_free_resource_list(&resources);
- if (!tpm_info.irq)
- interrupts = false;
+ if (resource_type(&tpm_info.res) != IORESOURCE_MEM) {
+ dev_err(&acpi_dev->dev,
+ FW_BUG "TPM2 ACPI table does not define a memory resource\n");
+ return -EINVAL;
+ }
if (is_itpm(acpi_dev))
itpm = true;
@@ -1031,80 +1011,135 @@ static struct acpi_driver tis_acpi_driver = {
};
#endif
+static struct platform_device *force_pdev;
+
+static int tpm_tis_plat_probe(struct platform_device *pdev)
+{
+ struct tpm_info tpm_info = {};
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no memory resource defined\n");
+ return -ENODEV;
+ }
+ tpm_info.res = *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res) {
+ tpm_info.irq = res->start;
+ } else {
+ if (pdev == force_pdev)
+ tpm_info.irq = -1;
+ else
+ /* When forcing auto probe the IRQ */
+ tpm_info.irq = 0;
+ }
+
+ return tpm_tis_init(&pdev->dev, &tpm_info, NULL);
+}
+
+static int tpm_tis_plat_remove(struct platform_device *pdev)
+{
+ struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
+
+ tpm_chip_unregister(chip);
+ tpm_tis_remove(chip);
+
+ return 0;
+}
+
static struct platform_driver tis_drv = {
+ .probe = tpm_tis_plat_probe,
+ .remove = tpm_tis_plat_remove,
.driver = {
.name = "tpm_tis",
.pm = &tpm_tis_pm,
},
};
-static struct platform_device *pdev;
-
static bool force;
+#ifdef CONFIG_X86
module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
+#endif
+
+static int tpm_tis_force_device(void)
+{
+ struct platform_device *pdev;
+ static const struct resource x86_resources[] = {
+ {
+ .start = 0xFED40000,
+ .end = 0xFED40000 + TIS_MEM_LEN - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ };
+
+ if (!force)
+ return 0;
+
+ /* The driver core will match the name tpm_tis of the device to
+ * the tpm_tis platform driver and complete the setup via
+ * tpm_tis_plat_probe
+ */
+ pdev = platform_device_register_simple("tpm_tis", -1, x86_resources,
+ ARRAY_SIZE(x86_resources));
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+ force_pdev = pdev;
+
+ return 0;
+}
+
static int __init init_tis(void)
{
int rc;
-#ifdef CONFIG_PNP
- if (!force) {
- rc = pnp_register_driver(&tis_pnp_driver);
- if (rc)
- return rc;
- }
-#endif
+
+ rc = tpm_tis_force_device();
+ if (rc)
+ goto err_force;
+
+ rc = platform_driver_register(&tis_drv);
+ if (rc)
+ goto err_platform;
+
#ifdef CONFIG_ACPI
- if (!force) {
- rc = acpi_bus_register_driver(&tis_acpi_driver);
- if (rc) {
-#ifdef CONFIG_PNP
- pnp_unregister_driver(&tis_pnp_driver);
-#endif
- return rc;
- }
- }
+ rc = acpi_bus_register_driver(&tis_acpi_driver);
+ if (rc)
+ goto err_acpi;
#endif
- if (!force)
- return 0;
- rc = platform_driver_register(&tis_drv);
- if (rc < 0)
- return rc;
- pdev = platform_device_register_simple("tpm_tis", -1, NULL, 0);
- if (IS_ERR(pdev)) {
- rc = PTR_ERR(pdev);
- goto err_dev;
+ if (IS_ENABLED(CONFIG_PNP)) {
+ rc = pnp_register_driver(&tis_pnp_driver);
+ if (rc)
+ goto err_pnp;
}
- rc = tpm_tis_init(&pdev->dev, &tis_default_info, NULL);
- if (rc)
- goto err_init;
+
return 0;
-err_init:
- platform_device_unregister(pdev);
-err_dev:
- platform_driver_unregister(&tis_drv);
+
+err_pnp:
+#ifdef CONFIG_ACPI
+ acpi_bus_unregister_driver(&tis_acpi_driver);
+err_acpi:
+#endif
+ platform_device_unregister(force_pdev);
+err_platform:
+ if (force_pdev)
+ platform_device_unregister(force_pdev);
+err_force:
return rc;
}
static void __exit cleanup_tis(void)
{
- struct tpm_chip *chip;
-#if defined(CONFIG_PNP) || defined(CONFIG_ACPI)
- if (!force) {
+ pnp_unregister_driver(&tis_pnp_driver);
#ifdef CONFIG_ACPI
- acpi_bus_unregister_driver(&tis_acpi_driver);
-#endif
-#ifdef CONFIG_PNP
- pnp_unregister_driver(&tis_pnp_driver);
+ acpi_bus_unregister_driver(&tis_acpi_driver);
#endif
- return;
- }
-#endif
- chip = dev_get_drvdata(&pdev->dev);
- tpm_chip_unregister(chip);
- tpm_tis_remove(chip);
- platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
+
+ if (force_pdev)
+ platform_device_unregister(force_pdev);
}
module_init(init_tis);
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index a15ce4ef39cd..b098d2d0b7c4 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -171,7 +171,7 @@ static const struct tty_operations ttyprintk_ops = {
.ioctl = tpk_ioctl,
};
-static struct tty_port_operations null_ops = { };
+static const struct tty_port_operations null_ops = { };
static struct tty_driver *ttyprintk_driver;
diff --git a/drivers/char/xillybus/xillybus_core.c b/drivers/char/xillybus/xillybus_core.c
index 77d6c127e691..dcd19f3f182e 100644
--- a/drivers/char/xillybus/xillybus_core.c
+++ b/drivers/char/xillybus/xillybus_core.c
@@ -509,7 +509,7 @@ static int xilly_setupchannels(struct xilly_endpoint *ep,
channel->log2_element_size = ((format > 2) ?
2 : format);
- bytebufsize = channel->rd_buf_size = bufsize *
+ bytebufsize = bufsize *
(1 << channel->log2_element_size);
buffers = devm_kcalloc(dev, bufnum,
@@ -523,6 +523,7 @@ static int xilly_setupchannels(struct xilly_endpoint *ep,
if (!is_writebuf) {
channel->num_rd_buffers = bufnum;
+ channel->rd_buf_size = bytebufsize;
channel->rd_allow_partial = allowpartial;
channel->rd_synchronous = synchronous;
channel->rd_exclusive_open = exclusive_open;
@@ -533,6 +534,7 @@ static int xilly_setupchannels(struct xilly_endpoint *ep,
bufnum, bytebufsize);
} else if (channelnum > 0) {
channel->num_wr_buffers = bufnum;
+ channel->wr_buf_size = bytebufsize;
channel->seekable = seekable;
channel->wr_supports_nonempty = supports_nonempty;
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index b038e3666058..bae4be6501df 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -43,7 +43,7 @@ obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o
-obj-$(CONFIG_ARCH_TANGOX) += clk-tango4.o
+obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_ARCH_U300) += clk-u300.o
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
index 19fed65587e8..7b09a265d79f 100644
--- a/drivers/clk/clk-gpio.c
+++ b/drivers/clk/clk-gpio.c
@@ -289,7 +289,7 @@ static void __init of_gpio_clk_setup(struct device_node *node,
num_parents = of_clk_get_parent_count(node);
if (num_parents < 0)
- return;
+ num_parents = 0;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c
index cd0f2726f5e0..89e9ca78bb94 100644
--- a/drivers/clk/clk-scpi.c
+++ b/drivers/clk/clk-scpi.c
@@ -299,7 +299,7 @@ static int scpi_clocks_probe(struct platform_device *pdev)
/* Add the virtual cpufreq device */
cpufreq_dev = platform_device_register_simple("scpi-cpufreq",
-1, NULL, 0);
- if (!cpufreq_dev)
+ if (IS_ERR(cpufreq_dev))
pr_warn("unable to register cpufreq device");
return 0;
diff --git a/drivers/clk/mvebu/dove-divider.c b/drivers/clk/mvebu/dove-divider.c
index d5c5bfa35a5a..3e0b52daa35f 100644
--- a/drivers/clk/mvebu/dove-divider.c
+++ b/drivers/clk/mvebu/dove-divider.c
@@ -247,7 +247,7 @@ static struct clk_onecell_data dove_divider_data = {
void __init dove_divider_clk_init(struct device_node *np)
{
- void *base;
+ void __iomem *base;
base = of_iomap(np, 0);
if (WARN_ON(!base))
diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c
index cf73e539e9f6..070037a29ea5 100644
--- a/drivers/clk/qcom/gcc-apq8084.c
+++ b/drivers/clk/qcom/gcc-apq8084.c
@@ -3587,7 +3587,6 @@ static const struct regmap_config gcc_apq8084_regmap_config = {
.val_bits = 32,
.max_register = 0x1fc0,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_apq8084_desc = {
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index b692ae881d6a..dd5402bac620 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -3005,7 +3005,6 @@ static const struct regmap_config gcc_ipq806x_regmap_config = {
.val_bits = 32,
.max_register = 0x3e40,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_ipq806x_desc = {
diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c
index f6a2b14dfec4..ad413036f7c7 100644
--- a/drivers/clk/qcom/gcc-msm8660.c
+++ b/drivers/clk/qcom/gcc-msm8660.c
@@ -2702,7 +2702,6 @@ static const struct regmap_config gcc_msm8660_regmap_config = {
.val_bits = 32,
.max_register = 0x363c,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8660_desc = {
diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c
index e3bf09d7d0ef..8cc9b2868b41 100644
--- a/drivers/clk/qcom/gcc-msm8916.c
+++ b/drivers/clk/qcom/gcc-msm8916.c
@@ -3336,7 +3336,6 @@ static const struct regmap_config gcc_msm8916_regmap_config = {
.val_bits = 32,
.max_register = 0x80000,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8916_desc = {
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c
index f31111e32d44..983dd7dc89a7 100644
--- a/drivers/clk/qcom/gcc-msm8960.c
+++ b/drivers/clk/qcom/gcc-msm8960.c
@@ -3468,7 +3468,6 @@ static const struct regmap_config gcc_msm8960_regmap_config = {
.val_bits = 32,
.max_register = 0x3660,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct regmap_config gcc_apq8064_regmap_config = {
@@ -3477,7 +3476,6 @@ static const struct regmap_config gcc_apq8064_regmap_config = {
.val_bits = 32,
.max_register = 0x3880,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8960_desc = {
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c
index df164d618e34..335952db309b 100644
--- a/drivers/clk/qcom/gcc-msm8974.c
+++ b/drivers/clk/qcom/gcc-msm8974.c
@@ -2680,7 +2680,6 @@ static const struct regmap_config gcc_msm8974_regmap_config = {
.val_bits = 32,
.max_register = 0x1fc0,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8974_desc = {
diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c
index 62e79fadd5f7..db3998e5e2d8 100644
--- a/drivers/clk/qcom/lcc-ipq806x.c
+++ b/drivers/clk/qcom/lcc-ipq806x.c
@@ -419,7 +419,6 @@ static const struct regmap_config lcc_ipq806x_regmap_config = {
.val_bits = 32,
.max_register = 0xfc,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc lcc_ipq806x_desc = {
diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c
index bf95bb0ea1b8..4fcf9d1d233c 100644
--- a/drivers/clk/qcom/lcc-msm8960.c
+++ b/drivers/clk/qcom/lcc-msm8960.c
@@ -524,7 +524,6 @@ static const struct regmap_config lcc_msm8960_regmap_config = {
.val_bits = 32,
.max_register = 0xfc,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc lcc_msm8960_desc = {
diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c
index 1e703fda8a0f..30777f9f1a43 100644
--- a/drivers/clk/qcom/mmcc-apq8084.c
+++ b/drivers/clk/qcom/mmcc-apq8084.c
@@ -3368,7 +3368,6 @@ static const struct regmap_config mmcc_apq8084_regmap_config = {
.val_bits = 32,
.max_register = 0x5104,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc mmcc_apq8084_desc = {
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c
index d73a048d3b9d..00e36192a1de 100644
--- a/drivers/clk/qcom/mmcc-msm8960.c
+++ b/drivers/clk/qcom/mmcc-msm8960.c
@@ -3029,7 +3029,6 @@ static const struct regmap_config mmcc_msm8960_regmap_config = {
.val_bits = 32,
.max_register = 0x334,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct regmap_config mmcc_apq8064_regmap_config = {
@@ -3038,7 +3037,6 @@ static const struct regmap_config mmcc_apq8064_regmap_config = {
.val_bits = 32,
.max_register = 0x350,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc mmcc_msm8960_desc = {
diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c
index bbe28ed93669..9d790bcadf25 100644
--- a/drivers/clk/qcom/mmcc-msm8974.c
+++ b/drivers/clk/qcom/mmcc-msm8974.c
@@ -2594,7 +2594,6 @@ static const struct regmap_config mmcc_msm8974_regmap_config = {
.val_bits = 32,
.max_register = 0x5104,
.fast_io = true,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc mmcc_msm8974_desc = {
diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c
index ebce98033fbb..bc7fbac83ab7 100644
--- a/drivers/clk/rockchip/clk-rk3036.c
+++ b/drivers/clk/rockchip/clk-rk3036.c
@@ -133,7 +133,7 @@ PNAME(mux_spdif_p) = { "spdif_src", "spdif_frac", "xin12m" };
PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" };
PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" };
PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" };
-PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" };
+PNAME(mux_mac_p) = { "mac_pll_src", "rmii_clkin" };
PNAME(mux_dclk_p) = { "dclk_lcdc", "dclk_cru" };
static struct rockchip_pll_clock rk3036_pll_clks[] __initdata = {
@@ -224,16 +224,16 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
RK2928_CLKGATE_CON(2), 2, GFLAGS),
COMPOSITE_NODIV(SCLK_TIMER0, "sclk_timer0", mux_timer_p, CLK_IGNORE_UNUSED,
- RK2928_CLKSEL_CON(2), 4, 1, DFLAGS,
+ RK2928_CLKSEL_CON(2), 4, 1, MFLAGS,
RK2928_CLKGATE_CON(1), 0, GFLAGS),
COMPOSITE_NODIV(SCLK_TIMER1, "sclk_timer1", mux_timer_p, CLK_IGNORE_UNUSED,
- RK2928_CLKSEL_CON(2), 5, 1, DFLAGS,
+ RK2928_CLKSEL_CON(2), 5, 1, MFLAGS,
RK2928_CLKGATE_CON(1), 1, GFLAGS),
COMPOSITE_NODIV(SCLK_TIMER2, "sclk_timer2", mux_timer_p, CLK_IGNORE_UNUSED,
- RK2928_CLKSEL_CON(2), 6, 1, DFLAGS,
+ RK2928_CLKSEL_CON(2), 6, 1, MFLAGS,
RK2928_CLKGATE_CON(2), 4, GFLAGS),
COMPOSITE_NODIV(SCLK_TIMER3, "sclk_timer3", mux_timer_p, CLK_IGNORE_UNUSED,
- RK2928_CLKSEL_CON(2), 7, 1, DFLAGS,
+ RK2928_CLKSEL_CON(2), 7, 1, MFLAGS,
RK2928_CLKGATE_CON(2), 5, GFLAGS),
MUX(0, "uart_pll_clk", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
@@ -242,11 +242,11 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 8, GFLAGS),
COMPOSITE_NOMUX(0, "uart1_src", "uart_pll_clk", 0,
- RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
- RK2928_CLKGATE_CON(1), 8, GFLAGS),
+ RK2928_CLKSEL_CON(14), 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(1), 10, GFLAGS),
COMPOSITE_NOMUX(0, "uart2_src", "uart_pll_clk", 0,
- RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
- RK2928_CLKGATE_CON(1), 8, GFLAGS),
+ RK2928_CLKSEL_CON(15), 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(1), 12, GFLAGS),
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(17), 0,
RK2928_CLKGATE_CON(1), 9, GFLAGS,
@@ -279,13 +279,13 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
RK2928_CLKGATE_CON(3), 2, GFLAGS),
COMPOSITE_NODIV(0, "sclk_sdmmc_src", mux_mmc_src_p, 0,
- RK2928_CLKSEL_CON(12), 8, 2, DFLAGS,
+ RK2928_CLKSEL_CON(12), 8, 2, MFLAGS,
RK2928_CLKGATE_CON(2), 11, GFLAGS),
DIV(SCLK_SDMMC, "sclk_sdmmc", "sclk_sdmmc_src", 0,
RK2928_CLKSEL_CON(11), 0, 7, DFLAGS),
COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0,
- RK2928_CLKSEL_CON(12), 10, 2, DFLAGS,
+ RK2928_CLKSEL_CON(12), 10, 2, MFLAGS,
RK2928_CLKGATE_CON(2), 13, GFLAGS),
DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
RK2928_CLKSEL_CON(11), 8, 7, DFLAGS),
@@ -344,12 +344,12 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
RK2928_CLKGATE_CON(10), 5, GFLAGS),
COMPOSITE_NOGATE(0, "mac_pll_src", mux_pll_src_3plls_p, 0,
- RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 4, 5, DFLAGS),
+ RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 9, 5, DFLAGS),
MUX(SCLK_MACREF, "mac_clk_ref", mux_mac_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(21), 3, 1, MFLAGS),
COMPOSITE_NOMUX(SCLK_MAC, "mac_clk", "mac_clk_ref", 0,
- RK2928_CLKSEL_CON(21), 9, 5, DFLAGS,
+ RK2928_CLKSEL_CON(21), 4, 5, DFLAGS,
RK2928_CLKGATE_CON(2), 6, GFLAGS),
MUX(SCLK_HDMI, "dclk_hdmi", mux_dclk_p, 0,
diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c
index be0ede522269..21f3ea909fab 100644
--- a/drivers/clk/rockchip/clk-rk3368.c
+++ b/drivers/clk/rockchip/clk-rk3368.c
@@ -780,13 +780,13 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK3368_CLKGATE_CON(20), 0, GFLAGS),
/* pclk_pd_alive gates */
- GATE(PCLK_TIMER1, "pclk_timer1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 8, GFLAGS),
- GATE(PCLK_TIMER0, "pclk_timer0", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 7, GFLAGS),
- GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 12, GFLAGS),
- GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 11, GFLAGS),
- GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 3, GFLAGS),
- GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 2, GFLAGS),
- GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 1, GFLAGS),
+ GATE(PCLK_TIMER1, "pclk_timer1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 13, GFLAGS),
+ GATE(PCLK_TIMER0, "pclk_timer0", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 12, GFLAGS),
+ GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(22), 9, GFLAGS),
+ GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(22), 8, GFLAGS),
+ GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 3, GFLAGS),
+ GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 2, GFLAGS),
+ GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 1, GFLAGS),
/*
* pclk_vio gates
@@ -796,12 +796,12 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
GATE(0, "pclk_dphytx", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 8, GFLAGS),
/* pclk_pd_pmu gates */
- GATE(PCLK_PMUGRF, "pclk_pmugrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 0, GFLAGS),
- GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3368_CLKGATE_CON(17), 4, GFLAGS),
- GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 3, GFLAGS),
- GATE(0, "pclk_pmu_noc", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS),
- GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 1, GFLAGS),
- GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS),
+ GATE(PCLK_PMUGRF, "pclk_pmugrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 5, GFLAGS),
+ GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3368_CLKGATE_CON(23), 4, GFLAGS),
+ GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 3, GFLAGS),
+ GATE(0, "pclk_pmu_noc", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 2, GFLAGS),
+ GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 1, GFLAGS),
+ GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 0, GFLAGS),
/* timer gates */
GATE(0, "sclk_timer15", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 11, GFLAGS),
diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c
index e1fe8f35d45c..74e7544f861b 100644
--- a/drivers/clk/tegra/clk-emc.c
+++ b/drivers/clk/tegra/clk-emc.c
@@ -450,8 +450,10 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra,
struct emc_timing *timing = tegra->timings + (i++);
err = load_one_timing_from_dt(tegra, timing, child);
- if (err)
+ if (err) {
+ of_node_put(child);
return err;
+ }
timing->ram_code = ram_code;
}
@@ -499,9 +501,9 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
* fuses until the apbmisc driver is loaded.
*/
err = load_timings_from_dt(tegra, node, node_ram_code);
+ of_node_put(node);
if (err)
return ERR_PTR(err);
- of_node_put(node);
break;
}
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index 19ce0738ee76..62ea38187b71 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -11,6 +11,7 @@ enum clk_id {
tegra_clk_afi,
tegra_clk_amx,
tegra_clk_amx1,
+ tegra_clk_apb2ape,
tegra_clk_apbdma,
tegra_clk_apbif,
tegra_clk_ape,
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index a534bfab30b3..6ac3f843e7ca 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -86,15 +86,21 @@
#define PLLE_SS_DISABLE (PLLE_SS_CNTL_BYPASS_SS | PLLE_SS_CNTL_INTERP_RESET |\
PLLE_SS_CNTL_SSC_BYP)
#define PLLE_SS_MAX_MASK 0x1ff
-#define PLLE_SS_MAX_VAL 0x25
+#define PLLE_SS_MAX_VAL_TEGRA114 0x25
+#define PLLE_SS_MAX_VAL_TEGRA210 0x21
#define PLLE_SS_INC_MASK (0xff << 16)
#define PLLE_SS_INC_VAL (0x1 << 16)
#define PLLE_SS_INCINTRV_MASK (0x3f << 24)
-#define PLLE_SS_INCINTRV_VAL (0x20 << 24)
+#define PLLE_SS_INCINTRV_VAL_TEGRA114 (0x20 << 24)
+#define PLLE_SS_INCINTRV_VAL_TEGRA210 (0x23 << 24)
#define PLLE_SS_COEFFICIENTS_MASK \
(PLLE_SS_MAX_MASK | PLLE_SS_INC_MASK | PLLE_SS_INCINTRV_MASK)
-#define PLLE_SS_COEFFICIENTS_VAL \
- (PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL)
+#define PLLE_SS_COEFFICIENTS_VAL_TEGRA114 \
+ (PLLE_SS_MAX_VAL_TEGRA114 | PLLE_SS_INC_VAL |\
+ PLLE_SS_INCINTRV_VAL_TEGRA114)
+#define PLLE_SS_COEFFICIENTS_VAL_TEGRA210 \
+ (PLLE_SS_MAX_VAL_TEGRA210 | PLLE_SS_INC_VAL |\
+ PLLE_SS_INCINTRV_VAL_TEGRA210)
#define PLLE_AUX_PLLP_SEL BIT(2)
#define PLLE_AUX_USE_LOCKDET BIT(3)
@@ -880,7 +886,7 @@ static int clk_plle_training(struct tegra_clk_pll *pll)
static int clk_plle_enable(struct clk_hw *hw)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
- unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+ unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
struct tegra_clk_pll_freq_table sel;
u32 val;
int err;
@@ -1378,7 +1384,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
u32 val;
int ret;
unsigned long flags = 0;
- unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+ unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
return -EINVAL;
@@ -1401,7 +1407,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
val |= PLLE_MISC_IDDQ_SW_CTRL;
val &= ~PLLE_MISC_IDDQ_SW_VALUE;
val |= PLLE_MISC_PLLE_PTS;
- val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK;
+ val &= ~(PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK);
pll_writel_misc(val, pll);
udelay(5);
@@ -1428,7 +1434,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
val = pll_readl(PLLE_SS_CTRL, pll);
val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT);
val &= ~PLLE_SS_COEFFICIENTS_MASK;
- val |= PLLE_SS_COEFFICIENTS_VAL;
+ val |= PLLE_SS_COEFFICIENTS_VAL_TEGRA114;
pll_writel(val, PLLE_SS_CTRL, pll);
val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS);
pll_writel(val, PLLE_SS_CTRL, pll);
@@ -2012,9 +2018,9 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw)
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct tegra_clk_pll_freq_table sel;
u32 val;
- int ret;
+ int ret = 0;
unsigned long flags = 0;
- unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+ unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
return -EINVAL;
@@ -2022,22 +2028,20 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw)
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
+ val = pll_readl(pll->params->aux_reg, pll);
+ if (val & PLLE_AUX_SEQ_ENABLE)
+ goto out;
+
val = pll_readl_base(pll);
val &= ~BIT(30); /* Disable lock override */
pll_writel_base(val, pll);
- val = pll_readl(pll->params->aux_reg, pll);
- val |= PLLE_AUX_ENABLE_SWCTL;
- val &= ~PLLE_AUX_SEQ_ENABLE;
- pll_writel(val, pll->params->aux_reg, pll);
- udelay(1);
-
val = pll_readl_misc(pll);
val |= PLLE_MISC_LOCK_ENABLE;
val |= PLLE_MISC_IDDQ_SW_CTRL;
val &= ~PLLE_MISC_IDDQ_SW_VALUE;
val |= PLLE_MISC_PLLE_PTS;
- val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK;
+ val &= ~(PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK);
pll_writel_misc(val, pll);
udelay(5);
@@ -2067,7 +2071,7 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw)
val = pll_readl(PLLE_SS_CTRL, pll);
val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT);
val &= ~PLLE_SS_COEFFICIENTS_MASK;
- val |= PLLE_SS_COEFFICIENTS_VAL;
+ val |= PLLE_SS_COEFFICIENTS_VAL_TEGRA210;
pll_writel(val, PLLE_SS_CTRL, pll);
val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS);
pll_writel(val, PLLE_SS_CTRL, pll);
@@ -2104,15 +2108,25 @@ static void clk_plle_tegra210_disable(struct clk_hw *hw)
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
+ /* If PLLE HW sequencer is enabled, SW should not disable PLLE */
+ val = pll_readl(pll->params->aux_reg, pll);
+ if (val & PLLE_AUX_SEQ_ENABLE)
+ goto out;
+
val = pll_readl_base(pll);
val &= ~PLLE_BASE_ENABLE;
pll_writel_base(val, pll);
+ val = pll_readl(pll->params->aux_reg, pll);
+ val |= PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL;
+ pll_writel(val, pll->params->aux_reg, pll);
+
val = pll_readl_misc(pll);
val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE;
pll_writel_misc(val, pll);
udelay(1);
+out:
if (pll->lock)
spin_unlock_irqrestore(pll->lock, flags);
}
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 6ad381a888a6..ea2b9cbf9e70 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -773,7 +773,7 @@ static struct tegra_periph_init_data periph_clks[] = {
XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src),
XUSB("xusb_dev_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src_8),
MUX8("dbgapb", mux_pllp_clkm_2, CLK_SOURCE_DBGAPB, 185, TEGRA_PERIPH_NO_RESET, tegra_clk_dbgapb),
- MUX8("msenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc),
+ MUX8("nvenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc),
MUX8("nvdec", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVDEC, 194, 0, tegra_clk_nvdec),
MUX8("nvjpg", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVJPG, 195, 0, tegra_clk_nvjpg),
MUX8("ape", mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm, CLK_SOURCE_APE, 198, TEGRA_PERIPH_ON_APB, tegra_clk_ape),
@@ -782,7 +782,7 @@ static struct tegra_periph_init_data periph_clks[] = {
NODIV("sor1", mux_clkm_sor1_brick_sor1_src, CLK_SOURCE_SOR1, 15, MASK(1), 183, 0, tegra_clk_sor1, &sor1_lock),
MUX8("sdmmc_legacy", mux_pllp_out3_clkm_pllp_pllc4, CLK_SOURCE_SDMMC_LEGACY, 193, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_sdmmc_legacy),
MUX8("qspi", mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_QSPI, 211, TEGRA_PERIPH_ON_APB, tegra_clk_qspi),
- MUX("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, TEGRA_PERIPH_ON_APB, tegra_clk_vi_i2c),
+ I2C("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, tegra_clk_vi_i2c),
MUX("mipibif", mux_pllp_clkm, CLK_SOURCE_MIPIBIF, 173, TEGRA_PERIPH_ON_APB, tegra_clk_mipibif),
MUX("uartape", mux_pllp_pllc_clkm, CLK_SOURCE_UARTAPE, 212, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_uartape),
MUX8("tsecb", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_TSECB, 206, 0, tegra_clk_tsecb),
@@ -829,6 +829,7 @@ static struct tegra_periph_init_data gate_clks[] = {
GATE("xusb_gate", "osc", 143, 0, tegra_clk_xusb_gate, 0),
GATE("pll_p_out_cpu", "pll_p", 223, 0, tegra_clk_pll_p_out_cpu, 0),
GATE("pll_p_out_adsp", "pll_p", 187, 0, tegra_clk_pll_p_out_adsp, 0),
+ GATE("apb2ape", "clk_m", 107, 0, tegra_clk_apb2ape, 0),
};
static struct tegra_periph_init_data div_clks[] = {
diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
index 4559a20e3af6..474de0f0c26d 100644
--- a/drivers/clk/tegra/clk-tegra-super-gen4.c
+++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
@@ -67,7 +67,7 @@ static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
"pll_p", "pll_p_out4", "unused",
"unused", "pll_x", "pll_x_out0" };
-const struct tegra_super_gen_info tegra_super_gen_info_gen4 = {
+static const struct tegra_super_gen_info tegra_super_gen_info_gen4 = {
.gen = gen4,
.sclk_parents = sclk_parents,
.cclk_g_parents = cclk_g_parents,
@@ -93,7 +93,7 @@ static const char *cclk_lp_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unu
"unused", "unused", "unused", "unused",
"dfllCPU_out" };
-const struct tegra_super_gen_info tegra_super_gen_info_gen5 = {
+static const struct tegra_super_gen_info tegra_super_gen_info_gen5 = {
.gen = gen5,
.sclk_parents = sclk_parents_gen5,
.cclk_g_parents = cclk_g_parents_gen5,
@@ -171,7 +171,7 @@ static void __init tegra_sclk_init(void __iomem *clk_base,
*dt_clk = clk;
}
-void __init tegra_super_clk_init(void __iomem *clk_base,
+static void __init tegra_super_clk_init(void __iomem *clk_base,
void __iomem *pmc_base,
struct tegra_clk *tegra_clks,
struct tegra_clk_pll_params *params,
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 58514c44ea83..637041fd53ad 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -59,8 +59,8 @@
#define PLLC3_MISC3 0x50c
#define PLLM_BASE 0x90
-#define PLLM_MISC0 0x9c
#define PLLM_MISC1 0x98
+#define PLLM_MISC2 0x9c
#define PLLP_BASE 0xa0
#define PLLP_MISC0 0xac
#define PLLP_MISC1 0x680
@@ -99,7 +99,7 @@
#define PLLC4_MISC0 0x5a8
#define PLLC4_OUT 0x5e4
#define PLLMB_BASE 0x5e8
-#define PLLMB_MISC0 0x5ec
+#define PLLMB_MISC1 0x5ec
#define PLLA1_BASE 0x6a4
#define PLLA1_MISC0 0x6a8
#define PLLA1_MISC1 0x6ac
@@ -243,7 +243,8 @@ static unsigned long tegra210_input_freq[] = {
};
static const char *mux_pllmcp_clkm[] = {
- "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3",
+ "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_mb", "pll_mb",
+ "pll_p",
};
#define mux_pllmcp_clkm_idx NULL
@@ -367,12 +368,12 @@ static const char *mux_pllmcp_clkm[] = {
/* PLLMB */
#define PLLMB_BASE_LOCK (1 << 27)
-#define PLLMB_MISC0_LOCK_OVERRIDE (1 << 18)
-#define PLLMB_MISC0_IDDQ (1 << 17)
-#define PLLMB_MISC0_LOCK_ENABLE (1 << 16)
+#define PLLMB_MISC1_LOCK_OVERRIDE (1 << 18)
+#define PLLMB_MISC1_IDDQ (1 << 17)
+#define PLLMB_MISC1_LOCK_ENABLE (1 << 16)
-#define PLLMB_MISC0_DEFAULT_VALUE 0x00030000
-#define PLLMB_MISC0_WRITE_MASK 0x0007ffff
+#define PLLMB_MISC1_DEFAULT_VALUE 0x00030000
+#define PLLMB_MISC1_WRITE_MASK 0x0007ffff
/* PLLP */
#define PLLP_BASE_OVERRIDE (1 << 28)
@@ -457,7 +458,8 @@ static void pllcx_check_defaults(struct tegra_clk_pll_params *params)
PLLCX_MISC3_WRITE_MASK);
}
-void tegra210_pllcx_set_defaults(const char *name, struct tegra_clk_pll *pllcx)
+static void tegra210_pllcx_set_defaults(const char *name,
+ struct tegra_clk_pll *pllcx)
{
pllcx->params->defaults_set = true;
@@ -482,22 +484,22 @@ void tegra210_pllcx_set_defaults(const char *name, struct tegra_clk_pll *pllcx)
udelay(1);
}
-void _pllc_set_defaults(struct tegra_clk_pll *pllcx)
+static void _pllc_set_defaults(struct tegra_clk_pll *pllcx)
{
tegra210_pllcx_set_defaults("PLL_C", pllcx);
}
-void _pllc2_set_defaults(struct tegra_clk_pll *pllcx)
+static void _pllc2_set_defaults(struct tegra_clk_pll *pllcx)
{
tegra210_pllcx_set_defaults("PLL_C2", pllcx);
}
-void _pllc3_set_defaults(struct tegra_clk_pll *pllcx)
+static void _pllc3_set_defaults(struct tegra_clk_pll *pllcx)
{
tegra210_pllcx_set_defaults("PLL_C3", pllcx);
}
-void _plla1_set_defaults(struct tegra_clk_pll *pllcx)
+static void _plla1_set_defaults(struct tegra_clk_pll *pllcx)
{
tegra210_pllcx_set_defaults("PLL_A1", pllcx);
}
@@ -507,7 +509,7 @@ void _plla1_set_defaults(struct tegra_clk_pll *pllcx)
* PLL with dynamic ramp and fractional SDM. Dynamic ramp is not used.
* Fractional SDM is allowed to provide exact audio rates.
*/
-void tegra210_plla_set_defaults(struct tegra_clk_pll *plla)
+static void tegra210_plla_set_defaults(struct tegra_clk_pll *plla)
{
u32 mask;
u32 val = readl_relaxed(clk_base + plla->params->base_reg);
@@ -559,7 +561,7 @@ void tegra210_plla_set_defaults(struct tegra_clk_pll *plla)
* PLLD
* PLL with fractional SDM.
*/
-void tegra210_plld_set_defaults(struct tegra_clk_pll *plld)
+static void tegra210_plld_set_defaults(struct tegra_clk_pll *plld)
{
u32 val;
u32 mask = 0xffff;
@@ -698,7 +700,7 @@ static void plldss_defaults(const char *pll_name, struct tegra_clk_pll *plldss,
udelay(1);
}
-void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2)
+static void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2)
{
plldss_defaults("PLL_D2", plld2, PLLD2_MISC0_DEFAULT_VALUE,
PLLD2_MISC1_CFG_DEFAULT_VALUE,
@@ -706,7 +708,7 @@ void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2)
PLLD2_MISC3_CTRL2_DEFAULT_VALUE);
}
-void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp)
+static void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp)
{
plldss_defaults("PLL_DP", plldp, PLLDP_MISC0_DEFAULT_VALUE,
PLLDP_MISC1_CFG_DEFAULT_VALUE,
@@ -719,7 +721,7 @@ void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp)
* Base and misc0 layout is the same as PLLD2/PLLDP, but no SDM/SSC support.
* VCO is exposed to the clock tree via fixed 1/3 and 1/5 dividers.
*/
-void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4)
+static void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4)
{
plldss_defaults("PLL_C4", pllc4, PLLC4_MISC0_DEFAULT_VALUE, 0, 0, 0);
}
@@ -728,7 +730,7 @@ void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4)
* PLLRE
* VCO is exposed to the clock tree directly along with post-divider output
*/
-void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
+static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
{
u32 mask;
u32 val = readl_relaxed(clk_base + pllre->params->base_reg);
@@ -780,13 +782,13 @@ static void pllx_get_dyn_steps(struct clk_hw *hw, u32 *step_a, u32 *step_b)
{
unsigned long input_rate;
- if (!IS_ERR_OR_NULL(hw->clk)) {
+ /* cf rate */
+ if (!IS_ERR_OR_NULL(hw->clk))
input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
- /* cf rate */
- input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate);
- } else {
+ else
input_rate = 38400000;
- }
+
+ input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate);
switch (input_rate) {
case 12000000:
@@ -841,7 +843,7 @@ static void pllx_check_defaults(struct tegra_clk_pll *pll)
PLLX_MISC5_WRITE_MASK);
}
-void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx)
+static void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx)
{
u32 val;
u32 step_a, step_b;
@@ -901,7 +903,7 @@ void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx)
}
/* PLLMB */
-void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
+static void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
{
u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg);
@@ -914,15 +916,15 @@ void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
* PLL is ON: check if defaults already set, then set those
* that can be updated in flight.
*/
- val = PLLMB_MISC0_DEFAULT_VALUE & (~PLLMB_MISC0_IDDQ);
- mask = PLLMB_MISC0_LOCK_ENABLE | PLLMB_MISC0_LOCK_OVERRIDE;
+ val = PLLMB_MISC1_DEFAULT_VALUE & (~PLLMB_MISC1_IDDQ);
+ mask = PLLMB_MISC1_LOCK_ENABLE | PLLMB_MISC1_LOCK_OVERRIDE;
_pll_misc_chk_default(clk_base, pllmb->params, 0, val,
- ~mask & PLLMB_MISC0_WRITE_MASK);
+ ~mask & PLLMB_MISC1_WRITE_MASK);
/* Enable lock detect */
val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]);
val &= ~mask;
- val |= PLLMB_MISC0_DEFAULT_VALUE & mask;
+ val |= PLLMB_MISC1_DEFAULT_VALUE & mask;
writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]);
udelay(1);
@@ -930,7 +932,7 @@ void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
}
/* set IDDQ, enable lock detect */
- writel_relaxed(PLLMB_MISC0_DEFAULT_VALUE,
+ writel_relaxed(PLLMB_MISC1_DEFAULT_VALUE,
clk_base + pllmb->params->ext_misc_reg[0]);
udelay(1);
}
@@ -960,7 +962,7 @@ static void pllp_check_defaults(struct tegra_clk_pll *pll, bool enabled)
~mask & PLLP_MISC1_WRITE_MASK);
}
-void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp)
+static void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp)
{
u32 mask;
u32 val = readl_relaxed(clk_base + pllp->params->base_reg);
@@ -1022,7 +1024,7 @@ static void pllu_check_defaults(struct tegra_clk_pll *pll, bool hw_control)
~mask & PLLU_MISC1_WRITE_MASK);
}
-void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu)
+static void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu)
{
u32 val = readl_relaxed(clk_base + pllu->params->base_reg);
@@ -1212,8 +1214,9 @@ static void tegra210_clk_pll_set_gain(struct tegra_clk_pll_freq_table *cfg)
cfg->m *= PLL_SDM_COEFF;
}
-unsigned long tegra210_clk_adjust_vco_min(struct tegra_clk_pll_params *params,
- unsigned long parent_rate)
+static unsigned long
+tegra210_clk_adjust_vco_min(struct tegra_clk_pll_params *params,
+ unsigned long parent_rate)
{
unsigned long vco_min = params->vco_min;
@@ -1386,7 +1389,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.mdiv_default = 3,
.div_nmp = &pllc_nmp,
.freq_table = pll_cx_freq_table,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .flags = TEGRA_PLL_USE_LOCK,
.set_defaults = _pllc_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
};
@@ -1425,7 +1428,7 @@ static struct tegra_clk_pll_params pll_c2_params = {
.ext_misc_reg[2] = PLLC2_MISC2,
.ext_misc_reg[3] = PLLC2_MISC3,
.freq_table = pll_cx_freq_table,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .flags = TEGRA_PLL_USE_LOCK,
.set_defaults = _pllc2_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
};
@@ -1455,7 +1458,7 @@ static struct tegra_clk_pll_params pll_c3_params = {
.ext_misc_reg[2] = PLLC3_MISC2,
.ext_misc_reg[3] = PLLC3_MISC3,
.freq_table = pll_cx_freq_table,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .flags = TEGRA_PLL_USE_LOCK,
.set_defaults = _pllc3_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
};
@@ -1505,7 +1508,6 @@ static struct tegra_clk_pll_params pll_c4_vco_params = {
.base_reg = PLLC4_BASE,
.misc_reg = PLLC4_MISC0,
.lock_mask = PLL_BASE_LOCK,
- .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
.lock_delay = 300,
.max_p = PLL_QLIN_PDIV_MAX,
.ext_misc_reg[0] = PLLC4_MISC0,
@@ -1517,8 +1519,7 @@ static struct tegra_clk_pll_params pll_c4_vco_params = {
.div_nmp = &pllss_nmp,
.freq_table = pll_c4_vco_freq_table,
.set_defaults = tegra210_pllc4_set_defaults,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
- TEGRA_PLL_VCO_OUT,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_VCO_OUT,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
};
@@ -1559,15 +1560,15 @@ static struct tegra_clk_pll_params pll_m_params = {
.vco_min = 800000000,
.vco_max = 1866000000,
.base_reg = PLLM_BASE,
- .misc_reg = PLLM_MISC1,
+ .misc_reg = PLLM_MISC2,
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLM_MISC_LOCK_ENABLE,
.lock_delay = 300,
- .iddq_reg = PLLM_MISC0,
+ .iddq_reg = PLLM_MISC2,
.iddq_bit_idx = PLLM_IDDQ_BIT,
.max_p = PLL_QLIN_PDIV_MAX,
- .ext_misc_reg[0] = PLLM_MISC0,
- .ext_misc_reg[0] = PLLM_MISC1,
+ .ext_misc_reg[0] = PLLM_MISC2,
+ .ext_misc_reg[1] = PLLM_MISC1,
.round_p_to_pdiv = pll_qlin_p_to_pdiv,
.pdiv_tohw = pll_qlin_pdiv_to_hw,
.div_nmp = &pllm_nmp,
@@ -1586,19 +1587,18 @@ static struct tegra_clk_pll_params pll_mb_params = {
.vco_min = 800000000,
.vco_max = 1866000000,
.base_reg = PLLMB_BASE,
- .misc_reg = PLLMB_MISC0,
+ .misc_reg = PLLMB_MISC1,
.lock_mask = PLL_BASE_LOCK,
- .lock_enable_bit_idx = PLLMB_MISC_LOCK_ENABLE,
.lock_delay = 300,
- .iddq_reg = PLLMB_MISC0,
+ .iddq_reg = PLLMB_MISC1,
.iddq_bit_idx = PLLMB_IDDQ_BIT,
.max_p = PLL_QLIN_PDIV_MAX,
- .ext_misc_reg[0] = PLLMB_MISC0,
+ .ext_misc_reg[0] = PLLMB_MISC1,
.round_p_to_pdiv = pll_qlin_p_to_pdiv,
.pdiv_tohw = pll_qlin_pdiv_to_hw,
.div_nmp = &pllm_nmp,
.freq_table = pll_m_freq_table,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .flags = TEGRA_PLL_USE_LOCK,
.set_defaults = tegra210_pllmb_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
};
@@ -1671,7 +1671,6 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.base_reg = PLLRE_BASE,
.misc_reg = PLLRE_MISC0,
.lock_mask = PLLRE_MISC_LOCK,
- .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE,
.lock_delay = 300,
.max_p = PLL_QLIN_PDIV_MAX,
.ext_misc_reg[0] = PLLRE_MISC0,
@@ -1681,8 +1680,7 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.pdiv_tohw = pll_qlin_pdiv_to_hw,
.div_nmp = &pllre_nmp,
.freq_table = pll_re_vco_freq_table,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_LOCK_MISC |
- TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_LOCK_MISC | TEGRA_PLL_VCO_OUT,
.set_defaults = tegra210_pllre_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
};
@@ -1712,7 +1710,6 @@ static struct tegra_clk_pll_params pll_p_params = {
.base_reg = PLLP_BASE,
.misc_reg = PLLP_MISC0,
.lock_mask = PLL_BASE_LOCK,
- .lock_enable_bit_idx = PLLP_MISC_LOCK_ENABLE,
.lock_delay = 300,
.iddq_reg = PLLP_MISC0,
.iddq_bit_idx = PLLXP_IDDQ_BIT,
@@ -1721,8 +1718,7 @@ static struct tegra_clk_pll_params pll_p_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_p_freq_table,
.fixed_rate = 408000000,
- .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
- TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK | TEGRA_PLL_VCO_OUT,
.set_defaults = tegra210_pllp_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
};
@@ -1750,7 +1746,7 @@ static struct tegra_clk_pll_params pll_a1_params = {
.ext_misc_reg[2] = PLLA1_MISC2,
.ext_misc_reg[3] = PLLA1_MISC3,
.freq_table = pll_cx_freq_table,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .flags = TEGRA_PLL_USE_LOCK,
.set_defaults = _plla1_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
};
@@ -1787,7 +1783,6 @@ static struct tegra_clk_pll_params pll_a_params = {
.base_reg = PLLA_BASE,
.misc_reg = PLLA_MISC0,
.lock_mask = PLL_BASE_LOCK,
- .lock_enable_bit_idx = PLLA_MISC_LOCK_ENABLE,
.lock_delay = 300,
.round_p_to_pdiv = pll_qlin_p_to_pdiv,
.pdiv_tohw = pll_qlin_pdiv_to_hw,
@@ -1802,8 +1797,7 @@ static struct tegra_clk_pll_params pll_a_params = {
.ext_misc_reg[1] = PLLA_MISC1,
.ext_misc_reg[2] = PLLA_MISC2,
.freq_table = pll_a_freq_table,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_MDIV_NEW |
- TEGRA_PLL_HAS_LOCK_ENABLE,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_MDIV_NEW,
.set_defaults = tegra210_plla_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
.set_gain = tegra210_clk_pll_set_gain,
@@ -1836,7 +1830,6 @@ static struct tegra_clk_pll_params pll_d_params = {
.base_reg = PLLD_BASE,
.misc_reg = PLLD_MISC0,
.lock_mask = PLL_BASE_LOCK,
- .lock_enable_bit_idx = PLLD_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.iddq_reg = PLLD_MISC0,
.iddq_bit_idx = PLLD_IDDQ_BIT,
@@ -1850,7 +1843,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.ext_misc_reg[0] = PLLD_MISC0,
.ext_misc_reg[1] = PLLD_MISC1,
.freq_table = pll_d_freq_table,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .flags = TEGRA_PLL_USE_LOCK,
.mdiv_default = 1,
.set_defaults = tegra210_plld_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
@@ -1876,7 +1869,6 @@ static struct tegra_clk_pll_params pll_d2_params = {
.base_reg = PLLD2_BASE,
.misc_reg = PLLD2_MISC0,
.lock_mask = PLL_BASE_LOCK,
- .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
.lock_delay = 300,
.iddq_reg = PLLD2_BASE,
.iddq_bit_idx = PLLSS_IDDQ_BIT,
@@ -1897,7 +1889,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
.mdiv_default = 1,
.freq_table = tegra210_pll_d2_freq_table,
.set_defaults = tegra210_plld2_set_defaults,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .flags = TEGRA_PLL_USE_LOCK,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
.set_gain = tegra210_clk_pll_set_gain,
.adjust_vco = tegra210_clk_adjust_vco_min,
@@ -1920,7 +1912,6 @@ static struct tegra_clk_pll_params pll_dp_params = {
.base_reg = PLLDP_BASE,
.misc_reg = PLLDP_MISC,
.lock_mask = PLL_BASE_LOCK,
- .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
.lock_delay = 300,
.iddq_reg = PLLDP_BASE,
.iddq_bit_idx = PLLSS_IDDQ_BIT,
@@ -1941,7 +1932,7 @@ static struct tegra_clk_pll_params pll_dp_params = {
.mdiv_default = 1,
.freq_table = pll_dp_freq_table,
.set_defaults = tegra210_plldp_set_defaults,
- .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .flags = TEGRA_PLL_USE_LOCK,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
.set_gain = tegra210_clk_pll_set_gain,
.adjust_vco = tegra210_clk_adjust_vco_min,
@@ -1973,7 +1964,6 @@ static struct tegra_clk_pll_params pll_u_vco_params = {
.base_reg = PLLU_BASE,
.misc_reg = PLLU_MISC0,
.lock_mask = PLL_BASE_LOCK,
- .lock_enable_bit_idx = PLLU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.iddq_reg = PLLU_MISC0,
.iddq_bit_idx = PLLU_IDDQ_BIT,
@@ -1983,8 +1973,7 @@ static struct tegra_clk_pll_params pll_u_vco_params = {
.pdiv_tohw = pll_qlin_pdiv_to_hw,
.div_nmp = &pllu_nmp,
.freq_table = pll_u_freq_table,
- .flags = TEGRA_PLLU | TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
- TEGRA_PLL_VCO_OUT,
+ .flags = TEGRA_PLLU | TEGRA_PLL_USE_LOCK | TEGRA_PLL_VCO_OUT,
.set_defaults = tegra210_pllu_set_defaults,
.calc_rate = tegra210_pll_fixed_mdiv_cfg,
};
@@ -2218,6 +2207,7 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
[tegra_clk_pll_c4_out1] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT1, .present = true },
[tegra_clk_pll_c4_out2] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT2, .present = true },
[tegra_clk_pll_c4_out3] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT3, .present = true },
+ [tegra_clk_apb2ape] = { .dt_id = TEGRA210_CLK_APB2APE, .present = true },
};
static struct tegra_devclk devclks[] __initdata = {
@@ -2519,7 +2509,7 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
/* PLLU_VCO */
val = readl(clk_base + pll_u_vco_params.base_reg);
- val &= ~BIT(24); /* disable PLLU_OVERRIDE */
+ val &= ~PLLU_BASE_OVERRIDE; /* disable PLLU_OVERRIDE */
writel(val, clk_base + pll_u_vco_params.base_reg);
clk = tegra_clk_register_pllre("pll_u_vco", "pll_ref", clk_base, pmc,
@@ -2738,8 +2728,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 },
{ TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 },
{ TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 },
- { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
- { TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 },
{ TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 },
{ TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 },
{ TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 },
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c
index 1c300388782b..cc739291a3ce 100644
--- a/drivers/clk/ti/dpll3xxx.c
+++ b/drivers/clk/ti/dpll3xxx.c
@@ -460,7 +460,8 @@ int omap3_noncore_dpll_enable(struct clk_hw *hw)
parent = clk_hw_get_parent(hw);
- if (clk_hw_get_rate(hw) == clk_get_rate(dd->clk_bypass)) {
+ if (clk_hw_get_rate(hw) ==
+ clk_hw_get_rate(__clk_get_hw(dd->clk_bypass))) {
WARN_ON(parent != __clk_get_hw(dd->clk_bypass));
r = _omap3_noncore_dpll_bypass(clk);
} else {
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c
index e62f8cb2c9b5..3bca438ecd19 100644
--- a/drivers/clk/versatile/clk-icst.c
+++ b/drivers/clk/versatile/clk-icst.c
@@ -78,6 +78,9 @@ static int vco_set(struct clk_icst *icst, struct icst_vco vco)
ret = regmap_read(icst->map, icst->vcoreg_off, &val);
if (ret)
return ret;
+
+ /* Mask the 18 bits used by the VCO */
+ val &= ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
/* This magic unlocks the VCO so it can be controlled */
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 33db7406c0e2..c346be650892 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -160,6 +160,7 @@ config CLKSRC_EFM32
config CLKSRC_LPC32XX
bool "Clocksource for LPC32XX" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
+ depends on ARM
select CLKSRC_MMIO
select CLKSRC_OF
help
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index c64d543d64bf..5152b3898155 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -32,6 +32,14 @@
#define CNTTIDR 0x08
#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4))
+#define CNTACR(n) (0x40 + ((n) * 4))
+#define CNTACR_RPCT BIT(0)
+#define CNTACR_RVCT BIT(1)
+#define CNTACR_RFRQ BIT(2)
+#define CNTACR_RVOFF BIT(3)
+#define CNTACR_RWVT BIT(4)
+#define CNTACR_RWPT BIT(5)
+
#define CNTVCT_LO 0x08
#define CNTVCT_HI 0x0c
#define CNTFRQ 0x10
@@ -67,7 +75,7 @@ static int arch_timer_ppi[MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
-static bool arch_timer_use_virtual = true;
+static enum ppi_nr arch_timer_uses_ppi = VIRT_PPI;
static bool arch_timer_c3stop;
static bool arch_timer_mem_use_virtual;
@@ -263,14 +271,22 @@ static void __arch_timer_setup(unsigned type,
clk->name = "arch_sys_timer";
clk->rating = 450;
clk->cpumask = cpumask_of(smp_processor_id());
- if (arch_timer_use_virtual) {
- clk->irq = arch_timer_ppi[VIRT_PPI];
+ clk->irq = arch_timer_ppi[arch_timer_uses_ppi];
+ switch (arch_timer_uses_ppi) {
+ case VIRT_PPI:
clk->set_state_shutdown = arch_timer_shutdown_virt;
+ clk->set_state_oneshot_stopped = arch_timer_shutdown_virt;
clk->set_next_event = arch_timer_set_next_event_virt;
- } else {
- clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
+ break;
+ case PHYS_SECURE_PPI:
+ case PHYS_NONSECURE_PPI:
+ case HYP_PPI:
clk->set_state_shutdown = arch_timer_shutdown_phys;
+ clk->set_state_oneshot_stopped = arch_timer_shutdown_phys;
clk->set_next_event = arch_timer_set_next_event_phys;
+ break;
+ default:
+ BUG();
}
} else {
clk->features |= CLOCK_EVT_FEAT_DYNIRQ;
@@ -279,10 +295,12 @@ static void __arch_timer_setup(unsigned type,
clk->cpumask = cpu_all_mask;
if (arch_timer_mem_use_virtual) {
clk->set_state_shutdown = arch_timer_shutdown_virt_mem;
+ clk->set_state_oneshot_stopped = arch_timer_shutdown_virt_mem;
clk->set_next_event =
arch_timer_set_next_event_virt_mem;
} else {
clk->set_state_shutdown = arch_timer_shutdown_phys_mem;
+ clk->set_state_oneshot_stopped = arch_timer_shutdown_phys_mem;
clk->set_next_event =
arch_timer_set_next_event_phys_mem;
}
@@ -338,17 +356,20 @@ static void arch_counter_set_user_access(void)
arch_timer_set_cntkctl(cntkctl);
}
+static bool arch_timer_has_nonsecure_ppi(void)
+{
+ return (arch_timer_uses_ppi == PHYS_SECURE_PPI &&
+ arch_timer_ppi[PHYS_NONSECURE_PPI]);
+}
+
static int arch_timer_setup(struct clock_event_device *clk)
{
__arch_timer_setup(ARCH_CP15_TIMER, clk);
- if (arch_timer_use_virtual)
- enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
- else {
- enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0);
- if (arch_timer_ppi[PHYS_NONSECURE_PPI])
- enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
- }
+ enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], 0);
+
+ if (arch_timer_has_nonsecure_ppi())
+ enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
arch_counter_set_user_access();
if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM))
@@ -390,7 +411,7 @@ static void arch_timer_banner(unsigned type)
(unsigned long)arch_timer_rate / 1000000,
(unsigned long)(arch_timer_rate / 10000) % 100,
type & ARCH_CP15_TIMER ?
- arch_timer_use_virtual ? "virt" : "phys" :
+ (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
"",
type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "",
type & ARCH_MEM_TIMER ?
@@ -460,7 +481,7 @@ static void __init arch_counter_register(unsigned type)
/* Register the CP15 based counter if we have one */
if (type & ARCH_CP15_TIMER) {
- if (IS_ENABLED(CONFIG_ARM64) || arch_timer_use_virtual)
+ if (IS_ENABLED(CONFIG_ARM64) || arch_timer_uses_ppi == VIRT_PPI)
arch_timer_read_counter = arch_counter_get_cntvct;
else
arch_timer_read_counter = arch_counter_get_cntpct;
@@ -490,13 +511,9 @@ static void arch_timer_stop(struct clock_event_device *clk)
pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
clk->irq, smp_processor_id());
- if (arch_timer_use_virtual)
- disable_percpu_irq(arch_timer_ppi[VIRT_PPI]);
- else {
- disable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI]);
- if (arch_timer_ppi[PHYS_NONSECURE_PPI])
- disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
- }
+ disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]);
+ if (arch_timer_has_nonsecure_ppi())
+ disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
clk->set_state_shutdown(clk);
}
@@ -562,12 +579,14 @@ static int __init arch_timer_register(void)
goto out;
}
- if (arch_timer_use_virtual) {
- ppi = arch_timer_ppi[VIRT_PPI];
+ ppi = arch_timer_ppi[arch_timer_uses_ppi];
+ switch (arch_timer_uses_ppi) {
+ case VIRT_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_virt,
"arch_timer", arch_timer_evt);
- } else {
- ppi = arch_timer_ppi[PHYS_SECURE_PPI];
+ break;
+ case PHYS_SECURE_PPI:
+ case PHYS_NONSECURE_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) {
@@ -578,6 +597,13 @@ static int __init arch_timer_register(void)
free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
arch_timer_evt);
}
+ break;
+ case HYP_PPI:
+ err = request_percpu_irq(ppi, arch_timer_handler_phys,
+ "arch_timer", arch_timer_evt);
+ break;
+ default:
+ BUG();
}
if (err) {
@@ -602,15 +628,10 @@ static int __init arch_timer_register(void)
out_unreg_notify:
unregister_cpu_notifier(&arch_timer_cpu_nb);
out_free_irq:
- if (arch_timer_use_virtual)
- free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);
- else {
- free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+ free_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], arch_timer_evt);
+ if (arch_timer_has_nonsecure_ppi())
+ free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
arch_timer_evt);
- if (arch_timer_ppi[PHYS_NONSECURE_PPI])
- free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
- arch_timer_evt);
- }
out_free:
free_percpu(arch_timer_evt);
@@ -697,12 +718,25 @@ static void __init arch_timer_init(void)
*
* If no interrupt provided for virtual timer, we'll have to
* stick to the physical timer. It'd better be accessible...
+ *
+ * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE
+ * accesses to CNTP_*_EL1 registers are silently redirected to
+ * their CNTHP_*_EL2 counterparts, and use a different PPI
+ * number.
*/
if (is_hyp_mode_available() || !arch_timer_ppi[VIRT_PPI]) {
- arch_timer_use_virtual = false;
+ bool has_ppi;
- if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
- !arch_timer_ppi[PHYS_NONSECURE_PPI]) {
+ if (is_kernel_in_hyp_mode()) {
+ arch_timer_uses_ppi = HYP_PPI;
+ has_ppi = !!arch_timer_ppi[HYP_PPI];
+ } else {
+ arch_timer_uses_ppi = PHYS_SECURE_PPI;
+ has_ppi = (!!arch_timer_ppi[PHYS_SECURE_PPI] ||
+ !!arch_timer_ppi[PHYS_NONSECURE_PPI]);
+ }
+
+ if (!has_ppi) {
pr_warn("arch_timer: No interrupt available, giving up\n");
return;
}
@@ -735,7 +769,7 @@ static void __init arch_timer_of_init(struct device_node *np)
*/
if (IS_ENABLED(CONFIG_ARM) &&
of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
- arch_timer_use_virtual = false;
+ arch_timer_uses_ppi = PHYS_SECURE_PPI;
arch_timer_init();
}
@@ -757,7 +791,6 @@ static void __init arch_timer_mem_init(struct device_node *np)
}
cnttidr = readl_relaxed(cntctlbase + CNTTIDR);
- iounmap(cntctlbase);
/*
* Try to find a virtual capable frame. Otherwise fall back to a
@@ -765,20 +798,31 @@ static void __init arch_timer_mem_init(struct device_node *np)
*/
for_each_available_child_of_node(np, frame) {
int n;
+ u32 cntacr;
if (of_property_read_u32(frame, "frame-number", &n)) {
pr_err("arch_timer: Missing frame-number\n");
- of_node_put(best_frame);
of_node_put(frame);
- return;
+ goto out;
}
- if (cnttidr & CNTTIDR_VIRT(n)) {
+ /* Try enabling everything, and see what sticks */
+ cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
+ CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
+ writel_relaxed(cntacr, cntctlbase + CNTACR(n));
+ cntacr = readl_relaxed(cntctlbase + CNTACR(n));
+
+ if ((cnttidr & CNTTIDR_VIRT(n)) &&
+ !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) {
of_node_put(best_frame);
best_frame = frame;
arch_timer_mem_use_virtual = true;
break;
}
+
+ if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
+ continue;
+
of_node_put(best_frame);
best_frame = of_node_get(frame);
}
@@ -786,24 +830,26 @@ static void __init arch_timer_mem_init(struct device_node *np)
base = arch_counter_base = of_iomap(best_frame, 0);
if (!base) {
pr_err("arch_timer: Can't map frame's registers\n");
- of_node_put(best_frame);
- return;
+ goto out;
}
if (arch_timer_mem_use_virtual)
irq = irq_of_parse_and_map(best_frame, 1);
else
irq = irq_of_parse_and_map(best_frame, 0);
- of_node_put(best_frame);
+
if (!irq) {
pr_err("arch_timer: Frame missing %s irq",
arch_timer_mem_use_virtual ? "virt" : "phys");
- return;
+ goto out;
}
arch_timer_detect_rate(base, np);
arch_timer_mem_register(base, irq);
arch_timer_common_init();
+out:
+ iounmap(cntctlbase);
+ of_node_put(best_frame);
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
arch_timer_mem_init);
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
index d189d8cb69f7..9df0d1699d22 100644
--- a/drivers/clocksource/arm_global_timer.c
+++ b/drivers/clocksource/arm_global_timer.c
@@ -16,6 +16,7 @@
#include <linux/clockchips.h>
#include <linux/cpu.h>
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -174,6 +175,7 @@ static int gt_clockevents_init(struct clock_event_device *clk)
clk->set_state_shutdown = gt_clockevent_shutdown;
clk->set_state_periodic = gt_clockevent_set_periodic;
clk->set_state_oneshot = gt_clockevent_shutdown;
+ clk->set_state_oneshot_stopped = gt_clockevent_shutdown;
clk->set_next_event = gt_clockevent_set_next_event;
clk->cpumask = cpumask_of(cpu);
clk->rating = 300;
@@ -221,6 +223,21 @@ static u64 notrace gt_sched_clock_read(void)
}
#endif
+static unsigned long gt_read_long(void)
+{
+ return readl_relaxed(gt_base + GT_COUNTER0);
+}
+
+static struct delay_timer gt_delay_timer = {
+ .read_current_timer = gt_read_long,
+};
+
+static void __init gt_delay_timer_init(void)
+{
+ gt_delay_timer.freq = gt_clk_rate;
+ register_current_timer_delay(&gt_delay_timer);
+}
+
static void __init gt_clocksource_init(void)
{
writel(0, gt_base + GT_CONTROL);
@@ -317,6 +334,7 @@ static void __init global_timer_of_register(struct device_node *np)
/* Immediately configure the timer on the boot CPU */
gt_clocksource_init();
gt_clockevents_init(this_cpu_ptr(gt_evt));
+ gt_delay_timer_init();
return;
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index ff44082a0827..be09bc0b5e26 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -313,6 +313,7 @@ static struct clock_event_device mct_comp_device = {
.set_state_periodic = mct_set_state_periodic,
.set_state_shutdown = mct_set_state_shutdown,
.set_state_oneshot = mct_set_state_shutdown,
+ .set_state_oneshot_stopped = mct_set_state_shutdown,
.tick_resume = mct_set_state_shutdown,
};
@@ -452,6 +453,7 @@ static int exynos4_local_timer_setup(struct mct_clock_event_device *mevt)
evt->set_state_periodic = set_state_periodic;
evt->set_state_shutdown = set_state_shutdown;
evt->set_state_oneshot = set_state_shutdown;
+ evt->set_state_oneshot_stopped = set_state_shutdown;
evt->tick_resume = set_state_shutdown;
evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
evt->rating = 450;
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index 8c77a529d0d4..b991b288c803 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -122,23 +122,23 @@ static void __init rk_timer_init(struct device_node *np)
pclk = of_clk_get_by_name(np, "pclk");
if (IS_ERR(pclk)) {
pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
- return;
+ goto out_unmap;
}
if (clk_prepare_enable(pclk)) {
pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
- return;
+ goto out_unmap;
}
timer_clk = of_clk_get_by_name(np, "timer");
if (IS_ERR(timer_clk)) {
pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
- return;
+ goto out_timer_clk;
}
if (clk_prepare_enable(timer_clk)) {
pr_err("Failed to enable timer clock\n");
- return;
+ goto out_timer_clk;
}
bc_timer.freq = clk_get_rate(timer_clk);
@@ -146,7 +146,7 @@ static void __init rk_timer_init(struct device_node *np)
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
- return;
+ goto out_irq;
}
ce->name = TIMER_NAME;
@@ -164,10 +164,19 @@ static void __init rk_timer_init(struct device_node *np)
ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
if (ret) {
pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
- return;
+ goto out_irq;
}
clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
+
+ return;
+
+out_irq:
+ clk_disable_unprepare(timer_clk);
+out_timer_clk:
+ clk_disable_unprepare(pclk);
+out_unmap:
+ iounmap(bc_timer.base);
}
CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c
index 1316876b487a..daae61e8c820 100644
--- a/drivers/clocksource/time-lpc32xx.c
+++ b/drivers/clocksource/time-lpc32xx.c
@@ -18,6 +18,7 @@
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
+#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
@@ -43,6 +44,7 @@
struct lpc32xx_clock_event_ddata {
struct clock_event_device evtdev;
void __iomem *base;
+ u32 ticks_per_jiffy;
};
/* Needed for the sched clock */
@@ -53,6 +55,15 @@ static u64 notrace lpc32xx_read_sched_clock(void)
return readl(clocksource_timer_counter);
}
+static unsigned long lpc32xx_delay_timer_read(void)
+{
+ return readl(clocksource_timer_counter);
+}
+
+static struct delay_timer lpc32xx_delay_timer = {
+ .read_current_timer = lpc32xx_delay_timer_read,
+};
+
static int lpc32xx_clkevt_next_event(unsigned long delta,
struct clock_event_device *evtdev)
{
@@ -60,14 +71,13 @@ static int lpc32xx_clkevt_next_event(unsigned long delta,
container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
/*
- * Place timer in reset and program the delta in the prescale
- * register (PR). When the prescale counter matches the value
- * in PR the counter register is incremented and the compare
- * match will trigger. After setup the timer is released from
- * reset and enabled.
+ * Place timer in reset and program the delta in the match
+ * channel 0 (MR0). When the timer counter matches the value
+ * in MR0 register the match will trigger an interrupt.
+ * After setup the timer is released from reset and enabled.
*/
writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
- writel_relaxed(delta, ddata->base + LPC32XX_TIMER_PR);
+ writel_relaxed(delta, ddata->base + LPC32XX_TIMER_MR0);
writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);
return 0;
@@ -86,11 +96,39 @@ static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev)
static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev)
{
+ struct lpc32xx_clock_event_ddata *ddata =
+ container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
+
/*
* When using oneshot, we must also disable the timer
* to wait for the first call to set_next_event().
*/
- return lpc32xx_clkevt_shutdown(evtdev);
+ writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);
+
+ /* Enable interrupt, reset on match and stop on match (MCR). */
+ writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
+ LPC32XX_TIMER_MCR_MR0S, ddata->base + LPC32XX_TIMER_MCR);
+ return 0;
+}
+
+static int lpc32xx_clkevt_periodic(struct clock_event_device *evtdev)
+{
+ struct lpc32xx_clock_event_ddata *ddata =
+ container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
+
+ /* Enable interrupt and reset on match. */
+ writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R,
+ ddata->base + LPC32XX_TIMER_MCR);
+
+ /*
+ * Place timer in reset and program the delta in the match
+ * channel 0 (MR0).
+ */
+ writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
+ writel_relaxed(ddata->ticks_per_jiffy, ddata->base + LPC32XX_TIMER_MR0);
+ writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);
+
+ return 0;
}
static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
@@ -108,11 +146,13 @@ static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = {
.evtdev = {
.name = "lpc3220 clockevent",
- .features = CLOCK_EVT_FEAT_ONESHOT,
+ .features = CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_PERIODIC,
.rating = 300,
.set_next_event = lpc32xx_clkevt_next_event,
.set_state_shutdown = lpc32xx_clkevt_shutdown,
.set_state_oneshot = lpc32xx_clkevt_oneshot,
+ .set_state_periodic = lpc32xx_clkevt_periodic,
},
};
@@ -162,6 +202,8 @@ static int __init lpc32xx_clocksource_init(struct device_node *np)
}
clocksource_timer_counter = base + LPC32XX_TIMER_TC;
+ lpc32xx_delay_timer.freq = rate;
+ register_current_timer_delay(&lpc32xx_delay_timer);
sched_clock_register(lpc32xx_read_sched_clock, 32, rate);
return 0;
@@ -210,18 +252,16 @@ static int __init lpc32xx_clockevent_init(struct device_node *np)
/*
* Disable timer and clear any pending interrupt (IR) on match
- * channel 0 (MR0). Configure a compare match value of 1 on MR0
- * and enable interrupt, reset on match and stop on match (MCR).
+ * channel 0 (MR0). Clear the prescaler as it's not used.
*/
writel_relaxed(0, base + LPC32XX_TIMER_TCR);
+ writel_relaxed(0, base + LPC32XX_TIMER_PR);
writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR);
- writel_relaxed(1, base + LPC32XX_TIMER_MR0);
- writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
- LPC32XX_TIMER_MCR_MR0S, base + LPC32XX_TIMER_MCR);
rate = clk_get_rate(clk);
lpc32xx_clk_event_ddata.base = base;
+ lpc32xx_clk_event_ddata.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
clockevents_config_and_register(&lpc32xx_clk_event_ddata.evtdev,
rate, 1, -1);
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 659879a56dba..a7f45853c103 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -19,6 +19,7 @@ config CPU_FREQ
if CPU_FREQ
config CPU_FREQ_GOV_COMMON
+ select IRQ_WORK
bool
config CPU_FREQ_BOOST_SW
@@ -296,6 +297,7 @@ endif
config QORIQ_CPUFREQ
tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
depends on OF && COMMON_CLK && (PPC_E500MC || ARM)
+ depends on !CPU_THERMAL || THERMAL
select CLK_QORIQ
help
This adds the CPUFreq driver support for Freescale QorIQ SoCs
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0031069b64c9..14b1f9393b05 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -84,10 +84,10 @@ config ARM_KIRKWOOD_CPUFREQ
SoCs.
config ARM_MT8173_CPUFREQ
- bool "Mediatek MT8173 CPUFreq support"
+ tristate "Mediatek MT8173 CPUFreq support"
depends on ARCH_MEDIATEK && REGULATOR
depends on ARM64 || (ARM_CPU_TOPOLOGY && COMPILE_TEST)
- depends on !CPU_THERMAL || THERMAL=y
+ depends on !CPU_THERMAL || THERMAL
select PM_OPP
help
This adds the CPUFreq driver support for Mediatek MT8173 SoC.
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 51eef87bbc37..59a7b380fbe2 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -70,6 +70,8 @@ struct acpi_cpufreq_data {
unsigned int cpu_feature;
unsigned int acpi_perf_cpu;
cpumask_var_t freqdomain_cpus;
+ void (*cpu_freq_write)(struct acpi_pct_register *reg, u32 val);
+ u32 (*cpu_freq_read)(struct acpi_pct_register *reg);
};
/* acpi_perf_data is a pointer to percpu data. */
@@ -243,125 +245,119 @@ static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data)
}
}
-struct msr_addr {
- u32 reg;
-};
+u32 cpu_freq_read_intel(struct acpi_pct_register *not_used)
+{
+ u32 val, dummy;
-struct io_addr {
- u16 port;
- u8 bit_width;
-};
+ rdmsr(MSR_IA32_PERF_CTL, val, dummy);
+ return val;
+}
+
+void cpu_freq_write_intel(struct acpi_pct_register *not_used, u32 val)
+{
+ u32 lo, hi;
+
+ rdmsr(MSR_IA32_PERF_CTL, lo, hi);
+ lo = (lo & ~INTEL_MSR_RANGE) | (val & INTEL_MSR_RANGE);
+ wrmsr(MSR_IA32_PERF_CTL, lo, hi);
+}
+
+u32 cpu_freq_read_amd(struct acpi_pct_register *not_used)
+{
+ u32 val, dummy;
+
+ rdmsr(MSR_AMD_PERF_CTL, val, dummy);
+ return val;
+}
+
+void cpu_freq_write_amd(struct acpi_pct_register *not_used, u32 val)
+{
+ wrmsr(MSR_AMD_PERF_CTL, val, 0);
+}
+
+u32 cpu_freq_read_io(struct acpi_pct_register *reg)
+{
+ u32 val;
+
+ acpi_os_read_port(reg->address, &val, reg->bit_width);
+ return val;
+}
+
+void cpu_freq_write_io(struct acpi_pct_register *reg, u32 val)
+{
+ acpi_os_write_port(reg->address, val, reg->bit_width);
+}
struct drv_cmd {
- unsigned int type;
- const struct cpumask *mask;
- union {
- struct msr_addr msr;
- struct io_addr io;
- } addr;
+ struct acpi_pct_register *reg;
u32 val;
+ union {
+ void (*write)(struct acpi_pct_register *reg, u32 val);
+ u32 (*read)(struct acpi_pct_register *reg);
+ } func;
};
/* Called via smp_call_function_single(), on the target CPU */
static void do_drv_read(void *_cmd)
{
struct drv_cmd *cmd = _cmd;
- u32 h;
- switch (cmd->type) {
- case SYSTEM_INTEL_MSR_CAPABLE:
- case SYSTEM_AMD_MSR_CAPABLE:
- rdmsr(cmd->addr.msr.reg, cmd->val, h);
- break;
- case SYSTEM_IO_CAPABLE:
- acpi_os_read_port((acpi_io_address)cmd->addr.io.port,
- &cmd->val,
- (u32)cmd->addr.io.bit_width);
- break;
- default:
- break;
- }
+ cmd->val = cmd->func.read(cmd->reg);
}
-/* Called via smp_call_function_many(), on the target CPUs */
-static void do_drv_write(void *_cmd)
+static u32 drv_read(struct acpi_cpufreq_data *data, const struct cpumask *mask)
{
- struct drv_cmd *cmd = _cmd;
- u32 lo, hi;
+ struct acpi_processor_performance *perf = to_perf_data(data);
+ struct drv_cmd cmd = {
+ .reg = &perf->control_register,
+ .func.read = data->cpu_freq_read,
+ };
+ int err;
- switch (cmd->type) {
- case SYSTEM_INTEL_MSR_CAPABLE:
- rdmsr(cmd->addr.msr.reg, lo, hi);
- lo = (lo & ~INTEL_MSR_RANGE) | (cmd->val & INTEL_MSR_RANGE);
- wrmsr(cmd->addr.msr.reg, lo, hi);
- break;
- case SYSTEM_AMD_MSR_CAPABLE:
- wrmsr(cmd->addr.msr.reg, cmd->val, 0);
- break;
- case SYSTEM_IO_CAPABLE:
- acpi_os_write_port((acpi_io_address)cmd->addr.io.port,
- cmd->val,
- (u32)cmd->addr.io.bit_width);
- break;
- default:
- break;
- }
+ err = smp_call_function_any(mask, do_drv_read, &cmd, 1);
+ WARN_ON_ONCE(err); /* smp_call_function_any() was buggy? */
+ return cmd.val;
}
-static void drv_read(struct drv_cmd *cmd)
+/* Called via smp_call_function_many(), on the target CPUs */
+static void do_drv_write(void *_cmd)
{
- int err;
- cmd->val = 0;
+ struct drv_cmd *cmd = _cmd;
- err = smp_call_function_any(cmd->mask, do_drv_read, cmd, 1);
- WARN_ON_ONCE(err); /* smp_call_function_any() was buggy? */
+ cmd->func.write(cmd->reg, cmd->val);
}
-static void drv_write(struct drv_cmd *cmd)
+static void drv_write(struct acpi_cpufreq_data *data,
+ const struct cpumask *mask, u32 val)
{
+ struct acpi_processor_performance *perf = to_perf_data(data);
+ struct drv_cmd cmd = {
+ .reg = &perf->control_register,
+ .val = val,
+ .func.write = data->cpu_freq_write,
+ };
int this_cpu;
this_cpu = get_cpu();
- if (cpumask_test_cpu(this_cpu, cmd->mask))
- do_drv_write(cmd);
- smp_call_function_many(cmd->mask, do_drv_write, cmd, 1);
+ if (cpumask_test_cpu(this_cpu, mask))
+ do_drv_write(&cmd);
+
+ smp_call_function_many(mask, do_drv_write, &cmd, 1);
put_cpu();
}
-static u32
-get_cur_val(const struct cpumask *mask, struct acpi_cpufreq_data *data)
+static u32 get_cur_val(const struct cpumask *mask, struct acpi_cpufreq_data *data)
{
- struct acpi_processor_performance *perf;
- struct drv_cmd cmd;
+ u32 val;
if (unlikely(cpumask_empty(mask)))
return 0;
- switch (data->cpu_feature) {
- case SYSTEM_INTEL_MSR_CAPABLE:
- cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
- cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
- break;
- case SYSTEM_AMD_MSR_CAPABLE:
- cmd.type = SYSTEM_AMD_MSR_CAPABLE;
- cmd.addr.msr.reg = MSR_AMD_PERF_CTL;
- break;
- case SYSTEM_IO_CAPABLE:
- cmd.type = SYSTEM_IO_CAPABLE;
- perf = to_perf_data(data);
- cmd.addr.io.port = perf->control_register.address;
- cmd.addr.io.bit_width = perf->control_register.bit_width;
- break;
- default:
- return 0;
- }
-
- cmd.mask = mask;
- drv_read(&cmd);
+ val = drv_read(data, mask);
- pr_debug("get_cur_val = %u\n", cmd.val);
+ pr_debug("get_cur_val = %u\n", val);
- return cmd.val;
+ return val;
}
static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
@@ -416,7 +412,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
{
struct acpi_cpufreq_data *data = policy->driver_data;
struct acpi_processor_performance *perf;
- struct drv_cmd cmd;
+ const struct cpumask *mask;
unsigned int next_perf_state = 0; /* Index into perf table */
int result = 0;
@@ -434,42 +430,21 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
} else {
pr_debug("Already at target state (P%d)\n",
next_perf_state);
- goto out;
+ return 0;
}
}
- switch (data->cpu_feature) {
- case SYSTEM_INTEL_MSR_CAPABLE:
- cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
- cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
- cmd.val = (u32) perf->states[next_perf_state].control;
- break;
- case SYSTEM_AMD_MSR_CAPABLE:
- cmd.type = SYSTEM_AMD_MSR_CAPABLE;
- cmd.addr.msr.reg = MSR_AMD_PERF_CTL;
- cmd.val = (u32) perf->states[next_perf_state].control;
- break;
- case SYSTEM_IO_CAPABLE:
- cmd.type = SYSTEM_IO_CAPABLE;
- cmd.addr.io.port = perf->control_register.address;
- cmd.addr.io.bit_width = perf->control_register.bit_width;
- cmd.val = (u32) perf->states[next_perf_state].control;
- break;
- default:
- result = -ENODEV;
- goto out;
- }
-
- /* cpufreq holds the hotplug lock, so we are safe from here on */
- if (policy->shared_type != CPUFREQ_SHARED_TYPE_ANY)
- cmd.mask = policy->cpus;
- else
- cmd.mask = cpumask_of(policy->cpu);
+ /*
+ * The core won't allow CPUs to go away until the governor has been
+ * stopped, so we can rely on the stability of policy->cpus.
+ */
+ mask = policy->shared_type == CPUFREQ_SHARED_TYPE_ANY ?
+ cpumask_of(policy->cpu) : policy->cpus;
- drv_write(&cmd);
+ drv_write(data, mask, perf->states[next_perf_state].control);
if (acpi_pstate_strict) {
- if (!check_freqs(cmd.mask, data->freq_table[index].frequency,
+ if (!check_freqs(mask, data->freq_table[index].frequency,
data)) {
pr_debug("acpi_cpufreq_target failed (%d)\n",
policy->cpu);
@@ -480,7 +455,6 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
if (!result)
perf->state = next_perf_state;
-out:
return result;
}
@@ -740,15 +714,21 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
}
pr_debug("SYSTEM IO addr space\n");
data->cpu_feature = SYSTEM_IO_CAPABLE;
+ data->cpu_freq_read = cpu_freq_read_io;
+ data->cpu_freq_write = cpu_freq_write_io;
break;
case ACPI_ADR_SPACE_FIXED_HARDWARE:
pr_debug("HARDWARE addr space\n");
if (check_est_cpu(cpu)) {
data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
+ data->cpu_freq_read = cpu_freq_read_intel;
+ data->cpu_freq_write = cpu_freq_write_intel;
break;
}
if (check_amd_hwpstate_cpu(cpu)) {
data->cpu_feature = SYSTEM_AMD_MSR_CAPABLE;
+ data->cpu_freq_read = cpu_freq_read_amd;
+ data->cpu_freq_write = cpu_freq_write_amd;
break;
}
result = -ENODEV;
diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c
index f6b79ab0070b..404360cad25c 100644
--- a/drivers/cpufreq/amd_freq_sensitivity.c
+++ b/drivers/cpufreq/amd_freq_sensitivity.c
@@ -21,7 +21,7 @@
#include <asm/msr.h>
#include <asm/cpufeature.h>
-#include "cpufreq_governor.h"
+#include "cpufreq_ondemand.h"
#define MSR_AMD64_FREQ_SENSITIVITY_ACTUAL 0xc0010080
#define MSR_AMD64_FREQ_SENSITIVITY_REFERENCE 0xc0010081
@@ -45,10 +45,10 @@ static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy,
long d_actual, d_reference;
struct msr actual, reference;
struct cpu_data_t *data = &per_cpu(cpu_data, policy->cpu);
- struct dbs_data *od_data = policy->governor_data;
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
+ struct dbs_data *od_data = policy_dbs->dbs_data;
struct od_dbs_tuners *od_tuners = od_data->tuners;
- struct od_cpu_dbs_info_s *od_info =
- od_data->cdata->get_cpu_dbs_info_s(policy->cpu);
+ struct od_policy_dbs_info *od_info = to_dbs_info(policy_dbs);
if (!od_info->freq_table)
return freq_next;
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index 0ca74d070058..f951f911786e 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -31,9 +31,8 @@
struct private_data {
struct device *cpu_dev;
- struct regulator *cpu_reg;
struct thermal_cooling_device *cdev;
- unsigned int voltage_tolerance; /* in percentage */
+ const char *reg_name;
};
static struct freq_attr *cpufreq_dt_attr[] = {
@@ -44,175 +43,128 @@ static struct freq_attr *cpufreq_dt_attr[] = {
static int set_target(struct cpufreq_policy *policy, unsigned int index)
{
- struct dev_pm_opp *opp;
- struct cpufreq_frequency_table *freq_table = policy->freq_table;
- struct clk *cpu_clk = policy->clk;
struct private_data *priv = policy->driver_data;
- struct device *cpu_dev = priv->cpu_dev;
- struct regulator *cpu_reg = priv->cpu_reg;
- unsigned long volt = 0, tol = 0;
- int volt_old = 0;
- unsigned int old_freq, new_freq;
- long freq_Hz, freq_exact;
- int ret;
-
- freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
- if (freq_Hz <= 0)
- freq_Hz = freq_table[index].frequency * 1000;
- freq_exact = freq_Hz;
- new_freq = freq_Hz / 1000;
- old_freq = clk_get_rate(cpu_clk) / 1000;
+ return dev_pm_opp_set_rate(priv->cpu_dev,
+ policy->freq_table[index].frequency * 1000);
+}
- if (!IS_ERR(cpu_reg)) {
- unsigned long opp_freq;
+/*
+ * An earlier version of opp-v1 bindings used to name the regulator
+ * "cpu0-supply", we still need to handle that for backwards compatibility.
+ */
+static const char *find_supply_name(struct device *dev)
+{
+ struct device_node *np;
+ struct property *pp;
+ int cpu = dev->id;
+ const char *name = NULL;
- rcu_read_lock();
- opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
- if (IS_ERR(opp)) {
- rcu_read_unlock();
- dev_err(cpu_dev, "failed to find OPP for %ld\n",
- freq_Hz);
- return PTR_ERR(opp);
- }
- volt = dev_pm_opp_get_voltage(opp);
- opp_freq = dev_pm_opp_get_freq(opp);
- rcu_read_unlock();
- tol = volt * priv->voltage_tolerance / 100;
- volt_old = regulator_get_voltage(cpu_reg);
- dev_dbg(cpu_dev, "Found OPP: %ld kHz, %ld uV\n",
- opp_freq / 1000, volt);
- }
+ np = of_node_get(dev->of_node);
- dev_dbg(cpu_dev, "%u MHz, %d mV --> %u MHz, %ld mV\n",
- old_freq / 1000, (volt_old > 0) ? volt_old / 1000 : -1,
- new_freq / 1000, volt ? volt / 1000 : -1);
+ /* This must be valid for sure */
+ if (WARN_ON(!np))
+ return NULL;
- /* scaling up? scale voltage before frequency */
- if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
- ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
- if (ret) {
- dev_err(cpu_dev, "failed to scale voltage up: %d\n",
- ret);
- return ret;
+ /* Try "cpu0" for older DTs */
+ if (!cpu) {
+ pp = of_find_property(np, "cpu0-supply", NULL);
+ if (pp) {
+ name = "cpu0";
+ goto node_put;
}
}
- ret = clk_set_rate(cpu_clk, freq_exact);
- if (ret) {
- dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
- if (!IS_ERR(cpu_reg) && volt_old > 0)
- regulator_set_voltage_tol(cpu_reg, volt_old, tol);
- return ret;
+ pp = of_find_property(np, "cpu-supply", NULL);
+ if (pp) {
+ name = "cpu";
+ goto node_put;
}
- /* scaling down? scale voltage after frequency */
- if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
- ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
- if (ret) {
- dev_err(cpu_dev, "failed to scale voltage down: %d\n",
- ret);
- clk_set_rate(cpu_clk, old_freq * 1000);
- }
- }
-
- return ret;
+ dev_dbg(dev, "no regulator for cpu%d\n", cpu);
+node_put:
+ of_node_put(np);
+ return name;
}
-static int allocate_resources(int cpu, struct device **cdev,
- struct regulator **creg, struct clk **cclk)
+static int resources_available(void)
{
struct device *cpu_dev;
struct regulator *cpu_reg;
struct clk *cpu_clk;
int ret = 0;
- char *reg_cpu0 = "cpu0", *reg_cpu = "cpu", *reg;
+ const char *name;
- cpu_dev = get_cpu_device(cpu);
+ cpu_dev = get_cpu_device(0);
if (!cpu_dev) {
- pr_err("failed to get cpu%d device\n", cpu);
+ pr_err("failed to get cpu0 device\n");
return -ENODEV;
}
- /* Try "cpu0" for older DTs */
- if (!cpu)
- reg = reg_cpu0;
- else
- reg = reg_cpu;
-
-try_again:
- cpu_reg = regulator_get_optional(cpu_dev, reg);
- ret = PTR_ERR_OR_ZERO(cpu_reg);
+ cpu_clk = clk_get(cpu_dev, NULL);
+ ret = PTR_ERR_OR_ZERO(cpu_clk);
if (ret) {
/*
- * If cpu's regulator supply node is present, but regulator is
- * not yet registered, we should try defering probe.
+ * If cpu's clk node is present, but clock is not yet
+ * registered, we should try defering probe.
*/
- if (ret == -EPROBE_DEFER) {
- dev_dbg(cpu_dev, "cpu%d regulator not ready, retry\n",
- cpu);
- return ret;
- }
-
- /* Try with "cpu-supply" */
- if (reg == reg_cpu0) {
- reg = reg_cpu;
- goto try_again;
- }
+ if (ret == -EPROBE_DEFER)
+ dev_dbg(cpu_dev, "clock not ready, retry\n");
+ else
+ dev_err(cpu_dev, "failed to get clock: %d\n", ret);
- dev_dbg(cpu_dev, "no regulator for cpu%d: %d\n", cpu, ret);
+ return ret;
}
- cpu_clk = clk_get(cpu_dev, NULL);
- ret = PTR_ERR_OR_ZERO(cpu_clk);
- if (ret) {
- /* put regulator */
- if (!IS_ERR(cpu_reg))
- regulator_put(cpu_reg);
+ clk_put(cpu_clk);
+ name = find_supply_name(cpu_dev);
+ /* Platform doesn't require regulator */
+ if (!name)
+ return 0;
+
+ cpu_reg = regulator_get_optional(cpu_dev, name);
+ ret = PTR_ERR_OR_ZERO(cpu_reg);
+ if (ret) {
/*
- * If cpu's clk node is present, but clock is not yet
- * registered, we should try defering probe.
+ * If cpu's regulator supply node is present, but regulator is
+ * not yet registered, we should try defering probe.
*/
if (ret == -EPROBE_DEFER)
- dev_dbg(cpu_dev, "cpu%d clock not ready, retry\n", cpu);
+ dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n");
else
- dev_err(cpu_dev, "failed to get cpu%d clock: %d\n", cpu,
- ret);
- } else {
- *cdev = cpu_dev;
- *creg = cpu_reg;
- *cclk = cpu_clk;
+ dev_dbg(cpu_dev, "no regulator for cpu0: %d\n", ret);
+
+ return ret;
}
- return ret;
+ regulator_put(cpu_reg);
+ return 0;
}
static int cpufreq_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *freq_table;
- struct device_node *np;
struct private_data *priv;
struct device *cpu_dev;
- struct regulator *cpu_reg;
struct clk *cpu_clk;
struct dev_pm_opp *suspend_opp;
- unsigned long min_uV = ~0, max_uV = 0;
unsigned int transition_latency;
- bool need_update = false;
+ bool opp_v1 = false;
+ const char *name;
int ret;
- ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk);
- if (ret) {
- pr_err("%s: Failed to allocate resources: %d\n", __func__, ret);
- return ret;
+ cpu_dev = get_cpu_device(policy->cpu);
+ if (!cpu_dev) {
+ pr_err("failed to get cpu%d device\n", policy->cpu);
+ return -ENODEV;
}
- np = of_node_get(cpu_dev->of_node);
- if (!np) {
- dev_err(cpu_dev, "failed to find cpu%d node\n", policy->cpu);
- ret = -ENOENT;
- goto out_put_reg_clk;
+ cpu_clk = clk_get(cpu_dev, NULL);
+ if (IS_ERR(cpu_clk)) {
+ ret = PTR_ERR(cpu_clk);
+ dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret);
+ return ret;
}
/* Get OPP-sharing information from "operating-points-v2" bindings */
@@ -223,9 +175,23 @@ static int cpufreq_init(struct cpufreq_policy *policy)
* finding shared-OPPs for backward compatibility.
*/
if (ret == -ENOENT)
- need_update = true;
+ opp_v1 = true;
else
- goto out_node_put;
+ goto out_put_clk;
+ }
+
+ /*
+ * OPP layer will be taking care of regulators now, but it needs to know
+ * the name of the regulator first.
+ */
+ name = find_supply_name(cpu_dev);
+ if (name) {
+ ret = dev_pm_opp_set_regulator(cpu_dev, name);
+ if (ret) {
+ dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n",
+ policy->cpu, ret);
+ goto out_put_clk;
+ }
}
/*
@@ -246,12 +212,12 @@ static int cpufreq_init(struct cpufreq_policy *policy)
*/
ret = dev_pm_opp_get_opp_count(cpu_dev);
if (ret <= 0) {
- pr_debug("OPP table is not ready, deferring probe\n");
+ dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n");
ret = -EPROBE_DEFER;
goto out_free_opp;
}
- if (need_update) {
+ if (opp_v1) {
struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data();
if (!pd || !pd->independent_clocks)
@@ -265,10 +231,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
if (ret)
dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
__func__, ret);
-
- of_property_read_u32(np, "clock-latency", &transition_latency);
- } else {
- transition_latency = dev_pm_opp_get_max_clock_latency(cpu_dev);
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -277,62 +239,16 @@ static int cpufreq_init(struct cpufreq_policy *policy)
goto out_free_opp;
}
- of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);
-
- if (!transition_latency)
- transition_latency = CPUFREQ_ETERNAL;
-
- if (!IS_ERR(cpu_reg)) {
- unsigned long opp_freq = 0;
-
- /*
- * Disable any OPPs where the connected regulator isn't able to
- * provide the specified voltage and record minimum and maximum
- * voltage levels.
- */
- while (1) {
- struct dev_pm_opp *opp;
- unsigned long opp_uV, tol_uV;
-
- rcu_read_lock();
- opp = dev_pm_opp_find_freq_ceil(cpu_dev, &opp_freq);
- if (IS_ERR(opp)) {
- rcu_read_unlock();
- break;
- }
- opp_uV = dev_pm_opp_get_voltage(opp);
- rcu_read_unlock();
-
- tol_uV = opp_uV * priv->voltage_tolerance / 100;
- if (regulator_is_supported_voltage(cpu_reg,
- opp_uV - tol_uV,
- opp_uV + tol_uV)) {
- if (opp_uV < min_uV)
- min_uV = opp_uV;
- if (opp_uV > max_uV)
- max_uV = opp_uV;
- } else {
- dev_pm_opp_disable(cpu_dev, opp_freq);
- }
-
- opp_freq++;
- }
-
- ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
- if (ret > 0)
- transition_latency += ret * 1000;
- }
+ priv->reg_name = name;
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
if (ret) {
- pr_err("failed to init cpufreq table: %d\n", ret);
+ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
goto out_free_priv;
}
priv->cpu_dev = cpu_dev;
- priv->cpu_reg = cpu_reg;
policy->driver_data = priv;
-
policy->clk = cpu_clk;
rcu_read_lock();
@@ -357,9 +273,11 @@ static int cpufreq_init(struct cpufreq_policy *policy)
cpufreq_dt_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs;
}
- policy->cpuinfo.transition_latency = transition_latency;
+ transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev);
+ if (!transition_latency)
+ transition_latency = CPUFREQ_ETERNAL;
- of_node_put(np);
+ policy->cpuinfo.transition_latency = transition_latency;
return 0;
@@ -369,12 +287,10 @@ out_free_priv:
kfree(priv);
out_free_opp:
dev_pm_opp_of_cpumask_remove_table(policy->cpus);
-out_node_put:
- of_node_put(np);
-out_put_reg_clk:
+ if (name)
+ dev_pm_opp_put_regulator(cpu_dev);
+out_put_clk:
clk_put(cpu_clk);
- if (!IS_ERR(cpu_reg))
- regulator_put(cpu_reg);
return ret;
}
@@ -386,9 +302,10 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
cpufreq_cooling_unregister(priv->cdev);
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
+ if (priv->reg_name)
+ dev_pm_opp_put_regulator(priv->cpu_dev);
+
clk_put(policy->clk);
- if (!IS_ERR(priv->cpu_reg))
- regulator_put(priv->cpu_reg);
kfree(priv);
return 0;
@@ -441,9 +358,6 @@ static struct cpufreq_driver dt_cpufreq_driver = {
static int dt_cpufreq_probe(struct platform_device *pdev)
{
- struct device *cpu_dev;
- struct regulator *cpu_reg;
- struct clk *cpu_clk;
int ret;
/*
@@ -453,19 +367,15 @@ static int dt_cpufreq_probe(struct platform_device *pdev)
*
* FIXME: Is checking this only for CPU0 sufficient ?
*/
- ret = allocate_resources(0, &cpu_dev, &cpu_reg, &cpu_clk);
+ ret = resources_available();
if (ret)
return ret;
- clk_put(cpu_clk);
- if (!IS_ERR(cpu_reg))
- regulator_put(cpu_reg);
-
dt_cpufreq_driver.driver_data = dev_get_platdata(&pdev->dev);
ret = cpufreq_register_driver(&dt_cpufreq_driver);
if (ret)
- dev_err(cpu_dev, "failed register driver: %d\n", ret);
+ dev_err(&pdev->dev, "failed register driver: %d\n", ret);
return ret;
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index e979ec78b695..4c7825856eab 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -38,48 +38,10 @@ static inline bool policy_is_inactive(struct cpufreq_policy *policy)
return cpumask_empty(policy->cpus);
}
-static bool suitable_policy(struct cpufreq_policy *policy, bool active)
-{
- return active == !policy_is_inactive(policy);
-}
-
-/* Finds Next Acive/Inactive policy */
-static struct cpufreq_policy *next_policy(struct cpufreq_policy *policy,
- bool active)
-{
- do {
- /* No more policies in the list */
- if (list_is_last(&policy->policy_list, &cpufreq_policy_list))
- return NULL;
-
- policy = list_next_entry(policy, policy_list);
- } while (!suitable_policy(policy, active));
-
- return policy;
-}
-
-static struct cpufreq_policy *first_policy(bool active)
-{
- struct cpufreq_policy *policy;
-
- /* No policies in the list */
- if (list_empty(&cpufreq_policy_list))
- return NULL;
-
- policy = list_first_entry(&cpufreq_policy_list, typeof(*policy),
- policy_list);
-
- if (!suitable_policy(policy, active))
- policy = next_policy(policy, active);
-
- return policy;
-}
-
/* Macros to iterate over CPU policies */
-#define for_each_suitable_policy(__policy, __active) \
- for (__policy = first_policy(__active); \
- __policy; \
- __policy = next_policy(__policy, __active))
+#define for_each_suitable_policy(__policy, __active) \
+ list_for_each_entry(__policy, &cpufreq_policy_list, policy_list) \
+ if ((__active) == !policy_is_inactive(__policy))
#define for_each_active_policy(__policy) \
for_each_suitable_policy(__policy, true)
@@ -102,7 +64,6 @@ static LIST_HEAD(cpufreq_governor_list);
static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
static DEFINE_RWLOCK(cpufreq_driver_lock);
-DEFINE_MUTEX(cpufreq_governor_lock);
/* Flag to suspend/resume CPUFreq governors */
static bool cpufreq_suspended;
@@ -113,10 +74,8 @@ static inline bool has_target(void)
}
/* internal prototypes */
-static int __cpufreq_governor(struct cpufreq_policy *policy,
- unsigned int event);
+static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
static unsigned int __cpufreq_get(struct cpufreq_policy *policy);
-static void handle_update(struct work_struct *work);
/**
* Two notifier lists: the "policy" list is involved in the
@@ -818,12 +777,7 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
ssize_t ret;
down_read(&policy->rwsem);
-
- if (fattr->show)
- ret = fattr->show(policy, buf);
- else
- ret = -EIO;
-
+ ret = fattr->show(policy, buf);
up_read(&policy->rwsem);
return ret;
@@ -838,18 +792,12 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
get_online_cpus();
- if (!cpu_online(policy->cpu))
- goto unlock;
-
- down_write(&policy->rwsem);
-
- if (fattr->store)
+ if (cpu_online(policy->cpu)) {
+ down_write(&policy->rwsem);
ret = fattr->store(policy, buf, count);
- else
- ret = -EIO;
+ up_write(&policy->rwsem);
+ }
- up_write(&policy->rwsem);
-unlock:
put_online_cpus();
return ret;
@@ -959,6 +907,11 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy)
return cpufreq_add_dev_symlink(policy);
}
+__weak struct cpufreq_governor *cpufreq_default_governor(void)
+{
+ return NULL;
+}
+
static int cpufreq_init_policy(struct cpufreq_policy *policy)
{
struct cpufreq_governor *gov = NULL;
@@ -968,11 +921,14 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)
/* Update governor of new_policy to the governor used before hotplug */
gov = find_governor(policy->last_governor);
- if (gov)
+ if (gov) {
pr_debug("Restoring governor %s for cpu %d\n",
policy->governor->name, policy->cpu);
- else
- gov = CPUFREQ_DEFAULT_GOVERNOR;
+ } else {
+ gov = cpufreq_default_governor();
+ if (!gov)
+ return -ENODATA;
+ }
new_policy.governor = gov;
@@ -996,36 +952,45 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp
if (cpumask_test_cpu(cpu, policy->cpus))
return 0;
+ down_write(&policy->rwsem);
if (has_target()) {
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_STOP);
if (ret) {
pr_err("%s: Failed to stop governor\n", __func__);
- return ret;
+ goto unlock;
}
}
- down_write(&policy->rwsem);
cpumask_set_cpu(cpu, policy->cpus);
- up_write(&policy->rwsem);
if (has_target()) {
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
if (!ret)
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
- if (ret) {
+ if (ret)
pr_err("%s: Failed to start governor\n", __func__);
- return ret;
- }
}
- return 0;
+unlock:
+ up_write(&policy->rwsem);
+ return ret;
+}
+
+static void handle_update(struct work_struct *work)
+{
+ struct cpufreq_policy *policy =
+ container_of(work, struct cpufreq_policy, update);
+ unsigned int cpu = policy->cpu;
+ pr_debug("handle_update for cpu %u called\n", cpu);
+ cpufreq_update_policy(cpu);
}
static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
{
struct device *dev = get_cpu_device(cpu);
struct cpufreq_policy *policy;
+ int ret;
if (WARN_ON(!dev))
return NULL;
@@ -1043,7 +1008,13 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
goto err_free_rcpumask;
- kobject_init(&policy->kobj, &ktype_cpufreq);
+ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
+ cpufreq_global_kobject, "policy%u", cpu);
+ if (ret) {
+ pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
+ goto err_free_real_cpus;
+ }
+
INIT_LIST_HEAD(&policy->policy_list);
init_rwsem(&policy->rwsem);
spin_lock_init(&policy->transition_lock);
@@ -1054,6 +1025,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
policy->cpu = cpu;
return policy;
+err_free_real_cpus:
+ free_cpumask_var(policy->real_cpus);
err_free_rcpumask:
free_cpumask_var(policy->related_cpus);
err_free_cpumask:
@@ -1158,16 +1131,6 @@ static int cpufreq_online(unsigned int cpu)
cpumask_copy(policy->related_cpus, policy->cpus);
/* Remember CPUs present at the policy creation time. */
cpumask_and(policy->real_cpus, policy->cpus, cpu_present_mask);
-
- /* Name and add the kobject */
- ret = kobject_add(&policy->kobj, cpufreq_global_kobject,
- "policy%u",
- cpumask_first(policy->related_cpus));
- if (ret) {
- pr_err("%s: failed to add policy->kobj: %d\n", __func__,
- ret);
- goto out_exit_policy;
- }
}
/*
@@ -1309,9 +1272,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
return ret;
}
-static void cpufreq_offline_prepare(unsigned int cpu)
+static void cpufreq_offline(unsigned int cpu)
{
struct cpufreq_policy *policy;
+ int ret;
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
@@ -1321,13 +1285,13 @@ static void cpufreq_offline_prepare(unsigned int cpu)
return;
}
+ down_write(&policy->rwsem);
if (has_target()) {
- int ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_STOP);
if (ret)
pr_err("%s: Failed to stop governor\n", __func__);
}
- down_write(&policy->rwsem);
cpumask_clear_cpu(cpu, policy->cpus);
if (policy_is_inactive(policy)) {
@@ -1340,39 +1304,27 @@ static void cpufreq_offline_prepare(unsigned int cpu)
/* Nominate new CPU */
policy->cpu = cpumask_any(policy->cpus);
}
- up_write(&policy->rwsem);
/* Start governor again for active policy */
if (!policy_is_inactive(policy)) {
if (has_target()) {
- int ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
if (!ret)
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
if (ret)
pr_err("%s: Failed to start governor\n", __func__);
}
- } else if (cpufreq_driver->stop_cpu) {
- cpufreq_driver->stop_cpu(policy);
- }
-}
-static void cpufreq_offline_finish(unsigned int cpu)
-{
- struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
-
- if (!policy) {
- pr_debug("%s: No cpu_data found\n", __func__);
- return;
+ goto unlock;
}
- /* Only proceed for inactive policies */
- if (!policy_is_inactive(policy))
- return;
+ if (cpufreq_driver->stop_cpu)
+ cpufreq_driver->stop_cpu(policy);
/* If cpu is last user of policy, free policy */
if (has_target()) {
- int ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
if (ret)
pr_err("%s: Failed to exit governor\n", __func__);
}
@@ -1386,6 +1338,9 @@ static void cpufreq_offline_finish(unsigned int cpu)
cpufreq_driver->exit(policy);
policy->freq_table = NULL;
}
+
+unlock:
+ up_write(&policy->rwsem);
}
/**
@@ -1401,10 +1356,8 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if (!policy)
return;
- if (cpu_online(cpu)) {
- cpufreq_offline_prepare(cpu);
- cpufreq_offline_finish(cpu);
- }
+ if (cpu_online(cpu))
+ cpufreq_offline(cpu);
cpumask_clear_cpu(cpu, policy->real_cpus);
remove_cpu_dev_symlink(policy, cpu);
@@ -1413,15 +1366,6 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
cpufreq_policy_free(policy, true);
}
-static void handle_update(struct work_struct *work)
-{
- struct cpufreq_policy *policy =
- container_of(work, struct cpufreq_policy, update);
- unsigned int cpu = policy->cpu;
- pr_debug("handle_update for cpu %u called\n", cpu);
- cpufreq_update_policy(cpu);
-}
-
/**
* cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're
* in deep trouble.
@@ -1584,6 +1528,7 @@ EXPORT_SYMBOL(cpufreq_generic_suspend);
void cpufreq_suspend(void)
{
struct cpufreq_policy *policy;
+ int ret;
if (!cpufreq_driver)
return;
@@ -1594,7 +1539,11 @@ void cpufreq_suspend(void)
pr_debug("%s: Suspending Governors\n", __func__);
for_each_active_policy(policy) {
- if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP))
+ down_write(&policy->rwsem);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ up_write(&policy->rwsem);
+
+ if (ret)
pr_err("%s: Failed to stop governor for policy: %p\n",
__func__, policy);
else if (cpufreq_driver->suspend
@@ -1616,6 +1565,7 @@ suspend:
void cpufreq_resume(void)
{
struct cpufreq_policy *policy;
+ int ret;
if (!cpufreq_driver)
return;
@@ -1628,13 +1578,20 @@ void cpufreq_resume(void)
pr_debug("%s: Resuming Governors\n", __func__);
for_each_active_policy(policy) {
- if (cpufreq_driver->resume && cpufreq_driver->resume(policy))
+ if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) {
pr_err("%s: Failed to resume driver: %p\n", __func__,
policy);
- else if (__cpufreq_governor(policy, CPUFREQ_GOV_START)
- || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))
- pr_err("%s: Failed to start governor for policy: %p\n",
- __func__, policy);
+ } else {
+ down_write(&policy->rwsem);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
+ if (!ret)
+ cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ up_write(&policy->rwsem);
+
+ if (ret)
+ pr_err("%s: Failed to start governor for policy: %p\n",
+ __func__, policy);
+ }
}
/*
@@ -1846,7 +1803,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int relation)
{
unsigned int old_target_freq = target_freq;
- int retval = -EINVAL;
+ struct cpufreq_frequency_table *freq_table;
+ int index, retval;
if (cpufreq_disabled())
return -ENODEV;
@@ -1873,34 +1831,28 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
policy->restore_freq = policy->cur;
if (cpufreq_driver->target)
- retval = cpufreq_driver->target(policy, target_freq, relation);
- else if (cpufreq_driver->target_index) {
- struct cpufreq_frequency_table *freq_table;
- int index;
-
- freq_table = cpufreq_frequency_get_table(policy->cpu);
- if (unlikely(!freq_table)) {
- pr_err("%s: Unable to find freq_table\n", __func__);
- goto out;
- }
+ return cpufreq_driver->target(policy, target_freq, relation);
- retval = cpufreq_frequency_table_target(policy, freq_table,
- target_freq, relation, &index);
- if (unlikely(retval)) {
- pr_err("%s: Unable to find matching freq\n", __func__);
- goto out;
- }
+ if (!cpufreq_driver->target_index)
+ return -EINVAL;
- if (freq_table[index].frequency == policy->cur) {
- retval = 0;
- goto out;
- }
+ freq_table = cpufreq_frequency_get_table(policy->cpu);
+ if (unlikely(!freq_table)) {
+ pr_err("%s: Unable to find freq_table\n", __func__);
+ return -EINVAL;
+ }
- retval = __target_index(policy, freq_table, index);
+ retval = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+ relation, &index);
+ if (unlikely(retval)) {
+ pr_err("%s: Unable to find matching freq\n", __func__);
+ return retval;
}
-out:
- return retval;
+ if (freq_table[index].frequency == policy->cur)
+ return 0;
+
+ return __target_index(policy, freq_table, index);
}
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
@@ -1920,20 +1872,14 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
-static int __cpufreq_governor(struct cpufreq_policy *policy,
- unsigned int event)
+__weak struct cpufreq_governor *cpufreq_fallback_governor(void)
{
- int ret;
+ return NULL;
+}
- /* Only must be defined when default governor is known to have latency
- restrictions, like e.g. conservative or ondemand.
- That this is the case is already ensured in Kconfig
- */
-#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
- struct cpufreq_governor *gov = &cpufreq_gov_performance;
-#else
- struct cpufreq_governor *gov = NULL;
-#endif
+static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
+{
+ int ret;
/* Don't start any governor operations if we are entering suspend */
if (cpufreq_suspended)
@@ -1948,12 +1894,14 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
if (policy->governor->max_transition_latency &&
policy->cpuinfo.transition_latency >
policy->governor->max_transition_latency) {
- if (!gov)
- return -EINVAL;
- else {
+ struct cpufreq_governor *gov = cpufreq_fallback_governor();
+
+ if (gov) {
pr_warn("%s governor failed, too long transition latency of HW, fallback to %s governor\n",
policy->governor->name, gov->name);
policy->governor = gov;
+ } else {
+ return -EINVAL;
}
}
@@ -1963,21 +1911,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
pr_debug("%s: for CPU %u, event %u\n", __func__, policy->cpu, event);
- mutex_lock(&cpufreq_governor_lock);
- if ((policy->governor_enabled && event == CPUFREQ_GOV_START)
- || (!policy->governor_enabled
- && (event == CPUFREQ_GOV_LIMITS || event == CPUFREQ_GOV_STOP))) {
- mutex_unlock(&cpufreq_governor_lock);
- return -EBUSY;
- }
-
- if (event == CPUFREQ_GOV_STOP)
- policy->governor_enabled = false;
- else if (event == CPUFREQ_GOV_START)
- policy->governor_enabled = true;
-
- mutex_unlock(&cpufreq_governor_lock);
-
ret = policy->governor->governor(policy, event);
if (!ret) {
@@ -1985,14 +1918,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
policy->governor->initialized++;
else if (event == CPUFREQ_GOV_POLICY_EXIT)
policy->governor->initialized--;
- } else {
- /* Restore original values */
- mutex_lock(&cpufreq_governor_lock);
- if (event == CPUFREQ_GOV_STOP)
- policy->governor_enabled = true;
- else if (event == CPUFREQ_GOV_START)
- policy->governor_enabled = false;
- mutex_unlock(&cpufreq_governor_lock);
}
if (((event == CPUFREQ_GOV_POLICY_INIT) && ret) ||
@@ -2147,7 +2072,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
old_gov = policy->governor;
/* end old governor */
if (old_gov) {
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_STOP);
if (ret) {
/* This can happen due to race with other operations */
pr_debug("%s: Failed to Stop Governor: %s (%d)\n",
@@ -2155,10 +2080,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
return ret;
}
- up_write(&policy->rwsem);
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
- down_write(&policy->rwsem);
-
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
if (ret) {
pr_err("%s: Failed to Exit Governor: %s (%d)\n",
__func__, old_gov->name, ret);
@@ -2168,32 +2090,30 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
/* start new governor */
policy->governor = new_policy->governor;
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
if (!ret) {
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
if (!ret)
goto out;
- up_write(&policy->rwsem);
- __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
- down_write(&policy->rwsem);
+ cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
}
/* new governor failed, so re-start old one */
pr_debug("starting governor %s failed\n", policy->governor->name);
if (old_gov) {
policy->governor = old_gov;
- if (__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT))
+ if (cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT))
policy->governor = NULL;
else
- __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ cpufreq_governor(policy, CPUFREQ_GOV_START);
}
return ret;
out:
pr_debug("governor: change or update limits\n");
- return __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ return cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
}
/**
@@ -2260,11 +2180,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
break;
case CPU_DOWN_PREPARE:
- cpufreq_offline_prepare(cpu);
- break;
-
- case CPU_POST_DEAD:
- cpufreq_offline_finish(cpu);
+ cpufreq_offline(cpu);
break;
case CPU_DOWN_FAILED:
@@ -2297,8 +2213,11 @@ static int cpufreq_boost_set_sw(int state)
__func__);
break;
}
+
+ down_write(&policy->rwsem);
policy->user_policy.max = policy->max;
- __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ up_write(&policy->rwsem);
}
}
@@ -2384,7 +2303,7 @@ EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
* submitted by the CPU Frequency driver.
*
* Registers a CPU Frequency driver to this core code. This code
- * returns zero on success, -EBUSY when another driver got here first
+ * returns zero on success, -EEXIST when another driver got here first
* (and isn't unregistered in the meantime).
*
*/
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 606ad74abe6e..bf4913f6453b 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -14,6 +14,22 @@
#include <linux/slab.h>
#include "cpufreq_governor.h"
+struct cs_policy_dbs_info {
+ struct policy_dbs_info policy_dbs;
+ unsigned int down_skip;
+ unsigned int requested_freq;
+};
+
+static inline struct cs_policy_dbs_info *to_dbs_info(struct policy_dbs_info *policy_dbs)
+{
+ return container_of(policy_dbs, struct cs_policy_dbs_info, policy_dbs);
+}
+
+struct cs_dbs_tuners {
+ unsigned int down_threshold;
+ unsigned int freq_step;
+};
+
/* Conservative governor macros */
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
@@ -21,21 +37,6 @@
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (10)
-static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info);
-
-static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
- unsigned int event);
-
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
-static
-#endif
-struct cpufreq_governor cpufreq_gov_conservative = {
- .name = "conservative",
- .governor = cs_cpufreq_governor_dbs,
- .max_transition_latency = TRANSITION_LATENCY_LIMIT,
- .owner = THIS_MODULE,
-};
-
static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
struct cpufreq_policy *policy)
{
@@ -57,27 +58,28 @@ static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
* Any frequency increase takes it to the maximum frequency. Frequency reduction
* happens at minimum steps of 5% (default) of maximum frequency
*/
-static void cs_check_cpu(int cpu, unsigned int load)
+static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
{
- struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu);
- struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy;
- struct dbs_data *dbs_data = policy->governor_data;
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
+ struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
+ struct dbs_data *dbs_data = policy_dbs->dbs_data;
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
+ unsigned int load = dbs_update(policy);
/*
* break out if we 'cannot' reduce the speed as the user might
* want freq_step to be zero
*/
if (cs_tuners->freq_step == 0)
- return;
+ goto out;
/* Check for frequency increase */
- if (load > cs_tuners->up_threshold) {
+ if (load > dbs_data->up_threshold) {
dbs_info->down_skip = 0;
/* if we are already at full speed then break out early */
if (dbs_info->requested_freq == policy->max)
- return;
+ goto out;
dbs_info->requested_freq += get_freq_target(cs_tuners, policy);
@@ -86,12 +88,12 @@ static void cs_check_cpu(int cpu, unsigned int load)
__cpufreq_driver_target(policy, dbs_info->requested_freq,
CPUFREQ_RELATION_H);
- return;
+ goto out;
}
/* if sampling_down_factor is active break out early */
- if (++dbs_info->down_skip < cs_tuners->sampling_down_factor)
- return;
+ if (++dbs_info->down_skip < dbs_data->sampling_down_factor)
+ goto out;
dbs_info->down_skip = 0;
/* Check for frequency decrease */
@@ -101,7 +103,7 @@ static void cs_check_cpu(int cpu, unsigned int load)
* if we cannot reduce the frequency anymore, break out early
*/
if (policy->cur == policy->min)
- return;
+ goto out;
freq_target = get_freq_target(cs_tuners, policy);
if (dbs_info->requested_freq > freq_target)
@@ -111,58 +113,25 @@ static void cs_check_cpu(int cpu, unsigned int load)
__cpufreq_driver_target(policy, dbs_info->requested_freq,
CPUFREQ_RELATION_L);
- return;
}
-}
-
-static unsigned int cs_dbs_timer(struct cpufreq_policy *policy, bool modify_all)
-{
- struct dbs_data *dbs_data = policy->governor_data;
- struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
-
- if (modify_all)
- dbs_check_cpu(dbs_data, policy->cpu);
- return delay_for_sampling_rate(cs_tuners->sampling_rate);
+ out:
+ return dbs_data->sampling_rate;
}
static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- struct cpufreq_freqs *freq = data;
- struct cs_cpu_dbs_info_s *dbs_info =
- &per_cpu(cs_cpu_dbs_info, freq->cpu);
- struct cpufreq_policy *policy = cpufreq_cpu_get_raw(freq->cpu);
-
- if (!policy)
- return 0;
-
- /* policy isn't governed by conservative governor */
- if (policy->governor != &cpufreq_gov_conservative)
- return 0;
-
- /*
- * we only care if our internally tracked freq moves outside the 'valid'
- * ranges of frequency available to us otherwise we do not change it
- */
- if (dbs_info->requested_freq > policy->max
- || dbs_info->requested_freq < policy->min)
- dbs_info->requested_freq = freq->new;
-
- return 0;
-}
+ void *data);
static struct notifier_block cs_cpufreq_notifier_block = {
.notifier_call = dbs_cpufreq_notifier,
};
/************************** sysfs interface ************************/
-static struct common_dbs_data cs_dbs_cdata;
+static struct dbs_governor cs_dbs_gov;
static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
const char *buf, size_t count)
{
- struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
@@ -170,22 +139,7 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
return -EINVAL;
- cs_tuners->sampling_down_factor = input;
- return count;
-}
-
-static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
- size_t count)
-{
- struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
- unsigned int input;
- int ret;
- ret = sscanf(buf, "%u", &input);
-
- if (ret != 1)
- return -EINVAL;
-
- cs_tuners->sampling_rate = max(input, dbs_data->min_sampling_rate);
+ dbs_data->sampling_down_factor = input;
return count;
}
@@ -200,7 +154,7 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
if (ret != 1 || input > 100 || input <= cs_tuners->down_threshold)
return -EINVAL;
- cs_tuners->up_threshold = input;
+ dbs_data->up_threshold = input;
return count;
}
@@ -214,7 +168,7 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
/* cannot be lower than 11 otherwise freq will not fall */
if (ret != 1 || input < 11 || input > 100 ||
- input >= cs_tuners->up_threshold)
+ input >= dbs_data->up_threshold)
return -EINVAL;
cs_tuners->down_threshold = input;
@@ -224,8 +178,7 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
const char *buf, size_t count)
{
- struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
- unsigned int input, j;
+ unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
@@ -235,21 +188,14 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
if (input > 1)
input = 1;
- if (input == cs_tuners->ignore_nice_load) /* nothing to do */
+ if (input == dbs_data->ignore_nice_load) /* nothing to do */
return count;
- cs_tuners->ignore_nice_load = input;
+ dbs_data->ignore_nice_load = input;
/* we need to re-evaluate prev_cpu_idle */
- for_each_online_cpu(j) {
- struct cs_cpu_dbs_info_s *dbs_info;
- dbs_info = &per_cpu(cs_cpu_dbs_info, j);
- dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
- &dbs_info->cdbs.prev_cpu_wall, 0);
- if (cs_tuners->ignore_nice_load)
- dbs_info->cdbs.prev_cpu_nice =
- kcpustat_cpu(j).cpustat[CPUTIME_NICE];
- }
+ gov_update_cpu_data(dbs_data);
+
return count;
}
@@ -275,55 +221,47 @@ static ssize_t store_freq_step(struct dbs_data *dbs_data, const char *buf,
return count;
}
-show_store_one(cs, sampling_rate);
-show_store_one(cs, sampling_down_factor);
-show_store_one(cs, up_threshold);
-show_store_one(cs, down_threshold);
-show_store_one(cs, ignore_nice_load);
-show_store_one(cs, freq_step);
-declare_show_sampling_rate_min(cs);
-
-gov_sys_pol_attr_rw(sampling_rate);
-gov_sys_pol_attr_rw(sampling_down_factor);
-gov_sys_pol_attr_rw(up_threshold);
-gov_sys_pol_attr_rw(down_threshold);
-gov_sys_pol_attr_rw(ignore_nice_load);
-gov_sys_pol_attr_rw(freq_step);
-gov_sys_pol_attr_ro(sampling_rate_min);
-
-static struct attribute *dbs_attributes_gov_sys[] = {
- &sampling_rate_min_gov_sys.attr,
- &sampling_rate_gov_sys.attr,
- &sampling_down_factor_gov_sys.attr,
- &up_threshold_gov_sys.attr,
- &down_threshold_gov_sys.attr,
- &ignore_nice_load_gov_sys.attr,
- &freq_step_gov_sys.attr,
+gov_show_one_common(sampling_rate);
+gov_show_one_common(sampling_down_factor);
+gov_show_one_common(up_threshold);
+gov_show_one_common(ignore_nice_load);
+gov_show_one_common(min_sampling_rate);
+gov_show_one(cs, down_threshold);
+gov_show_one(cs, freq_step);
+
+gov_attr_rw(sampling_rate);
+gov_attr_rw(sampling_down_factor);
+gov_attr_rw(up_threshold);
+gov_attr_rw(ignore_nice_load);
+gov_attr_ro(min_sampling_rate);
+gov_attr_rw(down_threshold);
+gov_attr_rw(freq_step);
+
+static struct attribute *cs_attributes[] = {
+ &min_sampling_rate.attr,
+ &sampling_rate.attr,
+ &sampling_down_factor.attr,
+ &up_threshold.attr,
+ &down_threshold.attr,
+ &ignore_nice_load.attr,
+ &freq_step.attr,
NULL
};
-static struct attribute_group cs_attr_group_gov_sys = {
- .attrs = dbs_attributes_gov_sys,
- .name = "conservative",
-};
+/************************** sysfs end ************************/
-static struct attribute *dbs_attributes_gov_pol[] = {
- &sampling_rate_min_gov_pol.attr,
- &sampling_rate_gov_pol.attr,
- &sampling_down_factor_gov_pol.attr,
- &up_threshold_gov_pol.attr,
- &down_threshold_gov_pol.attr,
- &ignore_nice_load_gov_pol.attr,
- &freq_step_gov_pol.attr,
- NULL
-};
+static struct policy_dbs_info *cs_alloc(void)
+{
+ struct cs_policy_dbs_info *dbs_info;
-static struct attribute_group cs_attr_group_gov_pol = {
- .attrs = dbs_attributes_gov_pol,
- .name = "conservative",
-};
+ dbs_info = kzalloc(sizeof(*dbs_info), GFP_KERNEL);
+ return dbs_info ? &dbs_info->policy_dbs : NULL;
+}
-/************************** sysfs end ************************/
+static void cs_free(struct policy_dbs_info *policy_dbs)
+{
+ kfree(to_dbs_info(policy_dbs));
+}
static int cs_init(struct dbs_data *dbs_data, bool notify)
{
@@ -335,11 +273,11 @@ static int cs_init(struct dbs_data *dbs_data, bool notify)
return -ENOMEM;
}
- tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
- tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
- tuners->ignore_nice_load = 0;
tuners->freq_step = DEF_FREQUENCY_STEP;
+ dbs_data->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
+ dbs_data->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
+ dbs_data->ignore_nice_load = 0;
dbs_data->tuners = tuners;
dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
@@ -361,35 +299,66 @@ static void cs_exit(struct dbs_data *dbs_data, bool notify)
kfree(dbs_data->tuners);
}
-define_get_cpu_dbs_routines(cs_cpu_dbs_info);
+static void cs_start(struct cpufreq_policy *policy)
+{
+ struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
+
+ dbs_info->down_skip = 0;
+ dbs_info->requested_freq = policy->cur;
+}
-static struct common_dbs_data cs_dbs_cdata = {
- .governor = GOV_CONSERVATIVE,
- .attr_group_gov_sys = &cs_attr_group_gov_sys,
- .attr_group_gov_pol = &cs_attr_group_gov_pol,
- .get_cpu_cdbs = get_cpu_cdbs,
- .get_cpu_dbs_info_s = get_cpu_dbs_info_s,
+static struct dbs_governor cs_dbs_gov = {
+ .gov = {
+ .name = "conservative",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
+ },
+ .kobj_type = { .default_attrs = cs_attributes },
.gov_dbs_timer = cs_dbs_timer,
- .gov_check_cpu = cs_check_cpu,
+ .alloc = cs_alloc,
+ .free = cs_free,
.init = cs_init,
.exit = cs_exit,
- .mutex = __MUTEX_INITIALIZER(cs_dbs_cdata.mutex),
+ .start = cs_start,
};
-static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
- unsigned int event)
+#define CPU_FREQ_GOV_CONSERVATIVE (&cs_dbs_gov.gov)
+
+static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+ void *data)
{
- return cpufreq_governor_dbs(policy, &cs_dbs_cdata, event);
+ struct cpufreq_freqs *freq = data;
+ struct cpufreq_policy *policy = cpufreq_cpu_get_raw(freq->cpu);
+ struct cs_policy_dbs_info *dbs_info;
+
+ if (!policy)
+ return 0;
+
+ /* policy isn't governed by conservative governor */
+ if (policy->governor != CPU_FREQ_GOV_CONSERVATIVE)
+ return 0;
+
+ dbs_info = to_dbs_info(policy->governor_data);
+ /*
+ * we only care if our internally tracked freq moves outside the 'valid'
+ * ranges of frequency available to us otherwise we do not change it
+ */
+ if (dbs_info->requested_freq > policy->max
+ || dbs_info->requested_freq < policy->min)
+ dbs_info->requested_freq = freq->new;
+
+ return 0;
}
static int __init cpufreq_gov_dbs_init(void)
{
- return cpufreq_register_governor(&cpufreq_gov_conservative);
+ return cpufreq_register_governor(CPU_FREQ_GOV_CONSERVATIVE);
}
static void __exit cpufreq_gov_dbs_exit(void)
{
- cpufreq_unregister_governor(&cpufreq_gov_conservative);
+ cpufreq_unregister_governor(CPU_FREQ_GOV_CONSERVATIVE);
}
MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
@@ -399,6 +368,11 @@ MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for "
MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+struct cpufreq_governor *cpufreq_default_governor(void)
+{
+ return CPU_FREQ_GOV_CONSERVATIVE;
+}
+
fs_initcall(cpufreq_gov_dbs_init);
#else
module_init(cpufreq_gov_dbs_init);
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index e0d111024d48..1c25ef405616 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -18,95 +18,193 @@
#include <linux/export.h>
#include <linux/kernel_stat.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include "cpufreq_governor.h"
-static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data)
-{
- if (have_governor_per_policy())
- return dbs_data->cdata->attr_group_gov_pol;
- else
- return dbs_data->cdata->attr_group_gov_sys;
-}
+static DEFINE_PER_CPU(struct cpu_dbs_info, cpu_dbs);
+
+static DEFINE_MUTEX(gov_dbs_data_mutex);
-void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
+/* Common sysfs tunables */
+/**
+ * store_sampling_rate - update sampling rate effective immediately if needed.
+ *
+ * If new rate is smaller than the old, simply updating
+ * dbs.sampling_rate might not be appropriate. For example, if the
+ * original sampling_rate was 1 second and the requested new sampling rate is 10
+ * ms because the user needs immediate reaction from ondemand governor, but not
+ * sure if higher frequency will be required or not, then, the governor may
+ * change the sampling rate too late; up to 1 second later. Thus, if we are
+ * reducing the sampling rate, we need to make the new value effective
+ * immediately.
+ *
+ * This must be called with dbs_data->mutex held, otherwise traversing
+ * policy_dbs_list isn't safe.
+ */
+ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
- struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
- struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
- struct cpufreq_policy *policy = cdbs->shared->policy;
- unsigned int sampling_rate;
- unsigned int max_load = 0;
- unsigned int ignore_nice;
- unsigned int j;
+ struct policy_dbs_info *policy_dbs;
+ unsigned int rate;
+ int ret;
+ ret = sscanf(buf, "%u", &rate);
+ if (ret != 1)
+ return -EINVAL;
- if (dbs_data->cdata->governor == GOV_ONDEMAND) {
- struct od_cpu_dbs_info_s *od_dbs_info =
- dbs_data->cdata->get_cpu_dbs_info_s(cpu);
+ dbs_data->sampling_rate = max(rate, dbs_data->min_sampling_rate);
+ /*
+ * We are operating under dbs_data->mutex and so the list and its
+ * entries can't be freed concurrently.
+ */
+ list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list) {
+ mutex_lock(&policy_dbs->timer_mutex);
/*
- * Sometimes, the ondemand governor uses an additional
- * multiplier to give long delays. So apply this multiplier to
- * the 'sampling_rate', so as to keep the wake-up-from-idle
- * detection logic a bit conservative.
+ * On 32-bit architectures this may race with the
+ * sample_delay_ns read in dbs_update_util_handler(), but that
+ * really doesn't matter. If the read returns a value that's
+ * too big, the sample will be skipped, but the next invocation
+ * of dbs_update_util_handler() (when the update has been
+ * completed) will take a sample.
+ *
+ * If this runs in parallel with dbs_work_handler(), we may end
+ * up overwriting the sample_delay_ns value that it has just
+ * written, but it will be corrected next time a sample is
+ * taken, so it shouldn't be significant.
*/
- sampling_rate = od_tuners->sampling_rate;
- sampling_rate *= od_dbs_info->rate_mult;
+ gov_update_sample_delay(policy_dbs, 0);
+ mutex_unlock(&policy_dbs->timer_mutex);
+ }
- ignore_nice = od_tuners->ignore_nice_load;
- } else {
- sampling_rate = cs_tuners->sampling_rate;
- ignore_nice = cs_tuners->ignore_nice_load;
+ return count;
+}
+EXPORT_SYMBOL_GPL(store_sampling_rate);
+
+/**
+ * gov_update_cpu_data - Update CPU load data.
+ * @dbs_data: Top-level governor data pointer.
+ *
+ * Update CPU load data for all CPUs in the domain governed by @dbs_data
+ * (that may be a single policy or a bunch of them if governor tunables are
+ * system-wide).
+ *
+ * Call under the @dbs_data mutex.
+ */
+void gov_update_cpu_data(struct dbs_data *dbs_data)
+{
+ struct policy_dbs_info *policy_dbs;
+
+ list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list) {
+ unsigned int j;
+
+ for_each_cpu(j, policy_dbs->policy->cpus) {
+ struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
+
+ j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall,
+ dbs_data->io_is_busy);
+ if (dbs_data->ignore_nice_load)
+ j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE];
+ }
}
+}
+EXPORT_SYMBOL_GPL(gov_update_cpu_data);
+
+static inline struct dbs_data *to_dbs_data(struct kobject *kobj)
+{
+ return container_of(kobj, struct dbs_data, kobj);
+}
+
+static inline struct governor_attr *to_gov_attr(struct attribute *attr)
+{
+ return container_of(attr, struct governor_attr, attr);
+}
+
+static ssize_t governor_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct dbs_data *dbs_data = to_dbs_data(kobj);
+ struct governor_attr *gattr = to_gov_attr(attr);
+
+ return gattr->show(dbs_data, buf);
+}
+
+static ssize_t governor_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dbs_data *dbs_data = to_dbs_data(kobj);
+ struct governor_attr *gattr = to_gov_attr(attr);
+ int ret = -EBUSY;
+
+ mutex_lock(&dbs_data->mutex);
+
+ if (dbs_data->usage_count)
+ ret = gattr->store(dbs_data, buf, count);
+
+ mutex_unlock(&dbs_data->mutex);
+
+ return ret;
+}
+
+/*
+ * Sysfs Ops for accessing governor attributes.
+ *
+ * All show/store invocations for governor specific sysfs attributes, will first
+ * call the below show/store callbacks and the attribute specific callback will
+ * be called from within it.
+ */
+static const struct sysfs_ops governor_sysfs_ops = {
+ .show = governor_show,
+ .store = governor_store,
+};
+
+unsigned int dbs_update(struct cpufreq_policy *policy)
+{
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
+ struct dbs_data *dbs_data = policy_dbs->dbs_data;
+ unsigned int ignore_nice = dbs_data->ignore_nice_load;
+ unsigned int max_load = 0;
+ unsigned int sampling_rate, io_busy, j;
+
+ /*
+ * Sometimes governors may use an additional multiplier to increase
+ * sample delays temporarily. Apply that multiplier to sampling_rate
+ * so as to keep the wake-up-from-idle detection logic a bit
+ * conservative.
+ */
+ sampling_rate = dbs_data->sampling_rate * policy_dbs->rate_mult;
+ /*
+ * For the purpose of ondemand, waiting for disk IO is an indication
+ * that you're performance critical, and not that the system is actually
+ * idle, so do not add the iowait time to the CPU idle time then.
+ */
+ io_busy = dbs_data->io_is_busy;
/* Get Absolute Load */
for_each_cpu(j, policy->cpus) {
- struct cpu_dbs_info *j_cdbs;
+ struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
u64 cur_wall_time, cur_idle_time;
unsigned int idle_time, wall_time;
unsigned int load;
- int io_busy = 0;
-
- j_cdbs = dbs_data->cdata->get_cpu_cdbs(j);
- /*
- * For the purpose of ondemand, waiting for disk IO is
- * an indication that you're performance critical, and
- * not that the system is actually idle. So do not add
- * the iowait time to the cpu idle time.
- */
- if (dbs_data->cdata->governor == GOV_ONDEMAND)
- io_busy = od_tuners->io_is_busy;
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time, io_busy);
- wall_time = (unsigned int)
- (cur_wall_time - j_cdbs->prev_cpu_wall);
+ wall_time = cur_wall_time - j_cdbs->prev_cpu_wall;
j_cdbs->prev_cpu_wall = cur_wall_time;
- if (cur_idle_time < j_cdbs->prev_cpu_idle)
- cur_idle_time = j_cdbs->prev_cpu_idle;
-
- idle_time = (unsigned int)
- (cur_idle_time - j_cdbs->prev_cpu_idle);
- j_cdbs->prev_cpu_idle = cur_idle_time;
+ if (cur_idle_time <= j_cdbs->prev_cpu_idle) {
+ idle_time = 0;
+ } else {
+ idle_time = cur_idle_time - j_cdbs->prev_cpu_idle;
+ j_cdbs->prev_cpu_idle = cur_idle_time;
+ }
if (ignore_nice) {
- u64 cur_nice;
- unsigned long cur_nice_jiffies;
-
- cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] -
- cdbs->prev_cpu_nice;
- /*
- * Assumption: nice time between sampling periods will
- * be less than 2^32 jiffies for 32 bit sys
- */
- cur_nice_jiffies = (unsigned long)
- cputime64_to_jiffies64(cur_nice);
+ u64 cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE];
- cdbs->prev_cpu_nice =
- kcpustat_cpu(j).cpustat[CPUTIME_NICE];
- idle_time += jiffies_to_usecs(cur_nice_jiffies);
+ idle_time += cputime_to_usecs(cur_nice - j_cdbs->prev_cpu_nice);
+ j_cdbs->prev_cpu_nice = cur_nice;
}
if (unlikely(!wall_time || wall_time < idle_time))
@@ -128,10 +226,10 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
* dropped down. So we perform the copy only once, upon the
* first wake-up from idle.)
*
- * Detecting this situation is easy: the governor's deferrable
- * timer would not have fired during CPU-idle periods. Hence
- * an unusually large 'wall_time' (as compared to the sampling
- * rate) indicates this scenario.
+ * Detecting this situation is easy: the governor's utilization
+ * update handler would not have run during CPU-idle periods.
+ * Hence, an unusually large 'wall_time' (as compared to the
+ * sampling rate) indicates this scenario.
*
* prev_load can be zero in two cases and we must recalculate it
* for both cases:
@@ -156,222 +254,224 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
if (load > max_load)
max_load = load;
}
-
- dbs_data->cdata->gov_check_cpu(cpu, max_load);
+ return max_load;
}
-EXPORT_SYMBOL_GPL(dbs_check_cpu);
+EXPORT_SYMBOL_GPL(dbs_update);
-void gov_add_timers(struct cpufreq_policy *policy, unsigned int delay)
+static void gov_set_update_util(struct policy_dbs_info *policy_dbs,
+ unsigned int delay_us)
{
- struct dbs_data *dbs_data = policy->governor_data;
- struct cpu_dbs_info *cdbs;
+ struct cpufreq_policy *policy = policy_dbs->policy;
int cpu;
+ gov_update_sample_delay(policy_dbs, delay_us);
+ policy_dbs->last_sample_time = 0;
+
for_each_cpu(cpu, policy->cpus) {
- cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
- cdbs->timer.expires = jiffies + delay;
- add_timer_on(&cdbs->timer, cpu);
+ struct cpu_dbs_info *cdbs = &per_cpu(cpu_dbs, cpu);
+
+ cpufreq_set_update_util_data(cpu, &cdbs->update_util);
}
}
-EXPORT_SYMBOL_GPL(gov_add_timers);
-static inline void gov_cancel_timers(struct cpufreq_policy *policy)
+static inline void gov_clear_update_util(struct cpufreq_policy *policy)
{
- struct dbs_data *dbs_data = policy->governor_data;
- struct cpu_dbs_info *cdbs;
int i;
- for_each_cpu(i, policy->cpus) {
- cdbs = dbs_data->cdata->get_cpu_cdbs(i);
- del_timer_sync(&cdbs->timer);
- }
-}
+ for_each_cpu(i, policy->cpus)
+ cpufreq_set_update_util_data(i, NULL);
-void gov_cancel_work(struct cpu_common_dbs_info *shared)
-{
- /* Tell dbs_timer_handler() to skip queuing up work items. */
- atomic_inc(&shared->skip_work);
- /*
- * If dbs_timer_handler() is already running, it may not notice the
- * incremented skip_work, so wait for it to complete to prevent its work
- * item from being queued up after the cancel_work_sync() below.
- */
- gov_cancel_timers(shared->policy);
- /*
- * In case dbs_timer_handler() managed to run and spawn a work item
- * before the timers have been canceled, wait for that work item to
- * complete and then cancel all of the timers set up by it. If
- * dbs_timer_handler() runs again at that point, it will see the
- * positive value of skip_work and won't spawn any more work items.
- */
- cancel_work_sync(&shared->work);
- gov_cancel_timers(shared->policy);
- atomic_set(&shared->skip_work, 0);
+ synchronize_sched();
}
-EXPORT_SYMBOL_GPL(gov_cancel_work);
-/* Will return if we need to evaluate cpu load again or not */
-static bool need_load_eval(struct cpu_common_dbs_info *shared,
- unsigned int sampling_rate)
+static void gov_cancel_work(struct cpufreq_policy *policy)
{
- if (policy_is_shared(shared->policy)) {
- ktime_t time_now = ktime_get();
- s64 delta_us = ktime_us_delta(time_now, shared->time_stamp);
-
- /* Do nothing if we recently have sampled */
- if (delta_us < (s64)(sampling_rate / 2))
- return false;
- else
- shared->time_stamp = time_now;
- }
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
- return true;
+ gov_clear_update_util(policy_dbs->policy);
+ irq_work_sync(&policy_dbs->irq_work);
+ cancel_work_sync(&policy_dbs->work);
+ atomic_set(&policy_dbs->work_count, 0);
+ policy_dbs->work_in_progress = false;
}
static void dbs_work_handler(struct work_struct *work)
{
- struct cpu_common_dbs_info *shared = container_of(work, struct
- cpu_common_dbs_info, work);
+ struct policy_dbs_info *policy_dbs;
struct cpufreq_policy *policy;
- struct dbs_data *dbs_data;
- unsigned int sampling_rate, delay;
- bool eval_load;
-
- policy = shared->policy;
- dbs_data = policy->governor_data;
+ struct dbs_governor *gov;
- /* Kill all timers */
- gov_cancel_timers(policy);
+ policy_dbs = container_of(work, struct policy_dbs_info, work);
+ policy = policy_dbs->policy;
+ gov = dbs_governor_of(policy);
- if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
- struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
-
- sampling_rate = cs_tuners->sampling_rate;
- } else {
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
-
- sampling_rate = od_tuners->sampling_rate;
- }
-
- eval_load = need_load_eval(shared, sampling_rate);
+ /*
+ * Make sure cpufreq_governor_limits() isn't evaluating load or the
+ * ondemand governor isn't updating the sampling rate in parallel.
+ */
+ mutex_lock(&policy_dbs->timer_mutex);
+ gov_update_sample_delay(policy_dbs, gov->gov_dbs_timer(policy));
+ mutex_unlock(&policy_dbs->timer_mutex);
+ /* Allow the utilization update handler to queue up more work. */
+ atomic_set(&policy_dbs->work_count, 0);
/*
- * Make sure cpufreq_governor_limits() isn't evaluating load in
- * parallel.
+ * If the update below is reordered with respect to the sample delay
+ * modification, the utilization update handler may end up using a stale
+ * sample delay value.
*/
- mutex_lock(&shared->timer_mutex);
- delay = dbs_data->cdata->gov_dbs_timer(policy, eval_load);
- mutex_unlock(&shared->timer_mutex);
+ smp_wmb();
+ policy_dbs->work_in_progress = false;
+}
- atomic_dec(&shared->skip_work);
+static void dbs_irq_work(struct irq_work *irq_work)
+{
+ struct policy_dbs_info *policy_dbs;
- gov_add_timers(policy, delay);
+ policy_dbs = container_of(irq_work, struct policy_dbs_info, irq_work);
+ schedule_work(&policy_dbs->work);
}
-static void dbs_timer_handler(unsigned long data)
+static void dbs_update_util_handler(struct update_util_data *data, u64 time,
+ unsigned long util, unsigned long max)
{
- struct cpu_dbs_info *cdbs = (struct cpu_dbs_info *)data;
- struct cpu_common_dbs_info *shared = cdbs->shared;
+ struct cpu_dbs_info *cdbs = container_of(data, struct cpu_dbs_info, update_util);
+ struct policy_dbs_info *policy_dbs = cdbs->policy_dbs;
+ u64 delta_ns, lst;
/*
- * Timer handler may not be allowed to queue the work at the moment,
- * because:
- * - Another timer handler has done that
- * - We are stopping the governor
- * - Or we are updating the sampling rate of the ondemand governor
+ * The work may not be allowed to be queued up right now.
+ * Possible reasons:
+ * - Work has already been queued up or is in progress.
+ * - It is too early (too little time from the previous sample).
*/
- if (atomic_inc_return(&shared->skip_work) > 1)
- atomic_dec(&shared->skip_work);
- else
- queue_work(system_wq, &shared->work);
-}
+ if (policy_dbs->work_in_progress)
+ return;
-static void set_sampling_rate(struct dbs_data *dbs_data,
- unsigned int sampling_rate)
-{
- if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
- struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
- cs_tuners->sampling_rate = sampling_rate;
- } else {
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
- od_tuners->sampling_rate = sampling_rate;
+ /*
+ * If the reads below are reordered before the check above, the value
+ * of sample_delay_ns used in the computation may be stale.
+ */
+ smp_rmb();
+ lst = READ_ONCE(policy_dbs->last_sample_time);
+ delta_ns = time - lst;
+ if ((s64)delta_ns < policy_dbs->sample_delay_ns)
+ return;
+
+ /*
+ * If the policy is not shared, the irq_work may be queued up right away
+ * at this point. Otherwise, we need to ensure that only one of the
+ * CPUs sharing the policy will do that.
+ */
+ if (policy_dbs->is_shared) {
+ if (!atomic_add_unless(&policy_dbs->work_count, 1, 1))
+ return;
+
+ /*
+ * If another CPU updated last_sample_time in the meantime, we
+ * shouldn't be here, so clear the work counter and bail out.
+ */
+ if (unlikely(lst != READ_ONCE(policy_dbs->last_sample_time))) {
+ atomic_set(&policy_dbs->work_count, 0);
+ return;
+ }
}
+
+ policy_dbs->last_sample_time = time;
+ policy_dbs->work_in_progress = true;
+ irq_work_queue(&policy_dbs->irq_work);
}
-static int alloc_common_dbs_info(struct cpufreq_policy *policy,
- struct common_dbs_data *cdata)
+static struct policy_dbs_info *alloc_policy_dbs_info(struct cpufreq_policy *policy,
+ struct dbs_governor *gov)
{
- struct cpu_common_dbs_info *shared;
+ struct policy_dbs_info *policy_dbs;
int j;
- /* Allocate memory for the common information for policy->cpus */
- shared = kzalloc(sizeof(*shared), GFP_KERNEL);
- if (!shared)
- return -ENOMEM;
+ /* Allocate memory for per-policy governor data. */
+ policy_dbs = gov->alloc();
+ if (!policy_dbs)
+ return NULL;
- /* Set shared for all CPUs, online+offline */
- for_each_cpu(j, policy->related_cpus)
- cdata->get_cpu_cdbs(j)->shared = shared;
+ policy_dbs->policy = policy;
+ mutex_init(&policy_dbs->timer_mutex);
+ atomic_set(&policy_dbs->work_count, 0);
+ init_irq_work(&policy_dbs->irq_work, dbs_irq_work);
+ INIT_WORK(&policy_dbs->work, dbs_work_handler);
- mutex_init(&shared->timer_mutex);
- atomic_set(&shared->skip_work, 0);
- INIT_WORK(&shared->work, dbs_work_handler);
- return 0;
+ /* Set policy_dbs for all CPUs, online+offline */
+ for_each_cpu(j, policy->related_cpus) {
+ struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
+
+ j_cdbs->policy_dbs = policy_dbs;
+ j_cdbs->update_util.func = dbs_update_util_handler;
+ }
+ return policy_dbs;
}
-static void free_common_dbs_info(struct cpufreq_policy *policy,
- struct common_dbs_data *cdata)
+static void free_policy_dbs_info(struct policy_dbs_info *policy_dbs,
+ struct dbs_governor *gov)
{
- struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(policy->cpu);
- struct cpu_common_dbs_info *shared = cdbs->shared;
int j;
- mutex_destroy(&shared->timer_mutex);
+ mutex_destroy(&policy_dbs->timer_mutex);
- for_each_cpu(j, policy->cpus)
- cdata->get_cpu_cdbs(j)->shared = NULL;
+ for_each_cpu(j, policy_dbs->policy->related_cpus) {
+ struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
- kfree(shared);
+ j_cdbs->policy_dbs = NULL;
+ j_cdbs->update_util.func = NULL;
+ }
+ gov->free(policy_dbs);
}
-static int cpufreq_governor_init(struct cpufreq_policy *policy,
- struct dbs_data *dbs_data,
- struct common_dbs_data *cdata)
+static int cpufreq_governor_init(struct cpufreq_policy *policy)
{
+ struct dbs_governor *gov = dbs_governor_of(policy);
+ struct dbs_data *dbs_data;
+ struct policy_dbs_info *policy_dbs;
unsigned int latency;
- int ret;
+ int ret = 0;
/* State should be equivalent to EXIT */
if (policy->governor_data)
return -EBUSY;
- if (dbs_data) {
- if (WARN_ON(have_governor_per_policy()))
- return -EINVAL;
+ policy_dbs = alloc_policy_dbs_info(policy, gov);
+ if (!policy_dbs)
+ return -ENOMEM;
- ret = alloc_common_dbs_info(policy, cdata);
- if (ret)
- return ret;
+ /* Protect gov->gdbs_data against concurrent updates. */
+ mutex_lock(&gov_dbs_data_mutex);
+ dbs_data = gov->gdbs_data;
+ if (dbs_data) {
+ if (WARN_ON(have_governor_per_policy())) {
+ ret = -EINVAL;
+ goto free_policy_dbs_info;
+ }
+ policy_dbs->dbs_data = dbs_data;
+ policy->governor_data = policy_dbs;
+
+ mutex_lock(&dbs_data->mutex);
dbs_data->usage_count++;
- policy->governor_data = dbs_data;
- return 0;
+ list_add(&policy_dbs->list, &dbs_data->policy_dbs_list);
+ mutex_unlock(&dbs_data->mutex);
+ goto out;
}
dbs_data = kzalloc(sizeof(*dbs_data), GFP_KERNEL);
- if (!dbs_data)
- return -ENOMEM;
-
- ret = alloc_common_dbs_info(policy, cdata);
- if (ret)
- goto free_dbs_data;
+ if (!dbs_data) {
+ ret = -ENOMEM;
+ goto free_policy_dbs_info;
+ }
- dbs_data->cdata = cdata;
- dbs_data->usage_count = 1;
+ INIT_LIST_HEAD(&dbs_data->policy_dbs_list);
+ mutex_init(&dbs_data->mutex);
- ret = cdata->init(dbs_data, !policy->governor->initialized);
+ ret = gov->init(dbs_data, !policy->governor->initialized);
if (ret)
- goto free_common_dbs_info;
+ goto free_policy_dbs_info;
/* policy latency is in ns. Convert it to us first */
latency = policy->cpuinfo.transition_latency / 1000;
@@ -381,216 +481,156 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy,
/* Bring kernel and HW constraints together */
dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
MIN_LATENCY_MULTIPLIER * latency);
- set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
- latency * LATENCY_MULTIPLIER));
+ dbs_data->sampling_rate = max(dbs_data->min_sampling_rate,
+ LATENCY_MULTIPLIER * latency);
if (!have_governor_per_policy())
- cdata->gdbs_data = dbs_data;
+ gov->gdbs_data = dbs_data;
- policy->governor_data = dbs_data;
+ policy->governor_data = policy_dbs;
- ret = sysfs_create_group(get_governor_parent_kobj(policy),
- get_sysfs_attr(dbs_data));
- if (ret)
- goto reset_gdbs_data;
+ policy_dbs->dbs_data = dbs_data;
+ dbs_data->usage_count = 1;
+ list_add(&policy_dbs->list, &dbs_data->policy_dbs_list);
- return 0;
+ gov->kobj_type.sysfs_ops = &governor_sysfs_ops;
+ ret = kobject_init_and_add(&dbs_data->kobj, &gov->kobj_type,
+ get_governor_parent_kobj(policy),
+ "%s", gov->gov.name);
+ if (!ret)
+ goto out;
+
+ /* Failure, so roll back. */
+ pr_err("cpufreq: Governor initialization failed (dbs_data kobject init error %d)\n", ret);
-reset_gdbs_data:
policy->governor_data = NULL;
if (!have_governor_per_policy())
- cdata->gdbs_data = NULL;
- cdata->exit(dbs_data, !policy->governor->initialized);
-free_common_dbs_info:
- free_common_dbs_info(policy, cdata);
-free_dbs_data:
+ gov->gdbs_data = NULL;
+ gov->exit(dbs_data, !policy->governor->initialized);
kfree(dbs_data);
+
+free_policy_dbs_info:
+ free_policy_dbs_info(policy_dbs, gov);
+
+out:
+ mutex_unlock(&gov_dbs_data_mutex);
return ret;
}
-static int cpufreq_governor_exit(struct cpufreq_policy *policy,
- struct dbs_data *dbs_data)
+static int cpufreq_governor_exit(struct cpufreq_policy *policy)
{
- struct common_dbs_data *cdata = dbs_data->cdata;
- struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(policy->cpu);
+ struct dbs_governor *gov = dbs_governor_of(policy);
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
+ struct dbs_data *dbs_data = policy_dbs->dbs_data;
+ int count;
- /* State should be equivalent to INIT */
- if (!cdbs->shared || cdbs->shared->policy)
- return -EBUSY;
+ /* Protect gov->gdbs_data against concurrent updates. */
+ mutex_lock(&gov_dbs_data_mutex);
+
+ mutex_lock(&dbs_data->mutex);
+ list_del(&policy_dbs->list);
+ count = --dbs_data->usage_count;
+ mutex_unlock(&dbs_data->mutex);
- if (!--dbs_data->usage_count) {
- sysfs_remove_group(get_governor_parent_kobj(policy),
- get_sysfs_attr(dbs_data));
+ if (!count) {
+ kobject_put(&dbs_data->kobj);
policy->governor_data = NULL;
if (!have_governor_per_policy())
- cdata->gdbs_data = NULL;
+ gov->gdbs_data = NULL;
- cdata->exit(dbs_data, policy->governor->initialized == 1);
+ gov->exit(dbs_data, policy->governor->initialized == 1);
+ mutex_destroy(&dbs_data->mutex);
kfree(dbs_data);
} else {
policy->governor_data = NULL;
}
- free_common_dbs_info(policy, cdata);
+ free_policy_dbs_info(policy_dbs, gov);
+
+ mutex_unlock(&gov_dbs_data_mutex);
return 0;
}
-static int cpufreq_governor_start(struct cpufreq_policy *policy,
- struct dbs_data *dbs_data)
+static int cpufreq_governor_start(struct cpufreq_policy *policy)
{
- struct common_dbs_data *cdata = dbs_data->cdata;
- unsigned int sampling_rate, ignore_nice, j, cpu = policy->cpu;
- struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu);
- struct cpu_common_dbs_info *shared = cdbs->shared;
- int io_busy = 0;
+ struct dbs_governor *gov = dbs_governor_of(policy);
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
+ struct dbs_data *dbs_data = policy_dbs->dbs_data;
+ unsigned int sampling_rate, ignore_nice, j;
+ unsigned int io_busy;
if (!policy->cur)
return -EINVAL;
- /* State should be equivalent to INIT */
- if (!shared || shared->policy)
- return -EBUSY;
+ policy_dbs->is_shared = policy_is_shared(policy);
+ policy_dbs->rate_mult = 1;
- if (cdata->governor == GOV_CONSERVATIVE) {
- struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
-
- sampling_rate = cs_tuners->sampling_rate;
- ignore_nice = cs_tuners->ignore_nice_load;
- } else {
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
-
- sampling_rate = od_tuners->sampling_rate;
- ignore_nice = od_tuners->ignore_nice_load;
- io_busy = od_tuners->io_is_busy;
- }
-
- shared->policy = policy;
- shared->time_stamp = ktime_get();
+ sampling_rate = dbs_data->sampling_rate;
+ ignore_nice = dbs_data->ignore_nice_load;
+ io_busy = dbs_data->io_is_busy;
for_each_cpu(j, policy->cpus) {
- struct cpu_dbs_info *j_cdbs = cdata->get_cpu_cdbs(j);
+ struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
unsigned int prev_load;
- j_cdbs->prev_cpu_idle =
- get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy);
+ j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy);
- prev_load = (unsigned int)(j_cdbs->prev_cpu_wall -
- j_cdbs->prev_cpu_idle);
- j_cdbs->prev_load = 100 * prev_load /
- (unsigned int)j_cdbs->prev_cpu_wall;
+ prev_load = j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle;
+ j_cdbs->prev_load = 100 * prev_load / (unsigned int)j_cdbs->prev_cpu_wall;
if (ignore_nice)
j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE];
-
- __setup_timer(&j_cdbs->timer, dbs_timer_handler,
- (unsigned long)j_cdbs,
- TIMER_DEFERRABLE | TIMER_IRQSAFE);
}
- if (cdata->governor == GOV_CONSERVATIVE) {
- struct cs_cpu_dbs_info_s *cs_dbs_info =
- cdata->get_cpu_dbs_info_s(cpu);
-
- cs_dbs_info->down_skip = 0;
- cs_dbs_info->requested_freq = policy->cur;
- } else {
- struct od_ops *od_ops = cdata->gov_ops;
- struct od_cpu_dbs_info_s *od_dbs_info = cdata->get_cpu_dbs_info_s(cpu);
-
- od_dbs_info->rate_mult = 1;
- od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
- od_ops->powersave_bias_init_cpu(cpu);
- }
+ gov->start(policy);
- gov_add_timers(policy, delay_for_sampling_rate(sampling_rate));
+ gov_set_update_util(policy_dbs, sampling_rate);
return 0;
}
-static int cpufreq_governor_stop(struct cpufreq_policy *policy,
- struct dbs_data *dbs_data)
+static int cpufreq_governor_stop(struct cpufreq_policy *policy)
{
- struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(policy->cpu);
- struct cpu_common_dbs_info *shared = cdbs->shared;
-
- /* State should be equivalent to START */
- if (!shared || !shared->policy)
- return -EBUSY;
-
- gov_cancel_work(shared);
- shared->policy = NULL;
-
+ gov_cancel_work(policy);
return 0;
}
-static int cpufreq_governor_limits(struct cpufreq_policy *policy,
- struct dbs_data *dbs_data)
+static int cpufreq_governor_limits(struct cpufreq_policy *policy)
{
- struct common_dbs_data *cdata = dbs_data->cdata;
- unsigned int cpu = policy->cpu;
- struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu);
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
- /* State should be equivalent to START */
- if (!cdbs->shared || !cdbs->shared->policy)
- return -EBUSY;
+ mutex_lock(&policy_dbs->timer_mutex);
+
+ if (policy->max < policy->cur)
+ __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
+ else if (policy->min > policy->cur)
+ __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
+
+ gov_update_sample_delay(policy_dbs, 0);
- mutex_lock(&cdbs->shared->timer_mutex);
- if (policy->max < cdbs->shared->policy->cur)
- __cpufreq_driver_target(cdbs->shared->policy, policy->max,
- CPUFREQ_RELATION_H);
- else if (policy->min > cdbs->shared->policy->cur)
- __cpufreq_driver_target(cdbs->shared->policy, policy->min,
- CPUFREQ_RELATION_L);
- dbs_check_cpu(dbs_data, cpu);
- mutex_unlock(&cdbs->shared->timer_mutex);
+ mutex_unlock(&policy_dbs->timer_mutex);
return 0;
}
-int cpufreq_governor_dbs(struct cpufreq_policy *policy,
- struct common_dbs_data *cdata, unsigned int event)
+int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event)
{
- struct dbs_data *dbs_data;
- int ret;
-
- /* Lock governor to block concurrent initialization of governor */
- mutex_lock(&cdata->mutex);
-
- if (have_governor_per_policy())
- dbs_data = policy->governor_data;
- else
- dbs_data = cdata->gdbs_data;
-
- if (!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT)) {
- ret = -EINVAL;
- goto unlock;
- }
-
- switch (event) {
- case CPUFREQ_GOV_POLICY_INIT:
- ret = cpufreq_governor_init(policy, dbs_data, cdata);
- break;
- case CPUFREQ_GOV_POLICY_EXIT:
- ret = cpufreq_governor_exit(policy, dbs_data);
- break;
- case CPUFREQ_GOV_START:
- ret = cpufreq_governor_start(policy, dbs_data);
- break;
- case CPUFREQ_GOV_STOP:
- ret = cpufreq_governor_stop(policy, dbs_data);
- break;
- case CPUFREQ_GOV_LIMITS:
- ret = cpufreq_governor_limits(policy, dbs_data);
- break;
- default:
- ret = -EINVAL;
+ if (event == CPUFREQ_GOV_POLICY_INIT) {
+ return cpufreq_governor_init(policy);
+ } else if (policy->governor_data) {
+ switch (event) {
+ case CPUFREQ_GOV_POLICY_EXIT:
+ return cpufreq_governor_exit(policy);
+ case CPUFREQ_GOV_START:
+ return cpufreq_governor_start(policy);
+ case CPUFREQ_GOV_STOP:
+ return cpufreq_governor_stop(policy);
+ case CPUFREQ_GOV_LIMITS:
+ return cpufreq_governor_limits(policy);
+ }
}
-
-unlock:
- mutex_unlock(&cdata->mutex);
-
- return ret;
+ return -EINVAL;
}
EXPORT_SYMBOL_GPL(cpufreq_governor_dbs);
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 91e767a058a7..61ff82fe0613 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -18,6 +18,7 @@
#define _CPUFREQ_GOVERNOR_H
#include <linux/atomic.h>
+#include <linux/irq_work.h>
#include <linux/cpufreq.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
@@ -41,96 +42,68 @@
enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE};
/*
- * Macro for creating governors sysfs routines
- *
- * - gov_sys: One governor instance per whole system
- * - gov_pol: One governor instance per policy
+ * Abbreviations:
+ * dbs: used as a shortform for demand based switching It helps to keep variable
+ * names smaller, simpler
+ * cdbs: common dbs
+ * od_*: On-demand governor
+ * cs_*: Conservative governor
*/
-/* Create attributes */
-#define gov_sys_attr_ro(_name) \
-static struct global_attr _name##_gov_sys = \
-__ATTR(_name, 0444, show_##_name##_gov_sys, NULL)
-
-#define gov_sys_attr_rw(_name) \
-static struct global_attr _name##_gov_sys = \
-__ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys)
-
-#define gov_pol_attr_ro(_name) \
-static struct freq_attr _name##_gov_pol = \
-__ATTR(_name, 0444, show_##_name##_gov_pol, NULL)
-
-#define gov_pol_attr_rw(_name) \
-static struct freq_attr _name##_gov_pol = \
-__ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol)
+/* Governor demand based switching data (per-policy or global). */
+struct dbs_data {
+ int usage_count;
+ void *tuners;
+ unsigned int min_sampling_rate;
+ unsigned int ignore_nice_load;
+ unsigned int sampling_rate;
+ unsigned int sampling_down_factor;
+ unsigned int up_threshold;
+ unsigned int io_is_busy;
-#define gov_sys_pol_attr_rw(_name) \
- gov_sys_attr_rw(_name); \
- gov_pol_attr_rw(_name)
+ struct kobject kobj;
+ struct list_head policy_dbs_list;
+ /*
+ * Protect concurrent updates to governor tunables from sysfs,
+ * policy_dbs_list and usage_count.
+ */
+ struct mutex mutex;
+};
-#define gov_sys_pol_attr_ro(_name) \
- gov_sys_attr_ro(_name); \
- gov_pol_attr_ro(_name)
+/* Governor's specific attributes */
+struct dbs_data;
+struct governor_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct dbs_data *dbs_data, char *buf);
+ ssize_t (*store)(struct dbs_data *dbs_data, const char *buf,
+ size_t count);
+};
-/* Create show/store routines */
-#define show_one(_gov, file_name) \
-static ssize_t show_##file_name##_gov_sys \
-(struct kobject *kobj, struct attribute *attr, char *buf) \
+#define gov_show_one(_gov, file_name) \
+static ssize_t show_##file_name \
+(struct dbs_data *dbs_data, char *buf) \
{ \
- struct _gov##_dbs_tuners *tuners = _gov##_dbs_cdata.gdbs_data->tuners; \
- return sprintf(buf, "%u\n", tuners->file_name); \
-} \
- \
-static ssize_t show_##file_name##_gov_pol \
-(struct cpufreq_policy *policy, char *buf) \
-{ \
- struct dbs_data *dbs_data = policy->governor_data; \
struct _gov##_dbs_tuners *tuners = dbs_data->tuners; \
return sprintf(buf, "%u\n", tuners->file_name); \
}
-#define store_one(_gov, file_name) \
-static ssize_t store_##file_name##_gov_sys \
-(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
-{ \
- struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
- return store_##file_name(dbs_data, buf, count); \
-} \
- \
-static ssize_t store_##file_name##_gov_pol \
-(struct cpufreq_policy *policy, const char *buf, size_t count) \
+#define gov_show_one_common(file_name) \
+static ssize_t show_##file_name \
+(struct dbs_data *dbs_data, char *buf) \
{ \
- struct dbs_data *dbs_data = policy->governor_data; \
- return store_##file_name(dbs_data, buf, count); \
+ return sprintf(buf, "%u\n", dbs_data->file_name); \
}
-#define show_store_one(_gov, file_name) \
-show_one(_gov, file_name); \
-store_one(_gov, file_name)
+#define gov_attr_ro(_name) \
+static struct governor_attr _name = \
+__ATTR(_name, 0444, show_##_name, NULL)
-/* create helper routines */
-#define define_get_cpu_dbs_routines(_dbs_info) \
-static struct cpu_dbs_info *get_cpu_cdbs(int cpu) \
-{ \
- return &per_cpu(_dbs_info, cpu).cdbs; \
-} \
- \
-static void *get_cpu_dbs_info_s(int cpu) \
-{ \
- return &per_cpu(_dbs_info, cpu); \
-}
-
-/*
- * Abbreviations:
- * dbs: used as a shortform for demand based switching It helps to keep variable
- * names smaller, simpler
- * cdbs: common dbs
- * od_*: On-demand governor
- * cs_*: Conservative governor
- */
+#define gov_attr_rw(_name) \
+static struct governor_attr _name = \
+__ATTR(_name, 0644, show_##_name, store_##_name)
/* Common to all CPUs of a policy */
-struct cpu_common_dbs_info {
+struct policy_dbs_info {
struct cpufreq_policy *policy;
/*
* Per policy mutex that serializes load evaluation from limit-change
@@ -138,11 +111,27 @@ struct cpu_common_dbs_info {
*/
struct mutex timer_mutex;
- ktime_t time_stamp;
- atomic_t skip_work;
+ u64 last_sample_time;
+ s64 sample_delay_ns;
+ atomic_t work_count;
+ struct irq_work irq_work;
struct work_struct work;
+ /* dbs_data may be shared between multiple policy objects */
+ struct dbs_data *dbs_data;
+ struct list_head list;
+ /* Multiplier for increasing sample delay temporarily. */
+ unsigned int rate_mult;
+ /* Status indicators */
+ bool is_shared; /* This object is used by multiple CPUs */
+ bool work_in_progress; /* Work is being queued up or in progress */
};
+static inline void gov_update_sample_delay(struct policy_dbs_info *policy_dbs,
+ unsigned int delay_us)
+{
+ policy_dbs->sample_delay_ns = delay_us * NSEC_PER_USEC;
+}
+
/* Per cpu structures */
struct cpu_dbs_info {
u64 prev_cpu_idle;
@@ -155,54 +144,14 @@ struct cpu_dbs_info {
* wake-up from idle.
*/
unsigned int prev_load;
- struct timer_list timer;
- struct cpu_common_dbs_info *shared;
-};
-
-struct od_cpu_dbs_info_s {
- struct cpu_dbs_info cdbs;
- struct cpufreq_frequency_table *freq_table;
- unsigned int freq_lo;
- unsigned int freq_lo_jiffies;
- unsigned int freq_hi_jiffies;
- unsigned int rate_mult;
- unsigned int sample_type:1;
-};
-
-struct cs_cpu_dbs_info_s {
- struct cpu_dbs_info cdbs;
- unsigned int down_skip;
- unsigned int requested_freq;
-};
-
-/* Per policy Governors sysfs tunables */
-struct od_dbs_tuners {
- unsigned int ignore_nice_load;
- unsigned int sampling_rate;
- unsigned int sampling_down_factor;
- unsigned int up_threshold;
- unsigned int powersave_bias;
- unsigned int io_is_busy;
-};
-
-struct cs_dbs_tuners {
- unsigned int ignore_nice_load;
- unsigned int sampling_rate;
- unsigned int sampling_down_factor;
- unsigned int up_threshold;
- unsigned int down_threshold;
- unsigned int freq_step;
+ struct update_util_data update_util;
+ struct policy_dbs_info *policy_dbs;
};
/* Common Governor data across policies */
-struct dbs_data;
-struct common_dbs_data {
- /* Common across governors */
- #define GOV_ONDEMAND 0
- #define GOV_CONSERVATIVE 1
- int governor;
- struct attribute_group *attr_group_gov_sys; /* one governor - system */
- struct attribute_group *attr_group_gov_pol; /* one governor - policy */
+struct dbs_governor {
+ struct cpufreq_governor gov;
+ struct kobj_type kobj_type;
/*
* Common data for platforms that don't set
@@ -210,74 +159,32 @@ struct common_dbs_data {
*/
struct dbs_data *gdbs_data;
- struct cpu_dbs_info *(*get_cpu_cdbs)(int cpu);
- void *(*get_cpu_dbs_info_s)(int cpu);
- unsigned int (*gov_dbs_timer)(struct cpufreq_policy *policy,
- bool modify_all);
- void (*gov_check_cpu)(int cpu, unsigned int load);
+ unsigned int (*gov_dbs_timer)(struct cpufreq_policy *policy);
+ struct policy_dbs_info *(*alloc)(void);
+ void (*free)(struct policy_dbs_info *policy_dbs);
int (*init)(struct dbs_data *dbs_data, bool notify);
void (*exit)(struct dbs_data *dbs_data, bool notify);
-
- /* Governor specific ops, see below */
- void *gov_ops;
-
- /*
- * Protects governor's data (struct dbs_data and struct common_dbs_data)
- */
- struct mutex mutex;
+ void (*start)(struct cpufreq_policy *policy);
};
-/* Governor Per policy data */
-struct dbs_data {
- struct common_dbs_data *cdata;
- unsigned int min_sampling_rate;
- int usage_count;
- void *tuners;
-};
+static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy)
+{
+ return container_of(policy->governor, struct dbs_governor, gov);
+}
-/* Governor specific ops, will be passed to dbs_data->gov_ops */
+/* Governor specific operations */
struct od_ops {
- void (*powersave_bias_init_cpu)(int cpu);
unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy,
unsigned int freq_next, unsigned int relation);
- void (*freq_increase)(struct cpufreq_policy *policy, unsigned int freq);
};
-static inline int delay_for_sampling_rate(unsigned int sampling_rate)
-{
- int delay = usecs_to_jiffies(sampling_rate);
-
- /* We want all CPUs to do sampling nearly on same jiffy */
- if (num_online_cpus() > 1)
- delay -= jiffies % delay;
-
- return delay;
-}
-
-#define declare_show_sampling_rate_min(_gov) \
-static ssize_t show_sampling_rate_min_gov_sys \
-(struct kobject *kobj, struct attribute *attr, char *buf) \
-{ \
- struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
- return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
-} \
- \
-static ssize_t show_sampling_rate_min_gov_pol \
-(struct cpufreq_policy *policy, char *buf) \
-{ \
- struct dbs_data *dbs_data = policy->governor_data; \
- return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
-}
-
-extern struct mutex cpufreq_governor_lock;
-
-void gov_add_timers(struct cpufreq_policy *policy, unsigned int delay);
-void gov_cancel_work(struct cpu_common_dbs_info *shared);
-void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
-int cpufreq_governor_dbs(struct cpufreq_policy *policy,
- struct common_dbs_data *cdata, unsigned int event);
+unsigned int dbs_update(struct cpufreq_policy *policy);
+int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event);
void od_register_powersave_bias_handler(unsigned int (*f)
(struct cpufreq_policy *, unsigned int, unsigned int),
unsigned int powersave_bias);
void od_unregister_powersave_bias_handler(void);
+ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
+ size_t count);
+void gov_update_cpu_data(struct dbs_data *dbs_data);
#endif /* _CPUFREQ_GOVERNOR_H */
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index eae51070c034..acd80272ded6 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -16,7 +16,8 @@
#include <linux/percpu-defs.h>
#include <linux/slab.h>
#include <linux/tick.h>
-#include "cpufreq_governor.h"
+
+#include "cpufreq_ondemand.h"
/* On-demand governor macros */
#define DEF_FREQUENCY_UP_THRESHOLD (80)
@@ -27,24 +28,10 @@
#define MIN_FREQUENCY_UP_THRESHOLD (11)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
-static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info);
-
static struct od_ops od_ops;
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
-static struct cpufreq_governor cpufreq_gov_ondemand;
-#endif
-
static unsigned int default_powersave_bias;
-static void ondemand_powersave_bias_init_cpu(int cpu)
-{
- struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
-
- dbs_info->freq_table = cpufreq_frequency_get_table(cpu);
- dbs_info->freq_lo = 0;
-}
-
/*
* Not all CPUs want IO time to be accounted as busy; this depends on how
* efficient idling at a higher frequency/voltage is.
@@ -70,8 +57,8 @@ static int should_io_be_busy(void)
/*
* Find right freq to be set now with powersave_bias on.
- * Returns the freq_hi to be used right now and will set freq_hi_jiffies,
- * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs.
+ * Returns the freq_hi to be used right now and will set freq_hi_delay_us,
+ * freq_lo, and freq_lo_delay_us in percpu area for averaging freqs.
*/
static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
unsigned int freq_next, unsigned int relation)
@@ -79,15 +66,15 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
unsigned int freq_req, freq_reduc, freq_avg;
unsigned int freq_hi, freq_lo;
unsigned int index = 0;
- unsigned int jiffies_total, jiffies_hi, jiffies_lo;
- struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
- policy->cpu);
- struct dbs_data *dbs_data = policy->governor_data;
+ unsigned int delay_hi_us;
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
+ struct od_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
+ struct dbs_data *dbs_data = policy_dbs->dbs_data;
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
if (!dbs_info->freq_table) {
dbs_info->freq_lo = 0;
- dbs_info->freq_lo_jiffies = 0;
+ dbs_info->freq_lo_delay_us = 0;
return freq_next;
}
@@ -110,31 +97,30 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
/* Find out how long we have to be in hi and lo freqs */
if (freq_hi == freq_lo) {
dbs_info->freq_lo = 0;
- dbs_info->freq_lo_jiffies = 0;
+ dbs_info->freq_lo_delay_us = 0;
return freq_lo;
}
- jiffies_total = usecs_to_jiffies(od_tuners->sampling_rate);
- jiffies_hi = (freq_avg - freq_lo) * jiffies_total;
- jiffies_hi += ((freq_hi - freq_lo) / 2);
- jiffies_hi /= (freq_hi - freq_lo);
- jiffies_lo = jiffies_total - jiffies_hi;
+ delay_hi_us = (freq_avg - freq_lo) * dbs_data->sampling_rate;
+ delay_hi_us += (freq_hi - freq_lo) / 2;
+ delay_hi_us /= freq_hi - freq_lo;
+ dbs_info->freq_hi_delay_us = delay_hi_us;
dbs_info->freq_lo = freq_lo;
- dbs_info->freq_lo_jiffies = jiffies_lo;
- dbs_info->freq_hi_jiffies = jiffies_hi;
+ dbs_info->freq_lo_delay_us = dbs_data->sampling_rate - delay_hi_us;
return freq_hi;
}
-static void ondemand_powersave_bias_init(void)
+static void ondemand_powersave_bias_init(struct cpufreq_policy *policy)
{
- int i;
- for_each_online_cpu(i) {
- ondemand_powersave_bias_init_cpu(i);
- }
+ struct od_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
+
+ dbs_info->freq_table = cpufreq_frequency_get_table(policy->cpu);
+ dbs_info->freq_lo = 0;
}
static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq)
{
- struct dbs_data *dbs_data = policy->governor_data;
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
+ struct dbs_data *dbs_data = policy_dbs->dbs_data;
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
if (od_tuners->powersave_bias)
@@ -152,21 +138,21 @@ static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq)
* (default), then we try to increase frequency. Else, we adjust the frequency
* proportional to load.
*/
-static void od_check_cpu(int cpu, unsigned int load)
+static void od_update(struct cpufreq_policy *policy)
{
- struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
- struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy;
- struct dbs_data *dbs_data = policy->governor_data;
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
+ struct od_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
+ struct dbs_data *dbs_data = policy_dbs->dbs_data;
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
+ unsigned int load = dbs_update(policy);
dbs_info->freq_lo = 0;
/* Check for frequency increase */
- if (load > od_tuners->up_threshold) {
+ if (load > dbs_data->up_threshold) {
/* If switching to max speed, apply sampling_down_factor */
if (policy->cur < policy->max)
- dbs_info->rate_mult =
- od_tuners->sampling_down_factor;
+ policy_dbs->rate_mult = dbs_data->sampling_down_factor;
dbs_freq_increase(policy, policy->max);
} else {
/* Calculate the next frequency proportional to load */
@@ -177,177 +163,70 @@ static void od_check_cpu(int cpu, unsigned int load)
freq_next = min_f + load * (max_f - min_f) / 100;
/* No longer fully busy, reset rate_mult */
- dbs_info->rate_mult = 1;
+ policy_dbs->rate_mult = 1;
- if (!od_tuners->powersave_bias) {
- __cpufreq_driver_target(policy, freq_next,
- CPUFREQ_RELATION_C);
- return;
- }
+ if (od_tuners->powersave_bias)
+ freq_next = od_ops.powersave_bias_target(policy,
+ freq_next,
+ CPUFREQ_RELATION_L);
- freq_next = od_ops.powersave_bias_target(policy, freq_next,
- CPUFREQ_RELATION_L);
__cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_C);
}
}
-static unsigned int od_dbs_timer(struct cpufreq_policy *policy, bool modify_all)
+static unsigned int od_dbs_timer(struct cpufreq_policy *policy)
{
- struct dbs_data *dbs_data = policy->governor_data;
- unsigned int cpu = policy->cpu;
- struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
- cpu);
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
- int delay = 0, sample_type = dbs_info->sample_type;
-
- if (!modify_all)
- goto max_delay;
+ struct policy_dbs_info *policy_dbs = policy->governor_data;
+ struct dbs_data *dbs_data = policy_dbs->dbs_data;
+ struct od_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
+ int sample_type = dbs_info->sample_type;
/* Common NORMAL_SAMPLE setup */
dbs_info->sample_type = OD_NORMAL_SAMPLE;
- if (sample_type == OD_SUB_SAMPLE) {
- delay = dbs_info->freq_lo_jiffies;
+ /*
+ * OD_SUB_SAMPLE doesn't make sense if sample_delay_ns is 0, so ignore
+ * it then.
+ */
+ if (sample_type == OD_SUB_SAMPLE && policy_dbs->sample_delay_ns > 0) {
__cpufreq_driver_target(policy, dbs_info->freq_lo,
CPUFREQ_RELATION_H);
- } else {
- dbs_check_cpu(dbs_data, cpu);
- if (dbs_info->freq_lo) {
- /* Setup timer for SUB_SAMPLE */
- dbs_info->sample_type = OD_SUB_SAMPLE;
- delay = dbs_info->freq_hi_jiffies;
- }
+ return dbs_info->freq_lo_delay_us;
}
-max_delay:
- if (!delay)
- delay = delay_for_sampling_rate(od_tuners->sampling_rate
- * dbs_info->rate_mult);
-
- return delay;
-}
-
-/************************** sysfs interface ************************/
-static struct common_dbs_data od_dbs_cdata;
-
-/**
- * update_sampling_rate - update sampling rate effective immediately if needed.
- * @new_rate: new sampling rate
- *
- * If new rate is smaller than the old, simply updating
- * dbs_tuners_int.sampling_rate might not be appropriate. For example, if the
- * original sampling_rate was 1 second and the requested new sampling rate is 10
- * ms because the user needs immediate reaction from ondemand governor, but not
- * sure if higher frequency will be required or not, then, the governor may
- * change the sampling rate too late; up to 1 second later. Thus, if we are
- * reducing the sampling rate, we need to make the new value effective
- * immediately.
- */
-static void update_sampling_rate(struct dbs_data *dbs_data,
- unsigned int new_rate)
-{
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
- struct cpumask cpumask;
- int cpu;
-
- od_tuners->sampling_rate = new_rate = max(new_rate,
- dbs_data->min_sampling_rate);
-
- /*
- * Lock governor so that governor start/stop can't execute in parallel.
- */
- mutex_lock(&od_dbs_cdata.mutex);
-
- cpumask_copy(&cpumask, cpu_online_mask);
-
- for_each_cpu(cpu, &cpumask) {
- struct cpufreq_policy *policy;
- struct od_cpu_dbs_info_s *dbs_info;
- struct cpu_dbs_info *cdbs;
- struct cpu_common_dbs_info *shared;
- unsigned long next_sampling, appointed_at;
-
- dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
- cdbs = &dbs_info->cdbs;
- shared = cdbs->shared;
-
- /*
- * A valid shared and shared->policy means governor hasn't
- * stopped or exited yet.
- */
- if (!shared || !shared->policy)
- continue;
-
- policy = shared->policy;
-
- /* clear all CPUs of this policy */
- cpumask_andnot(&cpumask, &cpumask, policy->cpus);
+ od_update(policy);
- /*
- * Update sampling rate for CPUs whose policy is governed by
- * dbs_data. In case of governor_per_policy, only a single
- * policy will be governed by dbs_data, otherwise there can be
- * multiple policies that are governed by the same dbs_data.
- */
- if (dbs_data != policy->governor_data)
- continue;
-
- /*
- * Checking this for any CPU should be fine, timers for all of
- * them are scheduled together.
- */
- next_sampling = jiffies + usecs_to_jiffies(new_rate);
- appointed_at = dbs_info->cdbs.timer.expires;
-
- if (time_before(next_sampling, appointed_at)) {
- gov_cancel_work(shared);
- gov_add_timers(policy, usecs_to_jiffies(new_rate));
-
- }
+ if (dbs_info->freq_lo) {
+ /* Setup timer for SUB_SAMPLE */
+ dbs_info->sample_type = OD_SUB_SAMPLE;
+ return dbs_info->freq_hi_delay_us;
}
- mutex_unlock(&od_dbs_cdata.mutex);
+ return dbs_data->sampling_rate * policy_dbs->rate_mult;
}
-static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
- size_t count)
-{
- unsigned int input;
- int ret;
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
-
- update_sampling_rate(dbs_data, input);
- return count;
-}
+/************************** sysfs interface ************************/
+static struct dbs_governor od_dbs_gov;
static ssize_t store_io_is_busy(struct dbs_data *dbs_data, const char *buf,
size_t count)
{
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input;
int ret;
- unsigned int j;
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
- od_tuners->io_is_busy = !!input;
+ dbs_data->io_is_busy = !!input;
/* we need to re-evaluate prev_cpu_idle */
- for_each_online_cpu(j) {
- struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
- j);
- dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
- &dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
- }
+ gov_update_cpu_data(dbs_data);
+
return count;
}
static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
size_t count)
{
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
@@ -357,40 +236,43 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
return -EINVAL;
}
- od_tuners->up_threshold = input;
+ dbs_data->up_threshold = input;
return count;
}
static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
const char *buf, size_t count)
{
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
- unsigned int input, j;
+ struct policy_dbs_info *policy_dbs;
+ unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
return -EINVAL;
- od_tuners->sampling_down_factor = input;
+
+ dbs_data->sampling_down_factor = input;
/* Reset down sampling multiplier in case it was active */
- for_each_online_cpu(j) {
- struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
- j);
- dbs_info->rate_mult = 1;
+ list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list) {
+ /*
+ * Doing this without locking might lead to using different
+ * rate_mult values in od_update() and od_dbs_timer().
+ */
+ mutex_lock(&policy_dbs->timer_mutex);
+ policy_dbs->rate_mult = 1;
+ mutex_unlock(&policy_dbs->timer_mutex);
}
+
return count;
}
static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
const char *buf, size_t count)
{
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input;
int ret;
- unsigned int j;
-
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
@@ -398,22 +280,14 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
if (input > 1)
input = 1;
- if (input == od_tuners->ignore_nice_load) { /* nothing to do */
+ if (input == dbs_data->ignore_nice_load) { /* nothing to do */
return count;
}
- od_tuners->ignore_nice_load = input;
+ dbs_data->ignore_nice_load = input;
/* we need to re-evaluate prev_cpu_idle */
- for_each_online_cpu(j) {
- struct od_cpu_dbs_info_s *dbs_info;
- dbs_info = &per_cpu(od_cpu_dbs_info, j);
- dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
- &dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
- if (od_tuners->ignore_nice_load)
- dbs_info->cdbs.prev_cpu_nice =
- kcpustat_cpu(j).cpustat[CPUTIME_NICE];
+ gov_update_cpu_data(dbs_data);
- }
return count;
}
@@ -421,6 +295,7 @@ static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf,
size_t count)
{
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
+ struct policy_dbs_info *policy_dbs;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
@@ -432,59 +307,54 @@ static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf,
input = 1000;
od_tuners->powersave_bias = input;
- ondemand_powersave_bias_init();
+
+ list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list)
+ ondemand_powersave_bias_init(policy_dbs->policy);
+
return count;
}
-show_store_one(od, sampling_rate);
-show_store_one(od, io_is_busy);
-show_store_one(od, up_threshold);
-show_store_one(od, sampling_down_factor);
-show_store_one(od, ignore_nice_load);
-show_store_one(od, powersave_bias);
-declare_show_sampling_rate_min(od);
-
-gov_sys_pol_attr_rw(sampling_rate);
-gov_sys_pol_attr_rw(io_is_busy);
-gov_sys_pol_attr_rw(up_threshold);
-gov_sys_pol_attr_rw(sampling_down_factor);
-gov_sys_pol_attr_rw(ignore_nice_load);
-gov_sys_pol_attr_rw(powersave_bias);
-gov_sys_pol_attr_ro(sampling_rate_min);
-
-static struct attribute *dbs_attributes_gov_sys[] = {
- &sampling_rate_min_gov_sys.attr,
- &sampling_rate_gov_sys.attr,
- &up_threshold_gov_sys.attr,
- &sampling_down_factor_gov_sys.attr,
- &ignore_nice_load_gov_sys.attr,
- &powersave_bias_gov_sys.attr,
- &io_is_busy_gov_sys.attr,
+gov_show_one_common(sampling_rate);
+gov_show_one_common(up_threshold);
+gov_show_one_common(sampling_down_factor);
+gov_show_one_common(ignore_nice_load);
+gov_show_one_common(min_sampling_rate);
+gov_show_one_common(io_is_busy);
+gov_show_one(od, powersave_bias);
+
+gov_attr_rw(sampling_rate);
+gov_attr_rw(io_is_busy);
+gov_attr_rw(up_threshold);
+gov_attr_rw(sampling_down_factor);
+gov_attr_rw(ignore_nice_load);
+gov_attr_rw(powersave_bias);
+gov_attr_ro(min_sampling_rate);
+
+static struct attribute *od_attributes[] = {
+ &min_sampling_rate.attr,
+ &sampling_rate.attr,
+ &up_threshold.attr,
+ &sampling_down_factor.attr,
+ &ignore_nice_load.attr,
+ &powersave_bias.attr,
+ &io_is_busy.attr,
NULL
};
-static struct attribute_group od_attr_group_gov_sys = {
- .attrs = dbs_attributes_gov_sys,
- .name = "ondemand",
-};
+/************************** sysfs end ************************/
-static struct attribute *dbs_attributes_gov_pol[] = {
- &sampling_rate_min_gov_pol.attr,
- &sampling_rate_gov_pol.attr,
- &up_threshold_gov_pol.attr,
- &sampling_down_factor_gov_pol.attr,
- &ignore_nice_load_gov_pol.attr,
- &powersave_bias_gov_pol.attr,
- &io_is_busy_gov_pol.attr,
- NULL
-};
+static struct policy_dbs_info *od_alloc(void)
+{
+ struct od_policy_dbs_info *dbs_info;
-static struct attribute_group od_attr_group_gov_pol = {
- .attrs = dbs_attributes_gov_pol,
- .name = "ondemand",
-};
+ dbs_info = kzalloc(sizeof(*dbs_info), GFP_KERNEL);
+ return dbs_info ? &dbs_info->policy_dbs : NULL;
+}
-/************************** sysfs end ************************/
+static void od_free(struct policy_dbs_info *policy_dbs)
+{
+ kfree(to_dbs_info(policy_dbs));
+}
static int od_init(struct dbs_data *dbs_data, bool notify)
{
@@ -503,7 +373,7 @@ static int od_init(struct dbs_data *dbs_data, bool notify)
put_cpu();
if (idle_time != -1ULL) {
/* Idle micro accounting is supported. Use finer thresholds */
- tuners->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
+ dbs_data->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
/*
* In nohz/micro accounting case we set the minimum frequency
* not depending on HZ, but fixed (very low). The deferred
@@ -511,17 +381,17 @@ static int od_init(struct dbs_data *dbs_data, bool notify)
*/
dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
} else {
- tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
+ dbs_data->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
/* For correct statistics, we need 10 ticks for each measure */
dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
jiffies_to_usecs(10);
}
- tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
- tuners->ignore_nice_load = 0;
+ dbs_data->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
+ dbs_data->ignore_nice_load = 0;
tuners->powersave_bias = default_powersave_bias;
- tuners->io_is_busy = should_io_be_busy();
+ dbs_data->io_is_busy = should_io_be_busy();
dbs_data->tuners = tuners;
return 0;
@@ -532,33 +402,38 @@ static void od_exit(struct dbs_data *dbs_data, bool notify)
kfree(dbs_data->tuners);
}
-define_get_cpu_dbs_routines(od_cpu_dbs_info);
+static void od_start(struct cpufreq_policy *policy)
+{
+ struct od_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
+
+ dbs_info->sample_type = OD_NORMAL_SAMPLE;
+ ondemand_powersave_bias_init(policy);
+}
static struct od_ops od_ops = {
- .powersave_bias_init_cpu = ondemand_powersave_bias_init_cpu,
.powersave_bias_target = generic_powersave_bias_target,
- .freq_increase = dbs_freq_increase,
};
-static struct common_dbs_data od_dbs_cdata = {
- .governor = GOV_ONDEMAND,
- .attr_group_gov_sys = &od_attr_group_gov_sys,
- .attr_group_gov_pol = &od_attr_group_gov_pol,
- .get_cpu_cdbs = get_cpu_cdbs,
- .get_cpu_dbs_info_s = get_cpu_dbs_info_s,
+static struct dbs_governor od_dbs_gov = {
+ .gov = {
+ .name = "ondemand",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
+ },
+ .kobj_type = { .default_attrs = od_attributes },
.gov_dbs_timer = od_dbs_timer,
- .gov_check_cpu = od_check_cpu,
- .gov_ops = &od_ops,
+ .alloc = od_alloc,
+ .free = od_free,
.init = od_init,
.exit = od_exit,
- .mutex = __MUTEX_INITIALIZER(od_dbs_cdata.mutex),
+ .start = od_start,
};
+#define CPU_FREQ_GOV_ONDEMAND (&od_dbs_gov.gov)
+
static void od_set_powersave_bias(unsigned int powersave_bias)
{
- struct cpufreq_policy *policy;
- struct dbs_data *dbs_data;
- struct od_dbs_tuners *od_tuners;
unsigned int cpu;
cpumask_t done;
@@ -567,22 +442,25 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
get_online_cpus();
for_each_online_cpu(cpu) {
- struct cpu_common_dbs_info *shared;
+ struct cpufreq_policy *policy;
+ struct policy_dbs_info *policy_dbs;
+ struct dbs_data *dbs_data;
+ struct od_dbs_tuners *od_tuners;
if (cpumask_test_cpu(cpu, &done))
continue;
- shared = per_cpu(od_cpu_dbs_info, cpu).cdbs.shared;
- if (!shared)
+ policy = cpufreq_cpu_get_raw(cpu);
+ if (!policy || policy->governor != CPU_FREQ_GOV_ONDEMAND)
continue;
- policy = shared->policy;
- cpumask_or(&done, &done, policy->cpus);
-
- if (policy->governor != &cpufreq_gov_ondemand)
+ policy_dbs = policy->governor_data;
+ if (!policy_dbs)
continue;
- dbs_data = policy->governor_data;
+ cpumask_or(&done, &done, policy->cpus);
+
+ dbs_data = policy_dbs->dbs_data;
od_tuners = dbs_data->tuners;
od_tuners->powersave_bias = default_powersave_bias;
}
@@ -605,30 +483,14 @@ void od_unregister_powersave_bias_handler(void)
}
EXPORT_SYMBOL_GPL(od_unregister_powersave_bias_handler);
-static int od_cpufreq_governor_dbs(struct cpufreq_policy *policy,
- unsigned int event)
-{
- return cpufreq_governor_dbs(policy, &od_dbs_cdata, event);
-}
-
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
-static
-#endif
-struct cpufreq_governor cpufreq_gov_ondemand = {
- .name = "ondemand",
- .governor = od_cpufreq_governor_dbs,
- .max_transition_latency = TRANSITION_LATENCY_LIMIT,
- .owner = THIS_MODULE,
-};
-
static int __init cpufreq_gov_dbs_init(void)
{
- return cpufreq_register_governor(&cpufreq_gov_ondemand);
+ return cpufreq_register_governor(CPU_FREQ_GOV_ONDEMAND);
}
static void __exit cpufreq_gov_dbs_exit(void)
{
- cpufreq_unregister_governor(&cpufreq_gov_ondemand);
+ cpufreq_unregister_governor(CPU_FREQ_GOV_ONDEMAND);
}
MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
@@ -638,6 +500,11 @@ MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for "
MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
+struct cpufreq_governor *cpufreq_default_governor(void)
+{
+ return CPU_FREQ_GOV_ONDEMAND;
+}
+
fs_initcall(cpufreq_gov_dbs_init);
#else
module_init(cpufreq_gov_dbs_init);
diff --git a/drivers/cpufreq/cpufreq_ondemand.h b/drivers/cpufreq/cpufreq_ondemand.h
new file mode 100644
index 000000000000..f0121db3cd9e
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_ondemand.h
@@ -0,0 +1,30 @@
+/*
+ * Header file for CPUFreq ondemand governor and related code.
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include "cpufreq_governor.h"
+
+struct od_policy_dbs_info {
+ struct policy_dbs_info policy_dbs;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int freq_lo;
+ unsigned int freq_lo_delay_us;
+ unsigned int freq_hi_delay_us;
+ unsigned int sample_type:1;
+};
+
+static inline struct od_policy_dbs_info *to_dbs_info(struct policy_dbs_info *policy_dbs)
+{
+ return container_of(policy_dbs, struct od_policy_dbs_info, policy_dbs);
+}
+
+struct od_dbs_tuners {
+ unsigned int powersave_bias;
+};
diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c
index cf117deb39b1..af9f4b96f5a8 100644
--- a/drivers/cpufreq/cpufreq_performance.c
+++ b/drivers/cpufreq/cpufreq_performance.c
@@ -33,10 +33,7 @@ static int cpufreq_governor_performance(struct cpufreq_policy *policy,
return 0;
}
-#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE_MODULE
-static
-#endif
-struct cpufreq_governor cpufreq_gov_performance = {
+static struct cpufreq_governor cpufreq_gov_performance = {
.name = "performance",
.governor = cpufreq_governor_performance,
.owner = THIS_MODULE,
@@ -52,6 +49,19 @@ static void __exit cpufreq_gov_performance_exit(void)
cpufreq_unregister_governor(&cpufreq_gov_performance);
}
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
+struct cpufreq_governor *cpufreq_default_governor(void)
+{
+ return &cpufreq_gov_performance;
+}
+#endif
+#ifndef CONFIG_CPU_FREQ_GOV_PERFORMANCE_MODULE
+struct cpufreq_governor *cpufreq_fallback_governor(void)
+{
+ return &cpufreq_gov_performance;
+}
+#endif
+
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION("CPUfreq policy governor 'performance'");
MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index e3b874c235ea..b8b400232a74 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -33,10 +33,7 @@ static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
return 0;
}
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE
-static
-#endif
-struct cpufreq_governor cpufreq_gov_powersave = {
+static struct cpufreq_governor cpufreq_gov_powersave = {
.name = "powersave",
.governor = cpufreq_governor_powersave,
.owner = THIS_MODULE,
@@ -57,6 +54,11 @@ MODULE_DESCRIPTION("CPUfreq policy governor 'powersave'");
MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE
+struct cpufreq_governor *cpufreq_default_governor(void)
+{
+ return &cpufreq_gov_powersave;
+}
+
fs_initcall(cpufreq_gov_powersave_init);
#else
module_init(cpufreq_gov_powersave_init);
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index 4dbf1db16aca..4d16f45ee1da 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -89,10 +89,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
return rc;
}
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
-static
-#endif
-struct cpufreq_governor cpufreq_gov_userspace = {
+static struct cpufreq_governor cpufreq_gov_userspace = {
.name = "userspace",
.governor = cpufreq_governor_userspace,
.store_setspeed = cpufreq_set,
@@ -116,6 +113,11 @@ MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");
MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
+struct cpufreq_governor *cpufreq_default_governor(void)
+{
+ return &cpufreq_gov_userspace;
+}
+
fs_initcall(cpufreq_gov_userspace_init);
#else
module_init(cpufreq_gov_userspace_init);
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index cd83d477e32d..cb5607495816 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -71,7 +71,7 @@ struct sample {
u64 mperf;
u64 tsc;
int freq;
- ktime_t time;
+ u64 time;
};
struct pstate_data {
@@ -103,13 +103,13 @@ struct _pid {
struct cpudata {
int cpu;
- struct timer_list timer;
+ struct update_util_data update_util;
struct pstate_data pstate;
struct vid_data vid;
struct _pid pid;
- ktime_t last_sample_time;
+ u64 last_sample_time;
u64 prev_aperf;
u64 prev_mperf;
u64 prev_tsc;
@@ -120,6 +120,7 @@ struct cpudata {
static struct cpudata **all_cpu_data;
struct pstate_adjust_policy {
int sample_rate_ms;
+ s64 sample_rate_ns;
int deadband;
int setpoint;
int p_gain_pct;
@@ -197,8 +198,8 @@ static struct perf_limits *limits = &powersave_limits;
static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
int deadband, int integral) {
- pid->setpoint = setpoint;
- pid->deadband = deadband;
+ pid->setpoint = int_tofp(setpoint);
+ pid->deadband = int_tofp(deadband);
pid->integral = int_tofp(integral);
pid->last_err = int_tofp(setpoint) - int_tofp(busy);
}
@@ -224,9 +225,9 @@ static signed int pid_calc(struct _pid *pid, int32_t busy)
int32_t pterm, dterm, fp_error;
int32_t integral_limit;
- fp_error = int_tofp(pid->setpoint) - busy;
+ fp_error = pid->setpoint - busy;
- if (abs(fp_error) <= int_tofp(pid->deadband))
+ if (abs(fp_error) <= pid->deadband)
return 0;
pterm = mul_fp(pid->p_gain, fp_error);
@@ -286,7 +287,7 @@ static inline void update_turbo_state(void)
cpu->pstate.max_pstate == cpu->pstate.turbo_pstate);
}
-static void intel_pstate_hwp_set(void)
+static void intel_pstate_hwp_set(const struct cpumask *cpumask)
{
int min, hw_min, max, hw_max, cpu, range, adj_range;
u64 value, cap;
@@ -296,9 +297,7 @@ static void intel_pstate_hwp_set(void)
hw_max = HWP_HIGHEST_PERF(cap);
range = hw_max - hw_min;
- get_online_cpus();
-
- for_each_online_cpu(cpu) {
+ for_each_cpu(cpu, cpumask) {
rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value);
adj_range = limits->min_perf_pct * range / 100;
min = hw_min + adj_range;
@@ -317,7 +316,12 @@ static void intel_pstate_hwp_set(void)
value |= HWP_MAX_PERF(max);
wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value);
}
+}
+static void intel_pstate_hwp_set_online_cpus(void)
+{
+ get_online_cpus();
+ intel_pstate_hwp_set(cpu_online_mask);
put_online_cpus();
}
@@ -439,7 +443,7 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
limits->no_turbo = clamp_t(int, input, 0, 1);
if (hwp_active)
- intel_pstate_hwp_set();
+ intel_pstate_hwp_set_online_cpus();
return count;
}
@@ -465,7 +469,7 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
int_tofp(100));
if (hwp_active)
- intel_pstate_hwp_set();
+ intel_pstate_hwp_set_online_cpus();
return count;
}
@@ -490,7 +494,7 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
int_tofp(100));
if (hwp_active)
- intel_pstate_hwp_set();
+ intel_pstate_hwp_set_online_cpus();
return count;
}
@@ -531,6 +535,9 @@ static void __init intel_pstate_sysfs_expose_params(void)
static void intel_pstate_hwp_enable(struct cpudata *cpudata)
{
+ /* First disable HWP notification interrupt as we don't process them */
+ wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00);
+
wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
}
@@ -712,7 +719,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
if (limits->no_turbo && !limits->turbo_disabled)
val |= (u64)1 << 32;
- wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
+ wrmsrl(MSR_IA32_PERF_CTL, val);
}
static int knl_get_turbo_pstate(void)
@@ -824,11 +831,11 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
* policy, or by cpu specific default values determined through
* experimentation.
*/
- max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), limits->max_perf));
+ max_perf_adj = fp_toint(max_perf * limits->max_perf);
*max = clamp_t(int, max_perf_adj,
cpu->pstate.min_pstate, cpu->pstate.turbo_pstate);
- min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits->min_perf));
+ min_perf = fp_toint(max_perf * limits->min_perf);
*min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
}
@@ -874,16 +881,10 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu)
core_pct = int_tofp(sample->aperf) * int_tofp(100);
core_pct = div64_u64(core_pct, int_tofp(sample->mperf));
- sample->freq = fp_toint(
- mul_fp(int_tofp(
- cpu->pstate.max_pstate_physical *
- cpu->pstate.scaling / 100),
- core_pct));
-
sample->core_pct_busy = (int32_t)core_pct;
}
-static inline void intel_pstate_sample(struct cpudata *cpu)
+static inline bool intel_pstate_sample(struct cpudata *cpu, u64 time)
{
u64 aperf, mperf;
unsigned long flags;
@@ -893,14 +894,14 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
rdmsrl(MSR_IA32_APERF, aperf);
rdmsrl(MSR_IA32_MPERF, mperf);
tsc = rdtsc();
- if ((cpu->prev_mperf == mperf) || (cpu->prev_tsc == tsc)) {
+ if (cpu->prev_mperf == mperf || cpu->prev_tsc == tsc) {
local_irq_restore(flags);
- return;
+ return false;
}
local_irq_restore(flags);
cpu->last_sample_time = cpu->sample.time;
- cpu->sample.time = ktime_get();
+ cpu->sample.time = time;
cpu->sample.aperf = aperf;
cpu->sample.mperf = mperf;
cpu->sample.tsc = tsc;
@@ -908,27 +909,16 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
cpu->sample.mperf -= cpu->prev_mperf;
cpu->sample.tsc -= cpu->prev_tsc;
- intel_pstate_calc_busy(cpu);
-
cpu->prev_aperf = aperf;
cpu->prev_mperf = mperf;
cpu->prev_tsc = tsc;
+ return true;
}
-static inline void intel_hwp_set_sample_time(struct cpudata *cpu)
-{
- int delay;
-
- delay = msecs_to_jiffies(50);
- mod_timer_pinned(&cpu->timer, jiffies + delay);
-}
-
-static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
+static inline int32_t get_avg_frequency(struct cpudata *cpu)
{
- int delay;
-
- delay = msecs_to_jiffies(pid_params.sample_rate_ms);
- mod_timer_pinned(&cpu->timer, jiffies + delay);
+ return div64_u64(cpu->pstate.max_pstate_physical * cpu->sample.aperf *
+ cpu->pstate.scaling, cpu->sample.mperf);
}
static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
@@ -954,7 +944,6 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
mperf = cpu->sample.mperf + delta_iowait_mperf;
cpu->prev_cummulative_iowait = cummulative_iowait;
-
/*
* The load can be estimated as the ratio of the mperf counter
* running at a constant frequency during active periods
@@ -970,8 +959,9 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
{
int32_t core_busy, max_pstate, current_pstate, sample_ratio;
- s64 duration_us;
- u32 sample_time;
+ u64 duration_ns;
+
+ intel_pstate_calc_busy(cpu);
/*
* core_busy is the ratio of actual performance to max
@@ -990,18 +980,16 @@ static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
/*
- * Since we have a deferred timer, it will not fire unless
- * we are in C0. So, determine if the actual elapsed time
- * is significantly greater (3x) than our sample interval. If it
- * is, then we were idle for a long enough period of time
- * to adjust our busyness.
+ * Since our utilization update callback will not run unless we are
+ * in C0, check if the actual elapsed time is significantly greater (3x)
+ * than our sample interval. If it is, then we were idle for a long
+ * enough period of time to adjust our busyness.
*/
- sample_time = pid_params.sample_rate_ms * USEC_PER_MSEC;
- duration_us = ktime_us_delta(cpu->sample.time,
- cpu->last_sample_time);
- if (duration_us > sample_time * 3) {
- sample_ratio = div_fp(int_tofp(sample_time),
- int_tofp(duration_us));
+ duration_ns = cpu->sample.time - cpu->last_sample_time;
+ if ((s64)duration_ns > pid_params.sample_rate_ns * 3
+ && cpu->last_sample_time > 0) {
+ sample_ratio = div_fp(int_tofp(pid_params.sample_rate_ns),
+ int_tofp(duration_ns));
core_busy = mul_fp(core_busy, sample_ratio);
}
@@ -1028,26 +1016,21 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
sample->mperf,
sample->aperf,
sample->tsc,
- sample->freq);
+ get_avg_frequency(cpu));
}
-static void intel_hwp_timer_func(unsigned long __data)
+static void intel_pstate_update_util(struct update_util_data *data, u64 time,
+ unsigned long util, unsigned long max)
{
- struct cpudata *cpu = (struct cpudata *) __data;
+ struct cpudata *cpu = container_of(data, struct cpudata, update_util);
+ u64 delta_ns = time - cpu->sample.time;
- intel_pstate_sample(cpu);
- intel_hwp_set_sample_time(cpu);
-}
+ if ((s64)delta_ns >= pid_params.sample_rate_ns) {
+ bool sample_taken = intel_pstate_sample(cpu, time);
-static void intel_pstate_timer_func(unsigned long __data)
-{
- struct cpudata *cpu = (struct cpudata *) __data;
-
- intel_pstate_sample(cpu);
-
- intel_pstate_adjust_busy_pstate(cpu);
-
- intel_pstate_set_sample_time(cpu);
+ if (sample_taken && !hwp_active)
+ intel_pstate_adjust_busy_pstate(cpu);
+ }
}
#define ICPU(model, policy) \
@@ -1095,24 +1078,19 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
cpu->cpu = cpunum;
- if (hwp_active)
+ if (hwp_active) {
intel_pstate_hwp_enable(cpu);
+ pid_params.sample_rate_ms = 50;
+ pid_params.sample_rate_ns = 50 * NSEC_PER_MSEC;
+ }
intel_pstate_get_cpu_pstates(cpu);
- init_timer_deferrable(&cpu->timer);
- cpu->timer.data = (unsigned long)cpu;
- cpu->timer.expires = jiffies + HZ/100;
-
- if (!hwp_active)
- cpu->timer.function = intel_pstate_timer_func;
- else
- cpu->timer.function = intel_hwp_timer_func;
-
intel_pstate_busy_pid_reset(cpu);
- intel_pstate_sample(cpu);
+ intel_pstate_sample(cpu, 0);
- add_timer_on(&cpu->timer, cpunum);
+ cpu->update_util.func = intel_pstate_update_util;
+ cpufreq_set_update_util_data(cpunum, &cpu->update_util);
pr_debug("intel_pstate: controlling: cpu %d\n", cpunum);
@@ -1128,7 +1106,7 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
if (!cpu)
return 0;
sample = &cpu->sample;
- return sample->freq;
+ return get_avg_frequency(cpu);
}
static int intel_pstate_set_policy(struct cpufreq_policy *policy)
@@ -1141,7 +1119,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
pr_debug("intel_pstate: set performance\n");
limits = &performance_limits;
if (hwp_active)
- intel_pstate_hwp_set();
+ intel_pstate_hwp_set(policy->cpus);
return 0;
}
@@ -1173,7 +1151,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
int_tofp(100));
if (hwp_active)
- intel_pstate_hwp_set();
+ intel_pstate_hwp_set(policy->cpus);
return 0;
}
@@ -1196,7 +1174,9 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
pr_debug("intel_pstate: CPU %d exiting\n", cpu_num);
- del_timer_sync(&all_cpu_data[cpu_num]->timer);
+ cpufreq_set_update_util_data(cpu_num, NULL);
+ synchronize_sched();
+
if (hwp_active)
return;
@@ -1260,6 +1240,7 @@ static int intel_pstate_msrs_not_valid(void)
static void copy_pid_params(struct pstate_adjust_policy *policy)
{
pid_params.sample_rate_ms = policy->sample_rate_ms;
+ pid_params.sample_rate_ns = pid_params.sample_rate_ms * NSEC_PER_MSEC;
pid_params.p_gain_pct = policy->p_gain_pct;
pid_params.i_gain_pct = policy->i_gain_pct;
pid_params.d_gain_pct = policy->d_gain_pct;
@@ -1397,6 +1378,11 @@ static inline bool intel_pstate_platform_pwr_mgmt_exists(void) { return false; }
static inline bool intel_pstate_has_acpi_ppc(void) { return false; }
#endif /* CONFIG_ACPI */
+static const struct x86_cpu_id hwp_support_ids[] __initconst = {
+ { X86_VENDOR_INTEL, 6, X86_MODEL_ANY, X86_FEATURE_HWP },
+ {}
+};
+
static int __init intel_pstate_init(void)
{
int cpu, rc = 0;
@@ -1406,17 +1392,16 @@ static int __init intel_pstate_init(void)
if (no_load)
return -ENODEV;
+ if (x86_match_cpu(hwp_support_ids) && !no_hwp) {
+ copy_cpu_funcs(&core_params.funcs);
+ hwp_active++;
+ goto hwp_cpu_matched;
+ }
+
id = x86_match_cpu(intel_pstate_cpu_ids);
if (!id)
return -ENODEV;
- /*
- * The Intel pstate driver will be ignored if the platform
- * firmware has its own power management modes.
- */
- if (intel_pstate_platform_pwr_mgmt_exists())
- return -ENODEV;
-
cpu_def = (struct cpu_defaults *)id->driver_data;
copy_pid_params(&cpu_def->pid_policy);
@@ -1425,17 +1410,20 @@ static int __init intel_pstate_init(void)
if (intel_pstate_msrs_not_valid())
return -ENODEV;
+hwp_cpu_matched:
+ /*
+ * The Intel pstate driver will be ignored if the platform
+ * firmware has its own power management modes.
+ */
+ if (intel_pstate_platform_pwr_mgmt_exists())
+ return -ENODEV;
+
pr_info("Intel P-state driver initializing.\n");
all_cpu_data = vzalloc(sizeof(void *) * num_possible_cpus());
if (!all_cpu_data)
return -ENOMEM;
- if (static_cpu_has_safe(X86_FEATURE_HWP) && !no_hwp) {
- pr_info("intel_pstate: HWP enabled\n");
- hwp_active++;
- }
-
if (!hwp_active && hwp_only)
goto out;
@@ -1446,12 +1434,16 @@ static int __init intel_pstate_init(void)
intel_pstate_debug_expose_params();
intel_pstate_sysfs_expose_params();
+ if (hwp_active)
+ pr_info("intel_pstate: HWP enabled\n");
+
return rc;
out:
get_online_cpus();
for_each_online_cpu(cpu) {
if (all_cpu_data[cpu]) {
- del_timer_sync(&all_cpu_data[cpu]->timer);
+ cpufreq_set_update_util_data(cpu, NULL);
+ synchronize_sched();
kfree(all_cpu_data[cpu]);
}
}
diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c
index 1efba340456d..2058e6d292ce 100644
--- a/drivers/cpufreq/mt8173-cpufreq.c
+++ b/drivers/cpufreq/mt8173-cpufreq.c
@@ -17,6 +17,7 @@
#include <linux/cpu_cooling.h>
#include <linux/cpufreq.h>
#include <linux/cpumask.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index 547890fd9572..50bf12033bbc 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -28,6 +28,8 @@
#include <linux/of.h>
#include <linux/reboot.h>
#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <trace/events/power.h>
#include <asm/cputhreads.h>
#include <asm/firmware.h>
@@ -42,13 +44,24 @@
static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
static bool rebooting, throttled, occ_reset;
+static unsigned int *core_to_chip_map;
+
+static const char * const throttle_reason[] = {
+ "No throttling",
+ "Power Cap",
+ "Processor Over Temperature",
+ "Power Supply Failure",
+ "Over Current",
+ "OCC Reset"
+};
static struct chip {
unsigned int id;
bool throttled;
+ bool restore;
+ u8 throttle_reason;
cpumask_t mask;
struct work_struct throttle;
- bool restore;
} *chips;
static int nr_chips;
@@ -312,13 +325,14 @@ static inline unsigned int get_nominal_index(void)
static void powernv_cpufreq_throttle_check(void *data)
{
unsigned int cpu = smp_processor_id();
+ unsigned int chip_id = core_to_chip_map[cpu_core_index_of_thread(cpu)];
unsigned long pmsr;
int pmsr_pmax, i;
pmsr = get_pmspr(SPRN_PMSR);
for (i = 0; i < nr_chips; i++)
- if (chips[i].id == cpu_to_chip_id(cpu))
+ if (chips[i].id == chip_id)
break;
/* Check for Pmax Capping */
@@ -328,17 +342,17 @@ static void powernv_cpufreq_throttle_check(void *data)
goto next;
chips[i].throttled = true;
if (pmsr_pmax < powernv_pstate_info.nominal)
- pr_crit("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
- cpu, chips[i].id, pmsr_pmax,
- powernv_pstate_info.nominal);
- else
- pr_info("CPU %d on Chip %u has Pmax reduced below turbo frequency (%d < %d)\n",
- cpu, chips[i].id, pmsr_pmax,
- powernv_pstate_info.max);
+ pr_warn_once("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
+ cpu, chips[i].id, pmsr_pmax,
+ powernv_pstate_info.nominal);
+ trace_powernv_throttle(chips[i].id,
+ throttle_reason[chips[i].throttle_reason],
+ pmsr_pmax);
} else if (chips[i].throttled) {
chips[i].throttled = false;
- pr_info("CPU %d on Chip %u has Pmax restored to %d\n", cpu,
- chips[i].id, pmsr_pmax);
+ trace_powernv_throttle(chips[i].id,
+ throttle_reason[chips[i].throttle_reason],
+ pmsr_pmax);
}
/* Check if Psafe_mode_active is set in PMSR. */
@@ -356,7 +370,7 @@ next:
if (throttled) {
pr_info("PMSR = %16lx\n", pmsr);
- pr_crit("CPU Frequency could be throttled\n");
+ pr_warn("CPU Frequency could be throttled\n");
}
}
@@ -423,18 +437,19 @@ void powernv_cpufreq_work_fn(struct work_struct *work)
{
struct chip *chip = container_of(work, struct chip, throttle);
unsigned int cpu;
- cpumask_var_t mask;
+ cpumask_t mask;
- smp_call_function_any(&chip->mask,
+ get_online_cpus();
+ cpumask_and(&mask, &chip->mask, cpu_online_mask);
+ smp_call_function_any(&mask,
powernv_cpufreq_throttle_check, NULL, 0);
if (!chip->restore)
- return;
+ goto out;
chip->restore = false;
- cpumask_copy(mask, &chip->mask);
- for_each_cpu_and(cpu, mask, cpu_online_mask) {
- int index, tcpu;
+ for_each_cpu(cpu, &mask) {
+ int index;
struct cpufreq_policy policy;
cpufreq_get_policy(&policy, cpu);
@@ -442,20 +457,12 @@ void powernv_cpufreq_work_fn(struct work_struct *work)
policy.cur,
CPUFREQ_RELATION_C, &index);
powernv_cpufreq_target_index(&policy, index);
- for_each_cpu(tcpu, policy.cpus)
- cpumask_clear_cpu(tcpu, mask);
+ cpumask_andnot(&mask, &mask, policy.cpus);
}
+out:
+ put_online_cpus();
}
-static char throttle_reason[][30] = {
- "No throttling",
- "Power Cap",
- "Processor Over Temperature",
- "Power Supply Failure",
- "Over Current",
- "OCC Reset"
- };
-
static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
unsigned long msg_type, void *_msg)
{
@@ -481,7 +488,7 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
*/
if (!throttled) {
throttled = true;
- pr_crit("CPU frequency is throttled for duration\n");
+ pr_warn("CPU frequency is throttled for duration\n");
}
break;
@@ -505,23 +512,18 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
return 0;
}
- if (omsg.throttle_status &&
+ for (i = 0; i < nr_chips; i++)
+ if (chips[i].id == omsg.chip)
+ break;
+
+ if (omsg.throttle_status >= 0 &&
omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS)
- pr_info("OCC: Chip %u Pmax reduced due to %s\n",
- (unsigned int)omsg.chip,
- throttle_reason[omsg.throttle_status]);
- else if (!omsg.throttle_status)
- pr_info("OCC: Chip %u %s\n", (unsigned int)omsg.chip,
- throttle_reason[omsg.throttle_status]);
- else
- return 0;
+ chips[i].throttle_reason = omsg.throttle_status;
- for (i = 0; i < nr_chips; i++)
- if (chips[i].id == omsg.chip) {
- if (!omsg.throttle_status)
- chips[i].restore = true;
- schedule_work(&chips[i].throttle);
- }
+ if (!omsg.throttle_status)
+ chips[i].restore = true;
+
+ schedule_work(&chips[i].throttle);
}
return 0;
}
@@ -556,29 +558,54 @@ static int init_chip_info(void)
unsigned int chip[256];
unsigned int cpu, i;
unsigned int prev_chip_id = UINT_MAX;
+ cpumask_t cpu_mask;
+ int ret = -ENOMEM;
+
+ core_to_chip_map = kcalloc(cpu_nr_cores(), sizeof(unsigned int),
+ GFP_KERNEL);
+ if (!core_to_chip_map)
+ goto out;
- for_each_possible_cpu(cpu) {
+ cpumask_copy(&cpu_mask, cpu_possible_mask);
+ for_each_cpu(cpu, &cpu_mask) {
unsigned int id = cpu_to_chip_id(cpu);
if (prev_chip_id != id) {
prev_chip_id = id;
chip[nr_chips++] = id;
}
+ core_to_chip_map[cpu_core_index_of_thread(cpu)] = id;
+ cpumask_andnot(&cpu_mask, &cpu_mask, cpu_sibling_mask(cpu));
}
- chips = kmalloc_array(nr_chips, sizeof(struct chip), GFP_KERNEL);
+ chips = kcalloc(nr_chips, sizeof(struct chip), GFP_KERNEL);
if (!chips)
- return -ENOMEM;
+ goto free_chip_map;
for (i = 0; i < nr_chips; i++) {
chips[i].id = chip[i];
- chips[i].throttled = false;
cpumask_copy(&chips[i].mask, cpumask_of_node(chip[i]));
INIT_WORK(&chips[i].throttle, powernv_cpufreq_work_fn);
- chips[i].restore = false;
}
return 0;
+free_chip_map:
+ kfree(core_to_chip_map);
+out:
+ return ret;
+}
+
+static inline void clean_chip_info(void)
+{
+ kfree(chips);
+ kfree(core_to_chip_map);
+}
+
+static inline void unregister_all_notifiers(void)
+{
+ opal_message_notifier_unregister(OPAL_MSG_OCC,
+ &powernv_cpufreq_opal_nb);
+ unregister_reboot_notifier(&powernv_cpufreq_reboot_nb);
}
static int __init powernv_cpufreq_init(void)
@@ -591,28 +618,35 @@ static int __init powernv_cpufreq_init(void)
/* Discover pstates from device tree and init */
rc = init_powernv_pstates();
- if (rc) {
- pr_info("powernv-cpufreq disabled. System does not support PState control\n");
- return rc;
- }
+ if (rc)
+ goto out;
/* Populate chip info */
rc = init_chip_info();
if (rc)
- return rc;
+ goto out;
register_reboot_notifier(&powernv_cpufreq_reboot_nb);
opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb);
- return cpufreq_register_driver(&powernv_cpufreq_driver);
+
+ rc = cpufreq_register_driver(&powernv_cpufreq_driver);
+ if (!rc)
+ return 0;
+
+ pr_info("Failed to register the cpufreq driver (%d)\n", rc);
+ unregister_all_notifiers();
+ clean_chip_info();
+out:
+ pr_info("Platform driver disabled. System does not support PState control\n");
+ return rc;
}
module_init(powernv_cpufreq_init);
static void __exit powernv_cpufreq_exit(void)
{
- unregister_reboot_notifier(&powernv_cpufreq_reboot_nb);
- opal_message_notifier_unregister(OPAL_MSG_OCC,
- &powernv_cpufreq_opal_nb);
cpufreq_unregister_driver(&powernv_cpufreq_driver);
+ unregister_all_notifiers();
+ clean_chip_info();
}
module_exit(powernv_cpufreq_exit);
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 0742b3296673..27fc733cb5b9 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -199,8 +199,8 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
static void get_typical_interval(struct menu_device *data)
{
int i, divisor;
- unsigned int max, thresh;
- uint64_t avg, stddev;
+ unsigned int max, thresh, avg;
+ uint64_t sum, variance;
thresh = UINT_MAX; /* Discard outliers above this value */
@@ -208,52 +208,51 @@ again:
/* First calculate the average of past intervals */
max = 0;
- avg = 0;
+ sum = 0;
divisor = 0;
for (i = 0; i < INTERVALS; i++) {
unsigned int value = data->intervals[i];
if (value <= thresh) {
- avg += value;
+ sum += value;
divisor++;
if (value > max)
max = value;
}
}
if (divisor == INTERVALS)
- avg >>= INTERVAL_SHIFT;
+ avg = sum >> INTERVAL_SHIFT;
else
- do_div(avg, divisor);
+ avg = div_u64(sum, divisor);
- /* Then try to determine standard deviation */
- stddev = 0;
+ /* Then try to determine variance */
+ variance = 0;
for (i = 0; i < INTERVALS; i++) {
unsigned int value = data->intervals[i];
if (value <= thresh) {
- int64_t diff = value - avg;
- stddev += diff * diff;
+ int64_t diff = (int64_t)value - avg;
+ variance += diff * diff;
}
}
if (divisor == INTERVALS)
- stddev >>= INTERVAL_SHIFT;
+ variance >>= INTERVAL_SHIFT;
else
- do_div(stddev, divisor);
+ do_div(variance, divisor);
/*
- * The typical interval is obtained when standard deviation is small
- * or standard deviation is small compared to the average interval.
- *
- * int_sqrt() formal parameter type is unsigned long. When the
- * greatest difference to an outlier exceeds ~65 ms * sqrt(divisor)
- * the resulting squared standard deviation exceeds the input domain
- * of int_sqrt on platforms where unsigned long is 32 bits in size.
- * In such case reject the candidate average.
+ * The typical interval is obtained when standard deviation is
+ * small (stddev <= 20 us, variance <= 400 us^2) or standard
+ * deviation is small compared to the average interval (avg >
+ * 6*stddev, avg^2 > 36*variance). The average is smaller than
+ * UINT_MAX aka U32_MAX, so computing its square does not
+ * overflow a u64. We simply reject this candidate average if
+ * the standard deviation is greater than 715 s (which is
+ * rather unlikely).
*
* Use this result only if there is no timer to wake us up sooner.
*/
- if (likely(stddev <= ULONG_MAX)) {
- stddev = int_sqrt(stddev);
- if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
- || stddev <= 20) {
+ if (likely(variance <= U64_MAX/36)) {
+ if ((((u64)avg*avg > variance*36) && (divisor * 4 >= INTERVALS * 3))
+ || variance <= 400) {
if (data->next_timer_us > avg)
data->predicted_us = avg;
return;
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 07d494276aad..477fffdb4f49 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -296,6 +296,7 @@ config CRYPTO_DEV_OMAP_AES
depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP2PLUS
select CRYPTO_AES
select CRYPTO_BLKCIPHER
+ select CRYPTO_ENGINE
help
OMAP processors have AES module accelerator. Select this if you
want to use the OMAP module for AES algorithms.
@@ -487,7 +488,7 @@ config CRYPTO_DEV_IMGTEC_HASH
config CRYPTO_DEV_SUN4I_SS
tristate "Support for Allwinner Security System cryptographic accelerator"
- depends on ARCH_SUNXI
+ depends on ARCH_SUNXI && !64BIT
select CRYPTO_MD5
select CRYPTO_SHA1
select CRYPTO_AES
@@ -507,6 +508,10 @@ config CRYPTO_DEV_ROCKCHIP
depends on OF && ARCH_ROCKCHIP
select CRYPTO_AES
select CRYPTO_DES
+ select CRYPTO_MD5
+ select CRYPTO_SHA1
+ select CRYPTO_SHA256
+ select CRYPTO_HASH
select CRYPTO_BLKCIPHER
help
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 3eb3f1279fb7..e3d40a8dfffb 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -369,12 +369,6 @@ static inline size_t atmel_aes_padlen(size_t len, size_t block_size)
return len ? block_size - len : 0;
}
-static inline struct aead_request *
-aead_request_cast(struct crypto_async_request *req)
-{
- return container_of(req, struct aead_request, base);
-}
-
static struct atmel_aes_dev *atmel_aes_find_dev(struct atmel_aes_base_ctx *ctx)
{
struct atmel_aes_dev *aes_dd = NULL;
@@ -2085,9 +2079,9 @@ static int atmel_aes_probe(struct platform_device *pdev)
}
aes_dd->io_base = devm_ioremap_resource(&pdev->dev, aes_res);
- if (!aes_dd->io_base) {
+ if (IS_ERR(aes_dd->io_base)) {
dev_err(dev, "can't ioremap\n");
- err = -ENOMEM;
+ err = PTR_ERR(aes_dd->io_base);
goto res_err;
}
diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
index 83b2d7425666..e08897109cab 100644
--- a/drivers/crypto/atmel-sha-regs.h
+++ b/drivers/crypto/atmel-sha-regs.h
@@ -8,6 +8,8 @@
#define SHA_CR_START (1 << 0)
#define SHA_CR_FIRST (1 << 4)
#define SHA_CR_SWRST (1 << 8)
+#define SHA_CR_WUIHV (1 << 12)
+#define SHA_CR_WUIEHV (1 << 13)
#define SHA_MR 0x04
#define SHA_MR_MODE_MASK (0x3 << 0)
@@ -15,6 +17,8 @@
#define SHA_MR_MODE_AUTO 0x1
#define SHA_MR_MODE_PDC 0x2
#define SHA_MR_PROCDLY (1 << 4)
+#define SHA_MR_UIHV (1 << 5)
+#define SHA_MR_UIEHV (1 << 6)
#define SHA_MR_ALGO_SHA1 (0 << 8)
#define SHA_MR_ALGO_SHA256 (1 << 8)
#define SHA_MR_ALGO_SHA384 (2 << 8)
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 8bf9914d4d15..97e34799e077 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -53,6 +53,7 @@
#define SHA_FLAGS_FINUP BIT(16)
#define SHA_FLAGS_SG BIT(17)
+#define SHA_FLAGS_ALGO_MASK GENMASK(22, 18)
#define SHA_FLAGS_SHA1 BIT(18)
#define SHA_FLAGS_SHA224 BIT(19)
#define SHA_FLAGS_SHA256 BIT(20)
@@ -60,11 +61,12 @@
#define SHA_FLAGS_SHA512 BIT(22)
#define SHA_FLAGS_ERROR BIT(23)
#define SHA_FLAGS_PAD BIT(24)
+#define SHA_FLAGS_RESTORE BIT(25)
#define SHA_OP_UPDATE 1
#define SHA_OP_FINAL 2
-#define SHA_BUFFER_LEN PAGE_SIZE
+#define SHA_BUFFER_LEN (PAGE_SIZE / 16)
#define ATMEL_SHA_DMA_THRESHOLD 56
@@ -73,10 +75,15 @@ struct atmel_sha_caps {
bool has_dualbuff;
bool has_sha224;
bool has_sha_384_512;
+ bool has_uihv;
};
struct atmel_sha_dev;
+/*
+ * .statesize = sizeof(struct atmel_sha_reqctx) must be <= PAGE_SIZE / 8 as
+ * tested by the ahash_prepare_alg() function.
+ */
struct atmel_sha_reqctx {
struct atmel_sha_dev *dd;
unsigned long flags;
@@ -95,7 +102,7 @@ struct atmel_sha_reqctx {
size_t block_size;
- u8 buffer[0] __aligned(sizeof(u32));
+ u8 buffer[SHA_BUFFER_LEN + SHA512_BLOCK_SIZE] __aligned(sizeof(u32));
};
struct atmel_sha_ctx {
@@ -122,6 +129,7 @@ struct atmel_sha_dev {
spinlock_t lock;
int err;
struct tasklet_struct done_task;
+ struct tasklet_struct queue_task;
unsigned long flags;
struct crypto_queue queue;
@@ -317,7 +325,8 @@ static int atmel_sha_init(struct ahash_request *req)
static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
{
struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
- u32 valcr = 0, valmr = SHA_MR_MODE_AUTO;
+ u32 valmr = SHA_MR_MODE_AUTO;
+ unsigned int i, hashsize = 0;
if (likely(dma)) {
if (!dd->caps.has_dma)
@@ -329,22 +338,62 @@ static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
}
- if (ctx->flags & SHA_FLAGS_SHA1)
+ switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
+ case SHA_FLAGS_SHA1:
valmr |= SHA_MR_ALGO_SHA1;
- else if (ctx->flags & SHA_FLAGS_SHA224)
+ hashsize = SHA1_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA224:
valmr |= SHA_MR_ALGO_SHA224;
- else if (ctx->flags & SHA_FLAGS_SHA256)
+ hashsize = SHA256_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA256:
valmr |= SHA_MR_ALGO_SHA256;
- else if (ctx->flags & SHA_FLAGS_SHA384)
+ hashsize = SHA256_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA384:
valmr |= SHA_MR_ALGO_SHA384;
- else if (ctx->flags & SHA_FLAGS_SHA512)
+ hashsize = SHA512_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA512:
valmr |= SHA_MR_ALGO_SHA512;
+ hashsize = SHA512_DIGEST_SIZE;
+ break;
+
+ default:
+ break;
+ }
/* Setting CR_FIRST only for the first iteration */
- if (!(ctx->digcnt[0] || ctx->digcnt[1]))
- valcr = SHA_CR_FIRST;
+ if (!(ctx->digcnt[0] || ctx->digcnt[1])) {
+ atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
+ } else if (dd->caps.has_uihv && (ctx->flags & SHA_FLAGS_RESTORE)) {
+ const u32 *hash = (const u32 *)ctx->digest;
+
+ /*
+ * Restore the hardware context: update the User Initialize
+ * Hash Value (UIHV) with the value saved when the latest
+ * 'update' operation completed on this very same crypto
+ * request.
+ */
+ ctx->flags &= ~SHA_FLAGS_RESTORE;
+ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV);
+ for (i = 0; i < hashsize / sizeof(u32); ++i)
+ atmel_sha_write(dd, SHA_REG_DIN(i), hash[i]);
+ atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
+ valmr |= SHA_MR_UIHV;
+ }
+ /*
+ * WARNING: If the UIHV feature is not available, the hardware CANNOT
+ * process concurrent requests: the internal registers used to store
+ * the hash/digest are still set to the partial digest output values
+ * computed during the latest round.
+ */
- atmel_sha_write(dd, SHA_CR, valcr);
atmel_sha_write(dd, SHA_MR, valmr);
}
@@ -713,23 +762,31 @@ static void atmel_sha_copy_hash(struct ahash_request *req)
{
struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
u32 *hash = (u32 *)ctx->digest;
- int i;
+ unsigned int i, hashsize;
- if (ctx->flags & SHA_FLAGS_SHA1)
- for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
- hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
- else if (ctx->flags & SHA_FLAGS_SHA224)
- for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(u32); i++)
- hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
- else if (ctx->flags & SHA_FLAGS_SHA256)
- for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++)
- hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
- else if (ctx->flags & SHA_FLAGS_SHA384)
- for (i = 0; i < SHA384_DIGEST_SIZE / sizeof(u32); i++)
- hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
- else
- for (i = 0; i < SHA512_DIGEST_SIZE / sizeof(u32); i++)
- hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
+ switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
+ case SHA_FLAGS_SHA1:
+ hashsize = SHA1_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA224:
+ case SHA_FLAGS_SHA256:
+ hashsize = SHA256_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA384:
+ case SHA_FLAGS_SHA512:
+ hashsize = SHA512_DIGEST_SIZE;
+ break;
+
+ default:
+ /* Should not happen... */
+ return;
+ }
+
+ for (i = 0; i < hashsize / sizeof(u32); ++i)
+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
+ ctx->flags |= SHA_FLAGS_RESTORE;
}
static void atmel_sha_copy_ready_hash(struct ahash_request *req)
@@ -788,7 +845,7 @@ static void atmel_sha_finish_req(struct ahash_request *req, int err)
req->base.complete(&req->base, err);
/* handle new request */
- tasklet_schedule(&dd->done_task);
+ tasklet_schedule(&dd->queue_task);
}
static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
@@ -922,36 +979,17 @@ static int atmel_sha_update(struct ahash_request *req)
static int atmel_sha_final(struct ahash_request *req)
{
struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
- struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
- struct atmel_sha_dev *dd = tctx->dd;
-
- int err = 0;
ctx->flags |= SHA_FLAGS_FINUP;
if (ctx->flags & SHA_FLAGS_ERROR)
return 0; /* uncompleted hash is not needed */
- if (ctx->bufcnt) {
- return atmel_sha_enqueue(req, SHA_OP_FINAL);
- } else if (!(ctx->flags & SHA_FLAGS_PAD)) { /* add padding */
- err = atmel_sha_hw_init(dd);
- if (err)
- goto err1;
-
- dd->flags |= SHA_FLAGS_BUSY;
- err = atmel_sha_final_req(dd);
- } else {
+ if (ctx->flags & SHA_FLAGS_PAD)
/* copy ready hash (+ finalize hmac) */
return atmel_sha_finish(req);
- }
-
-err1:
- if (err != -EINPROGRESS)
- /* done_task will not finish it, so do it here */
- atmel_sha_finish_req(req, err);
- return err;
+ return atmel_sha_enqueue(req, SHA_OP_FINAL);
}
static int atmel_sha_finup(struct ahash_request *req)
@@ -979,11 +1017,27 @@ static int atmel_sha_digest(struct ahash_request *req)
return atmel_sha_init(req) ?: atmel_sha_finup(req);
}
+
+static int atmel_sha_export(struct ahash_request *req, void *out)
+{
+ const struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+
+ memcpy(out, ctx, sizeof(*ctx));
+ return 0;
+}
+
+static int atmel_sha_import(struct ahash_request *req, const void *in)
+{
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+
+ memcpy(ctx, in, sizeof(*ctx));
+ return 0;
+}
+
static int atmel_sha_cra_init(struct crypto_tfm *tfm)
{
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
- sizeof(struct atmel_sha_reqctx) +
- SHA_BUFFER_LEN + SHA512_BLOCK_SIZE);
+ sizeof(struct atmel_sha_reqctx));
return 0;
}
@@ -995,8 +1049,11 @@ static struct ahash_alg sha_1_256_algs[] = {
.final = atmel_sha_final,
.finup = atmel_sha_finup,
.digest = atmel_sha_digest,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
.halg = {
.digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
.base = {
.cra_name = "sha1",
.cra_driver_name = "atmel-sha1",
@@ -1016,8 +1073,11 @@ static struct ahash_alg sha_1_256_algs[] = {
.final = atmel_sha_final,
.finup = atmel_sha_finup,
.digest = atmel_sha_digest,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
.halg = {
.digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
.base = {
.cra_name = "sha256",
.cra_driver_name = "atmel-sha256",
@@ -1039,8 +1099,11 @@ static struct ahash_alg sha_224_alg = {
.final = atmel_sha_final,
.finup = atmel_sha_finup,
.digest = atmel_sha_digest,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
.halg = {
.digestsize = SHA224_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
.base = {
.cra_name = "sha224",
.cra_driver_name = "atmel-sha224",
@@ -1062,8 +1125,11 @@ static struct ahash_alg sha_384_512_algs[] = {
.final = atmel_sha_final,
.finup = atmel_sha_finup,
.digest = atmel_sha_digest,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
.halg = {
.digestsize = SHA384_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
.base = {
.cra_name = "sha384",
.cra_driver_name = "atmel-sha384",
@@ -1083,8 +1149,11 @@ static struct ahash_alg sha_384_512_algs[] = {
.final = atmel_sha_final,
.finup = atmel_sha_finup,
.digest = atmel_sha_digest,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
.halg = {
.digestsize = SHA512_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
.base = {
.cra_name = "sha512",
.cra_driver_name = "atmel-sha512",
@@ -1100,16 +1169,18 @@ static struct ahash_alg sha_384_512_algs[] = {
},
};
+static void atmel_sha_queue_task(unsigned long data)
+{
+ struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
+
+ atmel_sha_handle_queue(dd, NULL);
+}
+
static void atmel_sha_done_task(unsigned long data)
{
struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
int err = 0;
- if (!(SHA_FLAGS_BUSY & dd->flags)) {
- atmel_sha_handle_queue(dd, NULL);
- return;
- }
-
if (SHA_FLAGS_CPU & dd->flags) {
if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
dd->flags &= ~SHA_FLAGS_OUTPUT_READY;
@@ -1272,14 +1343,23 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd)
dd->caps.has_dualbuff = 0;
dd->caps.has_sha224 = 0;
dd->caps.has_sha_384_512 = 0;
+ dd->caps.has_uihv = 0;
/* keep only major version number */
switch (dd->hw_version & 0xff0) {
+ case 0x510:
+ dd->caps.has_dma = 1;
+ dd->caps.has_dualbuff = 1;
+ dd->caps.has_sha224 = 1;
+ dd->caps.has_sha_384_512 = 1;
+ dd->caps.has_uihv = 1;
+ break;
case 0x420:
dd->caps.has_dma = 1;
dd->caps.has_dualbuff = 1;
dd->caps.has_sha224 = 1;
dd->caps.has_sha_384_512 = 1;
+ dd->caps.has_uihv = 1;
break;
case 0x410:
dd->caps.has_dma = 1;
@@ -1366,6 +1446,8 @@ static int atmel_sha_probe(struct platform_device *pdev)
tasklet_init(&sha_dd->done_task, atmel_sha_done_task,
(unsigned long)sha_dd);
+ tasklet_init(&sha_dd->queue_task, atmel_sha_queue_task,
+ (unsigned long)sha_dd);
crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH);
@@ -1404,9 +1486,9 @@ static int atmel_sha_probe(struct platform_device *pdev)
}
sha_dd->io_base = devm_ioremap_resource(&pdev->dev, sha_res);
- if (!sha_dd->io_base) {
+ if (IS_ERR(sha_dd->io_base)) {
dev_err(dev, "can't ioremap\n");
- err = -ENOMEM;
+ err = PTR_ERR(sha_dd->io_base);
goto res_err;
}
@@ -1464,6 +1546,7 @@ err_sha_dma:
iclk_unprepare:
clk_unprepare(sha_dd->iclk);
res_err:
+ tasklet_kill(&sha_dd->queue_task);
tasklet_kill(&sha_dd->done_task);
sha_dd_err:
dev_err(dev, "initialization failed.\n");
@@ -1484,6 +1567,7 @@ static int atmel_sha_remove(struct platform_device *pdev)
atmel_sha_unregister_algs(sha_dd);
+ tasklet_kill(&sha_dd->queue_task);
tasklet_kill(&sha_dd->done_task);
if (sha_dd->caps.has_dma)
diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
index 2c7a628d0375..bf467d7be35c 100644
--- a/drivers/crypto/atmel-tdes.c
+++ b/drivers/crypto/atmel-tdes.c
@@ -1417,9 +1417,9 @@ static int atmel_tdes_probe(struct platform_device *pdev)
}
tdes_dd->io_base = devm_ioremap_resource(&pdev->dev, tdes_res);
- if (!tdes_dd->io_base) {
+ if (IS_ERR(tdes_dd->io_base)) {
dev_err(dev, "can't ioremap\n");
- err = -ENOMEM;
+ err = PTR_ERR(tdes_dd->io_base);
goto res_err;
}
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 69d4a1326fee..44d30b45f3cc 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -534,7 +534,7 @@ static int caam_probe(struct platform_device *pdev)
* long pointers in master configuration register
*/
clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK, MCFGR_AWCACHE_CACH |
- MCFGR_AWCACHE_BUFF | MCFGR_WDENABLE |
+ MCFGR_AWCACHE_BUFF | MCFGR_WDENABLE | MCFGR_LARGE_BURST |
(sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0));
/*
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index f7e0d8d4c3da..6fd63a600614 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -65,7 +65,7 @@ static int caam_reset_hw_jr(struct device *dev)
/*
* Shutdown JobR independent of platform property code
*/
-int caam_jr_shutdown(struct device *dev)
+static int caam_jr_shutdown(struct device *dev)
{
struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
dma_addr_t inpbusaddr, outbusaddr;
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index a8a79975682f..0ba9c40597dc 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -455,7 +455,8 @@ struct caam_ctrl {
#define MCFGR_AXIPIPE_MASK (0xf << MCFGR_AXIPIPE_SHIFT)
#define MCFGR_AXIPRI 0x00000008 /* Assert AXI priority sideband */
-#define MCFGR_BURST_64 0x00000001 /* Max burst size */
+#define MCFGR_LARGE_BURST 0x00000004 /* 128/256-byte burst size */
+#define MCFGR_BURST_64 0x00000001 /* 64-byte burst size */
/* JRSTART register offsets */
#define JRSTART_JR0_START 0x00000001 /* Start Job ring 0 */
diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
index 55a1f3951578..b750592cc936 100644
--- a/drivers/crypto/ccp/Makefile
+++ b/drivers/crypto/ccp/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_CRYPTO_DEV_CCP_DD) += ccp.o
-ccp-objs := ccp-dev.o ccp-ops.o ccp-platform.o
+ccp-objs := ccp-dev.o ccp-ops.o ccp-dev-v3.o ccp-platform.o
ccp-$(CONFIG_PCI) += ccp-pci.o
obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
diff --git a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
index d89f20c04266..3d9acc53d247 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
@@ -220,6 +220,39 @@ static int ccp_aes_cmac_digest(struct ahash_request *req)
return ccp_aes_cmac_finup(req);
}
+static int ccp_aes_cmac_export(struct ahash_request *req, void *out)
+{
+ struct ccp_aes_cmac_req_ctx *rctx = ahash_request_ctx(req);
+ struct ccp_aes_cmac_exp_ctx state;
+
+ state.null_msg = rctx->null_msg;
+ memcpy(state.iv, rctx->iv, sizeof(state.iv));
+ state.buf_count = rctx->buf_count;
+ memcpy(state.buf, rctx->buf, sizeof(state.buf));
+
+ /* 'out' may not be aligned so memcpy from local variable */
+ memcpy(out, &state, sizeof(state));
+
+ return 0;
+}
+
+static int ccp_aes_cmac_import(struct ahash_request *req, const void *in)
+{
+ struct ccp_aes_cmac_req_ctx *rctx = ahash_request_ctx(req);
+ struct ccp_aes_cmac_exp_ctx state;
+
+ /* 'in' may not be aligned so memcpy to local variable */
+ memcpy(&state, in, sizeof(state));
+
+ memset(rctx, 0, sizeof(*rctx));
+ rctx->null_msg = state.null_msg;
+ memcpy(rctx->iv, state.iv, sizeof(rctx->iv));
+ rctx->buf_count = state.buf_count;
+ memcpy(rctx->buf, state.buf, sizeof(rctx->buf));
+
+ return 0;
+}
+
static int ccp_aes_cmac_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int key_len)
{
@@ -352,10 +385,13 @@ int ccp_register_aes_cmac_algs(struct list_head *head)
alg->final = ccp_aes_cmac_final;
alg->finup = ccp_aes_cmac_finup;
alg->digest = ccp_aes_cmac_digest;
+ alg->export = ccp_aes_cmac_export;
+ alg->import = ccp_aes_cmac_import;
alg->setkey = ccp_aes_cmac_setkey;
halg = &alg->halg;
halg->digestsize = AES_BLOCK_SIZE;
+ halg->statesize = sizeof(struct ccp_aes_cmac_exp_ctx);
base = &halg->base;
snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "cmac(aes)");
diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c
index 7984f910884d..89291c15015c 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes.c
@@ -1,7 +1,7 @@
/*
* AMD Cryptographic Coprocessor (CCP) AES crypto API support
*
- * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
*
@@ -259,6 +259,7 @@ static struct crypto_alg ccp_aes_rfc3686_defaults = {
struct ccp_aes_def {
enum ccp_aes_mode mode;
+ unsigned int version;
const char *name;
const char *driver_name;
unsigned int blocksize;
@@ -269,6 +270,7 @@ struct ccp_aes_def {
static struct ccp_aes_def aes_algs[] = {
{
.mode = CCP_AES_MODE_ECB,
+ .version = CCP_VERSION(3, 0),
.name = "ecb(aes)",
.driver_name = "ecb-aes-ccp",
.blocksize = AES_BLOCK_SIZE,
@@ -277,6 +279,7 @@ static struct ccp_aes_def aes_algs[] = {
},
{
.mode = CCP_AES_MODE_CBC,
+ .version = CCP_VERSION(3, 0),
.name = "cbc(aes)",
.driver_name = "cbc-aes-ccp",
.blocksize = AES_BLOCK_SIZE,
@@ -285,6 +288,7 @@ static struct ccp_aes_def aes_algs[] = {
},
{
.mode = CCP_AES_MODE_CFB,
+ .version = CCP_VERSION(3, 0),
.name = "cfb(aes)",
.driver_name = "cfb-aes-ccp",
.blocksize = AES_BLOCK_SIZE,
@@ -293,6 +297,7 @@ static struct ccp_aes_def aes_algs[] = {
},
{
.mode = CCP_AES_MODE_OFB,
+ .version = CCP_VERSION(3, 0),
.name = "ofb(aes)",
.driver_name = "ofb-aes-ccp",
.blocksize = 1,
@@ -301,6 +306,7 @@ static struct ccp_aes_def aes_algs[] = {
},
{
.mode = CCP_AES_MODE_CTR,
+ .version = CCP_VERSION(3, 0),
.name = "ctr(aes)",
.driver_name = "ctr-aes-ccp",
.blocksize = 1,
@@ -309,6 +315,7 @@ static struct ccp_aes_def aes_algs[] = {
},
{
.mode = CCP_AES_MODE_CTR,
+ .version = CCP_VERSION(3, 0),
.name = "rfc3686(ctr(aes))",
.driver_name = "rfc3686-ctr-aes-ccp",
.blocksize = 1,
@@ -357,8 +364,11 @@ static int ccp_register_aes_alg(struct list_head *head,
int ccp_register_aes_algs(struct list_head *head)
{
int i, ret;
+ unsigned int ccpversion = ccp_version();
for (i = 0; i < ARRAY_SIZE(aes_algs); i++) {
+ if (aes_algs[i].version > ccpversion)
+ continue;
ret = ccp_register_aes_alg(head, &aes_algs[i]);
if (ret)
return ret;
diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c
index d14b3f28e010..b5ad72897dc2 100644
--- a/drivers/crypto/ccp/ccp-crypto-sha.c
+++ b/drivers/crypto/ccp/ccp-crypto-sha.c
@@ -1,7 +1,7 @@
/*
* AMD Cryptographic Coprocessor (CCP) SHA crypto API support
*
- * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
*
@@ -207,6 +207,43 @@ static int ccp_sha_digest(struct ahash_request *req)
return ccp_sha_finup(req);
}
+static int ccp_sha_export(struct ahash_request *req, void *out)
+{
+ struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req);
+ struct ccp_sha_exp_ctx state;
+
+ state.type = rctx->type;
+ state.msg_bits = rctx->msg_bits;
+ state.first = rctx->first;
+ memcpy(state.ctx, rctx->ctx, sizeof(state.ctx));
+ state.buf_count = rctx->buf_count;
+ memcpy(state.buf, rctx->buf, sizeof(state.buf));
+
+ /* 'out' may not be aligned so memcpy from local variable */
+ memcpy(out, &state, sizeof(state));
+
+ return 0;
+}
+
+static int ccp_sha_import(struct ahash_request *req, const void *in)
+{
+ struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req);
+ struct ccp_sha_exp_ctx state;
+
+ /* 'in' may not be aligned so memcpy to local variable */
+ memcpy(&state, in, sizeof(state));
+
+ memset(rctx, 0, sizeof(*rctx));
+ rctx->type = state.type;
+ rctx->msg_bits = state.msg_bits;
+ rctx->first = state.first;
+ memcpy(rctx->ctx, state.ctx, sizeof(rctx->ctx));
+ rctx->buf_count = state.buf_count;
+ memcpy(rctx->buf, state.buf, sizeof(rctx->buf));
+
+ return 0;
+}
+
static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int key_len)
{
@@ -304,6 +341,7 @@ static void ccp_hmac_sha_cra_exit(struct crypto_tfm *tfm)
}
struct ccp_sha_def {
+ unsigned int version;
const char *name;
const char *drv_name;
enum ccp_sha_type type;
@@ -313,6 +351,7 @@ struct ccp_sha_def {
static struct ccp_sha_def sha_algs[] = {
{
+ .version = CCP_VERSION(3, 0),
.name = "sha1",
.drv_name = "sha1-ccp",
.type = CCP_SHA_TYPE_1,
@@ -320,6 +359,7 @@ static struct ccp_sha_def sha_algs[] = {
.block_size = SHA1_BLOCK_SIZE,
},
{
+ .version = CCP_VERSION(3, 0),
.name = "sha224",
.drv_name = "sha224-ccp",
.type = CCP_SHA_TYPE_224,
@@ -327,6 +367,7 @@ static struct ccp_sha_def sha_algs[] = {
.block_size = SHA224_BLOCK_SIZE,
},
{
+ .version = CCP_VERSION(3, 0),
.name = "sha256",
.drv_name = "sha256-ccp",
.type = CCP_SHA_TYPE_256,
@@ -403,9 +444,12 @@ static int ccp_register_sha_alg(struct list_head *head,
alg->final = ccp_sha_final;
alg->finup = ccp_sha_finup;
alg->digest = ccp_sha_digest;
+ alg->export = ccp_sha_export;
+ alg->import = ccp_sha_import;
halg = &alg->halg;
halg->digestsize = def->digest_size;
+ halg->statesize = sizeof(struct ccp_sha_exp_ctx);
base = &halg->base;
snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
@@ -440,8 +484,11 @@ static int ccp_register_sha_alg(struct list_head *head,
int ccp_register_sha_algs(struct list_head *head)
{
int i, ret;
+ unsigned int ccpversion = ccp_version();
for (i = 0; i < ARRAY_SIZE(sha_algs); i++) {
+ if (sha_algs[i].version > ccpversion)
+ continue;
ret = ccp_register_sha_alg(head, &sha_algs[i]);
if (ret)
return ret;
diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h
index 76a96f0f44c6..a326ec20bfa8 100644
--- a/drivers/crypto/ccp/ccp-crypto.h
+++ b/drivers/crypto/ccp/ccp-crypto.h
@@ -129,6 +129,15 @@ struct ccp_aes_cmac_req_ctx {
struct ccp_cmd cmd;
};
+struct ccp_aes_cmac_exp_ctx {
+ unsigned int null_msg;
+
+ u8 iv[AES_BLOCK_SIZE];
+
+ unsigned int buf_count;
+ u8 buf[AES_BLOCK_SIZE];
+};
+
/***** SHA related defines *****/
#define MAX_SHA_CONTEXT_SIZE SHA256_DIGEST_SIZE
#define MAX_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE
@@ -171,6 +180,19 @@ struct ccp_sha_req_ctx {
struct ccp_cmd cmd;
};
+struct ccp_sha_exp_ctx {
+ enum ccp_sha_type type;
+
+ u64 msg_bits;
+
+ unsigned int first;
+
+ u8 ctx[MAX_SHA_CONTEXT_SIZE];
+
+ unsigned int buf_count;
+ u8 buf[MAX_SHA_BLOCK_SIZE];
+};
+
/***** Common Context Structure *****/
struct ccp_ctx {
int (*complete)(struct crypto_async_request *req, int ret);
diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c
new file mode 100644
index 000000000000..7d5eab49179e
--- /dev/null
+++ b/drivers/crypto/ccp/ccp-dev-v3.c
@@ -0,0 +1,533 @@
+/*
+ * AMD Cryptographic Coprocessor (CCP) driver
+ *
+ * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
+ *
+ * Author: Tom Lendacky <thomas.lendacky@amd.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/ccp.h>
+
+#include "ccp-dev.h"
+
+static int ccp_do_cmd(struct ccp_op *op, u32 *cr, unsigned int cr_count)
+{
+ struct ccp_cmd_queue *cmd_q = op->cmd_q;
+ struct ccp_device *ccp = cmd_q->ccp;
+ void __iomem *cr_addr;
+ u32 cr0, cmd;
+ unsigned int i;
+ int ret = 0;
+
+ /* We could read a status register to see how many free slots
+ * are actually available, but reading that register resets it
+ * and you could lose some error information.
+ */
+ cmd_q->free_slots--;
+
+ cr0 = (cmd_q->id << REQ0_CMD_Q_SHIFT)
+ | (op->jobid << REQ0_JOBID_SHIFT)
+ | REQ0_WAIT_FOR_WRITE;
+
+ if (op->soc)
+ cr0 |= REQ0_STOP_ON_COMPLETE
+ | REQ0_INT_ON_COMPLETE;
+
+ if (op->ioc || !cmd_q->free_slots)
+ cr0 |= REQ0_INT_ON_COMPLETE;
+
+ /* Start at CMD_REQ1 */
+ cr_addr = ccp->io_regs + CMD_REQ0 + CMD_REQ_INCR;
+
+ mutex_lock(&ccp->req_mutex);
+
+ /* Write CMD_REQ1 through CMD_REQx first */
+ for (i = 0; i < cr_count; i++, cr_addr += CMD_REQ_INCR)
+ iowrite32(*(cr + i), cr_addr);
+
+ /* Tell the CCP to start */
+ wmb();
+ iowrite32(cr0, ccp->io_regs + CMD_REQ0);
+
+ mutex_unlock(&ccp->req_mutex);
+
+ if (cr0 & REQ0_INT_ON_COMPLETE) {
+ /* Wait for the job to complete */
+ ret = wait_event_interruptible(cmd_q->int_queue,
+ cmd_q->int_rcvd);
+ if (ret || cmd_q->cmd_error) {
+ /* On error delete all related jobs from the queue */
+ cmd = (cmd_q->id << DEL_Q_ID_SHIFT)
+ | op->jobid;
+
+ iowrite32(cmd, ccp->io_regs + DEL_CMD_Q_JOB);
+
+ if (!ret)
+ ret = -EIO;
+ } else if (op->soc) {
+ /* Delete just head job from the queue on SoC */
+ cmd = DEL_Q_ACTIVE
+ | (cmd_q->id << DEL_Q_ID_SHIFT)
+ | op->jobid;
+
+ iowrite32(cmd, ccp->io_regs + DEL_CMD_Q_JOB);
+ }
+
+ cmd_q->free_slots = CMD_Q_DEPTH(cmd_q->q_status);
+
+ cmd_q->int_rcvd = 0;
+ }
+
+ return ret;
+}
+
+static int ccp_perform_aes(struct ccp_op *op)
+{
+ u32 cr[6];
+
+ /* Fill out the register contents for REQ1 through REQ6 */
+ cr[0] = (CCP_ENGINE_AES << REQ1_ENGINE_SHIFT)
+ | (op->u.aes.type << REQ1_AES_TYPE_SHIFT)
+ | (op->u.aes.mode << REQ1_AES_MODE_SHIFT)
+ | (op->u.aes.action << REQ1_AES_ACTION_SHIFT)
+ | (op->ksb_key << REQ1_KEY_KSB_SHIFT);
+ cr[1] = op->src.u.dma.length - 1;
+ cr[2] = ccp_addr_lo(&op->src.u.dma);
+ cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
+ | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->src.u.dma);
+ cr[4] = ccp_addr_lo(&op->dst.u.dma);
+ cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->dst.u.dma);
+
+ if (op->u.aes.mode == CCP_AES_MODE_CFB)
+ cr[0] |= ((0x7f) << REQ1_AES_CFB_SIZE_SHIFT);
+
+ if (op->eom)
+ cr[0] |= REQ1_EOM;
+
+ if (op->init)
+ cr[0] |= REQ1_INIT;
+
+ return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
+}
+
+static int ccp_perform_xts_aes(struct ccp_op *op)
+{
+ u32 cr[6];
+
+ /* Fill out the register contents for REQ1 through REQ6 */
+ cr[0] = (CCP_ENGINE_XTS_AES_128 << REQ1_ENGINE_SHIFT)
+ | (op->u.xts.action << REQ1_AES_ACTION_SHIFT)
+ | (op->u.xts.unit_size << REQ1_XTS_AES_SIZE_SHIFT)
+ | (op->ksb_key << REQ1_KEY_KSB_SHIFT);
+ cr[1] = op->src.u.dma.length - 1;
+ cr[2] = ccp_addr_lo(&op->src.u.dma);
+ cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
+ | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->src.u.dma);
+ cr[4] = ccp_addr_lo(&op->dst.u.dma);
+ cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->dst.u.dma);
+
+ if (op->eom)
+ cr[0] |= REQ1_EOM;
+
+ if (op->init)
+ cr[0] |= REQ1_INIT;
+
+ return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
+}
+
+static int ccp_perform_sha(struct ccp_op *op)
+{
+ u32 cr[6];
+
+ /* Fill out the register contents for REQ1 through REQ6 */
+ cr[0] = (CCP_ENGINE_SHA << REQ1_ENGINE_SHIFT)
+ | (op->u.sha.type << REQ1_SHA_TYPE_SHIFT)
+ | REQ1_INIT;
+ cr[1] = op->src.u.dma.length - 1;
+ cr[2] = ccp_addr_lo(&op->src.u.dma);
+ cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
+ | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->src.u.dma);
+
+ if (op->eom) {
+ cr[0] |= REQ1_EOM;
+ cr[4] = lower_32_bits(op->u.sha.msg_bits);
+ cr[5] = upper_32_bits(op->u.sha.msg_bits);
+ } else {
+ cr[4] = 0;
+ cr[5] = 0;
+ }
+
+ return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
+}
+
+static int ccp_perform_rsa(struct ccp_op *op)
+{
+ u32 cr[6];
+
+ /* Fill out the register contents for REQ1 through REQ6 */
+ cr[0] = (CCP_ENGINE_RSA << REQ1_ENGINE_SHIFT)
+ | (op->u.rsa.mod_size << REQ1_RSA_MOD_SIZE_SHIFT)
+ | (op->ksb_key << REQ1_KEY_KSB_SHIFT)
+ | REQ1_EOM;
+ cr[1] = op->u.rsa.input_len - 1;
+ cr[2] = ccp_addr_lo(&op->src.u.dma);
+ cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
+ | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->src.u.dma);
+ cr[4] = ccp_addr_lo(&op->dst.u.dma);
+ cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->dst.u.dma);
+
+ return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
+}
+
+static int ccp_perform_passthru(struct ccp_op *op)
+{
+ u32 cr[6];
+
+ /* Fill out the register contents for REQ1 through REQ6 */
+ cr[0] = (CCP_ENGINE_PASSTHRU << REQ1_ENGINE_SHIFT)
+ | (op->u.passthru.bit_mod << REQ1_PT_BW_SHIFT)
+ | (op->u.passthru.byte_swap << REQ1_PT_BS_SHIFT);
+
+ if (op->src.type == CCP_MEMTYPE_SYSTEM)
+ cr[1] = op->src.u.dma.length - 1;
+ else
+ cr[1] = op->dst.u.dma.length - 1;
+
+ if (op->src.type == CCP_MEMTYPE_SYSTEM) {
+ cr[2] = ccp_addr_lo(&op->src.u.dma);
+ cr[3] = (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->src.u.dma);
+
+ if (op->u.passthru.bit_mod != CCP_PASSTHRU_BITWISE_NOOP)
+ cr[3] |= (op->ksb_key << REQ4_KSB_SHIFT);
+ } else {
+ cr[2] = op->src.u.ksb * CCP_KSB_BYTES;
+ cr[3] = (CCP_MEMTYPE_KSB << REQ4_MEMTYPE_SHIFT);
+ }
+
+ if (op->dst.type == CCP_MEMTYPE_SYSTEM) {
+ cr[4] = ccp_addr_lo(&op->dst.u.dma);
+ cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->dst.u.dma);
+ } else {
+ cr[4] = op->dst.u.ksb * CCP_KSB_BYTES;
+ cr[5] = (CCP_MEMTYPE_KSB << REQ6_MEMTYPE_SHIFT);
+ }
+
+ if (op->eom)
+ cr[0] |= REQ1_EOM;
+
+ return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
+}
+
+static int ccp_perform_ecc(struct ccp_op *op)
+{
+ u32 cr[6];
+
+ /* Fill out the register contents for REQ1 through REQ6 */
+ cr[0] = REQ1_ECC_AFFINE_CONVERT
+ | (CCP_ENGINE_ECC << REQ1_ENGINE_SHIFT)
+ | (op->u.ecc.function << REQ1_ECC_FUNCTION_SHIFT)
+ | REQ1_EOM;
+ cr[1] = op->src.u.dma.length - 1;
+ cr[2] = ccp_addr_lo(&op->src.u.dma);
+ cr[3] = (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->src.u.dma);
+ cr[4] = ccp_addr_lo(&op->dst.u.dma);
+ cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
+ | ccp_addr_hi(&op->dst.u.dma);
+
+ return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
+}
+
+static int ccp_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+ struct ccp_device *ccp = container_of(rng, struct ccp_device, hwrng);
+ u32 trng_value;
+ int len = min_t(int, sizeof(trng_value), max);
+
+ /*
+ * Locking is provided by the caller so we can update device
+ * hwrng-related fields safely
+ */
+ trng_value = ioread32(ccp->io_regs + TRNG_OUT_REG);
+ if (!trng_value) {
+ /* Zero is returned if not data is available or if a
+ * bad-entropy error is present. Assume an error if
+ * we exceed TRNG_RETRIES reads of zero.
+ */
+ if (ccp->hwrng_retries++ > TRNG_RETRIES)
+ return -EIO;
+
+ return 0;
+ }
+
+ /* Reset the counter and save the rng value */
+ ccp->hwrng_retries = 0;
+ memcpy(data, &trng_value, len);
+
+ return len;
+}
+
+static int ccp_init(struct ccp_device *ccp)
+{
+ struct device *dev = ccp->dev;
+ struct ccp_cmd_queue *cmd_q;
+ struct dma_pool *dma_pool;
+ char dma_pool_name[MAX_DMAPOOL_NAME_LEN];
+ unsigned int qmr, qim, i;
+ int ret;
+
+ /* Find available queues */
+ qim = 0;
+ qmr = ioread32(ccp->io_regs + Q_MASK_REG);
+ for (i = 0; i < MAX_HW_QUEUES; i++) {
+ if (!(qmr & (1 << i)))
+ continue;
+
+ /* Allocate a dma pool for this queue */
+ snprintf(dma_pool_name, sizeof(dma_pool_name), "%s_q%d",
+ ccp->name, i);
+ dma_pool = dma_pool_create(dma_pool_name, dev,
+ CCP_DMAPOOL_MAX_SIZE,
+ CCP_DMAPOOL_ALIGN, 0);
+ if (!dma_pool) {
+ dev_err(dev, "unable to allocate dma pool\n");
+ ret = -ENOMEM;
+ goto e_pool;
+ }
+
+ cmd_q = &ccp->cmd_q[ccp->cmd_q_count];
+ ccp->cmd_q_count++;
+
+ cmd_q->ccp = ccp;
+ cmd_q->id = i;
+ cmd_q->dma_pool = dma_pool;
+
+ /* Reserve 2 KSB regions for the queue */
+ cmd_q->ksb_key = KSB_START + ccp->ksb_start++;
+ cmd_q->ksb_ctx = KSB_START + ccp->ksb_start++;
+ ccp->ksb_count -= 2;
+
+ /* Preset some register values and masks that are queue
+ * number dependent
+ */
+ cmd_q->reg_status = ccp->io_regs + CMD_Q_STATUS_BASE +
+ (CMD_Q_STATUS_INCR * i);
+ cmd_q->reg_int_status = ccp->io_regs + CMD_Q_INT_STATUS_BASE +
+ (CMD_Q_STATUS_INCR * i);
+ cmd_q->int_ok = 1 << (i * 2);
+ cmd_q->int_err = 1 << ((i * 2) + 1);
+
+ cmd_q->free_slots = CMD_Q_DEPTH(ioread32(cmd_q->reg_status));
+
+ init_waitqueue_head(&cmd_q->int_queue);
+
+ /* Build queue interrupt mask (two interrupts per queue) */
+ qim |= cmd_q->int_ok | cmd_q->int_err;
+
+#ifdef CONFIG_ARM64
+ /* For arm64 set the recommended queue cache settings */
+ iowrite32(ccp->axcache, ccp->io_regs + CMD_Q_CACHE_BASE +
+ (CMD_Q_CACHE_INC * i));
+#endif
+
+ dev_dbg(dev, "queue #%u available\n", i);
+ }
+ if (ccp->cmd_q_count == 0) {
+ dev_notice(dev, "no command queues available\n");
+ ret = -EIO;
+ goto e_pool;
+ }
+ dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count);
+
+ /* Disable and clear interrupts until ready */
+ iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ cmd_q = &ccp->cmd_q[i];
+
+ ioread32(cmd_q->reg_int_status);
+ ioread32(cmd_q->reg_status);
+ }
+ iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
+
+ /* Request an irq */
+ ret = ccp->get_irq(ccp);
+ if (ret) {
+ dev_err(dev, "unable to allocate an IRQ\n");
+ goto e_pool;
+ }
+
+ /* Initialize the queues used to wait for KSB space and suspend */
+ init_waitqueue_head(&ccp->ksb_queue);
+ init_waitqueue_head(&ccp->suspend_queue);
+
+ /* Create a kthread for each queue */
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ struct task_struct *kthread;
+
+ cmd_q = &ccp->cmd_q[i];
+
+ kthread = kthread_create(ccp_cmd_queue_thread, cmd_q,
+ "%s-q%u", ccp->name, cmd_q->id);
+ if (IS_ERR(kthread)) {
+ dev_err(dev, "error creating queue thread (%ld)\n",
+ PTR_ERR(kthread));
+ ret = PTR_ERR(kthread);
+ goto e_kthread;
+ }
+
+ cmd_q->kthread = kthread;
+ wake_up_process(kthread);
+ }
+
+ /* Register the RNG */
+ ccp->hwrng.name = ccp->rngname;
+ ccp->hwrng.read = ccp_trng_read;
+ ret = hwrng_register(&ccp->hwrng);
+ if (ret) {
+ dev_err(dev, "error registering hwrng (%d)\n", ret);
+ goto e_kthread;
+ }
+
+ ccp_add_device(ccp);
+
+ /* Enable interrupts */
+ iowrite32(qim, ccp->io_regs + IRQ_MASK_REG);
+
+ return 0;
+
+e_kthread:
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ if (ccp->cmd_q[i].kthread)
+ kthread_stop(ccp->cmd_q[i].kthread);
+
+ ccp->free_irq(ccp);
+
+e_pool:
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ dma_pool_destroy(ccp->cmd_q[i].dma_pool);
+
+ return ret;
+}
+
+static void ccp_destroy(struct ccp_device *ccp)
+{
+ struct ccp_cmd_queue *cmd_q;
+ struct ccp_cmd *cmd;
+ unsigned int qim, i;
+
+ /* Remove this device from the list of available units first */
+ ccp_del_device(ccp);
+
+ /* Unregister the RNG */
+ hwrng_unregister(&ccp->hwrng);
+
+ /* Stop the queue kthreads */
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ if (ccp->cmd_q[i].kthread)
+ kthread_stop(ccp->cmd_q[i].kthread);
+
+ /* Build queue interrupt mask (two interrupt masks per queue) */
+ qim = 0;
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ cmd_q = &ccp->cmd_q[i];
+ qim |= cmd_q->int_ok | cmd_q->int_err;
+ }
+
+ /* Disable and clear interrupts */
+ iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ cmd_q = &ccp->cmd_q[i];
+
+ ioread32(cmd_q->reg_int_status);
+ ioread32(cmd_q->reg_status);
+ }
+ iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
+
+ ccp->free_irq(ccp);
+
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ dma_pool_destroy(ccp->cmd_q[i].dma_pool);
+
+ /* Flush the cmd and backlog queue */
+ while (!list_empty(&ccp->cmd)) {
+ /* Invoke the callback directly with an error code */
+ cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
+ list_del(&cmd->entry);
+ cmd->callback(cmd->data, -ENODEV);
+ }
+ while (!list_empty(&ccp->backlog)) {
+ /* Invoke the callback directly with an error code */
+ cmd = list_first_entry(&ccp->backlog, struct ccp_cmd, entry);
+ list_del(&cmd->entry);
+ cmd->callback(cmd->data, -ENODEV);
+ }
+}
+
+static irqreturn_t ccp_irq_handler(int irq, void *data)
+{
+ struct device *dev = data;
+ struct ccp_device *ccp = dev_get_drvdata(dev);
+ struct ccp_cmd_queue *cmd_q;
+ u32 q_int, status;
+ unsigned int i;
+
+ status = ioread32(ccp->io_regs + IRQ_STATUS_REG);
+
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ cmd_q = &ccp->cmd_q[i];
+
+ q_int = status & (cmd_q->int_ok | cmd_q->int_err);
+ if (q_int) {
+ cmd_q->int_status = status;
+ cmd_q->q_status = ioread32(cmd_q->reg_status);
+ cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
+
+ /* On error, only save the first error value */
+ if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error)
+ cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
+
+ cmd_q->int_rcvd = 1;
+
+ /* Acknowledge the interrupt and wake the kthread */
+ iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG);
+ wake_up_interruptible(&cmd_q->int_queue);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct ccp_actions ccp3_actions = {
+ .perform_aes = ccp_perform_aes,
+ .perform_xts_aes = ccp_perform_xts_aes,
+ .perform_sha = ccp_perform_sha,
+ .perform_rsa = ccp_perform_rsa,
+ .perform_passthru = ccp_perform_passthru,
+ .perform_ecc = ccp_perform_ecc,
+ .init = ccp_init,
+ .destroy = ccp_destroy,
+ .irqhandler = ccp_irq_handler,
+};
+
+struct ccp_vdata ccpv3 = {
+ .version = CCP_VERSION(3, 0),
+ .perform = &ccp3_actions,
+};
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index 861bacc1bb94..336e5b780fcb 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -1,7 +1,7 @@
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
- * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
*
@@ -16,6 +16,8 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/rwlock_types.h>
+#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/hw_random.h>
@@ -37,20 +39,107 @@ struct ccp_tasklet_data {
struct ccp_cmd *cmd;
};
-static struct ccp_device *ccp_dev;
-static inline struct ccp_device *ccp_get_device(void)
+/* List of CCPs, CCP count, read-write access lock, and access functions
+ *
+ * Lock structure: get ccp_unit_lock for reading whenever we need to
+ * examine the CCP list. While holding it for reading we can acquire
+ * the RR lock to update the round-robin next-CCP pointer. The unit lock
+ * must be acquired before the RR lock.
+ *
+ * If the unit-lock is acquired for writing, we have total control over
+ * the list, so there's no value in getting the RR lock.
+ */
+static DEFINE_RWLOCK(ccp_unit_lock);
+static LIST_HEAD(ccp_units);
+
+/* Round-robin counter */
+static DEFINE_RWLOCK(ccp_rr_lock);
+static struct ccp_device *ccp_rr;
+
+/* Ever-increasing value to produce unique unit numbers */
+static atomic_t ccp_unit_ordinal;
+unsigned int ccp_increment_unit_ordinal(void)
{
- return ccp_dev;
+ return atomic_inc_return(&ccp_unit_ordinal);
}
-static inline void ccp_add_device(struct ccp_device *ccp)
+/**
+ * ccp_add_device - add a CCP device to the list
+ *
+ * @ccp: ccp_device struct pointer
+ *
+ * Put this CCP on the unit list, which makes it available
+ * for use.
+ *
+ * Returns zero if a CCP device is present, -ENODEV otherwise.
+ */
+void ccp_add_device(struct ccp_device *ccp)
{
- ccp_dev = ccp;
+ unsigned long flags;
+
+ write_lock_irqsave(&ccp_unit_lock, flags);
+ list_add_tail(&ccp->entry, &ccp_units);
+ if (!ccp_rr)
+ /* We already have the list lock (we're first) so this
+ * pointer can't change on us. Set its initial value.
+ */
+ ccp_rr = ccp;
+ write_unlock_irqrestore(&ccp_unit_lock, flags);
}
-static inline void ccp_del_device(struct ccp_device *ccp)
+/**
+ * ccp_del_device - remove a CCP device from the list
+ *
+ * @ccp: ccp_device struct pointer
+ *
+ * Remove this unit from the list of devices. If the next device
+ * up for use is this one, adjust the pointer. If this is the last
+ * device, NULL the pointer.
+ */
+void ccp_del_device(struct ccp_device *ccp)
{
- ccp_dev = NULL;
+ unsigned long flags;
+
+ write_lock_irqsave(&ccp_unit_lock, flags);
+ if (ccp_rr == ccp) {
+ /* ccp_unit_lock is read/write; any read access
+ * will be suspended while we make changes to the
+ * list and RR pointer.
+ */
+ if (list_is_last(&ccp_rr->entry, &ccp_units))
+ ccp_rr = list_first_entry(&ccp_units, struct ccp_device,
+ entry);
+ else
+ ccp_rr = list_next_entry(ccp_rr, entry);
+ }
+ list_del(&ccp->entry);
+ if (list_empty(&ccp_units))
+ ccp_rr = NULL;
+ write_unlock_irqrestore(&ccp_unit_lock, flags);
+}
+
+static struct ccp_device *ccp_get_device(void)
+{
+ unsigned long flags;
+ struct ccp_device *dp = NULL;
+
+ /* We round-robin through the unit list.
+ * The (ccp_rr) pointer refers to the next unit to use.
+ */
+ read_lock_irqsave(&ccp_unit_lock, flags);
+ if (!list_empty(&ccp_units)) {
+ write_lock_irqsave(&ccp_rr_lock, flags);
+ dp = ccp_rr;
+ if (list_is_last(&ccp_rr->entry, &ccp_units))
+ ccp_rr = list_first_entry(&ccp_units, struct ccp_device,
+ entry);
+ else
+ ccp_rr = list_next_entry(ccp_rr, entry);
+ write_unlock_irqrestore(&ccp_rr_lock, flags);
+ }
+ read_unlock_irqrestore(&ccp_unit_lock, flags);
+
+ return dp;
}
/**
@@ -60,14 +149,41 @@ static inline void ccp_del_device(struct ccp_device *ccp)
*/
int ccp_present(void)
{
- if (ccp_get_device())
- return 0;
+ unsigned long flags;
+ int ret;
- return -ENODEV;
+ read_lock_irqsave(&ccp_unit_lock, flags);
+ ret = list_empty(&ccp_units);
+ read_unlock_irqrestore(&ccp_unit_lock, flags);
+
+ return ret ? -ENODEV : 0;
}
EXPORT_SYMBOL_GPL(ccp_present);
/**
+ * ccp_version - get the version of the CCP device
+ *
+ * Returns the version from the first unit on the list;
+ * otherwise a zero if no CCP device is present
+ */
+unsigned int ccp_version(void)
+{
+ struct ccp_device *dp;
+ unsigned long flags;
+ int ret = 0;
+
+ read_lock_irqsave(&ccp_unit_lock, flags);
+ if (!list_empty(&ccp_units)) {
+ dp = list_first_entry(&ccp_units, struct ccp_device, entry);
+ ret = dp->vdata->version;
+ }
+ read_unlock_irqrestore(&ccp_unit_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ccp_version);
+
+/**
* ccp_enqueue_cmd - queue an operation for processing by the CCP
*
* @cmd: ccp_cmd struct to be processed
@@ -221,7 +337,12 @@ static void ccp_do_cmd_complete(unsigned long data)
complete(&tdata->completion);
}
-static int ccp_cmd_queue_thread(void *data)
+/**
+ * ccp_cmd_queue_thread - create a kernel thread to manage a CCP queue
+ *
+ * @data: thread-specific data
+ */
+int ccp_cmd_queue_thread(void *data)
{
struct ccp_cmd_queue *cmd_q = (struct ccp_cmd_queue *)data;
struct ccp_cmd *cmd;
@@ -257,35 +378,6 @@ static int ccp_cmd_queue_thread(void *data)
return 0;
}
-static int ccp_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
-{
- struct ccp_device *ccp = container_of(rng, struct ccp_device, hwrng);
- u32 trng_value;
- int len = min_t(int, sizeof(trng_value), max);
-
- /*
- * Locking is provided by the caller so we can update device
- * hwrng-related fields safely
- */
- trng_value = ioread32(ccp->io_regs + TRNG_OUT_REG);
- if (!trng_value) {
- /* Zero is returned if not data is available or if a
- * bad-entropy error is present. Assume an error if
- * we exceed TRNG_RETRIES reads of zero.
- */
- if (ccp->hwrng_retries++ > TRNG_RETRIES)
- return -EIO;
-
- return 0;
- }
-
- /* Reset the counter and save the rng value */
- ccp->hwrng_retries = 0;
- memcpy(data, &trng_value, len);
-
- return len;
-}
-
/**
* ccp_alloc_struct - allocate and initialize the ccp_device struct
*
@@ -309,253 +401,11 @@ struct ccp_device *ccp_alloc_struct(struct device *dev)
ccp->ksb_count = KSB_COUNT;
ccp->ksb_start = 0;
- return ccp;
-}
-
-/**
- * ccp_init - initialize the CCP device
- *
- * @ccp: ccp_device struct
- */
-int ccp_init(struct ccp_device *ccp)
-{
- struct device *dev = ccp->dev;
- struct ccp_cmd_queue *cmd_q;
- struct dma_pool *dma_pool;
- char dma_pool_name[MAX_DMAPOOL_NAME_LEN];
- unsigned int qmr, qim, i;
- int ret;
-
- /* Find available queues */
- qim = 0;
- qmr = ioread32(ccp->io_regs + Q_MASK_REG);
- for (i = 0; i < MAX_HW_QUEUES; i++) {
- if (!(qmr & (1 << i)))
- continue;
-
- /* Allocate a dma pool for this queue */
- snprintf(dma_pool_name, sizeof(dma_pool_name), "ccp_q%d", i);
- dma_pool = dma_pool_create(dma_pool_name, dev,
- CCP_DMAPOOL_MAX_SIZE,
- CCP_DMAPOOL_ALIGN, 0);
- if (!dma_pool) {
- dev_err(dev, "unable to allocate dma pool\n");
- ret = -ENOMEM;
- goto e_pool;
- }
-
- cmd_q = &ccp->cmd_q[ccp->cmd_q_count];
- ccp->cmd_q_count++;
-
- cmd_q->ccp = ccp;
- cmd_q->id = i;
- cmd_q->dma_pool = dma_pool;
-
- /* Reserve 2 KSB regions for the queue */
- cmd_q->ksb_key = KSB_START + ccp->ksb_start++;
- cmd_q->ksb_ctx = KSB_START + ccp->ksb_start++;
- ccp->ksb_count -= 2;
-
- /* Preset some register values and masks that are queue
- * number dependent
- */
- cmd_q->reg_status = ccp->io_regs + CMD_Q_STATUS_BASE +
- (CMD_Q_STATUS_INCR * i);
- cmd_q->reg_int_status = ccp->io_regs + CMD_Q_INT_STATUS_BASE +
- (CMD_Q_STATUS_INCR * i);
- cmd_q->int_ok = 1 << (i * 2);
- cmd_q->int_err = 1 << ((i * 2) + 1);
-
- cmd_q->free_slots = CMD_Q_DEPTH(ioread32(cmd_q->reg_status));
-
- init_waitqueue_head(&cmd_q->int_queue);
-
- /* Build queue interrupt mask (two interrupts per queue) */
- qim |= cmd_q->int_ok | cmd_q->int_err;
+ ccp->ord = ccp_increment_unit_ordinal();
+ snprintf(ccp->name, MAX_CCP_NAME_LEN, "ccp-%u", ccp->ord);
+ snprintf(ccp->rngname, MAX_CCP_NAME_LEN, "ccp-%u-rng", ccp->ord);
-#ifdef CONFIG_ARM64
- /* For arm64 set the recommended queue cache settings */
- iowrite32(ccp->axcache, ccp->io_regs + CMD_Q_CACHE_BASE +
- (CMD_Q_CACHE_INC * i));
-#endif
-
- dev_dbg(dev, "queue #%u available\n", i);
- }
- if (ccp->cmd_q_count == 0) {
- dev_notice(dev, "no command queues available\n");
- ret = -EIO;
- goto e_pool;
- }
- dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count);
-
- /* Disable and clear interrupts until ready */
- iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
- for (i = 0; i < ccp->cmd_q_count; i++) {
- cmd_q = &ccp->cmd_q[i];
-
- ioread32(cmd_q->reg_int_status);
- ioread32(cmd_q->reg_status);
- }
- iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
-
- /* Request an irq */
- ret = ccp->get_irq(ccp);
- if (ret) {
- dev_err(dev, "unable to allocate an IRQ\n");
- goto e_pool;
- }
-
- /* Initialize the queues used to wait for KSB space and suspend */
- init_waitqueue_head(&ccp->ksb_queue);
- init_waitqueue_head(&ccp->suspend_queue);
-
- /* Create a kthread for each queue */
- for (i = 0; i < ccp->cmd_q_count; i++) {
- struct task_struct *kthread;
-
- cmd_q = &ccp->cmd_q[i];
-
- kthread = kthread_create(ccp_cmd_queue_thread, cmd_q,
- "ccp-q%u", cmd_q->id);
- if (IS_ERR(kthread)) {
- dev_err(dev, "error creating queue thread (%ld)\n",
- PTR_ERR(kthread));
- ret = PTR_ERR(kthread);
- goto e_kthread;
- }
-
- cmd_q->kthread = kthread;
- wake_up_process(kthread);
- }
-
- /* Register the RNG */
- ccp->hwrng.name = "ccp-rng";
- ccp->hwrng.read = ccp_trng_read;
- ret = hwrng_register(&ccp->hwrng);
- if (ret) {
- dev_err(dev, "error registering hwrng (%d)\n", ret);
- goto e_kthread;
- }
-
- /* Make the device struct available before enabling interrupts */
- ccp_add_device(ccp);
-
- /* Enable interrupts */
- iowrite32(qim, ccp->io_regs + IRQ_MASK_REG);
-
- return 0;
-
-e_kthread:
- for (i = 0; i < ccp->cmd_q_count; i++)
- if (ccp->cmd_q[i].kthread)
- kthread_stop(ccp->cmd_q[i].kthread);
-
- ccp->free_irq(ccp);
-
-e_pool:
- for (i = 0; i < ccp->cmd_q_count; i++)
- dma_pool_destroy(ccp->cmd_q[i].dma_pool);
-
- return ret;
-}
-
-/**
- * ccp_destroy - tear down the CCP device
- *
- * @ccp: ccp_device struct
- */
-void ccp_destroy(struct ccp_device *ccp)
-{
- struct ccp_cmd_queue *cmd_q;
- struct ccp_cmd *cmd;
- unsigned int qim, i;
-
- /* Remove general access to the device struct */
- ccp_del_device(ccp);
-
- /* Unregister the RNG */
- hwrng_unregister(&ccp->hwrng);
-
- /* Stop the queue kthreads */
- for (i = 0; i < ccp->cmd_q_count; i++)
- if (ccp->cmd_q[i].kthread)
- kthread_stop(ccp->cmd_q[i].kthread);
-
- /* Build queue interrupt mask (two interrupt masks per queue) */
- qim = 0;
- for (i = 0; i < ccp->cmd_q_count; i++) {
- cmd_q = &ccp->cmd_q[i];
- qim |= cmd_q->int_ok | cmd_q->int_err;
- }
-
- /* Disable and clear interrupts */
- iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
- for (i = 0; i < ccp->cmd_q_count; i++) {
- cmd_q = &ccp->cmd_q[i];
-
- ioread32(cmd_q->reg_int_status);
- ioread32(cmd_q->reg_status);
- }
- iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
-
- ccp->free_irq(ccp);
-
- for (i = 0; i < ccp->cmd_q_count; i++)
- dma_pool_destroy(ccp->cmd_q[i].dma_pool);
-
- /* Flush the cmd and backlog queue */
- while (!list_empty(&ccp->cmd)) {
- /* Invoke the callback directly with an error code */
- cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
- list_del(&cmd->entry);
- cmd->callback(cmd->data, -ENODEV);
- }
- while (!list_empty(&ccp->backlog)) {
- /* Invoke the callback directly with an error code */
- cmd = list_first_entry(&ccp->backlog, struct ccp_cmd, entry);
- list_del(&cmd->entry);
- cmd->callback(cmd->data, -ENODEV);
- }
-}
-
-/**
- * ccp_irq_handler - handle interrupts generated by the CCP device
- *
- * @irq: the irq associated with the interrupt
- * @data: the data value supplied when the irq was created
- */
-irqreturn_t ccp_irq_handler(int irq, void *data)
-{
- struct device *dev = data;
- struct ccp_device *ccp = dev_get_drvdata(dev);
- struct ccp_cmd_queue *cmd_q;
- u32 q_int, status;
- unsigned int i;
-
- status = ioread32(ccp->io_regs + IRQ_STATUS_REG);
-
- for (i = 0; i < ccp->cmd_q_count; i++) {
- cmd_q = &ccp->cmd_q[i];
-
- q_int = status & (cmd_q->int_ok | cmd_q->int_err);
- if (q_int) {
- cmd_q->int_status = status;
- cmd_q->q_status = ioread32(cmd_q->reg_status);
- cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
-
- /* On error, only save the first error value */
- if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error)
- cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
-
- cmd_q->int_rcvd = 1;
-
- /* Acknowledge the interrupt and wake the kthread */
- iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG);
- wake_up_interruptible(&cmd_q->int_queue);
- }
- }
-
- return IRQ_HANDLED;
+ return ccp;
}
#ifdef CONFIG_PM
@@ -577,41 +427,22 @@ bool ccp_queues_suspended(struct ccp_device *ccp)
}
#endif
-#ifdef CONFIG_X86
-static const struct x86_cpu_id ccp_support[] = {
- { X86_VENDOR_AMD, 22, },
- { },
-};
-#endif
-
static int __init ccp_mod_init(void)
{
#ifdef CONFIG_X86
- struct cpuinfo_x86 *cpuinfo = &boot_cpu_data;
int ret;
- if (!x86_match_cpu(ccp_support))
- return -ENODEV;
-
- switch (cpuinfo->x86) {
- case 22:
- if ((cpuinfo->x86_model < 48) || (cpuinfo->x86_model > 63))
- return -ENODEV;
-
- ret = ccp_pci_init();
- if (ret)
- return ret;
-
- /* Don't leave the driver loaded if init failed */
- if (!ccp_get_device()) {
- ccp_pci_exit();
- return -ENODEV;
- }
-
- return 0;
+ ret = ccp_pci_init();
+ if (ret)
+ return ret;
- break;
+ /* Don't leave the driver loaded if init failed */
+ if (ccp_present() != 0) {
+ ccp_pci_exit();
+ return -ENODEV;
}
+
+ return 0;
#endif
#ifdef CONFIG_ARM64
@@ -622,7 +453,7 @@ static int __init ccp_mod_init(void)
return ret;
/* Don't leave the driver loaded if init failed */
- if (!ccp_get_device()) {
+ if (ccp_present() != 0) {
ccp_platform_exit();
return -ENODEV;
}
@@ -636,13 +467,7 @@ static int __init ccp_mod_init(void)
static void __exit ccp_mod_exit(void)
{
#ifdef CONFIG_X86
- struct cpuinfo_x86 *cpuinfo = &boot_cpu_data;
-
- switch (cpuinfo->x86) {
- case 22:
- ccp_pci_exit();
- break;
- }
+ ccp_pci_exit();
#endif
#ifdef CONFIG_ARM64
diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h
index 6ff89031fb96..7745d0be491d 100644
--- a/drivers/crypto/ccp/ccp-dev.h
+++ b/drivers/crypto/ccp/ccp-dev.h
@@ -1,7 +1,7 @@
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
- * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
*
@@ -23,6 +23,7 @@
#include <linux/hw_random.h>
#include <linux/bitops.h>
+#define MAX_CCP_NAME_LEN 16
#define MAX_DMAPOOL_NAME_LEN 32
#define MAX_HW_QUEUES 5
@@ -140,6 +141,29 @@
#define CCP_ECC_RESULT_OFFSET 60
#define CCP_ECC_RESULT_SUCCESS 0x0001
+struct ccp_op;
+
+/* Structure for computation functions that are device-specific */
+struct ccp_actions {
+ int (*perform_aes)(struct ccp_op *);
+ int (*perform_xts_aes)(struct ccp_op *);
+ int (*perform_sha)(struct ccp_op *);
+ int (*perform_rsa)(struct ccp_op *);
+ int (*perform_passthru)(struct ccp_op *);
+ int (*perform_ecc)(struct ccp_op *);
+ int (*init)(struct ccp_device *);
+ void (*destroy)(struct ccp_device *);
+ irqreturn_t (*irqhandler)(int, void *);
+};
+
+/* Structure to hold CCP version-specific values */
+struct ccp_vdata {
+ unsigned int version;
+ struct ccp_actions *perform;
+};
+
+extern struct ccp_vdata ccpv3;
+
struct ccp_device;
struct ccp_cmd;
@@ -184,6 +208,13 @@ struct ccp_cmd_queue {
} ____cacheline_aligned;
struct ccp_device {
+ struct list_head entry;
+
+ struct ccp_vdata *vdata;
+ unsigned int ord;
+ char name[MAX_CCP_NAME_LEN];
+ char rngname[MAX_CCP_NAME_LEN];
+
struct device *dev;
/*
@@ -258,18 +289,132 @@ struct ccp_device {
unsigned int axcache;
};
+enum ccp_memtype {
+ CCP_MEMTYPE_SYSTEM = 0,
+ CCP_MEMTYPE_KSB,
+ CCP_MEMTYPE_LOCAL,
+ CCP_MEMTYPE__LAST,
+};
+
+struct ccp_dma_info {
+ dma_addr_t address;
+ unsigned int offset;
+ unsigned int length;
+ enum dma_data_direction dir;
+};
+
+struct ccp_dm_workarea {
+ struct device *dev;
+ struct dma_pool *dma_pool;
+ unsigned int length;
+
+ u8 *address;
+ struct ccp_dma_info dma;
+};
+
+struct ccp_sg_workarea {
+ struct scatterlist *sg;
+ int nents;
+
+ struct scatterlist *dma_sg;
+ struct device *dma_dev;
+ unsigned int dma_count;
+ enum dma_data_direction dma_dir;
+
+ unsigned int sg_used;
+
+ u64 bytes_left;
+};
+
+struct ccp_data {
+ struct ccp_sg_workarea sg_wa;
+ struct ccp_dm_workarea dm_wa;
+};
+
+struct ccp_mem {
+ enum ccp_memtype type;
+ union {
+ struct ccp_dma_info dma;
+ u32 ksb;
+ } u;
+};
+
+struct ccp_aes_op {
+ enum ccp_aes_type type;
+ enum ccp_aes_mode mode;
+ enum ccp_aes_action action;
+};
+
+struct ccp_xts_aes_op {
+ enum ccp_aes_action action;
+ enum ccp_xts_aes_unit_size unit_size;
+};
+
+struct ccp_sha_op {
+ enum ccp_sha_type type;
+ u64 msg_bits;
+};
+
+struct ccp_rsa_op {
+ u32 mod_size;
+ u32 input_len;
+};
+
+struct ccp_passthru_op {
+ enum ccp_passthru_bitwise bit_mod;
+ enum ccp_passthru_byteswap byte_swap;
+};
+
+struct ccp_ecc_op {
+ enum ccp_ecc_function function;
+};
+
+struct ccp_op {
+ struct ccp_cmd_queue *cmd_q;
+
+ u32 jobid;
+ u32 ioc;
+ u32 soc;
+ u32 ksb_key;
+ u32 ksb_ctx;
+ u32 init;
+ u32 eom;
+
+ struct ccp_mem src;
+ struct ccp_mem dst;
+
+ union {
+ struct ccp_aes_op aes;
+ struct ccp_xts_aes_op xts;
+ struct ccp_sha_op sha;
+ struct ccp_rsa_op rsa;
+ struct ccp_passthru_op passthru;
+ struct ccp_ecc_op ecc;
+ } u;
+};
+
+static inline u32 ccp_addr_lo(struct ccp_dma_info *info)
+{
+ return lower_32_bits(info->address + info->offset);
+}
+
+static inline u32 ccp_addr_hi(struct ccp_dma_info *info)
+{
+ return upper_32_bits(info->address + info->offset) & 0x0000ffff;
+}
+
int ccp_pci_init(void);
void ccp_pci_exit(void);
int ccp_platform_init(void);
void ccp_platform_exit(void);
+void ccp_add_device(struct ccp_device *ccp);
+void ccp_del_device(struct ccp_device *ccp);
+
struct ccp_device *ccp_alloc_struct(struct device *dev);
-int ccp_init(struct ccp_device *ccp);
-void ccp_destroy(struct ccp_device *ccp);
bool ccp_queues_suspended(struct ccp_device *ccp);
-
-irqreturn_t ccp_irq_handler(int irq, void *data);
+int ccp_cmd_queue_thread(void *data);
int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd);
diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
index 6613aee79b87..eefdf595f758 100644
--- a/drivers/crypto/ccp/ccp-ops.c
+++ b/drivers/crypto/ccp/ccp-ops.c
@@ -1,7 +1,7 @@
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
- * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
*
@@ -13,124 +13,12 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/pci_ids.h>
-#include <linux/kthread.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/ccp.h>
-#include <linux/scatterlist.h>
#include <crypto/scatterwalk.h>
-#include <crypto/sha.h>
+#include <linux/ccp.h>
#include "ccp-dev.h"
-enum ccp_memtype {
- CCP_MEMTYPE_SYSTEM = 0,
- CCP_MEMTYPE_KSB,
- CCP_MEMTYPE_LOCAL,
- CCP_MEMTYPE__LAST,
-};
-
-struct ccp_dma_info {
- dma_addr_t address;
- unsigned int offset;
- unsigned int length;
- enum dma_data_direction dir;
-};
-
-struct ccp_dm_workarea {
- struct device *dev;
- struct dma_pool *dma_pool;
- unsigned int length;
-
- u8 *address;
- struct ccp_dma_info dma;
-};
-
-struct ccp_sg_workarea {
- struct scatterlist *sg;
- int nents;
-
- struct scatterlist *dma_sg;
- struct device *dma_dev;
- unsigned int dma_count;
- enum dma_data_direction dma_dir;
-
- unsigned int sg_used;
-
- u64 bytes_left;
-};
-
-struct ccp_data {
- struct ccp_sg_workarea sg_wa;
- struct ccp_dm_workarea dm_wa;
-};
-
-struct ccp_mem {
- enum ccp_memtype type;
- union {
- struct ccp_dma_info dma;
- u32 ksb;
- } u;
-};
-
-struct ccp_aes_op {
- enum ccp_aes_type type;
- enum ccp_aes_mode mode;
- enum ccp_aes_action action;
-};
-
-struct ccp_xts_aes_op {
- enum ccp_aes_action action;
- enum ccp_xts_aes_unit_size unit_size;
-};
-
-struct ccp_sha_op {
- enum ccp_sha_type type;
- u64 msg_bits;
-};
-
-struct ccp_rsa_op {
- u32 mod_size;
- u32 input_len;
-};
-
-struct ccp_passthru_op {
- enum ccp_passthru_bitwise bit_mod;
- enum ccp_passthru_byteswap byte_swap;
-};
-
-struct ccp_ecc_op {
- enum ccp_ecc_function function;
-};
-
-struct ccp_op {
- struct ccp_cmd_queue *cmd_q;
-
- u32 jobid;
- u32 ioc;
- u32 soc;
- u32 ksb_key;
- u32 ksb_ctx;
- u32 init;
- u32 eom;
-
- struct ccp_mem src;
- struct ccp_mem dst;
-
- union {
- struct ccp_aes_op aes;
- struct ccp_xts_aes_op xts;
- struct ccp_sha_op sha;
- struct ccp_rsa_op rsa;
- struct ccp_passthru_op passthru;
- struct ccp_ecc_op ecc;
- } u;
-};
-
/* SHA initial context values */
static const __be32 ccp_sha1_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1),
@@ -152,253 +40,6 @@ static const __be32 ccp_sha256_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7),
};
-static u32 ccp_addr_lo(struct ccp_dma_info *info)
-{
- return lower_32_bits(info->address + info->offset);
-}
-
-static u32 ccp_addr_hi(struct ccp_dma_info *info)
-{
- return upper_32_bits(info->address + info->offset) & 0x0000ffff;
-}
-
-static int ccp_do_cmd(struct ccp_op *op, u32 *cr, unsigned int cr_count)
-{
- struct ccp_cmd_queue *cmd_q = op->cmd_q;
- struct ccp_device *ccp = cmd_q->ccp;
- void __iomem *cr_addr;
- u32 cr0, cmd;
- unsigned int i;
- int ret = 0;
-
- /* We could read a status register to see how many free slots
- * are actually available, but reading that register resets it
- * and you could lose some error information.
- */
- cmd_q->free_slots--;
-
- cr0 = (cmd_q->id << REQ0_CMD_Q_SHIFT)
- | (op->jobid << REQ0_JOBID_SHIFT)
- | REQ0_WAIT_FOR_WRITE;
-
- if (op->soc)
- cr0 |= REQ0_STOP_ON_COMPLETE
- | REQ0_INT_ON_COMPLETE;
-
- if (op->ioc || !cmd_q->free_slots)
- cr0 |= REQ0_INT_ON_COMPLETE;
-
- /* Start at CMD_REQ1 */
- cr_addr = ccp->io_regs + CMD_REQ0 + CMD_REQ_INCR;
-
- mutex_lock(&ccp->req_mutex);
-
- /* Write CMD_REQ1 through CMD_REQx first */
- for (i = 0; i < cr_count; i++, cr_addr += CMD_REQ_INCR)
- iowrite32(*(cr + i), cr_addr);
-
- /* Tell the CCP to start */
- wmb();
- iowrite32(cr0, ccp->io_regs + CMD_REQ0);
-
- mutex_unlock(&ccp->req_mutex);
-
- if (cr0 & REQ0_INT_ON_COMPLETE) {
- /* Wait for the job to complete */
- ret = wait_event_interruptible(cmd_q->int_queue,
- cmd_q->int_rcvd);
- if (ret || cmd_q->cmd_error) {
- /* On error delete all related jobs from the queue */
- cmd = (cmd_q->id << DEL_Q_ID_SHIFT)
- | op->jobid;
-
- iowrite32(cmd, ccp->io_regs + DEL_CMD_Q_JOB);
-
- if (!ret)
- ret = -EIO;
- } else if (op->soc) {
- /* Delete just head job from the queue on SoC */
- cmd = DEL_Q_ACTIVE
- | (cmd_q->id << DEL_Q_ID_SHIFT)
- | op->jobid;
-
- iowrite32(cmd, ccp->io_regs + DEL_CMD_Q_JOB);
- }
-
- cmd_q->free_slots = CMD_Q_DEPTH(cmd_q->q_status);
-
- cmd_q->int_rcvd = 0;
- }
-
- return ret;
-}
-
-static int ccp_perform_aes(struct ccp_op *op)
-{
- u32 cr[6];
-
- /* Fill out the register contents for REQ1 through REQ6 */
- cr[0] = (CCP_ENGINE_AES << REQ1_ENGINE_SHIFT)
- | (op->u.aes.type << REQ1_AES_TYPE_SHIFT)
- | (op->u.aes.mode << REQ1_AES_MODE_SHIFT)
- | (op->u.aes.action << REQ1_AES_ACTION_SHIFT)
- | (op->ksb_key << REQ1_KEY_KSB_SHIFT);
- cr[1] = op->src.u.dma.length - 1;
- cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
- | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->src.u.dma);
- cr[4] = ccp_addr_lo(&op->dst.u.dma);
- cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->dst.u.dma);
-
- if (op->u.aes.mode == CCP_AES_MODE_CFB)
- cr[0] |= ((0x7f) << REQ1_AES_CFB_SIZE_SHIFT);
-
- if (op->eom)
- cr[0] |= REQ1_EOM;
-
- if (op->init)
- cr[0] |= REQ1_INIT;
-
- return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
-}
-
-static int ccp_perform_xts_aes(struct ccp_op *op)
-{
- u32 cr[6];
-
- /* Fill out the register contents for REQ1 through REQ6 */
- cr[0] = (CCP_ENGINE_XTS_AES_128 << REQ1_ENGINE_SHIFT)
- | (op->u.xts.action << REQ1_AES_ACTION_SHIFT)
- | (op->u.xts.unit_size << REQ1_XTS_AES_SIZE_SHIFT)
- | (op->ksb_key << REQ1_KEY_KSB_SHIFT);
- cr[1] = op->src.u.dma.length - 1;
- cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
- | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->src.u.dma);
- cr[4] = ccp_addr_lo(&op->dst.u.dma);
- cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->dst.u.dma);
-
- if (op->eom)
- cr[0] |= REQ1_EOM;
-
- if (op->init)
- cr[0] |= REQ1_INIT;
-
- return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
-}
-
-static int ccp_perform_sha(struct ccp_op *op)
-{
- u32 cr[6];
-
- /* Fill out the register contents for REQ1 through REQ6 */
- cr[0] = (CCP_ENGINE_SHA << REQ1_ENGINE_SHIFT)
- | (op->u.sha.type << REQ1_SHA_TYPE_SHIFT)
- | REQ1_INIT;
- cr[1] = op->src.u.dma.length - 1;
- cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
- | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->src.u.dma);
-
- if (op->eom) {
- cr[0] |= REQ1_EOM;
- cr[4] = lower_32_bits(op->u.sha.msg_bits);
- cr[5] = upper_32_bits(op->u.sha.msg_bits);
- } else {
- cr[4] = 0;
- cr[5] = 0;
- }
-
- return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
-}
-
-static int ccp_perform_rsa(struct ccp_op *op)
-{
- u32 cr[6];
-
- /* Fill out the register contents for REQ1 through REQ6 */
- cr[0] = (CCP_ENGINE_RSA << REQ1_ENGINE_SHIFT)
- | (op->u.rsa.mod_size << REQ1_RSA_MOD_SIZE_SHIFT)
- | (op->ksb_key << REQ1_KEY_KSB_SHIFT)
- | REQ1_EOM;
- cr[1] = op->u.rsa.input_len - 1;
- cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
- | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->src.u.dma);
- cr[4] = ccp_addr_lo(&op->dst.u.dma);
- cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->dst.u.dma);
-
- return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
-}
-
-static int ccp_perform_passthru(struct ccp_op *op)
-{
- u32 cr[6];
-
- /* Fill out the register contents for REQ1 through REQ6 */
- cr[0] = (CCP_ENGINE_PASSTHRU << REQ1_ENGINE_SHIFT)
- | (op->u.passthru.bit_mod << REQ1_PT_BW_SHIFT)
- | (op->u.passthru.byte_swap << REQ1_PT_BS_SHIFT);
-
- if (op->src.type == CCP_MEMTYPE_SYSTEM)
- cr[1] = op->src.u.dma.length - 1;
- else
- cr[1] = op->dst.u.dma.length - 1;
-
- if (op->src.type == CCP_MEMTYPE_SYSTEM) {
- cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->src.u.dma);
-
- if (op->u.passthru.bit_mod != CCP_PASSTHRU_BITWISE_NOOP)
- cr[3] |= (op->ksb_key << REQ4_KSB_SHIFT);
- } else {
- cr[2] = op->src.u.ksb * CCP_KSB_BYTES;
- cr[3] = (CCP_MEMTYPE_KSB << REQ4_MEMTYPE_SHIFT);
- }
-
- if (op->dst.type == CCP_MEMTYPE_SYSTEM) {
- cr[4] = ccp_addr_lo(&op->dst.u.dma);
- cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->dst.u.dma);
- } else {
- cr[4] = op->dst.u.ksb * CCP_KSB_BYTES;
- cr[5] = (CCP_MEMTYPE_KSB << REQ6_MEMTYPE_SHIFT);
- }
-
- if (op->eom)
- cr[0] |= REQ1_EOM;
-
- return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
-}
-
-static int ccp_perform_ecc(struct ccp_op *op)
-{
- u32 cr[6];
-
- /* Fill out the register contents for REQ1 through REQ6 */
- cr[0] = REQ1_ECC_AFFINE_CONVERT
- | (CCP_ENGINE_ECC << REQ1_ENGINE_SHIFT)
- | (op->u.ecc.function << REQ1_ECC_FUNCTION_SHIFT)
- | REQ1_EOM;
- cr[1] = op->src.u.dma.length - 1;
- cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->src.u.dma);
- cr[4] = ccp_addr_lo(&op->dst.u.dma);
- cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
- | ccp_addr_hi(&op->dst.u.dma);
-
- return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
-}
-
static u32 ccp_alloc_ksb(struct ccp_device *ccp, unsigned int count)
{
int start;
@@ -837,7 +478,7 @@ static int ccp_copy_to_from_ksb(struct ccp_cmd_queue *cmd_q,
op.u.passthru.byte_swap = byte_swap;
- return ccp_perform_passthru(&op);
+ return cmd_q->ccp->vdata->perform->perform_passthru(&op);
}
static int ccp_copy_to_ksb(struct ccp_cmd_queue *cmd_q,
@@ -969,7 +610,7 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
}
}
- ret = ccp_perform_aes(&op);
+ ret = cmd_q->ccp->vdata->perform->perform_aes(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_src;
@@ -1131,7 +772,7 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
op.soc = 1;
}
- ret = ccp_perform_aes(&op);
+ ret = cmd_q->ccp->vdata->perform->perform_aes(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -1296,7 +937,7 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
if (!src.sg_wa.bytes_left)
op.eom = 1;
- ret = ccp_perform_xts_aes(&op);
+ ret = cmd_q->ccp->vdata->perform->perform_xts_aes(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -1453,7 +1094,7 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
if (sha->final && !src.sg_wa.bytes_left)
op.eom = 1;
- ret = ccp_perform_sha(&op);
+ ret = cmd_q->ccp->vdata->perform->perform_sha(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_data;
@@ -1633,7 +1274,7 @@ static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
op.u.rsa.mod_size = rsa->key_size;
op.u.rsa.input_len = i_len;
- ret = ccp_perform_rsa(&op);
+ ret = cmd_q->ccp->vdata->perform->perform_rsa(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -1758,7 +1399,7 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q,
op.dst.u.dma.offset = dst.sg_wa.sg_used;
op.dst.u.dma.length = op.src.u.dma.length;
- ret = ccp_perform_passthru(&op);
+ ret = cmd_q->ccp->vdata->perform->perform_passthru(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -1870,7 +1511,7 @@ static int ccp_run_ecc_mm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
op.u.ecc.function = cmd->u.ecc.function;
- ret = ccp_perform_ecc(&op);
+ ret = cmd_q->ccp->vdata->perform->perform_ecc(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -2034,7 +1675,7 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
op.u.ecc.function = cmd->u.ecc.function;
- ret = ccp_perform_ecc(&op);
+ ret = cmd_q->ccp->vdata->perform->perform_ecc(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
diff --git a/drivers/crypto/ccp/ccp-pci.c b/drivers/crypto/ccp/ccp-pci.c
index 7690467c42f8..0bf262e36b6b 100644
--- a/drivers/crypto/ccp/ccp-pci.c
+++ b/drivers/crypto/ccp/ccp-pci.c
@@ -1,7 +1,7 @@
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
- * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
*
@@ -59,9 +59,11 @@ static int ccp_get_msix_irqs(struct ccp_device *ccp)
ccp_pci->msix_count = ret;
for (v = 0; v < ccp_pci->msix_count; v++) {
/* Set the interrupt names and request the irqs */
- snprintf(ccp_pci->msix[v].name, name_len, "ccp-%u", v);
+ snprintf(ccp_pci->msix[v].name, name_len, "%s-%u",
+ ccp->name, v);
ccp_pci->msix[v].vector = msix_entry[v].vector;
- ret = request_irq(ccp_pci->msix[v].vector, ccp_irq_handler,
+ ret = request_irq(ccp_pci->msix[v].vector,
+ ccp->vdata->perform->irqhandler,
0, ccp_pci->msix[v].name, dev);
if (ret) {
dev_notice(dev, "unable to allocate MSI-X IRQ (%d)\n",
@@ -94,7 +96,8 @@ static int ccp_get_msi_irq(struct ccp_device *ccp)
return ret;
ccp->irq = pdev->irq;
- ret = request_irq(ccp->irq, ccp_irq_handler, 0, "ccp", dev);
+ ret = request_irq(ccp->irq, ccp->vdata->perform->irqhandler, 0,
+ ccp->name, dev);
if (ret) {
dev_notice(dev, "unable to allocate MSI IRQ (%d)\n", ret);
goto e_msi;
@@ -179,6 +182,12 @@ static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto e_err;
ccp->dev_specific = ccp_pci;
+ ccp->vdata = (struct ccp_vdata *)id->driver_data;
+ if (!ccp->vdata || !ccp->vdata->version) {
+ ret = -ENODEV;
+ dev_err(dev, "missing driver data\n");
+ goto e_err;
+ }
ccp->get_irq = ccp_get_irqs;
ccp->free_irq = ccp_free_irqs;
@@ -221,7 +230,7 @@ static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev_set_drvdata(dev, ccp);
- ret = ccp_init(ccp);
+ ret = ccp->vdata->perform->init(ccp);
if (ret)
goto e_iomap;
@@ -251,7 +260,7 @@ static void ccp_pci_remove(struct pci_dev *pdev)
if (!ccp)
return;
- ccp_destroy(ccp);
+ ccp->vdata->perform->destroy(ccp);
pci_iounmap(pdev, ccp->io_map);
@@ -312,7 +321,7 @@ static int ccp_pci_resume(struct pci_dev *pdev)
#endif
static const struct pci_device_id ccp_pci_table[] = {
- { PCI_VDEVICE(AMD, 0x1537), },
+ { PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&ccpv3 },
/* Last entry must be zero */
{ 0, }
};
diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c
index 66dd7c9d08c3..351f28d8c336 100644
--- a/drivers/crypto/ccp/ccp-platform.c
+++ b/drivers/crypto/ccp/ccp-platform.c
@@ -1,7 +1,7 @@
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
- * Copyright (C) 2014 Advanced Micro Devices, Inc.
+ * Copyright (C) 2014,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
*
@@ -32,6 +32,33 @@ struct ccp_platform {
int coherent;
};
+static const struct acpi_device_id ccp_acpi_match[];
+static const struct of_device_id ccp_of_match[];
+
+static struct ccp_vdata *ccp_get_of_version(struct platform_device *pdev)
+{
+#ifdef CONFIG_OF
+ const struct of_device_id *match;
+
+ match = of_match_node(ccp_of_match, pdev->dev.of_node);
+ if (match && match->data)
+ return (struct ccp_vdata *)match->data;
+#endif
+ return 0;
+}
+
+static struct ccp_vdata *ccp_get_acpi_version(struct platform_device *pdev)
+{
+#ifdef CONFIG_ACPI
+ const struct acpi_device_id *match;
+
+ match = acpi_match_device(ccp_acpi_match, &pdev->dev);
+ if (match && match->driver_data)
+ return (struct ccp_vdata *)match->driver_data;
+#endif
+ return 0;
+}
+
static int ccp_get_irq(struct ccp_device *ccp)
{
struct device *dev = ccp->dev;
@@ -43,7 +70,8 @@ static int ccp_get_irq(struct ccp_device *ccp)
return ret;
ccp->irq = ret;
- ret = request_irq(ccp->irq, ccp_irq_handler, 0, "ccp", dev);
+ ret = request_irq(ccp->irq, ccp->vdata->perform->irqhandler, 0,
+ ccp->name, dev);
if (ret) {
dev_notice(dev, "unable to allocate IRQ (%d)\n", ret);
return ret;
@@ -106,6 +134,13 @@ static int ccp_platform_probe(struct platform_device *pdev)
goto e_err;
ccp->dev_specific = ccp_platform;
+ ccp->vdata = pdev->dev.of_node ? ccp_get_of_version(pdev)
+ : ccp_get_acpi_version(pdev);
+ if (!ccp->vdata || !ccp->vdata->version) {
+ ret = -ENODEV;
+ dev_err(dev, "missing driver data\n");
+ goto e_err;
+ }
ccp->get_irq = ccp_get_irqs;
ccp->free_irq = ccp_free_irqs;
@@ -137,7 +172,7 @@ static int ccp_platform_probe(struct platform_device *pdev)
dev_set_drvdata(dev, ccp);
- ret = ccp_init(ccp);
+ ret = ccp->vdata->perform->init(ccp);
if (ret)
goto e_err;
@@ -155,7 +190,7 @@ static int ccp_platform_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ccp_device *ccp = dev_get_drvdata(dev);
- ccp_destroy(ccp);
+ ccp->vdata->perform->destroy(ccp);
dev_notice(dev, "disabled\n");
@@ -214,7 +249,7 @@ static int ccp_platform_resume(struct platform_device *pdev)
#ifdef CONFIG_ACPI
static const struct acpi_device_id ccp_acpi_match[] = {
- { "AMDI0C00", 0 },
+ { "AMDI0C00", (kernel_ulong_t)&ccpv3 },
{ },
};
MODULE_DEVICE_TABLE(acpi, ccp_acpi_match);
@@ -222,7 +257,8 @@ MODULE_DEVICE_TABLE(acpi, ccp_acpi_match);
#ifdef CONFIG_OF
static const struct of_device_id ccp_of_match[] = {
- { .compatible = "amd,ccp-seattle-v1a" },
+ { .compatible = "amd,ccp-seattle-v1a",
+ .data = (const void *)&ccpv3 },
{ },
};
MODULE_DEVICE_TABLE(of, ccp_of_match);
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index e52496a172d0..2296934455fc 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -1031,6 +1031,18 @@ static int aead_perform(struct aead_request *req, int encrypt,
BUG_ON(ivsize && !req->iv);
memcpy(crypt->iv, req->iv, ivsize);
+ buf = chainup_buffers(dev, req->src, crypt->auth_len,
+ &src_hook, flags, src_direction);
+ req_ctx->src = src_hook.next;
+ crypt->src_buf = src_hook.phys_next;
+ if (!buf)
+ goto free_buf_src;
+
+ lastlen = buf->buf_len;
+ if (lastlen >= authsize)
+ crypt->icv_rev_aes = buf->phys_addr +
+ buf->buf_len - authsize;
+
req_ctx->dst = NULL;
if (req->src != req->dst) {
@@ -1055,20 +1067,6 @@ static int aead_perform(struct aead_request *req, int encrypt,
}
}
- buf = chainup_buffers(dev, req->src, crypt->auth_len,
- &src_hook, flags, src_direction);
- req_ctx->src = src_hook.next;
- crypt->src_buf = src_hook.phys_next;
- if (!buf)
- goto free_buf_src;
-
- if (!encrypt || !req_ctx->dst) {
- lastlen = buf->buf_len;
- if (lastlen >= authsize)
- crypt->icv_rev_aes = buf->phys_addr +
- buf->buf_len - authsize;
- }
-
if (unlikely(lastlen < authsize)) {
/* The 12 hmac bytes are scattered,
* we need to copy them into a safe buffer */
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index dd355bd19474..d420ec751c7c 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -36,6 +36,7 @@
#include <linux/interrupt.h>
#include <crypto/scatterwalk.h>
#include <crypto/aes.h>
+#include <crypto/algapi.h>
#define DST_MAXBURST 4
#define DMA_MIN (DST_MAXBURST * sizeof(u32))
@@ -152,13 +153,10 @@ struct omap_aes_dev {
unsigned long flags;
int err;
- spinlock_t lock;
- struct crypto_queue queue;
-
struct tasklet_struct done_task;
- struct tasklet_struct queue_task;
struct ablkcipher_request *req;
+ struct crypto_engine *engine;
/*
* total is used by PIO mode for book keeping so introduce
@@ -532,9 +530,7 @@ static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
pr_debug("err: %d\n", err);
- dd->flags &= ~FLAGS_BUSY;
-
- req->base.complete(&req->base, err);
+ crypto_finalize_request(dd->engine, req, err);
}
static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
@@ -604,34 +600,25 @@ static int omap_aes_copy_sgs(struct omap_aes_dev *dd)
}
static int omap_aes_handle_queue(struct omap_aes_dev *dd,
- struct ablkcipher_request *req)
+ struct ablkcipher_request *req)
{
- struct crypto_async_request *async_req, *backlog;
- struct omap_aes_ctx *ctx;
- struct omap_aes_reqctx *rctx;
- unsigned long flags;
- int err, ret = 0, len;
-
- spin_lock_irqsave(&dd->lock, flags);
if (req)
- ret = ablkcipher_enqueue_request(&dd->queue, req);
- if (dd->flags & FLAGS_BUSY) {
- spin_unlock_irqrestore(&dd->lock, flags);
- return ret;
- }
- backlog = crypto_get_backlog(&dd->queue);
- async_req = crypto_dequeue_request(&dd->queue);
- if (async_req)
- dd->flags |= FLAGS_BUSY;
- spin_unlock_irqrestore(&dd->lock, flags);
+ return crypto_transfer_request_to_engine(dd->engine, req);
- if (!async_req)
- return ret;
+ return 0;
+}
- if (backlog)
- backlog->complete(backlog, -EINPROGRESS);
+static int omap_aes_prepare_req(struct crypto_engine *engine,
+ struct ablkcipher_request *req)
+{
+ struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+ struct omap_aes_dev *dd = omap_aes_find_dev(ctx);
+ struct omap_aes_reqctx *rctx;
+ int len;
- req = ablkcipher_request_cast(async_req);
+ if (!dd)
+ return -ENODEV;
/* assign new request to device */
dd->req = req;
@@ -662,16 +649,20 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd,
dd->ctx = ctx;
ctx->dd = dd;
- err = omap_aes_write_ctrl(dd);
- if (!err)
- err = omap_aes_crypt_dma_start(dd);
- if (err) {
- /* aes_task will not finish it, so do it here */
- omap_aes_finish_req(dd, err);
- tasklet_schedule(&dd->queue_task);
- }
+ return omap_aes_write_ctrl(dd);
+}
- return ret; /* return ret, which is enqueue return value */
+static int omap_aes_crypt_req(struct crypto_engine *engine,
+ struct ablkcipher_request *req)
+{
+ struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+ struct omap_aes_dev *dd = omap_aes_find_dev(ctx);
+
+ if (!dd)
+ return -ENODEV;
+
+ return omap_aes_crypt_dma_start(dd);
}
static void omap_aes_done_task(unsigned long data)
@@ -704,18 +695,10 @@ static void omap_aes_done_task(unsigned long data)
}
omap_aes_finish_req(dd, 0);
- omap_aes_handle_queue(dd, NULL);
pr_debug("exit\n");
}
-static void omap_aes_queue_task(unsigned long data)
-{
- struct omap_aes_dev *dd = (struct omap_aes_dev *)data;
-
- omap_aes_handle_queue(dd, NULL);
-}
-
static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
{
struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
@@ -1175,9 +1158,6 @@ static int omap_aes_probe(struct platform_device *pdev)
dd->dev = dev;
platform_set_drvdata(pdev, dd);
- spin_lock_init(&dd->lock);
- crypto_init_queue(&dd->queue, OMAP_AES_QUEUE_LENGTH);
-
err = (dev->of_node) ? omap_aes_get_res_of(dd, dev, &res) :
omap_aes_get_res_pdev(dd, pdev, &res);
if (err)
@@ -1209,7 +1189,6 @@ static int omap_aes_probe(struct platform_device *pdev)
(reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift);
tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd);
- tasklet_init(&dd->queue_task, omap_aes_queue_task, (unsigned long)dd);
err = omap_aes_dma_init(dd);
if (err && AES_REG_IRQ_STATUS(dd) && AES_REG_IRQ_ENABLE(dd)) {
@@ -1250,7 +1229,20 @@ static int omap_aes_probe(struct platform_device *pdev)
}
}
+ /* Initialize crypto engine */
+ dd->engine = crypto_engine_alloc_init(dev, 1);
+ if (!dd->engine)
+ goto err_algs;
+
+ dd->engine->prepare_request = omap_aes_prepare_req;
+ dd->engine->crypt_one_request = omap_aes_crypt_req;
+ err = crypto_engine_start(dd->engine);
+ if (err)
+ goto err_engine;
+
return 0;
+err_engine:
+ crypto_engine_exit(dd->engine);
err_algs:
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
@@ -1260,7 +1252,6 @@ err_algs:
omap_aes_dma_cleanup(dd);
err_irq:
tasklet_kill(&dd->done_task);
- tasklet_kill(&dd->queue_task);
pm_runtime_disable(dev);
err_res:
dd = NULL;
@@ -1286,8 +1277,8 @@ static int omap_aes_remove(struct platform_device *pdev)
crypto_unregister_alg(
&dd->pdata->algs_info[i].algs_list[j]);
+ crypto_engine_exit(dd->engine);
tasklet_kill(&dd->done_task);
- tasklet_kill(&dd->queue_task);
omap_aes_dma_cleanup(dd);
pm_runtime_disable(dd->dev);
dd = NULL;
diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h
index f96d427e502c..5a07208ce778 100644
--- a/drivers/crypto/qat/qat_common/adf_accel_devices.h
+++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h
@@ -55,8 +55,8 @@
#define ADF_DH895XCC_DEVICE_NAME "dh895xcc"
#define ADF_DH895XCCVF_DEVICE_NAME "dh895xccvf"
-#define ADF_C62X_DEVICE_NAME "c62x"
-#define ADF_C62XVF_DEVICE_NAME "c62xvf"
+#define ADF_C62X_DEVICE_NAME "c6xx"
+#define ADF_C62XVF_DEVICE_NAME "c6xxvf"
#define ADF_C3XXX_DEVICE_NAME "c3xxx"
#define ADF_C3XXXVF_DEVICE_NAME "c3xxxvf"
#define ADF_DH895XCC_PCI_DEVICE_ID 0x435
diff --git a/drivers/crypto/qat/qat_common/adf_aer.c b/drivers/crypto/qat/qat_common/adf_aer.c
index e78a1d7d88fc..b40d9c8dad96 100644
--- a/drivers/crypto/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/qat/qat_common/adf_aer.c
@@ -121,7 +121,6 @@ static void adf_device_reset_worker(struct work_struct *work)
adf_dev_restarting_notify(accel_dev);
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
- adf_dev_restore(accel_dev);
if (adf_dev_init(accel_dev) || adf_dev_start(accel_dev)) {
/* The device hanged and we can't restart it so stop here */
dev_err(&GET_DEV(accel_dev), "Restart device failed\n");
diff --git a/drivers/crypto/qat/qat_common/adf_cfg_user.h b/drivers/crypto/qat/qat_common/adf_cfg_user.h
index ef5988afd4c6..b5484bfa6996 100644
--- a/drivers/crypto/qat/qat_common/adf_cfg_user.h
+++ b/drivers/crypto/qat/qat_common/adf_cfg_user.h
@@ -58,7 +58,7 @@ struct adf_user_cfg_key_val {
uint64_t padding3;
};
enum adf_cfg_val_type type;
-};
+} __packed;
struct adf_user_cfg_section {
char name[ADF_CFG_MAX_SECTION_LEN_IN_BYTES];
@@ -70,7 +70,7 @@ struct adf_user_cfg_section {
struct adf_user_cfg_section *next;
uint64_t padding3;
};
-};
+} __packed;
struct adf_user_cfg_ctl_data {
union {
@@ -78,5 +78,5 @@ struct adf_user_cfg_ctl_data {
uint64_t padding;
};
uint8_t device_id;
-};
+} __packed;
#endif
diff --git a/drivers/crypto/qat/qat_common/adf_hw_arbiter.c b/drivers/crypto/qat/qat_common/adf_hw_arbiter.c
index f267d9e42e0b..d7dd18d9bef8 100644
--- a/drivers/crypto/qat/qat_common/adf_hw_arbiter.c
+++ b/drivers/crypto/qat/qat_common/adf_hw_arbiter.c
@@ -49,7 +49,6 @@
#include "adf_transport_internal.h"
#define ADF_ARB_NUM 4
-#define ADF_ARB_REQ_RING_NUM 8
#define ADF_ARB_REG_SIZE 0x4
#define ADF_ARB_WTR_SIZE 0x20
#define ADF_ARB_OFFSET 0x30000
@@ -64,15 +63,6 @@
ADF_CSR_WR(csr_addr, ADF_ARB_RINGSRVARBEN_OFFSET + \
(ADF_ARB_REG_SLOT * index), value)
-#define WRITE_CSR_ARB_RESPORDERING(csr_addr, index, value) \
- ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \
- ADF_ARB_RO_EN_OFFSET) + (ADF_ARB_REG_SIZE * index), value)
-
-#define WRITE_CSR_ARB_WEIGHT(csr_addr, arb, index, value) \
- ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \
- ADF_ARB_WTR_OFFSET) + (ADF_ARB_WTR_SIZE * arb) + \
- (ADF_ARB_REG_SIZE * index), value)
-
#define WRITE_CSR_ARB_SARCONFIG(csr_addr, index, value) \
ADF_CSR_WR(csr_addr, ADF_ARB_OFFSET + \
(ADF_ARB_REG_SIZE * index), value)
@@ -99,15 +89,6 @@ int adf_init_arb(struct adf_accel_dev *accel_dev)
for (arb = 0; arb < ADF_ARB_NUM; arb++)
WRITE_CSR_ARB_SARCONFIG(csr, arb, arb_cfg);
- /* Setup service weighting */
- for (arb = 0; arb < ADF_ARB_NUM; arb++)
- for (i = 0; i < ADF_ARB_REQ_RING_NUM; i++)
- WRITE_CSR_ARB_WEIGHT(csr, arb, i, 0xFFFFFFFF);
-
- /* Setup ring response ordering */
- for (i = 0; i < ADF_ARB_REQ_RING_NUM; i++)
- WRITE_CSR_ARB_RESPORDERING(csr, i, 0xFFFFFFFF);
-
/* Setup worker queue registers */
for (i = 0; i < hw_data->num_engines; i++)
WRITE_CSR_ARB_WQCFG(csr, i, i);
diff --git a/drivers/crypto/qat/qat_common/icp_qat_uclo.h b/drivers/crypto/qat/qat_common/icp_qat_uclo.h
index d97db990955d..5d1ee7e53492 100644
--- a/drivers/crypto/qat/qat_common/icp_qat_uclo.h
+++ b/drivers/crypto/qat/qat_common/icp_qat_uclo.h
@@ -112,27 +112,27 @@ enum icp_qat_uof_mem_region {
};
enum icp_qat_uof_regtype {
- ICP_NO_DEST,
- ICP_GPA_REL,
- ICP_GPA_ABS,
- ICP_GPB_REL,
- ICP_GPB_ABS,
- ICP_SR_REL,
- ICP_SR_RD_REL,
- ICP_SR_WR_REL,
- ICP_SR_ABS,
- ICP_SR_RD_ABS,
- ICP_SR_WR_ABS,
- ICP_DR_REL,
- ICP_DR_RD_REL,
- ICP_DR_WR_REL,
- ICP_DR_ABS,
- ICP_DR_RD_ABS,
- ICP_DR_WR_ABS,
- ICP_LMEM,
- ICP_LMEM0,
- ICP_LMEM1,
- ICP_NEIGH_REL,
+ ICP_NO_DEST = 0,
+ ICP_GPA_REL = 1,
+ ICP_GPA_ABS = 2,
+ ICP_GPB_REL = 3,
+ ICP_GPB_ABS = 4,
+ ICP_SR_REL = 5,
+ ICP_SR_RD_REL = 6,
+ ICP_SR_WR_REL = 7,
+ ICP_SR_ABS = 8,
+ ICP_SR_RD_ABS = 9,
+ ICP_SR_WR_ABS = 10,
+ ICP_DR_REL = 19,
+ ICP_DR_RD_REL = 20,
+ ICP_DR_WR_REL = 21,
+ ICP_DR_ABS = 22,
+ ICP_DR_RD_ABS = 23,
+ ICP_DR_WR_ABS = 24,
+ ICP_LMEM = 26,
+ ICP_LMEM0 = 27,
+ ICP_LMEM1 = 28,
+ ICP_NEIGH_REL = 31,
};
enum icp_qat_css_fwtype {
diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index 59e4c3af15ed..1e8852a8a057 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -1064,8 +1064,7 @@ static int qat_alg_aead_init(struct crypto_aead *tfm,
if (IS_ERR(ctx->hash_tfm))
return PTR_ERR(ctx->hash_tfm);
ctx->qat_hash_alg = hash;
- crypto_aead_set_reqsize(tfm, sizeof(struct aead_request) +
- sizeof(struct qat_crypto_request));
+ crypto_aead_set_reqsize(tfm, sizeof(struct qat_crypto_request));
return 0;
}
@@ -1114,8 +1113,7 @@ static int qat_alg_ablkcipher_init(struct crypto_tfm *tfm)
struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
spin_lock_init(&ctx->lock);
- tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
- sizeof(struct qat_crypto_request);
+ tfm->crt_ablkcipher.reqsize = sizeof(struct qat_crypto_request);
ctx->tfm = tfm;
return 0;
}
diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c
index 51c594fdacdc..e5c0727d4876 100644
--- a/drivers/crypto/qat/qat_common/qat_asym_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c
@@ -340,14 +340,16 @@ static int qat_rsa_enc(struct akcipher_request *req)
if (!ret)
return -EINPROGRESS;
-unmap_src:
- if (qat_req->src_align)
- dma_free_coherent(dev, ctx->key_sz, qat_req->src_align,
- qat_req->in.enc.m);
- else
- if (!dma_mapping_error(dev, qat_req->in.enc.m))
- dma_unmap_single(dev, qat_req->in.enc.m, ctx->key_sz,
- DMA_TO_DEVICE);
+
+ if (!dma_mapping_error(dev, qat_req->phy_out))
+ dma_unmap_single(dev, qat_req->phy_out,
+ sizeof(struct qat_rsa_output_params),
+ DMA_TO_DEVICE);
+unmap_in_params:
+ if (!dma_mapping_error(dev, qat_req->phy_in))
+ dma_unmap_single(dev, qat_req->phy_in,
+ sizeof(struct qat_rsa_input_params),
+ DMA_TO_DEVICE);
unmap_dst:
if (qat_req->dst_align)
dma_free_coherent(dev, ctx->key_sz, qat_req->dst_align,
@@ -356,15 +358,14 @@ unmap_dst:
if (!dma_mapping_error(dev, qat_req->out.enc.c))
dma_unmap_single(dev, qat_req->out.enc.c, ctx->key_sz,
DMA_FROM_DEVICE);
-unmap_in_params:
- if (!dma_mapping_error(dev, qat_req->phy_in))
- dma_unmap_single(dev, qat_req->phy_in,
- sizeof(struct qat_rsa_input_params),
- DMA_TO_DEVICE);
- if (!dma_mapping_error(dev, qat_req->phy_out))
- dma_unmap_single(dev, qat_req->phy_out,
- sizeof(struct qat_rsa_output_params),
- DMA_TO_DEVICE);
+unmap_src:
+ if (qat_req->src_align)
+ dma_free_coherent(dev, ctx->key_sz, qat_req->src_align,
+ qat_req->in.enc.m);
+ else
+ if (!dma_mapping_error(dev, qat_req->in.enc.m))
+ dma_unmap_single(dev, qat_req->in.enc.m, ctx->key_sz,
+ DMA_TO_DEVICE);
return ret;
}
@@ -472,14 +473,16 @@ static int qat_rsa_dec(struct akcipher_request *req)
if (!ret)
return -EINPROGRESS;
-unmap_src:
- if (qat_req->src_align)
- dma_free_coherent(dev, ctx->key_sz, qat_req->src_align,
- qat_req->in.dec.c);
- else
- if (!dma_mapping_error(dev, qat_req->in.dec.c))
- dma_unmap_single(dev, qat_req->in.dec.c, ctx->key_sz,
- DMA_TO_DEVICE);
+
+ if (!dma_mapping_error(dev, qat_req->phy_out))
+ dma_unmap_single(dev, qat_req->phy_out,
+ sizeof(struct qat_rsa_output_params),
+ DMA_TO_DEVICE);
+unmap_in_params:
+ if (!dma_mapping_error(dev, qat_req->phy_in))
+ dma_unmap_single(dev, qat_req->phy_in,
+ sizeof(struct qat_rsa_input_params),
+ DMA_TO_DEVICE);
unmap_dst:
if (qat_req->dst_align)
dma_free_coherent(dev, ctx->key_sz, qat_req->dst_align,
@@ -488,15 +491,14 @@ unmap_dst:
if (!dma_mapping_error(dev, qat_req->out.dec.m))
dma_unmap_single(dev, qat_req->out.dec.m, ctx->key_sz,
DMA_FROM_DEVICE);
-unmap_in_params:
- if (!dma_mapping_error(dev, qat_req->phy_in))
- dma_unmap_single(dev, qat_req->phy_in,
- sizeof(struct qat_rsa_input_params),
- DMA_TO_DEVICE);
- if (!dma_mapping_error(dev, qat_req->phy_out))
- dma_unmap_single(dev, qat_req->phy_out,
- sizeof(struct qat_rsa_output_params),
- DMA_TO_DEVICE);
+unmap_src:
+ if (qat_req->src_align)
+ dma_free_coherent(dev, ctx->key_sz, qat_req->src_align,
+ qat_req->in.dec.c);
+ else
+ if (!dma_mapping_error(dev, qat_req->in.dec.c))
+ dma_unmap_single(dev, qat_req->in.dec.c, ctx->key_sz,
+ DMA_TO_DEVICE);
return ret;
}
diff --git a/drivers/crypto/qat/qat_common/qat_uclo.c b/drivers/crypto/qat/qat_common/qat_uclo.c
index 25d15f19c2b3..9b961b37a282 100644
--- a/drivers/crypto/qat/qat_common/qat_uclo.c
+++ b/drivers/crypto/qat/qat_common/qat_uclo.c
@@ -688,7 +688,7 @@ static int qat_uclo_map_ae(struct icp_qat_fw_loader_handle *handle, int max_ae)
int mflag = 0;
struct icp_qat_uclo_objhandle *obj_handle = handle->obj_handle;
- for (ae = 0; ae <= max_ae; ae++) {
+ for (ae = 0; ae < max_ae; ae++) {
if (!test_bit(ae,
(unsigned long *)&handle->hal_handle->ae_mask))
continue;
diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile
index 7051c6c715f3..30f91297b4b6 100644
--- a/drivers/crypto/rockchip/Makefile
+++ b/drivers/crypto/rockchip/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rk_crypto.o
rk_crypto-objs := rk3288_crypto.o \
rk3288_crypto_ablkcipher.o \
+ rk3288_crypto_ahash.o
diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c
index da9c73dce4af..af508258d2ea 100644
--- a/drivers/crypto/rockchip/rk3288_crypto.c
+++ b/drivers/crypto/rockchip/rk3288_crypto.c
@@ -208,6 +208,8 @@ static void rk_crypto_tasklet_cb(unsigned long data)
if (crypto_tfm_alg_type(async_req->tfm) == CRYPTO_ALG_TYPE_ABLKCIPHER)
dev->ablk_req = ablkcipher_request_cast(async_req);
+ else
+ dev->ahash_req = ahash_request_cast(async_req);
err = dev->start(dev);
if (err)
dev->complete(dev, err);
@@ -220,6 +222,9 @@ static struct rk_crypto_tmp *rk_cipher_algs[] = {
&rk_cbc_des_alg,
&rk_ecb_des3_ede_alg,
&rk_cbc_des3_ede_alg,
+ &rk_ahash_sha1,
+ &rk_ahash_sha256,
+ &rk_ahash_md5,
};
static int rk_crypto_register(struct rk_crypto_info *crypto_info)
@@ -229,15 +234,24 @@ static int rk_crypto_register(struct rk_crypto_info *crypto_info)
for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
rk_cipher_algs[i]->dev = crypto_info;
- err = crypto_register_alg(&rk_cipher_algs[i]->alg);
+ if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
+ err = crypto_register_alg(
+ &rk_cipher_algs[i]->alg.crypto);
+ else
+ err = crypto_register_ahash(
+ &rk_cipher_algs[i]->alg.hash);
if (err)
goto err_cipher_algs;
}
return 0;
err_cipher_algs:
- for (k = 0; k < i; k++)
- crypto_unregister_alg(&rk_cipher_algs[k]->alg);
+ for (k = 0; k < i; k++) {
+ if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
+ crypto_unregister_alg(&rk_cipher_algs[k]->alg.crypto);
+ else
+ crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
+ }
return err;
}
@@ -245,8 +259,12 @@ static void rk_crypto_unregister(void)
{
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++)
- crypto_unregister_alg(&rk_cipher_algs[i]->alg);
+ for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
+ if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
+ crypto_unregister_alg(&rk_cipher_algs[i]->alg.crypto);
+ else
+ crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
+ }
}
static void rk_crypto_action(void *data)
diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h
index e499c2c6c903..d7b71fea320b 100644
--- a/drivers/crypto/rockchip/rk3288_crypto.h
+++ b/drivers/crypto/rockchip/rk3288_crypto.h
@@ -6,6 +6,10 @@
#include <crypto/algapi.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <crypto/internal/hash.h>
+
+#include <crypto/md5.h>
+#include <crypto/sha.h>
#define _SBF(v, f) ((v) << (f))
@@ -149,6 +153,28 @@
#define RK_CRYPTO_TDES_KEY3_0 0x0130
#define RK_CRYPTO_TDES_KEY3_1 0x0134
+/* HASH */
+#define RK_CRYPTO_HASH_CTRL 0x0180
+#define RK_CRYPTO_HASH_SWAP_DO BIT(3)
+#define RK_CRYPTO_HASH_SWAP_DI BIT(2)
+#define RK_CRYPTO_HASH_SHA1 _SBF(0x00, 0)
+#define RK_CRYPTO_HASH_MD5 _SBF(0x01, 0)
+#define RK_CRYPTO_HASH_SHA256 _SBF(0x02, 0)
+#define RK_CRYPTO_HASH_PRNG _SBF(0x03, 0)
+
+#define RK_CRYPTO_HASH_STS 0x0184
+#define RK_CRYPTO_HASH_DONE BIT(0)
+
+#define RK_CRYPTO_HASH_MSG_LEN 0x0188
+#define RK_CRYPTO_HASH_DOUT_0 0x018c
+#define RK_CRYPTO_HASH_DOUT_1 0x0190
+#define RK_CRYPTO_HASH_DOUT_2 0x0194
+#define RK_CRYPTO_HASH_DOUT_3 0x0198
+#define RK_CRYPTO_HASH_DOUT_4 0x019c
+#define RK_CRYPTO_HASH_DOUT_5 0x01a0
+#define RK_CRYPTO_HASH_DOUT_6 0x01a4
+#define RK_CRYPTO_HASH_DOUT_7 0x01a8
+
#define CRYPTO_READ(dev, offset) \
readl_relaxed(((dev)->reg + (offset)))
#define CRYPTO_WRITE(dev, offset, val) \
@@ -166,6 +192,7 @@ struct rk_crypto_info {
struct crypto_queue queue;
struct tasklet_struct crypto_tasklet;
struct ablkcipher_request *ablk_req;
+ struct ahash_request *ahash_req;
/* device lock */
spinlock_t lock;
@@ -195,15 +222,36 @@ struct rk_crypto_info {
void (*unload_data)(struct rk_crypto_info *dev);
};
+/* the private variable of hash */
+struct rk_ahash_ctx {
+ struct rk_crypto_info *dev;
+ /* for fallback */
+ struct crypto_ahash *fallback_tfm;
+};
+
+/* the privete variable of hash for fallback */
+struct rk_ahash_rctx {
+ struct ahash_request fallback_req;
+};
+
/* the private variable of cipher */
struct rk_cipher_ctx {
struct rk_crypto_info *dev;
unsigned int keylen;
};
+enum alg_type {
+ ALG_TYPE_HASH,
+ ALG_TYPE_CIPHER,
+};
+
struct rk_crypto_tmp {
- struct rk_crypto_info *dev;
- struct crypto_alg alg;
+ struct rk_crypto_info *dev;
+ union {
+ struct crypto_alg crypto;
+ struct ahash_alg hash;
+ } alg;
+ enum alg_type type;
};
extern struct rk_crypto_tmp rk_ecb_aes_alg;
@@ -213,4 +261,8 @@ extern struct rk_crypto_tmp rk_cbc_des_alg;
extern struct rk_crypto_tmp rk_ecb_des3_ede_alg;
extern struct rk_crypto_tmp rk_cbc_des3_ede_alg;
+extern struct rk_crypto_tmp rk_ahash_sha1;
+extern struct rk_crypto_tmp rk_ahash_sha256;
+extern struct rk_crypto_tmp rk_ahash_md5;
+
#endif
diff --git a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
index d98b681f6c06..b5a3afe222e4 100644
--- a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
+++ b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
@@ -336,7 +336,7 @@ static int rk_ablk_cra_init(struct crypto_tfm *tfm)
struct crypto_alg *alg = tfm->__crt_alg;
struct rk_crypto_tmp *algt;
- algt = container_of(alg, struct rk_crypto_tmp, alg);
+ algt = container_of(alg, struct rk_crypto_tmp, alg.crypto);
ctx->dev = algt->dev;
ctx->dev->align_size = crypto_tfm_alg_alignmask(tfm) + 1;
@@ -357,7 +357,8 @@ static void rk_ablk_cra_exit(struct crypto_tfm *tfm)
}
struct rk_crypto_tmp rk_ecb_aes_alg = {
- .alg = {
+ .type = ALG_TYPE_CIPHER,
+ .alg.crypto = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-rk",
.cra_priority = 300,
@@ -381,7 +382,8 @@ struct rk_crypto_tmp rk_ecb_aes_alg = {
};
struct rk_crypto_tmp rk_cbc_aes_alg = {
- .alg = {
+ .type = ALG_TYPE_CIPHER,
+ .alg.crypto = {
.cra_name = "cbc(aes)",
.cra_driver_name = "cbc-aes-rk",
.cra_priority = 300,
@@ -406,7 +408,8 @@ struct rk_crypto_tmp rk_cbc_aes_alg = {
};
struct rk_crypto_tmp rk_ecb_des_alg = {
- .alg = {
+ .type = ALG_TYPE_CIPHER,
+ .alg.crypto = {
.cra_name = "ecb(des)",
.cra_driver_name = "ecb-des-rk",
.cra_priority = 300,
@@ -430,7 +433,8 @@ struct rk_crypto_tmp rk_ecb_des_alg = {
};
struct rk_crypto_tmp rk_cbc_des_alg = {
- .alg = {
+ .type = ALG_TYPE_CIPHER,
+ .alg.crypto = {
.cra_name = "cbc(des)",
.cra_driver_name = "cbc-des-rk",
.cra_priority = 300,
@@ -455,7 +459,8 @@ struct rk_crypto_tmp rk_cbc_des_alg = {
};
struct rk_crypto_tmp rk_ecb_des3_ede_alg = {
- .alg = {
+ .type = ALG_TYPE_CIPHER,
+ .alg.crypto = {
.cra_name = "ecb(des3_ede)",
.cra_driver_name = "ecb-des3-ede-rk",
.cra_priority = 300,
@@ -480,7 +485,8 @@ struct rk_crypto_tmp rk_ecb_des3_ede_alg = {
};
struct rk_crypto_tmp rk_cbc_des3_ede_alg = {
- .alg = {
+ .type = ALG_TYPE_CIPHER,
+ .alg.crypto = {
.cra_name = "cbc(des3_ede)",
.cra_driver_name = "cbc-des3-ede-rk",
.cra_priority = 300,
diff --git a/drivers/crypto/rockchip/rk3288_crypto_ahash.c b/drivers/crypto/rockchip/rk3288_crypto_ahash.c
new file mode 100644
index 000000000000..718588219f75
--- /dev/null
+++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c
@@ -0,0 +1,404 @@
+/*
+ * Crypto acceleration support for Rockchip RK3288
+ *
+ * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * Author: Zain Wang <zain.wang@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Some ideas are from marvell/cesa.c and s5p-sss.c driver.
+ */
+#include "rk3288_crypto.h"
+
+/*
+ * IC can not process zero message hash,
+ * so we put the fixed hash out when met zero message.
+ */
+
+static int zero_message_process(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ int rk_digest_size = crypto_ahash_digestsize(tfm);
+
+ switch (rk_digest_size) {
+ case SHA1_DIGEST_SIZE:
+ memcpy(req->result, sha1_zero_message_hash, rk_digest_size);
+ break;
+ case SHA256_DIGEST_SIZE:
+ memcpy(req->result, sha256_zero_message_hash, rk_digest_size);
+ break;
+ case MD5_DIGEST_SIZE:
+ memcpy(req->result, md5_zero_message_hash, rk_digest_size);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void rk_ahash_crypto_complete(struct rk_crypto_info *dev, int err)
+{
+ if (dev->ahash_req->base.complete)
+ dev->ahash_req->base.complete(&dev->ahash_req->base, err);
+}
+
+static void rk_ahash_reg_init(struct rk_crypto_info *dev)
+{
+ int reg_status = 0;
+
+ reg_status = CRYPTO_READ(dev, RK_CRYPTO_CTRL) |
+ RK_CRYPTO_HASH_FLUSH | _SBF(0xffff, 16);
+ CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, reg_status);
+
+ reg_status = CRYPTO_READ(dev, RK_CRYPTO_CTRL);
+ reg_status &= (~RK_CRYPTO_HASH_FLUSH);
+ reg_status |= _SBF(0xffff, 16);
+ CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, reg_status);
+
+ memset_io(dev->reg + RK_CRYPTO_HASH_DOUT_0, 0, 32);
+
+ CRYPTO_WRITE(dev, RK_CRYPTO_INTENA, RK_CRYPTO_HRDMA_ERR_ENA |
+ RK_CRYPTO_HRDMA_DONE_ENA);
+
+ CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, RK_CRYPTO_HRDMA_ERR_INT |
+ RK_CRYPTO_HRDMA_DONE_INT);
+
+ CRYPTO_WRITE(dev, RK_CRYPTO_HASH_CTRL, dev->mode |
+ RK_CRYPTO_HASH_SWAP_DO);
+
+ CRYPTO_WRITE(dev, RK_CRYPTO_CONF, RK_CRYPTO_BYTESWAP_HRFIFO |
+ RK_CRYPTO_BYTESWAP_BRFIFO |
+ RK_CRYPTO_BYTESWAP_BTFIFO);
+
+ CRYPTO_WRITE(dev, RK_CRYPTO_HASH_MSG_LEN, dev->total);
+}
+
+static int rk_ahash_init(struct ahash_request *req)
+{
+ struct rk_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ return crypto_ahash_init(&rctx->fallback_req);
+}
+
+static int rk_ahash_update(struct ahash_request *req)
+{
+ struct rk_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+ rctx->fallback_req.nbytes = req->nbytes;
+ rctx->fallback_req.src = req->src;
+
+ return crypto_ahash_update(&rctx->fallback_req);
+}
+
+static int rk_ahash_final(struct ahash_request *req)
+{
+ struct rk_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+ rctx->fallback_req.result = req->result;
+
+ return crypto_ahash_final(&rctx->fallback_req);
+}
+
+static int rk_ahash_finup(struct ahash_request *req)
+{
+ struct rk_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ rctx->fallback_req.nbytes = req->nbytes;
+ rctx->fallback_req.src = req->src;
+ rctx->fallback_req.result = req->result;
+
+ return crypto_ahash_finup(&rctx->fallback_req);
+}
+
+static int rk_ahash_import(struct ahash_request *req, const void *in)
+{
+ struct rk_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ return crypto_ahash_import(&rctx->fallback_req, in);
+}
+
+static int rk_ahash_export(struct ahash_request *req, void *out)
+{
+ struct rk_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ return crypto_ahash_export(&rctx->fallback_req, out);
+}
+
+static int rk_ahash_digest(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk_ahash_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
+ struct rk_crypto_info *dev = NULL;
+ unsigned long flags;
+ int ret;
+
+ if (!req->nbytes)
+ return zero_message_process(req);
+
+ dev = tctx->dev;
+ dev->total = req->nbytes;
+ dev->left_bytes = req->nbytes;
+ dev->aligned = 0;
+ dev->mode = 0;
+ dev->align_size = 4;
+ dev->sg_dst = NULL;
+ dev->sg_src = req->src;
+ dev->first = req->src;
+ dev->nents = sg_nents(req->src);
+
+ switch (crypto_ahash_digestsize(tfm)) {
+ case SHA1_DIGEST_SIZE:
+ dev->mode = RK_CRYPTO_HASH_SHA1;
+ break;
+ case SHA256_DIGEST_SIZE:
+ dev->mode = RK_CRYPTO_HASH_SHA256;
+ break;
+ case MD5_DIGEST_SIZE:
+ dev->mode = RK_CRYPTO_HASH_MD5;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rk_ahash_reg_init(dev);
+
+ spin_lock_irqsave(&dev->lock, flags);
+ ret = crypto_enqueue_request(&dev->queue, &req->base);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ tasklet_schedule(&dev->crypto_tasklet);
+
+ /*
+ * it will take some time to process date after last dma transmission.
+ *
+ * waiting time is relative with the last date len,
+ * so cannot set a fixed time here.
+ * 10-50 makes system not call here frequently wasting
+ * efficiency, and make it response quickly when dma
+ * complete.
+ */
+ while (!CRYPTO_READ(dev, RK_CRYPTO_HASH_STS))
+ usleep_range(10, 50);
+
+ memcpy_fromio(req->result, dev->reg + RK_CRYPTO_HASH_DOUT_0,
+ crypto_ahash_digestsize(tfm));
+
+ return 0;
+}
+
+static void crypto_ahash_dma_start(struct rk_crypto_info *dev)
+{
+ CRYPTO_WRITE(dev, RK_CRYPTO_HRDMAS, dev->addr_in);
+ CRYPTO_WRITE(dev, RK_CRYPTO_HRDMAL, (dev->count + 3) / 4);
+ CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, RK_CRYPTO_HASH_START |
+ (RK_CRYPTO_HASH_START << 16));
+}
+
+static int rk_ahash_set_data_start(struct rk_crypto_info *dev)
+{
+ int err;
+
+ err = dev->load_data(dev, dev->sg_src, NULL);
+ if (!err)
+ crypto_ahash_dma_start(dev);
+ return err;
+}
+
+static int rk_ahash_start(struct rk_crypto_info *dev)
+{
+ return rk_ahash_set_data_start(dev);
+}
+
+static int rk_ahash_crypto_rx(struct rk_crypto_info *dev)
+{
+ int err = 0;
+
+ dev->unload_data(dev);
+ if (dev->left_bytes) {
+ if (dev->aligned) {
+ if (sg_is_last(dev->sg_src)) {
+ dev_warn(dev->dev, "[%s:%d], Lack of data\n",
+ __func__, __LINE__);
+ err = -ENOMEM;
+ goto out_rx;
+ }
+ dev->sg_src = sg_next(dev->sg_src);
+ }
+ err = rk_ahash_set_data_start(dev);
+ } else {
+ dev->complete(dev, 0);
+ }
+
+out_rx:
+ return err;
+}
+
+static int rk_cra_hash_init(struct crypto_tfm *tfm)
+{
+ struct rk_ahash_ctx *tctx = crypto_tfm_ctx(tfm);
+ struct rk_crypto_tmp *algt;
+ struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
+
+ const char *alg_name = crypto_tfm_alg_name(tfm);
+
+ algt = container_of(alg, struct rk_crypto_tmp, alg.hash);
+
+ tctx->dev = algt->dev;
+ tctx->dev->addr_vir = (void *)__get_free_page(GFP_KERNEL);
+ if (!tctx->dev->addr_vir) {
+ dev_err(tctx->dev->dev, "failed to kmalloc for addr_vir\n");
+ return -ENOMEM;
+ }
+ tctx->dev->start = rk_ahash_start;
+ tctx->dev->update = rk_ahash_crypto_rx;
+ tctx->dev->complete = rk_ahash_crypto_complete;
+
+ /* for fallback */
+ tctx->fallback_tfm = crypto_alloc_ahash(alg_name, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(tctx->fallback_tfm)) {
+ dev_err(tctx->dev->dev, "Could not load fallback driver.\n");
+ return PTR_ERR(tctx->fallback_tfm);
+ }
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct rk_ahash_rctx) +
+ crypto_ahash_reqsize(tctx->fallback_tfm));
+
+ return tctx->dev->enable_clk(tctx->dev);
+}
+
+static void rk_cra_hash_exit(struct crypto_tfm *tfm)
+{
+ struct rk_ahash_ctx *tctx = crypto_tfm_ctx(tfm);
+
+ free_page((unsigned long)tctx->dev->addr_vir);
+ return tctx->dev->disable_clk(tctx->dev);
+}
+
+struct rk_crypto_tmp rk_ahash_sha1 = {
+ .type = ALG_TYPE_HASH,
+ .alg.hash = {
+ .init = rk_ahash_init,
+ .update = rk_ahash_update,
+ .final = rk_ahash_final,
+ .finup = rk_ahash_finup,
+ .export = rk_ahash_export,
+ .import = rk_ahash_import,
+ .digest = rk_ahash_digest,
+ .halg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct sha1_state),
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "rk-sha1",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct rk_ahash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = rk_cra_hash_init,
+ .cra_exit = rk_cra_hash_exit,
+ .cra_module = THIS_MODULE,
+ }
+ }
+ }
+};
+
+struct rk_crypto_tmp rk_ahash_sha256 = {
+ .type = ALG_TYPE_HASH,
+ .alg.hash = {
+ .init = rk_ahash_init,
+ .update = rk_ahash_update,
+ .final = rk_ahash_final,
+ .finup = rk_ahash_finup,
+ .export = rk_ahash_export,
+ .import = rk_ahash_import,
+ .digest = rk_ahash_digest,
+ .halg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct sha256_state),
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "rk-sha256",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct rk_ahash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = rk_cra_hash_init,
+ .cra_exit = rk_cra_hash_exit,
+ .cra_module = THIS_MODULE,
+ }
+ }
+ }
+};
+
+struct rk_crypto_tmp rk_ahash_md5 = {
+ .type = ALG_TYPE_HASH,
+ .alg.hash = {
+ .init = rk_ahash_init,
+ .update = rk_ahash_update,
+ .final = rk_ahash_final,
+ .finup = rk_ahash_finup,
+ .export = rk_ahash_export,
+ .import = rk_ahash_import,
+ .digest = rk_ahash_digest,
+ .halg = {
+ .digestsize = MD5_DIGEST_SIZE,
+ .statesize = sizeof(struct md5_state),
+ .base = {
+ .cra_name = "md5",
+ .cra_driver_name = "rk-md5",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct rk_ahash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = rk_cra_hash_init,
+ .cra_exit = rk_cra_hash_exit,
+ .cra_module = THIS_MODULE,
+ }
+ }
+ }
+};
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index f214a8755827..5f161a9777e3 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -224,6 +224,7 @@ static inline struct samsung_aes_variant *find_s5p_sss_version
{
if (IS_ENABLED(CONFIG_OF) && (pdev->dev.of_node)) {
const struct of_device_id *match;
+
match = of_match_node(s5p_sss_dt_match,
pdev->dev.of_node);
return (struct samsung_aes_variant *)match->data;
@@ -382,7 +383,7 @@ static void s5p_set_aes(struct s5p_aes_dev *dev,
void __iomem *keystart;
if (iv)
- memcpy(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10);
+ memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10);
if (keylen == AES_KEYSIZE_256)
keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0);
@@ -391,13 +392,12 @@ static void s5p_set_aes(struct s5p_aes_dev *dev,
else
keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(4);
- memcpy(keystart, key, keylen);
+ memcpy_toio(keystart, key, keylen);
}
static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
{
struct ablkcipher_request *req = dev->req;
-
uint32_t aes_control;
int err;
unsigned long flags;
@@ -518,7 +518,7 @@ static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
struct s5p_aes_dev *dev = ctx->dev;
if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
- pr_err("request size is not exact amount of AES blocks\n");
+ dev_err(dev->dev, "request size is not exact amount of AES blocks\n");
return -EINVAL;
}
@@ -566,7 +566,7 @@ static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req)
static int s5p_aes_cra_init(struct crypto_tfm *tfm)
{
- struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
ctx->dev = s5p_dev;
tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_aes_reqctx);
@@ -701,7 +701,7 @@ static int s5p_aes_probe(struct platform_device *pdev)
goto err_algs;
}
- pr_info("s5p-sss driver registered\n");
+ dev_info(dev, "s5p-sss driver registered\n");
return 0;
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index 6c4f91c5e6b3..c3f3d89e4831 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -182,7 +182,6 @@ struct sahara_sha_reqctx {
u8 buf[SAHARA_MAX_SHA_BLOCK_SIZE];
u8 rembuf[SAHARA_MAX_SHA_BLOCK_SIZE];
u8 context[SHA256_DIGEST_SIZE + 4];
- struct mutex mutex;
unsigned int mode;
unsigned int digest_size;
unsigned int context_size;
@@ -1096,7 +1095,6 @@ static int sahara_sha_enqueue(struct ahash_request *req, int last)
if (!req->nbytes && !last)
return 0;
- mutex_lock(&rctx->mutex);
rctx->last = last;
if (!rctx->active) {
@@ -1109,7 +1107,6 @@ static int sahara_sha_enqueue(struct ahash_request *req, int last)
mutex_unlock(&dev->queue_mutex);
wake_up_process(dev->kthread);
- mutex_unlock(&rctx->mutex);
return ret;
}
@@ -1137,8 +1134,6 @@ static int sahara_sha_init(struct ahash_request *req)
rctx->context_size = rctx->digest_size + 4;
rctx->active = 0;
- mutex_init(&rctx->mutex);
-
return 0;
}
@@ -1167,26 +1162,18 @@ static int sahara_sha_digest(struct ahash_request *req)
static int sahara_sha_export(struct ahash_request *req, void *out)
{
- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
- struct sahara_ctx *ctx = crypto_ahash_ctx(ahash);
struct sahara_sha_reqctx *rctx = ahash_request_ctx(req);
- memcpy(out, ctx, sizeof(struct sahara_ctx));
- memcpy(out + sizeof(struct sahara_sha_reqctx), rctx,
- sizeof(struct sahara_sha_reqctx));
+ memcpy(out, rctx, sizeof(struct sahara_sha_reqctx));
return 0;
}
static int sahara_sha_import(struct ahash_request *req, const void *in)
{
- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
- struct sahara_ctx *ctx = crypto_ahash_ctx(ahash);
struct sahara_sha_reqctx *rctx = ahash_request_ctx(req);
- memcpy(ctx, in, sizeof(struct sahara_ctx));
- memcpy(rctx, in + sizeof(struct sahara_sha_reqctx),
- sizeof(struct sahara_sha_reqctx));
+ memcpy(rctx, in, sizeof(struct sahara_sha_reqctx));
return 0;
}
@@ -1272,6 +1259,7 @@ static struct ahash_alg sha_v3_algs[] = {
.export = sahara_sha_export,
.import = sahara_sha_import,
.halg.digestsize = SHA1_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct sahara_sha_reqctx),
.halg.base = {
.cra_name = "sha1",
.cra_driver_name = "sahara-sha1",
@@ -1299,6 +1287,7 @@ static struct ahash_alg sha_v4_algs[] = {
.export = sahara_sha_export,
.import = sahara_sha_import,
.halg.digestsize = SHA256_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct sahara_sha_reqctx),
.halg.base = {
.cra_name = "sha256",
.cra_driver_name = "sahara-sha256",
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
index a19ee127edca..7be3fbcd8d78 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
@@ -251,11 +251,10 @@ static int sun4i_ss_cipher_poll(struct ablkcipher_request *areq)
spaces = readl(ss->base + SS_FCSR);
rx_cnt = SS_RXFIFO_SPACES(spaces);
tx_cnt = SS_TXFIFO_SPACES(spaces);
- dev_dbg(ss->dev, "%x %u/%u %u/%u cnt=%u %u/%u %u/%u cnt=%u %u %u\n",
+ dev_dbg(ss->dev, "%x %u/%u %u/%u cnt=%u %u/%u %u/%u cnt=%u %u\n",
mode,
oi, mi.length, ileft, areq->nbytes, rx_cnt,
- oo, mo.length, oleft, areq->nbytes, tx_cnt,
- todo, ob);
+ oo, mo.length, oleft, areq->nbytes, tx_cnt, ob);
if (tx_cnt == 0)
continue;
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
index 4c243c1ffc7f..790f7cadc1ed 100644
--- a/drivers/crypto/ux500/cryp/cryp_core.c
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -1440,9 +1440,9 @@ static int ux500_cryp_probe(struct platform_device *pdev)
device_data->phybase = res->start;
device_data->base = devm_ioremap_resource(dev, res);
- if (!device_data->base) {
+ if (IS_ERR(device_data->base)) {
dev_err(dev, "[%s]: ioremap failed!", __func__);
- ret = -ENOMEM;
+ ret = PTR_ERR(device_data->base);
goto out;
}
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
index d6fdc583ce5d..574e87c7f2b8 100644
--- a/drivers/crypto/ux500/hash/hash_core.c
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -1659,9 +1659,9 @@ static int ux500_hash_probe(struct platform_device *pdev)
device_data->phybase = res->start;
device_data->base = devm_ioremap_resource(dev, res);
- if (!device_data->base) {
+ if (IS_ERR(device_data->base)) {
dev_err(dev, "%s: ioremap() failed!\n", __func__);
- ret = -ENOMEM;
+ ret = PTR_ERR(device_data->base);
goto out;
}
spin_lock_init(&device_data->ctx_lock);
diff --git a/drivers/devfreq/tegra-devfreq.c b/drivers/devfreq/tegra-devfreq.c
index 848b93ee930f..fe9dce0245bf 100644
--- a/drivers/devfreq/tegra-devfreq.c
+++ b/drivers/devfreq/tegra-devfreq.c
@@ -500,6 +500,8 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
clk_set_min_rate(tegra->emc_clock, rate);
clk_set_rate(tegra->emc_clock, 0);
+ *freq = rate;
+
return 0;
}
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 79b1390f2016..d96d87c56f2e 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -341,12 +341,13 @@ config MV_XOR
config MXS_DMA
bool "MXS DMA support"
- depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q
+ depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q || SOC_IMX6UL
select STMP_DEVICE
select DMA_ENGINE
help
Support the MXS DMA engine. This engine including APBH-DMA
- and APBX-DMA is integrated into Freescale i.MX23/28/MX6Q/MX6DL chips.
+ and APBX-DMA is integrated into Freescale
+ i.MX23/28/MX6Q/MX6DL/MX6UL chips.
config MX3_IPU
bool "MX3x Image Processing Unit support"
@@ -408,15 +409,6 @@ config PXA_DMA
16 to 32 channels for peripheral to memory or memory to memory
transfers.
-config QCOM_BAM_DMA
- tristate "QCOM BAM DMA support"
- depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
- select DMA_ENGINE
- select DMA_VIRTUAL_CHANNELS
- ---help---
- Enable support for the QCOM BAM DMA controller. This controller
- provides DMA capabilities for a variety of on-chip devices.
-
config SIRF_DMA
tristate "CSR SiRFprimaII/SiRFmarco DMA support"
depends on ARCH_SIRF
@@ -539,6 +531,8 @@ config ZX_DMA
# driver files
source "drivers/dma/bestcomm/Kconfig"
+source "drivers/dma/qcom/Kconfig"
+
source "drivers/dma/dw/Kconfig"
source "drivers/dma/hsu/Kconfig"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 2dd0a067a0ca..6084127c1486 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -52,7 +52,6 @@ obj-$(CONFIG_PCH_DMA) += pch_dma.o
obj-$(CONFIG_PL330_DMA) += pl330.o
obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
obj-$(CONFIG_PXA_DMA) += pxa_dma.o
-obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o
obj-$(CONFIG_RENESAS_DMA) += sh/
obj-$(CONFIG_SIRF_DMA) += sirf-dma.o
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
@@ -67,4 +66,5 @@ obj-$(CONFIG_TI_EDMA) += edma.o
obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
obj-$(CONFIG_ZX_DMA) += zx296702_dma.o
+obj-y += qcom/
obj-y += xilinx/
diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c
index eed6bda01790..4a748c3435d7 100644
--- a/drivers/dma/acpi-dma.c
+++ b/drivers/dma/acpi-dma.c
@@ -438,7 +438,7 @@ struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
return ERR_PTR(-ENODEV);
}
- dev_dbg(dev, "found DMA channel \"%s\" at index %d\n", name, index);
+ dev_dbg(dev, "Looking for DMA channel \"%s\" at index %d...\n", name, index);
return acpi_dma_request_slave_chan_by_index(dev, index);
}
EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_name);
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 64f5d1bdbb48..8e304b1befc5 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -176,6 +176,7 @@
#define AT_XDMAC_MAX_CHAN 0x20
#define AT_XDMAC_MAX_CSIZE 16 /* 16 data */
#define AT_XDMAC_MAX_DWIDTH 8 /* 64 bits */
+#define AT_XDMAC_RESIDUE_MAX_RETRIES 5
#define AT_XDMAC_DMA_BUSWIDTHS\
(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
@@ -1395,8 +1396,8 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct at_xdmac_desc *desc, *_desc;
struct list_head *descs_list;
enum dma_status ret;
- int residue;
- u32 cur_nda, mask, value;
+ int residue, retry;
+ u32 cur_nda, check_nda, cur_ubc, mask, value;
u8 dwidth = 0;
unsigned long flags;
@@ -1433,7 +1434,42 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
cpu_relax();
}
+ /*
+ * When processing the residue, we need to read two registers but we
+ * can't do it in an atomic way. AT_XDMAC_CNDA is used to find where
+ * we stand in the descriptor list and AT_XDMAC_CUBC is used
+ * to know how many data are remaining for the current descriptor.
+ * Since the dma channel is not paused to not loose data, between the
+ * AT_XDMAC_CNDA and AT_XDMAC_CUBC read, we may have change of
+ * descriptor.
+ * For that reason, after reading AT_XDMAC_CUBC, we check if we are
+ * still using the same descriptor by reading a second time
+ * AT_XDMAC_CNDA. If AT_XDMAC_CNDA has changed, it means we have to
+ * read again AT_XDMAC_CUBC.
+ * Memory barriers are used to ensure the read order of the registers.
+ * A max number of retries is set because unlikely it can never ends if
+ * we are transferring a lot of data with small buffers.
+ */
cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
+ rmb();
+ cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
+ for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) {
+ rmb();
+ check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
+
+ if (likely(cur_nda == check_nda))
+ break;
+
+ cur_nda = check_nda;
+ rmb();
+ cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
+ }
+
+ if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) {
+ ret = DMA_ERROR;
+ goto spin_unlock;
+ }
+
/*
* Remove size of all microblocks already transferred and the current
* one. Then add the remaining size to transfer of the current
@@ -1446,7 +1482,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda)
break;
}
- residue += at_xdmac_chan_read(atchan, AT_XDMAC_CUBC) << dwidth;
+ residue += cur_ubc << dwidth;
dma_set_residue(txstate, residue);
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index c50a247be2e0..0cb259c59916 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -496,6 +496,7 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
caps->src_addr_widths = device->src_addr_widths;
caps->dst_addr_widths = device->dst_addr_widths;
caps->directions = device->directions;
+ caps->max_burst = device->max_burst;
caps->residue_granularity = device->residue_granularity;
caps->descriptor_reuse = device->descriptor_reuse;
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index e893318560db..5ad0ec1f0e29 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -156,7 +156,6 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
/* Enable interrupts */
channel_set_bit(dw, MASK.XFER, dwc->mask);
- channel_set_bit(dw, MASK.BLOCK, dwc->mask);
channel_set_bit(dw, MASK.ERROR, dwc->mask);
dwc->initialized = true;
@@ -588,6 +587,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
spin_unlock_irqrestore(&dwc->lock, flags);
}
+
+ /* Re-enable interrupts */
+ channel_set_bit(dw, MASK.BLOCK, dwc->mask);
}
/* ------------------------------------------------------------------------- */
@@ -618,11 +620,8 @@ static void dw_dma_tasklet(unsigned long data)
dwc_scan_descriptors(dw, dwc);
}
- /*
- * Re-enable interrupts.
- */
+ /* Re-enable interrupts */
channel_set_bit(dw, MASK.XFER, dw->all_chan_mask);
- channel_set_bit(dw, MASK.BLOCK, dw->all_chan_mask);
channel_set_bit(dw, MASK.ERROR, dw->all_chan_mask);
}
@@ -1261,6 +1260,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
int dw_dma_cyclic_start(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+ struct dw_dma *dw = to_dw_dma(chan->device);
unsigned long flags;
if (!test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) {
@@ -1269,7 +1269,12 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
}
spin_lock_irqsave(&dwc->lock, flags);
+
+ /* Enable interrupts to perform cyclic transfer */
+ channel_set_bit(dw, MASK.BLOCK, dwc->mask);
+
dwc_dostart(dwc, dwc->cdesc->desc[0]);
+
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c
index 4c30fdd092b3..358f9689a3f5 100644
--- a/drivers/dma/dw/pci.c
+++ b/drivers/dma/dw/pci.c
@@ -108,6 +108,10 @@ static const struct pci_device_id dw_pci_id_table[] = {
/* Haswell */
{ PCI_VDEVICE(INTEL, 0x9c60) },
+
+ /* Broadwell */
+ { PCI_VDEVICE(INTEL, 0x9ce0) },
+
{ }
};
MODULE_DEVICE_TABLE(pci, dw_pci_id_table);
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 241ff2b1402b..0a50c18d85b8 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -150,7 +150,7 @@ enum dw_dma_msize {
#define DWC_CTLL_DST_INC (0<<7) /* DAR update/not */
#define DWC_CTLL_DST_DEC (1<<7)
#define DWC_CTLL_DST_FIX (2<<7)
-#define DWC_CTLL_SRC_INC (0<<7) /* SAR update/not */
+#define DWC_CTLL_SRC_INC (0<<9) /* SAR update/not */
#define DWC_CTLL_SRC_DEC (1<<9)
#define DWC_CTLL_SRC_FIX (2<<9)
#define DWC_CTLL_DST_MSIZE(n) ((n)<<11) /* burst, #elements */
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index d92d65549406..ee3463e774f8 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -113,6 +113,9 @@
#define GET_NUM_REGN(x) ((x & 0x300000) >> 20) /* bits 20-21 */
#define CHMAP_EXIST BIT(24)
+/* CCSTAT register */
+#define EDMA_CCSTAT_ACTV BIT(4)
+
/*
* Max of 20 segments per channel to conserve PaRAM slots
* Also note that MAX_NR_SG should be atleast the no.of periods
@@ -866,6 +869,13 @@ static int edma_terminate_all(struct dma_chan *chan)
return 0;
}
+static void edma_synchronize(struct dma_chan *chan)
+{
+ struct edma_chan *echan = to_edma_chan(chan);
+
+ vchan_synchronize(&echan->vchan);
+}
+
static int edma_slave_config(struct dma_chan *chan,
struct dma_slave_config *cfg)
{
@@ -1362,36 +1372,36 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
static void edma_completion_handler(struct edma_chan *echan)
{
struct device *dev = echan->vchan.chan.device->dev;
- struct edma_desc *edesc = echan->edesc;
-
- if (!edesc)
- return;
+ struct edma_desc *edesc;
spin_lock(&echan->vchan.lock);
- if (edesc->cyclic) {
- vchan_cyclic_callback(&edesc->vdesc);
- spin_unlock(&echan->vchan.lock);
- return;
- } else if (edesc->processed == edesc->pset_nr) {
- edesc->residue = 0;
- edma_stop(echan);
- vchan_cookie_complete(&edesc->vdesc);
- echan->edesc = NULL;
-
- dev_dbg(dev, "Transfer completed on channel %d\n",
- echan->ch_num);
- } else {
- dev_dbg(dev, "Sub transfer completed on channel %d\n",
- echan->ch_num);
-
- edma_pause(echan);
-
- /* Update statistics for tx_status */
- edesc->residue -= edesc->sg_len;
- edesc->residue_stat = edesc->residue;
- edesc->processed_stat = edesc->processed;
+ edesc = echan->edesc;
+ if (edesc) {
+ if (edesc->cyclic) {
+ vchan_cyclic_callback(&edesc->vdesc);
+ spin_unlock(&echan->vchan.lock);
+ return;
+ } else if (edesc->processed == edesc->pset_nr) {
+ edesc->residue = 0;
+ edma_stop(echan);
+ vchan_cookie_complete(&edesc->vdesc);
+ echan->edesc = NULL;
+
+ dev_dbg(dev, "Transfer completed on channel %d\n",
+ echan->ch_num);
+ } else {
+ dev_dbg(dev, "Sub transfer completed on channel %d\n",
+ echan->ch_num);
+
+ edma_pause(echan);
+
+ /* Update statistics for tx_status */
+ edesc->residue -= edesc->sg_len;
+ edesc->residue_stat = edesc->residue;
+ edesc->processed_stat = edesc->processed;
+ }
+ edma_execute(echan);
}
- edma_execute(echan);
spin_unlock(&echan->vchan.lock);
}
@@ -1680,9 +1690,20 @@ static void edma_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&echan->vchan.lock, flags);
}
+/*
+ * This limit exists to avoid a possible infinite loop when waiting for proof
+ * that a particular transfer is completed. This limit can be hit if there
+ * are large bursts to/from slow devices or the CPU is never able to catch
+ * the DMA hardware idle. On an AM335x transfering 48 bytes from the UART
+ * RX-FIFO, as many as 55 loops have been seen.
+ */
+#define EDMA_MAX_TR_WAIT_LOOPS 1000
+
static u32 edma_residue(struct edma_desc *edesc)
{
bool dst = edesc->direction == DMA_DEV_TO_MEM;
+ int loop_count = EDMA_MAX_TR_WAIT_LOOPS;
+ struct edma_chan *echan = edesc->echan;
struct edma_pset *pset = edesc->pset;
dma_addr_t done, pos;
int i;
@@ -1691,7 +1712,32 @@ static u32 edma_residue(struct edma_desc *edesc)
* We always read the dst/src position from the first RamPar
* pset. That's the one which is active now.
*/
- pos = edma_get_position(edesc->echan->ecc, edesc->echan->slot[0], dst);
+ pos = edma_get_position(echan->ecc, echan->slot[0], dst);
+
+ /*
+ * "pos" may represent a transfer request that is still being
+ * processed by the EDMACC or EDMATC. We will busy wait until
+ * any one of the situations occurs:
+ * 1. the DMA hardware is idle
+ * 2. a new transfer request is setup
+ * 3. we hit the loop limit
+ */
+ while (edma_read(echan->ecc, EDMA_CCSTAT) & EDMA_CCSTAT_ACTV) {
+ /* check if a new transfer request is setup */
+ if (edma_get_position(echan->ecc,
+ echan->slot[0], dst) != pos) {
+ break;
+ }
+
+ if (!--loop_count) {
+ dev_dbg_ratelimited(echan->vchan.chan.device->dev,
+ "%s: timeout waiting for PaRAM update\n",
+ __func__);
+ break;
+ }
+
+ cpu_relax();
+ }
/*
* Cyclic is simple. Just subtract pset[0].addr from pos.
@@ -1798,6 +1844,7 @@ static void edma_dma_init(struct edma_cc *ecc, bool legacy_mode)
s_ddev->device_pause = edma_dma_pause;
s_ddev->device_resume = edma_dma_resume;
s_ddev->device_terminate_all = edma_terminate_all;
+ s_ddev->device_synchronize = edma_synchronize;
s_ddev->src_addr_widths = EDMA_DMA_BUSWIDTHS;
s_ddev->dst_addr_widths = EDMA_DMA_BUSWIDTHS;
@@ -1823,6 +1870,7 @@ static void edma_dma_init(struct edma_cc *ecc, bool legacy_mode)
m_ddev->device_pause = edma_dma_pause;
m_ddev->device_resume = edma_dma_resume;
m_ddev->device_terminate_all = edma_terminate_all;
+ m_ddev->device_synchronize = edma_synchronize;
m_ddev->src_addr_widths = EDMA_DMA_BUSWIDTHS;
m_ddev->dst_addr_widths = EDMA_DMA_BUSWIDTHS;
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index 57ff46284f15..21f08cc3352b 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -421,23 +421,25 @@ static int m2p_hw_interrupt(struct ep93xx_dma_chan *edmac)
desc->size);
}
- switch (irq_status & (M2P_INTERRUPT_STALL | M2P_INTERRUPT_NFB)) {
- case M2P_INTERRUPT_STALL:
- /* Disable interrupts */
- control = readl(edmac->regs + M2P_CONTROL);
- control &= ~(M2P_CONTROL_STALLINT | M2P_CONTROL_NFBINT);
- m2p_set_control(edmac, control);
-
- return INTERRUPT_DONE;
-
- case M2P_INTERRUPT_NFB:
- if (ep93xx_dma_advance_active(edmac))
- m2p_fill_desc(edmac);
+ /*
+ * Even latest E2 silicon revision sometimes assert STALL interrupt
+ * instead of NFB. Therefore we treat them equally, basing on the
+ * amount of data we still have to transfer.
+ */
+ if (!(irq_status & (M2P_INTERRUPT_STALL | M2P_INTERRUPT_NFB)))
+ return INTERRUPT_UNKNOWN;
+ if (ep93xx_dma_advance_active(edmac)) {
+ m2p_fill_desc(edmac);
return INTERRUPT_NEXT_BUFFER;
}
- return INTERRUPT_UNKNOWN;
+ /* Disable interrupts */
+ control = readl(edmac->regs + M2P_CONTROL);
+ control &= ~(M2P_CONTROL_STALLINT | M2P_CONTROL_NFBINT);
+ m2p_set_control(edmac, control);
+
+ return INTERRUPT_DONE;
}
/*
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 2209f75fdf05..aac85c30c2cf 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -522,6 +522,8 @@ static dma_cookie_t fsldma_run_tx_complete_actions(struct fsldma_chan *chan,
chan_dbg(chan, "LD %p callback\n", desc);
txd->callback(txd->callback_param);
}
+
+ dma_descriptor_unmap(txd);
}
/* Run any dependencies */
diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index 3cb7b2c78197..1953e57505f4 100644
--- a/drivers/dma/idma64.c
+++ b/drivers/dma/idma64.c
@@ -289,6 +289,9 @@ static void idma64_desc_fill(struct idma64_chan *idma64c,
/* Trigger an interrupt after the last block is transfered */
lli->ctllo |= IDMA64C_CTLL_INT_EN;
+
+ /* Disable LLP transfer in the last block */
+ lli->ctllo &= ~(IDMA64C_CTLL_LLP_S_EN | IDMA64C_CTLL_LLP_D_EN);
}
static struct dma_async_tx_descriptor *idma64_prep_slave_sg(
diff --git a/drivers/dma/idma64.h b/drivers/dma/idma64.h
index 8423f13ed0da..dc6874424188 100644
--- a/drivers/dma/idma64.h
+++ b/drivers/dma/idma64.h
@@ -71,7 +71,7 @@
#define IDMA64C_CFGH_SRC_PER(x) ((x) << 0) /* src peripheral */
#define IDMA64C_CFGH_DST_PER(x) ((x) << 4) /* dst peripheral */
#define IDMA64C_CFGH_RD_ISSUE_THD(x) ((x) << 8)
-#define IDMA64C_CFGH_RW_ISSUE_THD(x) ((x) << 18)
+#define IDMA64C_CFGH_WR_ISSUE_THD(x) ((x) << 18)
/* Interrupt registers */
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index 1d5df2ef148b..bd09961443b1 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -31,6 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
#include <linux/prefetch.h>
+#include <linux/sizes.h>
#include "dma.h"
#include "registers.h"
#include "hw.h"
@@ -290,24 +291,30 @@ static dma_cookie_t ioat_tx_submit_unlock(struct dma_async_tx_descriptor *tx)
}
static struct ioat_ring_ent *
-ioat_alloc_ring_ent(struct dma_chan *chan, gfp_t flags)
+ioat_alloc_ring_ent(struct dma_chan *chan, int idx, gfp_t flags)
{
struct ioat_dma_descriptor *hw;
struct ioat_ring_ent *desc;
struct ioatdma_device *ioat_dma;
+ struct ioatdma_chan *ioat_chan = to_ioat_chan(chan);
+ int chunk;
dma_addr_t phys;
+ u8 *pos;
+ off_t offs;
ioat_dma = to_ioatdma_device(chan->device);
- hw = pci_pool_alloc(ioat_dma->dma_pool, flags, &phys);
- if (!hw)
- return NULL;
+
+ chunk = idx / IOAT_DESCS_PER_2M;
+ idx &= (IOAT_DESCS_PER_2M - 1);
+ offs = idx * IOAT_DESC_SZ;
+ pos = (u8 *)ioat_chan->descs[chunk].virt + offs;
+ phys = ioat_chan->descs[chunk].hw + offs;
+ hw = (struct ioat_dma_descriptor *)pos;
memset(hw, 0, sizeof(*hw));
desc = kmem_cache_zalloc(ioat_cache, flags);
- if (!desc) {
- pci_pool_free(ioat_dma->dma_pool, hw, phys);
+ if (!desc)
return NULL;
- }
dma_async_tx_descriptor_init(&desc->txd, chan);
desc->txd.tx_submit = ioat_tx_submit_unlock;
@@ -318,32 +325,63 @@ ioat_alloc_ring_ent(struct dma_chan *chan, gfp_t flags)
void ioat_free_ring_ent(struct ioat_ring_ent *desc, struct dma_chan *chan)
{
- struct ioatdma_device *ioat_dma;
-
- ioat_dma = to_ioatdma_device(chan->device);
- pci_pool_free(ioat_dma->dma_pool, desc->hw, desc->txd.phys);
kmem_cache_free(ioat_cache, desc);
}
struct ioat_ring_ent **
ioat_alloc_ring(struct dma_chan *c, int order, gfp_t flags)
{
+ struct ioatdma_chan *ioat_chan = to_ioat_chan(c);
struct ioat_ring_ent **ring;
- int descs = 1 << order;
- int i;
-
- if (order > ioat_get_max_alloc_order())
- return NULL;
+ int total_descs = 1 << order;
+ int i, chunks;
/* allocate the array to hold the software ring */
- ring = kcalloc(descs, sizeof(*ring), flags);
+ ring = kcalloc(total_descs, sizeof(*ring), flags);
if (!ring)
return NULL;
- for (i = 0; i < descs; i++) {
- ring[i] = ioat_alloc_ring_ent(c, flags);
+
+ ioat_chan->desc_chunks = chunks = (total_descs * IOAT_DESC_SZ) / SZ_2M;
+
+ for (i = 0; i < chunks; i++) {
+ struct ioat_descs *descs = &ioat_chan->descs[i];
+
+ descs->virt = dma_alloc_coherent(to_dev(ioat_chan),
+ SZ_2M, &descs->hw, flags);
+ if (!descs->virt && (i > 0)) {
+ int idx;
+
+ for (idx = 0; idx < i; idx++) {
+ dma_free_coherent(to_dev(ioat_chan), SZ_2M,
+ descs->virt, descs->hw);
+ descs->virt = NULL;
+ descs->hw = 0;
+ }
+
+ ioat_chan->desc_chunks = 0;
+ kfree(ring);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < total_descs; i++) {
+ ring[i] = ioat_alloc_ring_ent(c, i, flags);
if (!ring[i]) {
+ int idx;
+
while (i--)
ioat_free_ring_ent(ring[i], c);
+
+ for (idx = 0; idx < ioat_chan->desc_chunks; idx++) {
+ dma_free_coherent(to_dev(ioat_chan),
+ SZ_2M,
+ ioat_chan->descs[idx].virt,
+ ioat_chan->descs[idx].hw);
+ ioat_chan->descs[idx].virt = NULL;
+ ioat_chan->descs[idx].hw = 0;
+ }
+
+ ioat_chan->desc_chunks = 0;
kfree(ring);
return NULL;
}
@@ -351,7 +389,7 @@ ioat_alloc_ring(struct dma_chan *c, int order, gfp_t flags)
}
/* link descs */
- for (i = 0; i < descs-1; i++) {
+ for (i = 0; i < total_descs-1; i++) {
struct ioat_ring_ent *next = ring[i+1];
struct ioat_dma_descriptor *hw = ring[i]->hw;
@@ -362,114 +400,6 @@ ioat_alloc_ring(struct dma_chan *c, int order, gfp_t flags)
return ring;
}
-static bool reshape_ring(struct ioatdma_chan *ioat_chan, int order)
-{
- /* reshape differs from normal ring allocation in that we want
- * to allocate a new software ring while only
- * extending/truncating the hardware ring
- */
- struct dma_chan *c = &ioat_chan->dma_chan;
- const u32 curr_size = ioat_ring_size(ioat_chan);
- const u16 active = ioat_ring_active(ioat_chan);
- const u32 new_size = 1 << order;
- struct ioat_ring_ent **ring;
- u32 i;
-
- if (order > ioat_get_max_alloc_order())
- return false;
-
- /* double check that we have at least 1 free descriptor */
- if (active == curr_size)
- return false;
-
- /* when shrinking, verify that we can hold the current active
- * set in the new ring
- */
- if (active >= new_size)
- return false;
-
- /* allocate the array to hold the software ring */
- ring = kcalloc(new_size, sizeof(*ring), GFP_NOWAIT);
- if (!ring)
- return false;
-
- /* allocate/trim descriptors as needed */
- if (new_size > curr_size) {
- /* copy current descriptors to the new ring */
- for (i = 0; i < curr_size; i++) {
- u16 curr_idx = (ioat_chan->tail+i) & (curr_size-1);
- u16 new_idx = (ioat_chan->tail+i) & (new_size-1);
-
- ring[new_idx] = ioat_chan->ring[curr_idx];
- set_desc_id(ring[new_idx], new_idx);
- }
-
- /* add new descriptors to the ring */
- for (i = curr_size; i < new_size; i++) {
- u16 new_idx = (ioat_chan->tail+i) & (new_size-1);
-
- ring[new_idx] = ioat_alloc_ring_ent(c, GFP_NOWAIT);
- if (!ring[new_idx]) {
- while (i--) {
- u16 new_idx = (ioat_chan->tail+i) &
- (new_size-1);
-
- ioat_free_ring_ent(ring[new_idx], c);
- }
- kfree(ring);
- return false;
- }
- set_desc_id(ring[new_idx], new_idx);
- }
-
- /* hw link new descriptors */
- for (i = curr_size-1; i < new_size; i++) {
- u16 new_idx = (ioat_chan->tail+i) & (new_size-1);
- struct ioat_ring_ent *next =
- ring[(new_idx+1) & (new_size-1)];
- struct ioat_dma_descriptor *hw = ring[new_idx]->hw;
-
- hw->next = next->txd.phys;
- }
- } else {
- struct ioat_dma_descriptor *hw;
- struct ioat_ring_ent *next;
-
- /* copy current descriptors to the new ring, dropping the
- * removed descriptors
- */
- for (i = 0; i < new_size; i++) {
- u16 curr_idx = (ioat_chan->tail+i) & (curr_size-1);
- u16 new_idx = (ioat_chan->tail+i) & (new_size-1);
-
- ring[new_idx] = ioat_chan->ring[curr_idx];
- set_desc_id(ring[new_idx], new_idx);
- }
-
- /* free deleted descriptors */
- for (i = new_size; i < curr_size; i++) {
- struct ioat_ring_ent *ent;
-
- ent = ioat_get_ring_ent(ioat_chan, ioat_chan->tail+i);
- ioat_free_ring_ent(ent, c);
- }
-
- /* fix up hardware ring */
- hw = ring[(ioat_chan->tail+new_size-1) & (new_size-1)]->hw;
- next = ring[(ioat_chan->tail+new_size) & (new_size-1)];
- hw->next = next->txd.phys;
- }
-
- dev_dbg(to_dev(ioat_chan), "%s: allocated %d descriptors\n",
- __func__, new_size);
-
- kfree(ioat_chan->ring);
- ioat_chan->ring = ring;
- ioat_chan->alloc_order = order;
-
- return true;
-}
-
/**
* ioat_check_space_lock - verify space and grab ring producer lock
* @ioat: ioat,3 channel (ring) to operate on
@@ -478,9 +408,6 @@ static bool reshape_ring(struct ioatdma_chan *ioat_chan, int order)
int ioat_check_space_lock(struct ioatdma_chan *ioat_chan, int num_descs)
__acquires(&ioat_chan->prep_lock)
{
- bool retry;
-
- retry:
spin_lock_bh(&ioat_chan->prep_lock);
/* never allow the last descriptor to be consumed, we need at
* least one free at all times to allow for on-the-fly ring
@@ -493,23 +420,7 @@ int ioat_check_space_lock(struct ioatdma_chan *ioat_chan, int num_descs)
ioat_chan->produce = num_descs;
return 0; /* with ioat->prep_lock held */
}
- retry = test_and_set_bit(IOAT_RESHAPE_PENDING, &ioat_chan->state);
- spin_unlock_bh(&ioat_chan->prep_lock);
-
- /* is another cpu already trying to expand the ring? */
- if (retry)
- goto retry;
-
- spin_lock_bh(&ioat_chan->cleanup_lock);
- spin_lock_bh(&ioat_chan->prep_lock);
- retry = reshape_ring(ioat_chan, ioat_chan->alloc_order + 1);
- clear_bit(IOAT_RESHAPE_PENDING, &ioat_chan->state);
spin_unlock_bh(&ioat_chan->prep_lock);
- spin_unlock_bh(&ioat_chan->cleanup_lock);
-
- /* if we were able to expand the ring retry the allocation */
- if (retry)
- goto retry;
dev_dbg_ratelimited(to_dev(ioat_chan),
"%s: ring full! num_descs: %d (%x:%x:%x)\n",
@@ -823,19 +734,6 @@ static void check_active(struct ioatdma_chan *ioat_chan)
if (test_and_clear_bit(IOAT_CHAN_ACTIVE, &ioat_chan->state))
mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
- else if (ioat_chan->alloc_order > ioat_get_alloc_order()) {
- /* if the ring is idle, empty, and oversized try to step
- * down the size
- */
- reshape_ring(ioat_chan, ioat_chan->alloc_order - 1);
-
- /* keep shrinking until we get back to our minimum
- * default size
- */
- if (ioat_chan->alloc_order > ioat_get_alloc_order())
- mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
- }
-
}
void ioat_timer_event(unsigned long data)
@@ -861,32 +759,42 @@ void ioat_timer_event(unsigned long data)
return;
}
+ spin_lock_bh(&ioat_chan->cleanup_lock);
+
+ /* handle the no-actives case */
+ if (!ioat_ring_active(ioat_chan)) {
+ spin_lock_bh(&ioat_chan->prep_lock);
+ check_active(ioat_chan);
+ spin_unlock_bh(&ioat_chan->prep_lock);
+ spin_unlock_bh(&ioat_chan->cleanup_lock);
+ return;
+ }
+
/* if we haven't made progress and we have already
* acknowledged a pending completion once, then be more
* forceful with a restart
*/
- spin_lock_bh(&ioat_chan->cleanup_lock);
if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
__cleanup(ioat_chan, phys_complete);
else if (test_bit(IOAT_COMPLETION_ACK, &ioat_chan->state)) {
+ u32 chanerr;
+
+ chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
+ dev_warn(to_dev(ioat_chan), "Restarting channel...\n");
+ dev_warn(to_dev(ioat_chan), "CHANSTS: %#Lx CHANERR: %#x\n",
+ status, chanerr);
+ dev_warn(to_dev(ioat_chan), "Active descriptors: %d\n",
+ ioat_ring_active(ioat_chan));
+
spin_lock_bh(&ioat_chan->prep_lock);
ioat_restart_channel(ioat_chan);
spin_unlock_bh(&ioat_chan->prep_lock);
spin_unlock_bh(&ioat_chan->cleanup_lock);
return;
- } else {
+ } else
set_bit(IOAT_COMPLETION_ACK, &ioat_chan->state);
- mod_timer(&ioat_chan->timer, jiffies + COMPLETION_TIMEOUT);
- }
-
- if (ioat_ring_active(ioat_chan))
- mod_timer(&ioat_chan->timer, jiffies + COMPLETION_TIMEOUT);
- else {
- spin_lock_bh(&ioat_chan->prep_lock);
- check_active(ioat_chan);
- spin_unlock_bh(&ioat_chan->prep_lock);
- }
+ mod_timer(&ioat_chan->timer, jiffies + COMPLETION_TIMEOUT);
spin_unlock_bh(&ioat_chan->cleanup_lock);
}
@@ -906,40 +814,6 @@ ioat_tx_status(struct dma_chan *c, dma_cookie_t cookie,
return dma_cookie_status(c, cookie, txstate);
}
-static int ioat_irq_reinit(struct ioatdma_device *ioat_dma)
-{
- struct pci_dev *pdev = ioat_dma->pdev;
- int irq = pdev->irq, i;
-
- if (!is_bwd_ioat(pdev))
- return 0;
-
- switch (ioat_dma->irq_mode) {
- case IOAT_MSIX:
- for (i = 0; i < ioat_dma->dma_dev.chancnt; i++) {
- struct msix_entry *msix = &ioat_dma->msix_entries[i];
- struct ioatdma_chan *ioat_chan;
-
- ioat_chan = ioat_chan_by_index(ioat_dma, i);
- devm_free_irq(&pdev->dev, msix->vector, ioat_chan);
- }
-
- pci_disable_msix(pdev);
- break;
- case IOAT_MSI:
- pci_disable_msi(pdev);
- /* fall through */
- case IOAT_INTX:
- devm_free_irq(&pdev->dev, irq, ioat_dma);
- break;
- default:
- return 0;
- }
- ioat_dma->irq_mode = IOAT_NOIRQ;
-
- return ioat_dma_setup_interrupts(ioat_dma);
-}
-
int ioat_reset_hw(struct ioatdma_chan *ioat_chan)
{
/* throw away whatever the channel was doing and get it
@@ -979,9 +853,21 @@ int ioat_reset_hw(struct ioatdma_chan *ioat_chan)
}
}
+ if (is_bwd_ioat(pdev) && (ioat_dma->irq_mode == IOAT_MSIX)) {
+ ioat_dma->msixtba0 = readq(ioat_dma->reg_base + 0x1000);
+ ioat_dma->msixdata0 = readq(ioat_dma->reg_base + 0x1008);
+ ioat_dma->msixpba = readq(ioat_dma->reg_base + 0x1800);
+ }
+
+
err = ioat_reset_sync(ioat_chan, msecs_to_jiffies(200));
- if (!err)
- err = ioat_irq_reinit(ioat_dma);
+ if (!err) {
+ if (is_bwd_ioat(pdev) && (ioat_dma->irq_mode == IOAT_MSIX)) {
+ writeq(ioat_dma->msixtba0, ioat_dma->reg_base + 0x1000);
+ writeq(ioat_dma->msixdata0, ioat_dma->reg_base + 0x1008);
+ writeq(ioat_dma->msixpba, ioat_dma->reg_base + 0x1800);
+ }
+ }
if (err)
dev_err(&pdev->dev, "Failed to reset: %d\n", err);
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
index b8f48074789f..a9bc1a15b0d1 100644
--- a/drivers/dma/ioat/dma.h
+++ b/drivers/dma/ioat/dma.h
@@ -62,7 +62,6 @@ enum ioat_irq_mode {
* struct ioatdma_device - internal representation of a IOAT device
* @pdev: PCI-Express device
* @reg_base: MMIO register space base address
- * @dma_pool: for allocating DMA descriptors
* @completion_pool: DMA buffers for completion ops
* @sed_hw_pool: DMA super descriptor pools
* @dma_dev: embedded struct dma_device
@@ -76,8 +75,7 @@ enum ioat_irq_mode {
struct ioatdma_device {
struct pci_dev *pdev;
void __iomem *reg_base;
- struct pci_pool *dma_pool;
- struct pci_pool *completion_pool;
+ struct dma_pool *completion_pool;
#define MAX_SED_POOLS 5
struct dma_pool *sed_hw_pool[MAX_SED_POOLS];
struct dma_device dma_dev;
@@ -88,6 +86,16 @@ struct ioatdma_device {
struct dca_provider *dca;
enum ioat_irq_mode irq_mode;
u32 cap;
+
+ /* shadow version for CB3.3 chan reset errata workaround */
+ u64 msixtba0;
+ u64 msixdata0;
+ u32 msixpba;
+};
+
+struct ioat_descs {
+ void *virt;
+ dma_addr_t hw;
};
struct ioatdma_chan {
@@ -100,7 +108,6 @@ struct ioatdma_chan {
#define IOAT_COMPLETION_ACK 1
#define IOAT_RESET_PENDING 2
#define IOAT_KOBJ_INIT_FAIL 3
- #define IOAT_RESHAPE_PENDING 4
#define IOAT_RUN 5
#define IOAT_CHAN_ACTIVE 6
struct timer_list timer;
@@ -133,6 +140,8 @@ struct ioatdma_chan {
u16 produce;
struct ioat_ring_ent **ring;
spinlock_t prep_lock;
+ struct ioat_descs descs[2];
+ int desc_chunks;
};
struct ioat_sysfs_entry {
@@ -302,10 +311,8 @@ static inline bool is_ioat_bug(unsigned long err)
}
#define IOAT_MAX_ORDER 16
-#define ioat_get_alloc_order() \
- (min(ioat_ring_alloc_order, IOAT_MAX_ORDER))
-#define ioat_get_max_alloc_order() \
- (min(ioat_ring_max_alloc_order, IOAT_MAX_ORDER))
+#define IOAT_MAX_DESCS 65536
+#define IOAT_DESCS_PER_2M 32768
static inline u32 ioat_ring_size(struct ioatdma_chan *ioat_chan)
{
diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h
index 690e3b4f8202..8e67895bcca3 100644
--- a/drivers/dma/ioat/hw.h
+++ b/drivers/dma/ioat/hw.h
@@ -73,6 +73,8 @@
int system_has_dca_enabled(struct pci_dev *pdev);
+#define IOAT_DESC_SZ 64
+
struct ioat_dma_descriptor {
uint32_t size;
union {
diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
index 4ef0c5e07912..efdee1a69fc4 100644
--- a/drivers/dma/ioat/init.c
+++ b/drivers/dma/ioat/init.c
@@ -28,6 +28,7 @@
#include <linux/prefetch.h>
#include <linux/dca.h>
#include <linux/aer.h>
+#include <linux/sizes.h>
#include "dma.h"
#include "registers.h"
#include "hw.h"
@@ -136,14 +137,6 @@ int ioat_pending_level = 4;
module_param(ioat_pending_level, int, 0644);
MODULE_PARM_DESC(ioat_pending_level,
"high-water mark for pushing ioat descriptors (default: 4)");
-int ioat_ring_alloc_order = 8;
-module_param(ioat_ring_alloc_order, int, 0644);
-MODULE_PARM_DESC(ioat_ring_alloc_order,
- "ioat+: allocate 2^n descriptors per channel (default: 8 max: 16)");
-int ioat_ring_max_alloc_order = IOAT_MAX_ORDER;
-module_param(ioat_ring_max_alloc_order, int, 0644);
-MODULE_PARM_DESC(ioat_ring_max_alloc_order,
- "ioat+: upper limit for ring size (default: 16)");
static char ioat_interrupt_style[32] = "msix";
module_param_string(ioat_interrupt_style, ioat_interrupt_style,
sizeof(ioat_interrupt_style), 0644);
@@ -504,23 +497,14 @@ static int ioat_probe(struct ioatdma_device *ioat_dma)
struct pci_dev *pdev = ioat_dma->pdev;
struct device *dev = &pdev->dev;
- /* DMA coherent memory pool for DMA descriptor allocations */
- ioat_dma->dma_pool = pci_pool_create("dma_desc_pool", pdev,
- sizeof(struct ioat_dma_descriptor),
- 64, 0);
- if (!ioat_dma->dma_pool) {
- err = -ENOMEM;
- goto err_dma_pool;
- }
-
- ioat_dma->completion_pool = pci_pool_create("completion_pool", pdev,
+ ioat_dma->completion_pool = dma_pool_create("completion_pool", dev,
sizeof(u64),
SMP_CACHE_BYTES,
SMP_CACHE_BYTES);
if (!ioat_dma->completion_pool) {
err = -ENOMEM;
- goto err_completion_pool;
+ goto err_out;
}
ioat_enumerate_channels(ioat_dma);
@@ -546,10 +530,8 @@ static int ioat_probe(struct ioatdma_device *ioat_dma)
err_self_test:
ioat_disable_interrupts(ioat_dma);
err_setup_interrupts:
- pci_pool_destroy(ioat_dma->completion_pool);
-err_completion_pool:
- pci_pool_destroy(ioat_dma->dma_pool);
-err_dma_pool:
+ dma_pool_destroy(ioat_dma->completion_pool);
+err_out:
return err;
}
@@ -559,8 +541,7 @@ static int ioat_register(struct ioatdma_device *ioat_dma)
if (err) {
ioat_disable_interrupts(ioat_dma);
- pci_pool_destroy(ioat_dma->completion_pool);
- pci_pool_destroy(ioat_dma->dma_pool);
+ dma_pool_destroy(ioat_dma->completion_pool);
}
return err;
@@ -576,8 +557,7 @@ static void ioat_dma_remove(struct ioatdma_device *ioat_dma)
dma_async_device_unregister(dma);
- pci_pool_destroy(ioat_dma->dma_pool);
- pci_pool_destroy(ioat_dma->completion_pool);
+ dma_pool_destroy(ioat_dma->completion_pool);
INIT_LIST_HEAD(&dma->channels);
}
@@ -666,10 +646,19 @@ static void ioat_free_chan_resources(struct dma_chan *c)
ioat_free_ring_ent(desc, c);
}
+ for (i = 0; i < ioat_chan->desc_chunks; i++) {
+ dma_free_coherent(to_dev(ioat_chan), SZ_2M,
+ ioat_chan->descs[i].virt,
+ ioat_chan->descs[i].hw);
+ ioat_chan->descs[i].virt = NULL;
+ ioat_chan->descs[i].hw = 0;
+ }
+ ioat_chan->desc_chunks = 0;
+
kfree(ioat_chan->ring);
ioat_chan->ring = NULL;
ioat_chan->alloc_order = 0;
- pci_pool_free(ioat_dma->completion_pool, ioat_chan->completion,
+ dma_pool_free(ioat_dma->completion_pool, ioat_chan->completion,
ioat_chan->completion_dma);
spin_unlock_bh(&ioat_chan->prep_lock);
spin_unlock_bh(&ioat_chan->cleanup_lock);
@@ -701,7 +690,7 @@ static int ioat_alloc_chan_resources(struct dma_chan *c)
/* allocate a completion writeback area */
/* doing 2 32bit writes to mmio since 1 64b write doesn't work */
ioat_chan->completion =
- pci_pool_alloc(ioat_chan->ioat_dma->completion_pool,
+ dma_pool_alloc(ioat_chan->ioat_dma->completion_pool,
GFP_KERNEL, &ioat_chan->completion_dma);
if (!ioat_chan->completion)
return -ENOMEM;
@@ -712,7 +701,7 @@ static int ioat_alloc_chan_resources(struct dma_chan *c)
writel(((u64)ioat_chan->completion_dma) >> 32,
ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
- order = ioat_get_alloc_order();
+ order = IOAT_MAX_ORDER;
ring = ioat_alloc_ring(c, order, GFP_KERNEL);
if (!ring)
return -ENOMEM;
diff --git a/drivers/dma/ioat/prep.c b/drivers/dma/ioat/prep.c
index 6bb4a13a8fbd..243421af888f 100644
--- a/drivers/dma/ioat/prep.c
+++ b/drivers/dma/ioat/prep.c
@@ -26,7 +26,7 @@
#include "hw.h"
#include "dma.h"
-#define MAX_SCF 1024
+#define MAX_SCF 256
/* provide a lookup table for setting the source address in the base or
* extended descriptor of an xor or pq descriptor
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index e4f43125e0fb..f039cfadf17b 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -1300,10 +1300,10 @@ static int iop_adma_probe(struct platform_device *pdev)
* note: writecombine gives slightly better performance, but
* requires that we explicitly flush the writes
*/
- adev->dma_desc_pool_virt = dma_alloc_writecombine(&pdev->dev,
- plat_data->pool_size,
- &adev->dma_desc_pool,
- GFP_KERNEL);
+ adev->dma_desc_pool_virt = dma_alloc_wc(&pdev->dev,
+ plat_data->pool_size,
+ &adev->dma_desc_pool,
+ GFP_KERNEL);
if (!adev->dma_desc_pool_virt) {
ret = -ENOMEM;
goto err_free_adev;
diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c
index 068e920ecb68..1502b24b7c7d 100644
--- a/drivers/dma/mic_x100_dma.c
+++ b/drivers/dma/mic_x100_dma.c
@@ -483,7 +483,7 @@ static int mic_dma_setup_irq(struct mic_dma_chan *ch)
mic_dma_intr_handler, mic_dma_thread_fn,
"mic dma_channel", ch, ch->ch_num);
if (IS_ERR(ch->cookie))
- return IS_ERR(ch->cookie);
+ return PTR_ERR(ch->cookie);
return 0;
}
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 14091f878f80..3922a5d56806 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -964,8 +964,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
* requires that we explicitly flush the writes
*/
mv_chan->dma_desc_pool_virt =
- dma_alloc_writecombine(&pdev->dev, MV_XOR_POOL_SIZE,
- &mv_chan->dma_desc_pool, GFP_KERNEL);
+ dma_alloc_wc(&pdev->dev, MV_XOR_POOL_SIZE, &mv_chan->dma_desc_pool,
+ GFP_KERNEL);
if (!mv_chan->dma_desc_pool_virt)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index 9794b073d7d7..43bd5aee7ffe 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -1009,6 +1009,13 @@ static int omap_dma_terminate_all(struct dma_chan *chan)
return 0;
}
+static void omap_dma_synchronize(struct dma_chan *chan)
+{
+ struct omap_chan *c = to_omap_dma_chan(chan);
+
+ vchan_synchronize(&c->vc);
+}
+
static int omap_dma_pause(struct dma_chan *chan)
{
struct omap_chan *c = to_omap_dma_chan(chan);
@@ -1112,6 +1119,7 @@ static int omap_dma_probe(struct platform_device *pdev)
od->ddev.device_pause = omap_dma_pause;
od->ddev.device_resume = omap_dma_resume;
od->ddev.device_terminate_all = omap_dma_terminate_all;
+ od->ddev.device_synchronize = omap_dma_synchronize;
od->ddev.src_addr_widths = OMAP_DMA_BUSWIDTHS;
od->ddev.dst_addr_widths = OMAP_DMA_BUSWIDTHS;
od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 17ee758b419f..372b4359da97 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -33,6 +33,9 @@
#define PL330_MAX_CHAN 8
#define PL330_MAX_IRQS 32
#define PL330_MAX_PERI 32
+#define PL330_MAX_BURST 16
+
+#define PL330_QUIRK_BROKEN_NO_FLUSHP BIT(0)
enum pl330_cachectrl {
CCTRL0, /* Noncacheable and nonbufferable */
@@ -488,6 +491,17 @@ struct pl330_dmac {
/* Peripheral channels connected to this DMAC */
unsigned int num_peripherals;
struct dma_pl330_chan *peripherals; /* keep at end */
+ int quirks;
+};
+
+static struct pl330_of_quirks {
+ char *quirk;
+ int id;
+} of_quirks[] = {
+ {
+ .quirk = "arm,pl330-broken-no-flushp",
+ .id = PL330_QUIRK_BROKEN_NO_FLUSHP,
+ }
};
struct dma_pl330_desc {
@@ -1137,47 +1151,67 @@ static inline int _ldst_memtomem(unsigned dry_run, u8 buf[],
return off;
}
-static inline int _ldst_devtomem(unsigned dry_run, u8 buf[],
- const struct _xfer_spec *pxs, int cyc)
+static inline int _ldst_devtomem(struct pl330_dmac *pl330, unsigned dry_run,
+ u8 buf[], const struct _xfer_spec *pxs,
+ int cyc)
{
int off = 0;
+ enum pl330_cond cond;
+
+ if (pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP)
+ cond = BURST;
+ else
+ cond = SINGLE;
while (cyc--) {
- off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->desc->peri);
- off += _emit_LDP(dry_run, &buf[off], SINGLE, pxs->desc->peri);
+ off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
+ off += _emit_LDP(dry_run, &buf[off], cond, pxs->desc->peri);
off += _emit_ST(dry_run, &buf[off], ALWAYS);
- off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri);
+
+ if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
+ off += _emit_FLUSHP(dry_run, &buf[off],
+ pxs->desc->peri);
}
return off;
}
-static inline int _ldst_memtodev(unsigned dry_run, u8 buf[],
- const struct _xfer_spec *pxs, int cyc)
+static inline int _ldst_memtodev(struct pl330_dmac *pl330,
+ unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs, int cyc)
{
int off = 0;
+ enum pl330_cond cond;
+
+ if (pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP)
+ cond = BURST;
+ else
+ cond = SINGLE;
while (cyc--) {
- off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->desc->peri);
+ off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
off += _emit_LD(dry_run, &buf[off], ALWAYS);
- off += _emit_STP(dry_run, &buf[off], SINGLE, pxs->desc->peri);
- off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri);
+ off += _emit_STP(dry_run, &buf[off], cond, pxs->desc->peri);
+
+ if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
+ off += _emit_FLUSHP(dry_run, &buf[off],
+ pxs->desc->peri);
}
return off;
}
-static int _bursts(unsigned dry_run, u8 buf[],
+static int _bursts(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[],
const struct _xfer_spec *pxs, int cyc)
{
int off = 0;
switch (pxs->desc->rqtype) {
case DMA_MEM_TO_DEV:
- off += _ldst_memtodev(dry_run, &buf[off], pxs, cyc);
+ off += _ldst_memtodev(pl330, dry_run, &buf[off], pxs, cyc);
break;
case DMA_DEV_TO_MEM:
- off += _ldst_devtomem(dry_run, &buf[off], pxs, cyc);
+ off += _ldst_devtomem(pl330, dry_run, &buf[off], pxs, cyc);
break;
case DMA_MEM_TO_MEM:
off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc);
@@ -1191,7 +1225,7 @@ static int _bursts(unsigned dry_run, u8 buf[],
}
/* Returns bytes consumed and updates bursts */
-static inline int _loop(unsigned dry_run, u8 buf[],
+static inline int _loop(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[],
unsigned long *bursts, const struct _xfer_spec *pxs)
{
int cyc, cycmax, szlp, szlpend, szbrst, off;
@@ -1199,7 +1233,7 @@ static inline int _loop(unsigned dry_run, u8 buf[],
struct _arg_LPEND lpend;
if (*bursts == 1)
- return _bursts(dry_run, buf, pxs, 1);
+ return _bursts(pl330, dry_run, buf, pxs, 1);
/* Max iterations possible in DMALP is 256 */
if (*bursts >= 256*256) {
@@ -1217,7 +1251,7 @@ static inline int _loop(unsigned dry_run, u8 buf[],
}
szlp = _emit_LP(1, buf, 0, 0);
- szbrst = _bursts(1, buf, pxs, 1);
+ szbrst = _bursts(pl330, 1, buf, pxs, 1);
lpend.cond = ALWAYS;
lpend.forever = false;
@@ -1249,7 +1283,7 @@ static inline int _loop(unsigned dry_run, u8 buf[],
off += _emit_LP(dry_run, &buf[off], 1, lcnt1);
ljmp1 = off;
- off += _bursts(dry_run, &buf[off], pxs, cyc);
+ off += _bursts(pl330, dry_run, &buf[off], pxs, cyc);
lpend.cond = ALWAYS;
lpend.forever = false;
@@ -1272,8 +1306,9 @@ static inline int _loop(unsigned dry_run, u8 buf[],
return off;
}
-static inline int _setup_loops(unsigned dry_run, u8 buf[],
- const struct _xfer_spec *pxs)
+static inline int _setup_loops(struct pl330_dmac *pl330,
+ unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs)
{
struct pl330_xfer *x = &pxs->desc->px;
u32 ccr = pxs->ccr;
@@ -1282,15 +1317,16 @@ static inline int _setup_loops(unsigned dry_run, u8 buf[],
while (bursts) {
c = bursts;
- off += _loop(dry_run, &buf[off], &c, pxs);
+ off += _loop(pl330, dry_run, &buf[off], &c, pxs);
bursts -= c;
}
return off;
}
-static inline int _setup_xfer(unsigned dry_run, u8 buf[],
- const struct _xfer_spec *pxs)
+static inline int _setup_xfer(struct pl330_dmac *pl330,
+ unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs)
{
struct pl330_xfer *x = &pxs->desc->px;
int off = 0;
@@ -1301,7 +1337,7 @@ static inline int _setup_xfer(unsigned dry_run, u8 buf[],
off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr);
/* Setup Loop(s) */
- off += _setup_loops(dry_run, &buf[off], pxs);
+ off += _setup_loops(pl330, dry_run, &buf[off], pxs);
return off;
}
@@ -1310,8 +1346,9 @@ static inline int _setup_xfer(unsigned dry_run, u8 buf[],
* A req is a sequence of one or more xfer units.
* Returns the number of bytes taken to setup the MC for the req.
*/
-static int _setup_req(unsigned dry_run, struct pl330_thread *thrd,
- unsigned index, struct _xfer_spec *pxs)
+static int _setup_req(struct pl330_dmac *pl330, unsigned dry_run,
+ struct pl330_thread *thrd, unsigned index,
+ struct _xfer_spec *pxs)
{
struct _pl330_req *req = &thrd->req[index];
struct pl330_xfer *x;
@@ -1328,7 +1365,7 @@ static int _setup_req(unsigned dry_run, struct pl330_thread *thrd,
if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr)))
return -EINVAL;
- off += _setup_xfer(dry_run, &buf[off], pxs);
+ off += _setup_xfer(pl330, dry_run, &buf[off], pxs);
/* DMASEV peripheral/event */
off += _emit_SEV(dry_run, &buf[off], thrd->ev);
@@ -1422,7 +1459,7 @@ static int pl330_submit_req(struct pl330_thread *thrd,
xs.desc = desc;
/* First dry run to check if req is acceptable */
- ret = _setup_req(1, thrd, idx, &xs);
+ ret = _setup_req(pl330, 1, thrd, idx, &xs);
if (ret < 0)
goto xfer_exit;
@@ -1436,7 +1473,7 @@ static int pl330_submit_req(struct pl330_thread *thrd,
/* Hook the request */
thrd->lstenq = idx;
thrd->req[idx].desc = desc;
- _setup_req(0, thrd, idx, &xs);
+ _setup_req(pl330, 0, thrd, idx, &xs);
ret = 0;
@@ -2781,6 +2818,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
struct resource *res;
int i, ret, irq;
int num_chan;
+ struct device_node *np = adev->dev.of_node;
pdat = dev_get_platdata(&adev->dev);
@@ -2800,6 +2838,11 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
pl330->mcbufsz = pdat ? pdat->mcbuf_sz : 0;
+ /* get quirk */
+ for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
+ if (of_property_read_bool(np, of_quirks[i].quirk))
+ pl330->quirks |= of_quirks[i].id;
+
res = &adev->res;
pl330->base = devm_ioremap_resource(&adev->dev, res);
if (IS_ERR(pl330->base))
@@ -2895,6 +2938,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
pd->dst_addr_widths = PL330_DMA_BUSWIDTHS;
pd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
pd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+ pd->max_burst = ((pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) ?
+ 1 : PL330_MAX_BURST);
ret = dma_async_device_register(pd);
if (ret) {
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index f2a0310ae771..debca824bed6 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -583,6 +583,8 @@ static void set_updater_desc(struct pxad_desc_sw *sw_desc,
(PXA_DCMD_LENGTH & sizeof(u32));
if (flags & DMA_PREP_INTERRUPT)
updater->dcmd |= PXA_DCMD_ENDIRQEN;
+ if (sw_desc->cyclic)
+ sw_desc->hw_desc[sw_desc->nb_desc - 2]->ddadr = sw_desc->first;
}
static bool is_desc_completed(struct virt_dma_desc *vd)
@@ -673,6 +675,10 @@ static irqreturn_t pxad_chan_handler(int irq, void *dev_id)
dev_dbg(&chan->vc.chan.dev->device,
"%s(): checking txd %p[%x]: completed=%d\n",
__func__, vd, vd->tx.cookie, is_desc_completed(vd));
+ if (to_pxad_sw_desc(vd)->cyclic) {
+ vchan_cyclic_callback(vd);
+ break;
+ }
if (is_desc_completed(vd)) {
list_del(&vd->node);
vchan_cookie_complete(vd);
@@ -1080,7 +1086,7 @@ pxad_prep_dma_cyclic(struct dma_chan *dchan,
return NULL;
pxad_get_config(chan, dir, &dcmd, &dsadr, &dtadr);
- dcmd |= PXA_DCMD_ENDIRQEN | (PXA_DCMD_LENGTH | period_len);
+ dcmd |= PXA_DCMD_ENDIRQEN | (PXA_DCMD_LENGTH & period_len);
dev_dbg(&chan->vc.chan.dev->device,
"%s(): buf_addr=0x%lx len=%zu period=%zu dir=%d flags=%lx\n",
__func__, (unsigned long)buf_addr, len, period_len, dir, flags);
diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig
new file mode 100644
index 000000000000..a7761c4025f4
--- /dev/null
+++ b/drivers/dma/qcom/Kconfig
@@ -0,0 +1,29 @@
+config QCOM_BAM_DMA
+ tristate "QCOM BAM DMA support"
+ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ ---help---
+ Enable support for the QCOM BAM DMA controller. This controller
+ provides DMA capabilities for a variety of on-chip devices.
+
+config QCOM_HIDMA_MGMT
+ tristate "Qualcomm Technologies HIDMA Management support"
+ select DMA_ENGINE
+ help
+ Enable support for the Qualcomm Technologies HIDMA Management.
+ Each DMA device requires one management interface driver
+ for basic initialization before QCOM_HIDMA channel driver can
+ start managing the channels. In a virtualized environment,
+ the guest OS would run QCOM_HIDMA channel driver and the
+ host would run the QCOM_HIDMA_MGMT management driver.
+
+config QCOM_HIDMA
+ tristate "Qualcomm Technologies HIDMA Channel support"
+ select DMA_ENGINE
+ help
+ Enable support for the Qualcomm Technologies HIDMA controller.
+ The HIDMA controller supports optimized buffer copies
+ (user to kernel, kernel to kernel, etc.). It only supports
+ memcpy interface. The core is not intended for general
+ purpose slave DMA.
diff --git a/drivers/dma/qcom/Makefile b/drivers/dma/qcom/Makefile
new file mode 100644
index 000000000000..bfea6990229f
--- /dev/null
+++ b/drivers/dma/qcom/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o
+obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o
+hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o
diff --git a/drivers/dma/qcom_bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 5a250cdc8376..d5e0a9c3ad5d 100644
--- a/drivers/dma/qcom_bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -49,13 +49,13 @@
#include <linux/clk.h>
#include <linux/dmaengine.h>
-#include "dmaengine.h"
-#include "virt-dma.h"
+#include "../dmaengine.h"
+#include "../virt-dma.h"
struct bam_desc_hw {
- u32 addr; /* Buffer physical address */
- u16 size; /* Buffer size in bytes */
- u16 flags;
+ __le32 addr; /* Buffer physical address */
+ __le16 size; /* Buffer size in bytes */
+ __le16 flags;
};
#define DESC_FLAG_INT BIT(15)
@@ -502,8 +502,8 @@ static int bam_alloc_chan(struct dma_chan *chan)
return 0;
/* allocate FIFO descriptor space, but only if necessary */
- bchan->fifo_virt = dma_alloc_writecombine(bdev->dev, BAM_DESC_FIFO_SIZE,
- &bchan->fifo_phys, GFP_KERNEL);
+ bchan->fifo_virt = dma_alloc_wc(bdev->dev, BAM_DESC_FIFO_SIZE,
+ &bchan->fifo_phys, GFP_KERNEL);
if (!bchan->fifo_virt) {
dev_err(bdev->dev, "Failed to allocate desc fifo\n");
@@ -538,8 +538,8 @@ static void bam_free_chan(struct dma_chan *chan)
bam_reset_channel(bchan);
spin_unlock_irqrestore(&bchan->vc.lock, flags);
- dma_free_writecombine(bdev->dev, BAM_DESC_FIFO_SIZE, bchan->fifo_virt,
- bchan->fifo_phys);
+ dma_free_wc(bdev->dev, BAM_DESC_FIFO_SIZE, bchan->fifo_virt,
+ bchan->fifo_phys);
bchan->fifo_virt = NULL;
/* mask irq for pipe/channel */
@@ -632,14 +632,15 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
unsigned int curr_offset = 0;
do {
- desc->addr = sg_dma_address(sg) + curr_offset;
+ desc->addr = cpu_to_le32(sg_dma_address(sg) +
+ curr_offset);
if (remainder > BAM_MAX_DATA_SIZE) {
- desc->size = BAM_MAX_DATA_SIZE;
+ desc->size = cpu_to_le16(BAM_MAX_DATA_SIZE);
remainder -= BAM_MAX_DATA_SIZE;
curr_offset += BAM_MAX_DATA_SIZE;
} else {
- desc->size = remainder;
+ desc->size = cpu_to_le16(remainder);
remainder = 0;
}
@@ -915,9 +916,11 @@ static void bam_start_dma(struct bam_chan *bchan)
/* set any special flags on the last descriptor */
if (async_desc->num_desc == async_desc->xfer_len)
- desc[async_desc->xfer_len - 1].flags = async_desc->flags;
+ desc[async_desc->xfer_len - 1].flags =
+ cpu_to_le16(async_desc->flags);
else
- desc[async_desc->xfer_len - 1].flags |= DESC_FLAG_INT;
+ desc[async_desc->xfer_len - 1].flags |=
+ cpu_to_le16(DESC_FLAG_INT);
if (bchan->tail + async_desc->xfer_len > MAX_DESCRIPTORS) {
u32 partial = MAX_DESCRIPTORS - bchan->tail;
@@ -1231,9 +1234,9 @@ static int bam_dma_remove(struct platform_device *pdev)
bam_dma_terminate_all(&bdev->channels[i].vc.chan);
tasklet_kill(&bdev->channels[i].vc.task);
- dma_free_writecombine(bdev->dev, BAM_DESC_FIFO_SIZE,
- bdev->channels[i].fifo_virt,
- bdev->channels[i].fifo_phys);
+ dma_free_wc(bdev->dev, BAM_DESC_FIFO_SIZE,
+ bdev->channels[i].fifo_virt,
+ bdev->channels[i].fifo_phys);
}
tasklet_kill(&bdev->task);
diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c
new file mode 100644
index 000000000000..cccc78efbca9
--- /dev/null
+++ b/drivers/dma/qcom/hidma.c
@@ -0,0 +1,706 @@
+/*
+ * Qualcomm Technologies HIDMA DMA engine interface
+ *
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
+ * Copyright (C) Semihalf 2009
+ * Copyright (C) Ilya Yanok, Emcraft Systems 2010
+ * Copyright (C) Alexander Popov, Promcontroller 2014
+ *
+ * Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
+ * (defines, structures and comments) was taken from MPC5121 DMA driver
+ * written by Hongjun Chen <hong-jun.chen@freescale.com>.
+ *
+ * Approved as OSADL project by a majority of OSADL members and funded
+ * by OSADL membership fees in 2009; for details see www.osadl.org.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
+/* Linux Foundation elects GPLv2 license only. */
+
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of_dma.h>
+#include <linux/property.h>
+#include <linux/delay.h>
+#include <linux/acpi.h>
+#include <linux/irq.h>
+#include <linux/atomic.h>
+#include <linux/pm_runtime.h>
+
+#include "../dmaengine.h"
+#include "hidma.h"
+
+/*
+ * Default idle time is 2 seconds. This parameter can
+ * be overridden by changing the following
+ * /sys/bus/platform/devices/QCOM8061:<xy>/power/autosuspend_delay_ms
+ * during kernel boot.
+ */
+#define HIDMA_AUTOSUSPEND_TIMEOUT 2000
+#define HIDMA_ERR_INFO_SW 0xFF
+#define HIDMA_ERR_CODE_UNEXPECTED_TERMINATE 0x0
+#define HIDMA_NR_DEFAULT_DESC 10
+
+static inline struct hidma_dev *to_hidma_dev(struct dma_device *dmadev)
+{
+ return container_of(dmadev, struct hidma_dev, ddev);
+}
+
+static inline
+struct hidma_dev *to_hidma_dev_from_lldev(struct hidma_lldev **_lldevp)
+{
+ return container_of(_lldevp, struct hidma_dev, lldev);
+}
+
+static inline struct hidma_chan *to_hidma_chan(struct dma_chan *dmach)
+{
+ return container_of(dmach, struct hidma_chan, chan);
+}
+
+static inline
+struct hidma_desc *to_hidma_desc(struct dma_async_tx_descriptor *t)
+{
+ return container_of(t, struct hidma_desc, desc);
+}
+
+static void hidma_free(struct hidma_dev *dmadev)
+{
+ INIT_LIST_HEAD(&dmadev->ddev.channels);
+}
+
+static unsigned int nr_desc_prm;
+module_param(nr_desc_prm, uint, 0644);
+MODULE_PARM_DESC(nr_desc_prm, "number of descriptors (default: 0)");
+
+
+/* process completed descriptors */
+static void hidma_process_completed(struct hidma_chan *mchan)
+{
+ struct dma_device *ddev = mchan->chan.device;
+ struct hidma_dev *mdma = to_hidma_dev(ddev);
+ struct dma_async_tx_descriptor *desc;
+ dma_cookie_t last_cookie;
+ struct hidma_desc *mdesc;
+ unsigned long irqflags;
+ struct list_head list;
+
+ INIT_LIST_HEAD(&list);
+
+ /* Get all completed descriptors */
+ spin_lock_irqsave(&mchan->lock, irqflags);
+ list_splice_tail_init(&mchan->completed, &list);
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+ /* Execute callbacks and run dependencies */
+ list_for_each_entry(mdesc, &list, node) {
+ enum dma_status llstat;
+
+ desc = &mdesc->desc;
+
+ spin_lock_irqsave(&mchan->lock, irqflags);
+ dma_cookie_complete(desc);
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+ llstat = hidma_ll_status(mdma->lldev, mdesc->tre_ch);
+ if (desc->callback && (llstat == DMA_COMPLETE))
+ desc->callback(desc->callback_param);
+
+ last_cookie = desc->cookie;
+ dma_run_dependencies(desc);
+ }
+
+ /* Free descriptors */
+ spin_lock_irqsave(&mchan->lock, irqflags);
+ list_splice_tail_init(&list, &mchan->free);
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+}
+
+/*
+ * Called once for each submitted descriptor.
+ * PM is locked once for each descriptor that is currently
+ * in execution.
+ */
+static void hidma_callback(void *data)
+{
+ struct hidma_desc *mdesc = data;
+ struct hidma_chan *mchan = to_hidma_chan(mdesc->desc.chan);
+ struct dma_device *ddev = mchan->chan.device;
+ struct hidma_dev *dmadev = to_hidma_dev(ddev);
+ unsigned long irqflags;
+ bool queued = false;
+
+ spin_lock_irqsave(&mchan->lock, irqflags);
+ if (mdesc->node.next) {
+ /* Delete from the active list, add to completed list */
+ list_move_tail(&mdesc->node, &mchan->completed);
+ queued = true;
+
+ /* calculate the next running descriptor */
+ mchan->running = list_first_entry(&mchan->active,
+ struct hidma_desc, node);
+ }
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+ hidma_process_completed(mchan);
+
+ if (queued) {
+ pm_runtime_mark_last_busy(dmadev->ddev.dev);
+ pm_runtime_put_autosuspend(dmadev->ddev.dev);
+ }
+}
+
+static int hidma_chan_init(struct hidma_dev *dmadev, u32 dma_sig)
+{
+ struct hidma_chan *mchan;
+ struct dma_device *ddev;
+
+ mchan = devm_kzalloc(dmadev->ddev.dev, sizeof(*mchan), GFP_KERNEL);
+ if (!mchan)
+ return -ENOMEM;
+
+ ddev = &dmadev->ddev;
+ mchan->dma_sig = dma_sig;
+ mchan->dmadev = dmadev;
+ mchan->chan.device = ddev;
+ dma_cookie_init(&mchan->chan);
+
+ INIT_LIST_HEAD(&mchan->free);
+ INIT_LIST_HEAD(&mchan->prepared);
+ INIT_LIST_HEAD(&mchan->active);
+ INIT_LIST_HEAD(&mchan->completed);
+
+ spin_lock_init(&mchan->lock);
+ list_add_tail(&mchan->chan.device_node, &ddev->channels);
+ dmadev->ddev.chancnt++;
+ return 0;
+}
+
+static void hidma_issue_task(unsigned long arg)
+{
+ struct hidma_dev *dmadev = (struct hidma_dev *)arg;
+
+ pm_runtime_get_sync(dmadev->ddev.dev);
+ hidma_ll_start(dmadev->lldev);
+}
+
+static void hidma_issue_pending(struct dma_chan *dmach)
+{
+ struct hidma_chan *mchan = to_hidma_chan(dmach);
+ struct hidma_dev *dmadev = mchan->dmadev;
+ unsigned long flags;
+ int status;
+
+ spin_lock_irqsave(&mchan->lock, flags);
+ if (!mchan->running) {
+ struct hidma_desc *desc = list_first_entry(&mchan->active,
+ struct hidma_desc,
+ node);
+ mchan->running = desc;
+ }
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ /* PM will be released in hidma_callback function. */
+ status = pm_runtime_get(dmadev->ddev.dev);
+ if (status < 0)
+ tasklet_schedule(&dmadev->task);
+ else
+ hidma_ll_start(dmadev->lldev);
+}
+
+static enum dma_status hidma_tx_status(struct dma_chan *dmach,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct hidma_chan *mchan = to_hidma_chan(dmach);
+ enum dma_status ret;
+
+ ret = dma_cookie_status(dmach, cookie, txstate);
+ if (ret == DMA_COMPLETE)
+ return ret;
+
+ if (mchan->paused && (ret == DMA_IN_PROGRESS)) {
+ unsigned long flags;
+ dma_cookie_t runcookie;
+
+ spin_lock_irqsave(&mchan->lock, flags);
+ if (mchan->running)
+ runcookie = mchan->running->desc.cookie;
+ else
+ runcookie = -EINVAL;
+
+ if (runcookie == cookie)
+ ret = DMA_PAUSED;
+
+ spin_unlock_irqrestore(&mchan->lock, flags);
+ }
+
+ return ret;
+}
+
+/*
+ * Submit descriptor to hardware.
+ * Lock the PM for each descriptor we are sending.
+ */
+static dma_cookie_t hidma_tx_submit(struct dma_async_tx_descriptor *txd)
+{
+ struct hidma_chan *mchan = to_hidma_chan(txd->chan);
+ struct hidma_dev *dmadev = mchan->dmadev;
+ struct hidma_desc *mdesc;
+ unsigned long irqflags;
+ dma_cookie_t cookie;
+
+ pm_runtime_get_sync(dmadev->ddev.dev);
+ if (!hidma_ll_isenabled(dmadev->lldev)) {
+ pm_runtime_mark_last_busy(dmadev->ddev.dev);
+ pm_runtime_put_autosuspend(dmadev->ddev.dev);
+ return -ENODEV;
+ }
+
+ mdesc = container_of(txd, struct hidma_desc, desc);
+ spin_lock_irqsave(&mchan->lock, irqflags);
+
+ /* Move descriptor to active */
+ list_move_tail(&mdesc->node, &mchan->active);
+
+ /* Update cookie */
+ cookie = dma_cookie_assign(txd);
+
+ hidma_ll_queue_request(dmadev->lldev, mdesc->tre_ch);
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+ return cookie;
+}
+
+static int hidma_alloc_chan_resources(struct dma_chan *dmach)
+{
+ struct hidma_chan *mchan = to_hidma_chan(dmach);
+ struct hidma_dev *dmadev = mchan->dmadev;
+ struct hidma_desc *mdesc, *tmp;
+ unsigned long irqflags;
+ LIST_HEAD(descs);
+ unsigned int i;
+ int rc = 0;
+
+ if (mchan->allocated)
+ return 0;
+
+ /* Alloc descriptors for this channel */
+ for (i = 0; i < dmadev->nr_descriptors; i++) {
+ mdesc = kzalloc(sizeof(struct hidma_desc), GFP_NOWAIT);
+ if (!mdesc) {
+ rc = -ENOMEM;
+ break;
+ }
+ dma_async_tx_descriptor_init(&mdesc->desc, dmach);
+ mdesc->desc.tx_submit = hidma_tx_submit;
+
+ rc = hidma_ll_request(dmadev->lldev, mchan->dma_sig,
+ "DMA engine", hidma_callback, mdesc,
+ &mdesc->tre_ch);
+ if (rc) {
+ dev_err(dmach->device->dev,
+ "channel alloc failed at %u\n", i);
+ kfree(mdesc);
+ break;
+ }
+ list_add_tail(&mdesc->node, &descs);
+ }
+
+ if (rc) {
+ /* return the allocated descriptors */
+ list_for_each_entry_safe(mdesc, tmp, &descs, node) {
+ hidma_ll_free(dmadev->lldev, mdesc->tre_ch);
+ kfree(mdesc);
+ }
+ return rc;
+ }
+
+ spin_lock_irqsave(&mchan->lock, irqflags);
+ list_splice_tail_init(&descs, &mchan->free);
+ mchan->allocated = true;
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+ return 1;
+}
+
+static struct dma_async_tx_descriptor *
+hidma_prep_dma_memcpy(struct dma_chan *dmach, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct hidma_chan *mchan = to_hidma_chan(dmach);
+ struct hidma_desc *mdesc = NULL;
+ struct hidma_dev *mdma = mchan->dmadev;
+ unsigned long irqflags;
+
+ /* Get free descriptor */
+ spin_lock_irqsave(&mchan->lock, irqflags);
+ if (!list_empty(&mchan->free)) {
+ mdesc = list_first_entry(&mchan->free, struct hidma_desc, node);
+ list_del(&mdesc->node);
+ }
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+ if (!mdesc)
+ return NULL;
+
+ hidma_ll_set_transfer_params(mdma->lldev, mdesc->tre_ch,
+ src, dest, len, flags);
+
+ /* Place descriptor in prepared list */
+ spin_lock_irqsave(&mchan->lock, irqflags);
+ list_add_tail(&mdesc->node, &mchan->prepared);
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+ return &mdesc->desc;
+}
+
+static int hidma_terminate_channel(struct dma_chan *chan)
+{
+ struct hidma_chan *mchan = to_hidma_chan(chan);
+ struct hidma_dev *dmadev = to_hidma_dev(mchan->chan.device);
+ struct hidma_desc *tmp, *mdesc;
+ unsigned long irqflags;
+ LIST_HEAD(list);
+ int rc;
+
+ pm_runtime_get_sync(dmadev->ddev.dev);
+ /* give completed requests a chance to finish */
+ hidma_process_completed(mchan);
+
+ spin_lock_irqsave(&mchan->lock, irqflags);
+ list_splice_init(&mchan->active, &list);
+ list_splice_init(&mchan->prepared, &list);
+ list_splice_init(&mchan->completed, &list);
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+ /* this suspends the existing transfer */
+ rc = hidma_ll_pause(dmadev->lldev);
+ if (rc) {
+ dev_err(dmadev->ddev.dev, "channel did not pause\n");
+ goto out;
+ }
+
+ /* return all user requests */
+ list_for_each_entry_safe(mdesc, tmp, &list, node) {
+ struct dma_async_tx_descriptor *txd = &mdesc->desc;
+ dma_async_tx_callback callback = mdesc->desc.callback;
+ void *param = mdesc->desc.callback_param;
+
+ dma_descriptor_unmap(txd);
+
+ if (callback)
+ callback(param);
+
+ dma_run_dependencies(txd);
+
+ /* move myself to free_list */
+ list_move(&mdesc->node, &mchan->free);
+ }
+
+ rc = hidma_ll_resume(dmadev->lldev);
+out:
+ pm_runtime_mark_last_busy(dmadev->ddev.dev);
+ pm_runtime_put_autosuspend(dmadev->ddev.dev);
+ return rc;
+}
+
+static int hidma_terminate_all(struct dma_chan *chan)
+{
+ struct hidma_chan *mchan = to_hidma_chan(chan);
+ struct hidma_dev *dmadev = to_hidma_dev(mchan->chan.device);
+ int rc;
+
+ rc = hidma_terminate_channel(chan);
+ if (rc)
+ return rc;
+
+ /* reinitialize the hardware */
+ pm_runtime_get_sync(dmadev->ddev.dev);
+ rc = hidma_ll_setup(dmadev->lldev);
+ pm_runtime_mark_last_busy(dmadev->ddev.dev);
+ pm_runtime_put_autosuspend(dmadev->ddev.dev);
+ return rc;
+}
+
+static void hidma_free_chan_resources(struct dma_chan *dmach)
+{
+ struct hidma_chan *mchan = to_hidma_chan(dmach);
+ struct hidma_dev *mdma = mchan->dmadev;
+ struct hidma_desc *mdesc, *tmp;
+ unsigned long irqflags;
+ LIST_HEAD(descs);
+
+ /* terminate running transactions and free descriptors */
+ hidma_terminate_channel(dmach);
+
+ spin_lock_irqsave(&mchan->lock, irqflags);
+
+ /* Move data */
+ list_splice_tail_init(&mchan->free, &descs);
+
+ /* Free descriptors */
+ list_for_each_entry_safe(mdesc, tmp, &descs, node) {
+ hidma_ll_free(mdma->lldev, mdesc->tre_ch);
+ list_del(&mdesc->node);
+ kfree(mdesc);
+ }
+
+ mchan->allocated = 0;
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+}
+
+static int hidma_pause(struct dma_chan *chan)
+{
+ struct hidma_chan *mchan;
+ struct hidma_dev *dmadev;
+
+ mchan = to_hidma_chan(chan);
+ dmadev = to_hidma_dev(mchan->chan.device);
+ if (!mchan->paused) {
+ pm_runtime_get_sync(dmadev->ddev.dev);
+ if (hidma_ll_pause(dmadev->lldev))
+ dev_warn(dmadev->ddev.dev, "channel did not stop\n");
+ mchan->paused = true;
+ pm_runtime_mark_last_busy(dmadev->ddev.dev);
+ pm_runtime_put_autosuspend(dmadev->ddev.dev);
+ }
+ return 0;
+}
+
+static int hidma_resume(struct dma_chan *chan)
+{
+ struct hidma_chan *mchan;
+ struct hidma_dev *dmadev;
+ int rc = 0;
+
+ mchan = to_hidma_chan(chan);
+ dmadev = to_hidma_dev(mchan->chan.device);
+ if (mchan->paused) {
+ pm_runtime_get_sync(dmadev->ddev.dev);
+ rc = hidma_ll_resume(dmadev->lldev);
+ if (!rc)
+ mchan->paused = false;
+ else
+ dev_err(dmadev->ddev.dev,
+ "failed to resume the channel");
+ pm_runtime_mark_last_busy(dmadev->ddev.dev);
+ pm_runtime_put_autosuspend(dmadev->ddev.dev);
+ }
+ return rc;
+}
+
+static irqreturn_t hidma_chirq_handler(int chirq, void *arg)
+{
+ struct hidma_lldev *lldev = arg;
+
+ /*
+ * All interrupts are request driven.
+ * HW doesn't send an interrupt by itself.
+ */
+ return hidma_ll_inthandler(chirq, lldev);
+}
+
+static int hidma_probe(struct platform_device *pdev)
+{
+ struct hidma_dev *dmadev;
+ struct resource *trca_resource;
+ struct resource *evca_resource;
+ int chirq;
+ void __iomem *evca;
+ void __iomem *trca;
+ int rc;
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, HIDMA_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ trca_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ trca = devm_ioremap_resource(&pdev->dev, trca_resource);
+ if (IS_ERR(trca)) {
+ rc = -ENOMEM;
+ goto bailout;
+ }
+
+ evca_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ evca = devm_ioremap_resource(&pdev->dev, evca_resource);
+ if (IS_ERR(evca)) {
+ rc = -ENOMEM;
+ goto bailout;
+ }
+
+ /*
+ * This driver only handles the channel IRQs.
+ * Common IRQ is handled by the management driver.
+ */
+ chirq = platform_get_irq(pdev, 0);
+ if (chirq < 0) {
+ rc = -ENODEV;
+ goto bailout;
+ }
+
+ dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL);
+ if (!dmadev) {
+ rc = -ENOMEM;
+ goto bailout;
+ }
+
+ INIT_LIST_HEAD(&dmadev->ddev.channels);
+ spin_lock_init(&dmadev->lock);
+ dmadev->ddev.dev = &pdev->dev;
+ pm_runtime_get_sync(dmadev->ddev.dev);
+
+ dma_cap_set(DMA_MEMCPY, dmadev->ddev.cap_mask);
+ if (WARN_ON(!pdev->dev.dma_mask)) {
+ rc = -ENXIO;
+ goto dmafree;
+ }
+
+ dmadev->dev_evca = evca;
+ dmadev->evca_resource = evca_resource;
+ dmadev->dev_trca = trca;
+ dmadev->trca_resource = trca_resource;
+ dmadev->ddev.device_prep_dma_memcpy = hidma_prep_dma_memcpy;
+ dmadev->ddev.device_alloc_chan_resources = hidma_alloc_chan_resources;
+ dmadev->ddev.device_free_chan_resources = hidma_free_chan_resources;
+ dmadev->ddev.device_tx_status = hidma_tx_status;
+ dmadev->ddev.device_issue_pending = hidma_issue_pending;
+ dmadev->ddev.device_pause = hidma_pause;
+ dmadev->ddev.device_resume = hidma_resume;
+ dmadev->ddev.device_terminate_all = hidma_terminate_all;
+ dmadev->ddev.copy_align = 8;
+
+ device_property_read_u32(&pdev->dev, "desc-count",
+ &dmadev->nr_descriptors);
+
+ if (!dmadev->nr_descriptors && nr_desc_prm)
+ dmadev->nr_descriptors = nr_desc_prm;
+
+ if (!dmadev->nr_descriptors)
+ dmadev->nr_descriptors = HIDMA_NR_DEFAULT_DESC;
+
+ dmadev->chidx = readl(dmadev->dev_trca + 0x28);
+
+ /* Set DMA mask to 64 bits. */
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (rc) {
+ dev_warn(&pdev->dev, "unable to set coherent mask to 64");
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (rc)
+ goto dmafree;
+ }
+
+ dmadev->lldev = hidma_ll_init(dmadev->ddev.dev,
+ dmadev->nr_descriptors, dmadev->dev_trca,
+ dmadev->dev_evca, dmadev->chidx);
+ if (!dmadev->lldev) {
+ rc = -EPROBE_DEFER;
+ goto dmafree;
+ }
+
+ rc = devm_request_irq(&pdev->dev, chirq, hidma_chirq_handler, 0,
+ "qcom-hidma", dmadev->lldev);
+ if (rc)
+ goto uninit;
+
+ INIT_LIST_HEAD(&dmadev->ddev.channels);
+ rc = hidma_chan_init(dmadev, 0);
+ if (rc)
+ goto uninit;
+
+ rc = dma_async_device_register(&dmadev->ddev);
+ if (rc)
+ goto uninit;
+
+ dmadev->irq = chirq;
+ tasklet_init(&dmadev->task, hidma_issue_task, (unsigned long)dmadev);
+ dev_info(&pdev->dev, "HI-DMA engine driver registration complete\n");
+ platform_set_drvdata(pdev, dmadev);
+ pm_runtime_mark_last_busy(dmadev->ddev.dev);
+ pm_runtime_put_autosuspend(dmadev->ddev.dev);
+ return 0;
+
+uninit:
+ hidma_ll_uninit(dmadev->lldev);
+dmafree:
+ if (dmadev)
+ hidma_free(dmadev);
+bailout:
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ return rc;
+}
+
+static int hidma_remove(struct platform_device *pdev)
+{
+ struct hidma_dev *dmadev = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(dmadev->ddev.dev);
+ dma_async_device_unregister(&dmadev->ddev);
+ devm_free_irq(dmadev->ddev.dev, dmadev->irq, dmadev->lldev);
+ hidma_ll_uninit(dmadev->lldev);
+ hidma_free(dmadev);
+
+ dev_info(&pdev->dev, "HI-DMA engine removed\n");
+ pm_runtime_put_sync_suspend(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_ACPI)
+static const struct acpi_device_id hidma_acpi_ids[] = {
+ {"QCOM8061"},
+ {},
+};
+#endif
+
+static const struct of_device_id hidma_match[] = {
+ {.compatible = "qcom,hidma-1.0",},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, hidma_match);
+
+static struct platform_driver hidma_driver = {
+ .probe = hidma_probe,
+ .remove = hidma_remove,
+ .driver = {
+ .name = "hidma",
+ .of_match_table = hidma_match,
+ .acpi_match_table = ACPI_PTR(hidma_acpi_ids),
+ },
+};
+
+module_platform_driver(hidma_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/qcom/hidma.h b/drivers/dma/qcom/hidma.h
new file mode 100644
index 000000000000..231e306f6d87
--- /dev/null
+++ b/drivers/dma/qcom/hidma.h
@@ -0,0 +1,160 @@
+/*
+ * Qualcomm Technologies HIDMA data structures
+ *
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef QCOM_HIDMA_H
+#define QCOM_HIDMA_H
+
+#include <linux/kfifo.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+
+#define TRE_SIZE 32 /* each TRE is 32 bytes */
+#define TRE_CFG_IDX 0
+#define TRE_LEN_IDX 1
+#define TRE_SRC_LOW_IDX 2
+#define TRE_SRC_HI_IDX 3
+#define TRE_DEST_LOW_IDX 4
+#define TRE_DEST_HI_IDX 5
+
+struct hidma_tx_status {
+ u8 err_info; /* error record in this transfer */
+ u8 err_code; /* completion code */
+};
+
+struct hidma_tre {
+ atomic_t allocated; /* if this channel is allocated */
+ bool queued; /* flag whether this is pending */
+ u16 status; /* status */
+ u32 chidx; /* index of the tre */
+ u32 dma_sig; /* signature of the tre */
+ const char *dev_name; /* name of the device */
+ void (*callback)(void *data); /* requester callback */
+ void *data; /* Data associated with this channel*/
+ struct hidma_lldev *lldev; /* lldma device pointer */
+ u32 tre_local[TRE_SIZE / sizeof(u32) + 1]; /* TRE local copy */
+ u32 tre_index; /* the offset where this was written*/
+ u32 int_flags; /* interrupt flags */
+};
+
+struct hidma_lldev {
+ bool initialized; /* initialized flag */
+ u8 trch_state; /* trch_state of the device */
+ u8 evch_state; /* evch_state of the device */
+ u8 chidx; /* channel index in the core */
+ u32 nr_tres; /* max number of configs */
+ spinlock_t lock; /* reentrancy */
+ struct hidma_tre *trepool; /* trepool of user configs */
+ struct device *dev; /* device */
+ void __iomem *trca; /* Transfer Channel address */
+ void __iomem *evca; /* Event Channel address */
+ struct hidma_tre
+ **pending_tre_list; /* Pointers to pending TREs */
+ struct hidma_tx_status
+ *tx_status_list; /* Pointers to pending TREs status*/
+ s32 pending_tre_count; /* Number of TREs pending */
+
+ void *tre_ring; /* TRE ring */
+ dma_addr_t tre_ring_handle; /* TRE ring to be shared with HW */
+ u32 tre_ring_size; /* Byte size of the ring */
+ u32 tre_processed_off; /* last processed TRE */
+
+ void *evre_ring; /* EVRE ring */
+ dma_addr_t evre_ring_handle; /* EVRE ring to be shared with HW */
+ u32 evre_ring_size; /* Byte size of the ring */
+ u32 evre_processed_off; /* last processed EVRE */
+
+ u32 tre_write_offset; /* TRE write location */
+ struct tasklet_struct task; /* task delivering notifications */
+ DECLARE_KFIFO_PTR(handoff_fifo,
+ struct hidma_tre *); /* pending TREs FIFO */
+};
+
+struct hidma_desc {
+ struct dma_async_tx_descriptor desc;
+ /* link list node for this channel*/
+ struct list_head node;
+ u32 tre_ch;
+};
+
+struct hidma_chan {
+ bool paused;
+ bool allocated;
+ char dbg_name[16];
+ u32 dma_sig;
+
+ /*
+ * active descriptor on this channel
+ * It is used by the DMA complete notification to
+ * locate the descriptor that initiated the transfer.
+ */
+ struct dentry *debugfs;
+ struct dentry *stats;
+ struct hidma_dev *dmadev;
+ struct hidma_desc *running;
+
+ struct dma_chan chan;
+ struct list_head free;
+ struct list_head prepared;
+ struct list_head active;
+ struct list_head completed;
+
+ /* Lock for this structure */
+ spinlock_t lock;
+};
+
+struct hidma_dev {
+ int irq;
+ int chidx;
+ u32 nr_descriptors;
+
+ struct hidma_lldev *lldev;
+ void __iomem *dev_trca;
+ struct resource *trca_resource;
+ void __iomem *dev_evca;
+ struct resource *evca_resource;
+
+ /* used to protect the pending channel list*/
+ spinlock_t lock;
+ struct dma_device ddev;
+
+ struct dentry *debugfs;
+ struct dentry *stats;
+
+ /* Task delivering issue_pending */
+ struct tasklet_struct task;
+};
+
+int hidma_ll_request(struct hidma_lldev *llhndl, u32 dev_id,
+ const char *dev_name,
+ void (*callback)(void *data), void *data, u32 *tre_ch);
+
+void hidma_ll_free(struct hidma_lldev *llhndl, u32 tre_ch);
+enum dma_status hidma_ll_status(struct hidma_lldev *llhndl, u32 tre_ch);
+bool hidma_ll_isenabled(struct hidma_lldev *llhndl);
+void hidma_ll_queue_request(struct hidma_lldev *llhndl, u32 tre_ch);
+void hidma_ll_start(struct hidma_lldev *llhndl);
+int hidma_ll_pause(struct hidma_lldev *llhndl);
+int hidma_ll_resume(struct hidma_lldev *llhndl);
+void hidma_ll_set_transfer_params(struct hidma_lldev *llhndl, u32 tre_ch,
+ dma_addr_t src, dma_addr_t dest, u32 len, u32 flags);
+int hidma_ll_setup(struct hidma_lldev *lldev);
+struct hidma_lldev *hidma_ll_init(struct device *dev, u32 max_channels,
+ void __iomem *trca, void __iomem *evca,
+ u8 chidx);
+int hidma_ll_uninit(struct hidma_lldev *llhndl);
+irqreturn_t hidma_ll_inthandler(int irq, void *arg);
+void hidma_cleanup_pending_tre(struct hidma_lldev *llhndl, u8 err_info,
+ u8 err_code);
+#endif
diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c
new file mode 100644
index 000000000000..ef491b893f40
--- /dev/null
+++ b/drivers/dma/qcom/hidma_mgmt.c
@@ -0,0 +1,302 @@
+/*
+ * Qualcomm Technologies HIDMA DMA engine Management interface
+ *
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/dmaengine.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/property.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/bitops.h>
+
+#include "hidma_mgmt.h"
+
+#define HIDMA_QOS_N_OFFSET 0x300
+#define HIDMA_CFG_OFFSET 0x400
+#define HIDMA_MAX_BUS_REQ_LEN_OFFSET 0x41C
+#define HIDMA_MAX_XACTIONS_OFFSET 0x420
+#define HIDMA_HW_VERSION_OFFSET 0x424
+#define HIDMA_CHRESET_TIMEOUT_OFFSET 0x418
+
+#define HIDMA_MAX_WR_XACTIONS_MASK GENMASK(4, 0)
+#define HIDMA_MAX_RD_XACTIONS_MASK GENMASK(4, 0)
+#define HIDMA_WEIGHT_MASK GENMASK(6, 0)
+#define HIDMA_MAX_BUS_REQ_LEN_MASK GENMASK(15, 0)
+#define HIDMA_CHRESET_TIMEOUT_MASK GENMASK(19, 0)
+
+#define HIDMA_MAX_WR_XACTIONS_BIT_POS 16
+#define HIDMA_MAX_BUS_WR_REQ_BIT_POS 16
+#define HIDMA_WRR_BIT_POS 8
+#define HIDMA_PRIORITY_BIT_POS 15
+
+#define HIDMA_AUTOSUSPEND_TIMEOUT 2000
+#define HIDMA_MAX_CHANNEL_WEIGHT 15
+
+int hidma_mgmt_setup(struct hidma_mgmt_dev *mgmtdev)
+{
+ unsigned int i;
+ u32 val;
+
+ if (!is_power_of_2(mgmtdev->max_write_request) ||
+ (mgmtdev->max_write_request < 128) ||
+ (mgmtdev->max_write_request > 1024)) {
+ dev_err(&mgmtdev->pdev->dev, "invalid write request %d\n",
+ mgmtdev->max_write_request);
+ return -EINVAL;
+ }
+
+ if (!is_power_of_2(mgmtdev->max_read_request) ||
+ (mgmtdev->max_read_request < 128) ||
+ (mgmtdev->max_read_request > 1024)) {
+ dev_err(&mgmtdev->pdev->dev, "invalid read request %d\n",
+ mgmtdev->max_read_request);
+ return -EINVAL;
+ }
+
+ if (mgmtdev->max_wr_xactions > HIDMA_MAX_WR_XACTIONS_MASK) {
+ dev_err(&mgmtdev->pdev->dev,
+ "max_wr_xactions cannot be bigger than %ld\n",
+ HIDMA_MAX_WR_XACTIONS_MASK);
+ return -EINVAL;
+ }
+
+ if (mgmtdev->max_rd_xactions > HIDMA_MAX_RD_XACTIONS_MASK) {
+ dev_err(&mgmtdev->pdev->dev,
+ "max_rd_xactions cannot be bigger than %ld\n",
+ HIDMA_MAX_RD_XACTIONS_MASK);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < mgmtdev->dma_channels; i++) {
+ if (mgmtdev->priority[i] > 1) {
+ dev_err(&mgmtdev->pdev->dev,
+ "priority can be 0 or 1\n");
+ return -EINVAL;
+ }
+
+ if (mgmtdev->weight[i] > HIDMA_MAX_CHANNEL_WEIGHT) {
+ dev_err(&mgmtdev->pdev->dev,
+ "max value of weight can be %d.\n",
+ HIDMA_MAX_CHANNEL_WEIGHT);
+ return -EINVAL;
+ }
+
+ /* weight needs to be at least one */
+ if (mgmtdev->weight[i] == 0)
+ mgmtdev->weight[i] = 1;
+ }
+
+ pm_runtime_get_sync(&mgmtdev->pdev->dev);
+ val = readl(mgmtdev->virtaddr + HIDMA_MAX_BUS_REQ_LEN_OFFSET);
+ val &= ~(HIDMA_MAX_BUS_REQ_LEN_MASK << HIDMA_MAX_BUS_WR_REQ_BIT_POS);
+ val |= mgmtdev->max_write_request << HIDMA_MAX_BUS_WR_REQ_BIT_POS;
+ val &= ~HIDMA_MAX_BUS_REQ_LEN_MASK;
+ val |= mgmtdev->max_read_request;
+ writel(val, mgmtdev->virtaddr + HIDMA_MAX_BUS_REQ_LEN_OFFSET);
+
+ val = readl(mgmtdev->virtaddr + HIDMA_MAX_XACTIONS_OFFSET);
+ val &= ~(HIDMA_MAX_WR_XACTIONS_MASK << HIDMA_MAX_WR_XACTIONS_BIT_POS);
+ val |= mgmtdev->max_wr_xactions << HIDMA_MAX_WR_XACTIONS_BIT_POS;
+ val &= ~HIDMA_MAX_RD_XACTIONS_MASK;
+ val |= mgmtdev->max_rd_xactions;
+ writel(val, mgmtdev->virtaddr + HIDMA_MAX_XACTIONS_OFFSET);
+
+ mgmtdev->hw_version =
+ readl(mgmtdev->virtaddr + HIDMA_HW_VERSION_OFFSET);
+ mgmtdev->hw_version_major = (mgmtdev->hw_version >> 28) & 0xF;
+ mgmtdev->hw_version_minor = (mgmtdev->hw_version >> 16) & 0xF;
+
+ for (i = 0; i < mgmtdev->dma_channels; i++) {
+ u32 weight = mgmtdev->weight[i];
+ u32 priority = mgmtdev->priority[i];
+
+ val = readl(mgmtdev->virtaddr + HIDMA_QOS_N_OFFSET + (4 * i));
+ val &= ~(1 << HIDMA_PRIORITY_BIT_POS);
+ val |= (priority & 0x1) << HIDMA_PRIORITY_BIT_POS;
+ val &= ~(HIDMA_WEIGHT_MASK << HIDMA_WRR_BIT_POS);
+ val |= (weight & HIDMA_WEIGHT_MASK) << HIDMA_WRR_BIT_POS;
+ writel(val, mgmtdev->virtaddr + HIDMA_QOS_N_OFFSET + (4 * i));
+ }
+
+ val = readl(mgmtdev->virtaddr + HIDMA_CHRESET_TIMEOUT_OFFSET);
+ val &= ~HIDMA_CHRESET_TIMEOUT_MASK;
+ val |= mgmtdev->chreset_timeout_cycles & HIDMA_CHRESET_TIMEOUT_MASK;
+ writel(val, mgmtdev->virtaddr + HIDMA_CHRESET_TIMEOUT_OFFSET);
+
+ pm_runtime_mark_last_busy(&mgmtdev->pdev->dev);
+ pm_runtime_put_autosuspend(&mgmtdev->pdev->dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hidma_mgmt_setup);
+
+static int hidma_mgmt_probe(struct platform_device *pdev)
+{
+ struct hidma_mgmt_dev *mgmtdev;
+ struct resource *res;
+ void __iomem *virtaddr;
+ int irq;
+ int rc;
+ u32 val;
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, HIDMA_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ virtaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(virtaddr)) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "irq resources not found\n");
+ rc = irq;
+ goto out;
+ }
+
+ mgmtdev = devm_kzalloc(&pdev->dev, sizeof(*mgmtdev), GFP_KERNEL);
+ if (!mgmtdev) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ mgmtdev->pdev = pdev;
+ mgmtdev->addrsize = resource_size(res);
+ mgmtdev->virtaddr = virtaddr;
+
+ rc = device_property_read_u32(&pdev->dev, "dma-channels",
+ &mgmtdev->dma_channels);
+ if (rc) {
+ dev_err(&pdev->dev, "number of channels missing\n");
+ goto out;
+ }
+
+ rc = device_property_read_u32(&pdev->dev,
+ "channel-reset-timeout-cycles",
+ &mgmtdev->chreset_timeout_cycles);
+ if (rc) {
+ dev_err(&pdev->dev, "channel reset timeout missing\n");
+ goto out;
+ }
+
+ rc = device_property_read_u32(&pdev->dev, "max-write-burst-bytes",
+ &mgmtdev->max_write_request);
+ if (rc) {
+ dev_err(&pdev->dev, "max-write-burst-bytes missing\n");
+ goto out;
+ }
+
+ rc = device_property_read_u32(&pdev->dev, "max-read-burst-bytes",
+ &mgmtdev->max_read_request);
+ if (rc) {
+ dev_err(&pdev->dev, "max-read-burst-bytes missing\n");
+ goto out;
+ }
+
+ rc = device_property_read_u32(&pdev->dev, "max-write-transactions",
+ &mgmtdev->max_wr_xactions);
+ if (rc) {
+ dev_err(&pdev->dev, "max-write-transactions missing\n");
+ goto out;
+ }
+
+ rc = device_property_read_u32(&pdev->dev, "max-read-transactions",
+ &mgmtdev->max_rd_xactions);
+ if (rc) {
+ dev_err(&pdev->dev, "max-read-transactions missing\n");
+ goto out;
+ }
+
+ mgmtdev->priority = devm_kcalloc(&pdev->dev,
+ mgmtdev->dma_channels,
+ sizeof(*mgmtdev->priority),
+ GFP_KERNEL);
+ if (!mgmtdev->priority) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ mgmtdev->weight = devm_kcalloc(&pdev->dev,
+ mgmtdev->dma_channels,
+ sizeof(*mgmtdev->weight), GFP_KERNEL);
+ if (!mgmtdev->weight) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = hidma_mgmt_setup(mgmtdev);
+ if (rc) {
+ dev_err(&pdev->dev, "setup failed\n");
+ goto out;
+ }
+
+ /* start the HW */
+ val = readl(mgmtdev->virtaddr + HIDMA_CFG_OFFSET);
+ val |= 1;
+ writel(val, mgmtdev->virtaddr + HIDMA_CFG_OFFSET);
+
+ rc = hidma_mgmt_init_sys(mgmtdev);
+ if (rc) {
+ dev_err(&pdev->dev, "sysfs setup failed\n");
+ goto out;
+ }
+
+ dev_info(&pdev->dev,
+ "HW rev: %d.%d @ %pa with %d physical channels\n",
+ mgmtdev->hw_version_major, mgmtdev->hw_version_minor,
+ &res->start, mgmtdev->dma_channels);
+
+ platform_set_drvdata(pdev, mgmtdev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+ return 0;
+out:
+ pm_runtime_put_sync_suspend(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ return rc;
+}
+
+#if IS_ENABLED(CONFIG_ACPI)
+static const struct acpi_device_id hidma_mgmt_acpi_ids[] = {
+ {"QCOM8060"},
+ {},
+};
+#endif
+
+static const struct of_device_id hidma_mgmt_match[] = {
+ {.compatible = "qcom,hidma-mgmt-1.0",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, hidma_mgmt_match);
+
+static struct platform_driver hidma_mgmt_driver = {
+ .probe = hidma_mgmt_probe,
+ .driver = {
+ .name = "hidma-mgmt",
+ .of_match_table = hidma_mgmt_match,
+ .acpi_match_table = ACPI_PTR(hidma_mgmt_acpi_ids),
+ },
+};
+
+module_platform_driver(hidma_mgmt_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/qcom/hidma_mgmt.h b/drivers/dma/qcom/hidma_mgmt.h
new file mode 100644
index 000000000000..f7daf33769f4
--- /dev/null
+++ b/drivers/dma/qcom/hidma_mgmt.h
@@ -0,0 +1,39 @@
+/*
+ * Qualcomm Technologies HIDMA Management common header
+ *
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+struct hidma_mgmt_dev {
+ u8 hw_version_major;
+ u8 hw_version_minor;
+
+ u32 max_wr_xactions;
+ u32 max_rd_xactions;
+ u32 max_write_request;
+ u32 max_read_request;
+ u32 dma_channels;
+ u32 chreset_timeout_cycles;
+ u32 hw_version;
+ u32 *priority;
+ u32 *weight;
+
+ /* Hardware device constants */
+ void __iomem *virtaddr;
+ resource_size_t addrsize;
+
+ struct kobject **chroots;
+ struct platform_device *pdev;
+};
+
+int hidma_mgmt_init_sys(struct hidma_mgmt_dev *dev);
+int hidma_mgmt_setup(struct hidma_mgmt_dev *mgmtdev);
diff --git a/drivers/dma/qcom/hidma_mgmt_sys.c b/drivers/dma/qcom/hidma_mgmt_sys.c
new file mode 100644
index 000000000000..d61f1068a34b
--- /dev/null
+++ b/drivers/dma/qcom/hidma_mgmt_sys.c
@@ -0,0 +1,295 @@
+/*
+ * Qualcomm Technologies HIDMA Management SYS interface
+ *
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+
+#include "hidma_mgmt.h"
+
+struct hidma_chan_attr {
+ struct hidma_mgmt_dev *mdev;
+ int index;
+ struct kobj_attribute attr;
+};
+
+struct hidma_mgmt_fileinfo {
+ char *name;
+ int mode;
+ int (*get)(struct hidma_mgmt_dev *mdev);
+ int (*set)(struct hidma_mgmt_dev *mdev, u64 val);
+};
+
+#define IMPLEMENT_GETSET(name) \
+static int get_##name(struct hidma_mgmt_dev *mdev) \
+{ \
+ return mdev->name; \
+} \
+static int set_##name(struct hidma_mgmt_dev *mdev, u64 val) \
+{ \
+ u64 tmp; \
+ int rc; \
+ \
+ tmp = mdev->name; \
+ mdev->name = val; \
+ rc = hidma_mgmt_setup(mdev); \
+ if (rc) \
+ mdev->name = tmp; \
+ return rc; \
+}
+
+#define DECLARE_ATTRIBUTE(name, mode) \
+ {#name, mode, get_##name, set_##name}
+
+IMPLEMENT_GETSET(hw_version_major)
+IMPLEMENT_GETSET(hw_version_minor)
+IMPLEMENT_GETSET(max_wr_xactions)
+IMPLEMENT_GETSET(max_rd_xactions)
+IMPLEMENT_GETSET(max_write_request)
+IMPLEMENT_GETSET(max_read_request)
+IMPLEMENT_GETSET(dma_channels)
+IMPLEMENT_GETSET(chreset_timeout_cycles)
+
+static int set_priority(struct hidma_mgmt_dev *mdev, unsigned int i, u64 val)
+{
+ u64 tmp;
+ int rc;
+
+ if (i >= mdev->dma_channels)
+ return -EINVAL;
+
+ tmp = mdev->priority[i];
+ mdev->priority[i] = val;
+ rc = hidma_mgmt_setup(mdev);
+ if (rc)
+ mdev->priority[i] = tmp;
+ return rc;
+}
+
+static int set_weight(struct hidma_mgmt_dev *mdev, unsigned int i, u64 val)
+{
+ u64 tmp;
+ int rc;
+
+ if (i >= mdev->dma_channels)
+ return -EINVAL;
+
+ tmp = mdev->weight[i];
+ mdev->weight[i] = val;
+ rc = hidma_mgmt_setup(mdev);
+ if (rc)
+ mdev->weight[i] = tmp;
+ return rc;
+}
+
+static struct hidma_mgmt_fileinfo hidma_mgmt_files[] = {
+ DECLARE_ATTRIBUTE(hw_version_major, S_IRUGO),
+ DECLARE_ATTRIBUTE(hw_version_minor, S_IRUGO),
+ DECLARE_ATTRIBUTE(dma_channels, S_IRUGO),
+ DECLARE_ATTRIBUTE(chreset_timeout_cycles, S_IRUGO),
+ DECLARE_ATTRIBUTE(max_wr_xactions, S_IRUGO),
+ DECLARE_ATTRIBUTE(max_rd_xactions, S_IRUGO),
+ DECLARE_ATTRIBUTE(max_write_request, S_IRUGO),
+ DECLARE_ATTRIBUTE(max_read_request, S_IRUGO),
+};
+
+static ssize_t show_values(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct hidma_mgmt_dev *mdev = platform_get_drvdata(pdev);
+ unsigned int i;
+
+ buf[0] = 0;
+
+ for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
+ if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) {
+ sprintf(buf, "%d\n", hidma_mgmt_files[i].get(mdev));
+ break;
+ }
+ }
+ return strlen(buf);
+}
+
+static ssize_t set_values(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct hidma_mgmt_dev *mdev = platform_get_drvdata(pdev);
+ unsigned long tmp;
+ unsigned int i;
+ int rc;
+
+ rc = kstrtoul(buf, 0, &tmp);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
+ if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) {
+ rc = hidma_mgmt_files[i].set(mdev, tmp);
+ if (rc)
+ return rc;
+
+ break;
+ }
+ }
+ return count;
+}
+
+static ssize_t show_values_channel(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct hidma_chan_attr *chattr;
+ struct hidma_mgmt_dev *mdev;
+
+ buf[0] = 0;
+ chattr = container_of(attr, struct hidma_chan_attr, attr);
+ mdev = chattr->mdev;
+ if (strcmp(attr->attr.name, "priority") == 0)
+ sprintf(buf, "%d\n", mdev->priority[chattr->index]);
+ else if (strcmp(attr->attr.name, "weight") == 0)
+ sprintf(buf, "%d\n", mdev->weight[chattr->index]);
+
+ return strlen(buf);
+}
+
+static ssize_t set_values_channel(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct hidma_chan_attr *chattr;
+ struct hidma_mgmt_dev *mdev;
+ unsigned long tmp;
+ int rc;
+
+ chattr = container_of(attr, struct hidma_chan_attr, attr);
+ mdev = chattr->mdev;
+
+ rc = kstrtoul(buf, 0, &tmp);
+ if (rc)
+ return rc;
+
+ if (strcmp(attr->attr.name, "priority") == 0) {
+ rc = set_priority(mdev, chattr->index, tmp);
+ if (rc)
+ return rc;
+ } else if (strcmp(attr->attr.name, "weight") == 0) {
+ rc = set_weight(mdev, chattr->index, tmp);
+ if (rc)
+ return rc;
+ }
+ return count;
+}
+
+static int create_sysfs_entry(struct hidma_mgmt_dev *dev, char *name, int mode)
+{
+ struct device_attribute *attrs;
+ char *name_copy;
+
+ attrs = devm_kmalloc(&dev->pdev->dev,
+ sizeof(struct device_attribute), GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+
+ name_copy = devm_kstrdup(&dev->pdev->dev, name, GFP_KERNEL);
+ if (!name_copy)
+ return -ENOMEM;
+
+ attrs->attr.name = name_copy;
+ attrs->attr.mode = mode;
+ attrs->show = show_values;
+ attrs->store = set_values;
+ sysfs_attr_init(&attrs->attr);
+
+ return device_create_file(&dev->pdev->dev, attrs);
+}
+
+static int create_sysfs_entry_channel(struct hidma_mgmt_dev *mdev, char *name,
+ int mode, int index,
+ struct kobject *parent)
+{
+ struct hidma_chan_attr *chattr;
+ char *name_copy;
+
+ chattr = devm_kmalloc(&mdev->pdev->dev, sizeof(*chattr), GFP_KERNEL);
+ if (!chattr)
+ return -ENOMEM;
+
+ name_copy = devm_kstrdup(&mdev->pdev->dev, name, GFP_KERNEL);
+ if (!name_copy)
+ return -ENOMEM;
+
+ chattr->mdev = mdev;
+ chattr->index = index;
+ chattr->attr.attr.name = name_copy;
+ chattr->attr.attr.mode = mode;
+ chattr->attr.show = show_values_channel;
+ chattr->attr.store = set_values_channel;
+ sysfs_attr_init(&chattr->attr.attr);
+
+ return sysfs_create_file(parent, &chattr->attr.attr);
+}
+
+int hidma_mgmt_init_sys(struct hidma_mgmt_dev *mdev)
+{
+ unsigned int i;
+ int rc;
+ int required;
+ struct kobject *chanops;
+
+ required = sizeof(*mdev->chroots) * mdev->dma_channels;
+ mdev->chroots = devm_kmalloc(&mdev->pdev->dev, required, GFP_KERNEL);
+ if (!mdev->chroots)
+ return -ENOMEM;
+
+ chanops = kobject_create_and_add("chanops", &mdev->pdev->dev.kobj);
+ if (!chanops)
+ return -ENOMEM;
+
+ /* create each channel directory here */
+ for (i = 0; i < mdev->dma_channels; i++) {
+ char name[20];
+
+ snprintf(name, sizeof(name), "chan%d", i);
+ mdev->chroots[i] = kobject_create_and_add(name, chanops);
+ if (!mdev->chroots[i])
+ return -ENOMEM;
+ }
+
+ /* populate common parameters */
+ for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
+ rc = create_sysfs_entry(mdev, hidma_mgmt_files[i].name,
+ hidma_mgmt_files[i].mode);
+ if (rc)
+ return rc;
+ }
+
+ /* populate parameters that are per channel */
+ for (i = 0; i < mdev->dma_channels; i++) {
+ rc = create_sysfs_entry_channel(mdev, "priority",
+ (S_IRUGO | S_IWUGO), i,
+ mdev->chroots[i]);
+ if (rc)
+ return rc;
+
+ rc = create_sysfs_entry_channel(mdev, "weight",
+ (S_IRUGO | S_IWUGO), i,
+ mdev->chroots[i]);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hidma_mgmt_init_sys);
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index f32c430eb16c..6e0685f1a838 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -12,7 +12,7 @@ config RENESAS_DMA
config SH_DMAE_BASE
bool "Renesas SuperH DMA Engine support"
- depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
+ depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
depends on !SUPERH || SH_DMA
depends on !SH_DMA_API
default y
@@ -41,7 +41,7 @@ endif
config RCAR_DMAC
tristate "Renesas R-Car Gen2 DMA Controller"
- depends on ARCH_SHMOBILE || COMPILE_TEST
+ depends on ARCH_RENESAS || COMPILE_TEST
select RENESAS_DMA
help
This driver supports the general purpose DMA controller found in the
@@ -49,7 +49,7 @@ config RCAR_DMAC
config RENESAS_USB_DMAC
tristate "Renesas USB-DMA Controller"
- depends on ARCH_SHMOBILE || COMPILE_TEST
+ depends on ARCH_RENESAS || COMPILE_TEST
select RENESAS_DMA
select DMA_VIRTUAL_CHANNELS
help
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 7820d07e7bee..dfb17926297b 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -413,7 +413,7 @@ static int rcar_dmac_init(struct rcar_dmac *dmac)
u16 dmaor;
/* Clear all channels and enable the DMAC globally. */
- rcar_dmac_write(dmac, RCAR_DMACHCLR, 0x7fff);
+ rcar_dmac_write(dmac, RCAR_DMACHCLR, GENMASK(dmac->n_channels - 1, 0));
rcar_dmac_write(dmac, RCAR_DMAOR,
RCAR_DMAOR_PRI_FIXED | RCAR_DMAOR_DME);
diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c
index 11707df1a689..80d86402490e 100644
--- a/drivers/dma/sh/shdmac.c
+++ b/drivers/dma/sh/shdmac.c
@@ -699,7 +699,7 @@ static int sh_dmae_probe(struct platform_device *pdev)
struct resource *chan, *dmars, *errirq_res, *chanirq_res;
if (pdev->dev.of_node)
- pdata = of_match_device(sh_dmae_of_match, &pdev->dev)->data;
+ pdata = of_device_get_match_data(&pdev->dev);
else
pdata = dev_get_platdata(&pdev->dev);
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index 22ea2419ee56..e48350e65089 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -989,7 +989,7 @@ static int sirfsoc_dma_remove(struct platform_device *op)
return 0;
}
-static int sirfsoc_dma_runtime_suspend(struct device *dev)
+static int __maybe_unused sirfsoc_dma_runtime_suspend(struct device *dev)
{
struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
@@ -997,7 +997,7 @@ static int sirfsoc_dma_runtime_suspend(struct device *dev)
return 0;
}
-static int sirfsoc_dma_runtime_resume(struct device *dev)
+static int __maybe_unused sirfsoc_dma_runtime_resume(struct device *dev)
{
struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
int ret;
@@ -1010,8 +1010,7 @@ static int sirfsoc_dma_runtime_resume(struct device *dev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int sirfsoc_dma_pm_suspend(struct device *dev)
+static int __maybe_unused sirfsoc_dma_pm_suspend(struct device *dev)
{
struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
struct sirfsoc_dma_regs *save = &sdma->regs_save;
@@ -1062,7 +1061,7 @@ static int sirfsoc_dma_pm_suspend(struct device *dev)
return 0;
}
-static int sirfsoc_dma_pm_resume(struct device *dev)
+static int __maybe_unused sirfsoc_dma_pm_resume(struct device *dev)
{
struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
struct sirfsoc_dma_regs *save = &sdma->regs_save;
@@ -1121,7 +1120,6 @@ static int sirfsoc_dma_pm_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops sirfsoc_dma_pm_ops = {
SET_RUNTIME_PM_OPS(sirfsoc_dma_runtime_suspend, sirfsoc_dma_runtime_resume, NULL)
diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index 1661d518224a..e0df233dde92 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -1271,6 +1271,7 @@ static const struct of_device_id sun4i_dma_match[] = {
{ .compatible = "allwinner,sun4i-a10-dma" },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, sun4i_dma_match);
static struct platform_driver sun4i_dma_driver = {
.probe = sun4i_dma_probe,
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 935da8192f59..3871f29e523d 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -1292,40 +1292,19 @@ static const struct tegra_dma_chip_data tegra148_dma_chip_data = {
.support_separate_wcount_reg = true,
};
-
-static const struct of_device_id tegra_dma_of_match[] = {
- {
- .compatible = "nvidia,tegra148-apbdma",
- .data = &tegra148_dma_chip_data,
- }, {
- .compatible = "nvidia,tegra114-apbdma",
- .data = &tegra114_dma_chip_data,
- }, {
- .compatible = "nvidia,tegra30-apbdma",
- .data = &tegra30_dma_chip_data,
- }, {
- .compatible = "nvidia,tegra20-apbdma",
- .data = &tegra20_dma_chip_data,
- }, {
- },
-};
-MODULE_DEVICE_TABLE(of, tegra_dma_of_match);
-
static int tegra_dma_probe(struct platform_device *pdev)
{
struct resource *res;
struct tegra_dma *tdma;
int ret;
int i;
- const struct tegra_dma_chip_data *cdata = NULL;
- const struct of_device_id *match;
+ const struct tegra_dma_chip_data *cdata;
- match = of_match_device(tegra_dma_of_match, &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "Error: No device match found\n");
+ cdata = of_device_get_match_data(&pdev->dev);
+ if (!cdata) {
+ dev_err(&pdev->dev, "Error: No device match data found\n");
return -ENODEV;
}
- cdata = match->data;
tdma = devm_kzalloc(&pdev->dev, sizeof(*tdma) + cdata->nr_channels *
sizeof(struct tegra_dma_channel), GFP_KERNEL);
@@ -1612,6 +1591,24 @@ static const struct dev_pm_ops tegra_dma_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(tegra_dma_pm_suspend, tegra_dma_pm_resume)
};
+static const struct of_device_id tegra_dma_of_match[] = {
+ {
+ .compatible = "nvidia,tegra148-apbdma",
+ .data = &tegra148_dma_chip_data,
+ }, {
+ .compatible = "nvidia,tegra114-apbdma",
+ .data = &tegra114_dma_chip_data,
+ }, {
+ .compatible = "nvidia,tegra30-apbdma",
+ .data = &tegra30_dma_chip_data,
+ }, {
+ .compatible = "nvidia,tegra20-apbdma",
+ .data = &tegra20_dma_chip_data,
+ }, {
+ },
+};
+MODULE_DEVICE_TABLE(of, tegra_dma_of_match);
+
static struct platform_driver tegra_dmac_driver = {
.driver = {
.name = "tegra-apbdma",
diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c
index 6f4b5017ca3b..0ee0321868d3 100644
--- a/drivers/dma/xilinx/xilinx_vdma.c
+++ b/drivers/dma/xilinx/xilinx_vdma.c
@@ -28,6 +28,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_dma.h>
@@ -190,8 +191,7 @@ struct xilinx_vdma_tx_descriptor {
* @desc_offset: TX descriptor registers offset
* @lock: Descriptor operation lock
* @pending_list: Descriptors waiting
- * @active_desc: Active descriptor
- * @allocated_desc: Allocated descriptor
+ * @active_list: Descriptors ready to submit
* @done_list: Complete descriptors
* @common: DMA common channel
* @desc_pool: Descriptors pool
@@ -206,6 +206,7 @@ struct xilinx_vdma_tx_descriptor {
* @tasklet: Cleanup work after irq
* @config: Device configuration info
* @flush_on_fsync: Flush on Frame sync
+ * @desc_pendingcount: Descriptor pending count
*/
struct xilinx_vdma_chan {
struct xilinx_vdma_device *xdev;
@@ -213,8 +214,7 @@ struct xilinx_vdma_chan {
u32 desc_offset;
spinlock_t lock;
struct list_head pending_list;
- struct xilinx_vdma_tx_descriptor *active_desc;
- struct xilinx_vdma_tx_descriptor *allocated_desc;
+ struct list_head active_list;
struct list_head done_list;
struct dma_chan common;
struct dma_pool *desc_pool;
@@ -229,6 +229,7 @@ struct xilinx_vdma_chan {
struct tasklet_struct tasklet;
struct xilinx_vdma_config config;
bool flush_on_fsync;
+ u32 desc_pendingcount;
};
/**
@@ -254,6 +255,9 @@ struct xilinx_vdma_device {
container_of(chan, struct xilinx_vdma_chan, common)
#define to_vdma_tx_descriptor(tx) \
container_of(tx, struct xilinx_vdma_tx_descriptor, async_tx)
+#define xilinx_vdma_poll_timeout(chan, reg, val, cond, delay_us, timeout_us) \
+ readl_poll_timeout(chan->xdev->regs + chan->ctrl_offset + reg, val, \
+ cond, delay_us, timeout_us)
/* IO accessors */
static inline u32 vdma_read(struct xilinx_vdma_chan *chan, u32 reg)
@@ -342,19 +346,11 @@ static struct xilinx_vdma_tx_descriptor *
xilinx_vdma_alloc_tx_descriptor(struct xilinx_vdma_chan *chan)
{
struct xilinx_vdma_tx_descriptor *desc;
- unsigned long flags;
-
- if (chan->allocated_desc)
- return chan->allocated_desc;
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
if (!desc)
return NULL;
- spin_lock_irqsave(&chan->lock, flags);
- chan->allocated_desc = desc;
- spin_unlock_irqrestore(&chan->lock, flags);
-
INIT_LIST_HEAD(&desc->segments);
return desc;
@@ -412,9 +408,7 @@ static void xilinx_vdma_free_descriptors(struct xilinx_vdma_chan *chan)
xilinx_vdma_free_desc_list(chan, &chan->pending_list);
xilinx_vdma_free_desc_list(chan, &chan->done_list);
-
- xilinx_vdma_free_tx_descriptor(chan, chan->active_desc);
- chan->active_desc = NULL;
+ xilinx_vdma_free_desc_list(chan, &chan->active_list);
spin_unlock_irqrestore(&chan->lock, flags);
}
@@ -560,18 +554,17 @@ static bool xilinx_vdma_is_idle(struct xilinx_vdma_chan *chan)
*/
static void xilinx_vdma_halt(struct xilinx_vdma_chan *chan)
{
- int loop = XILINX_VDMA_LOOP_COUNT;
+ int err;
+ u32 val;
vdma_ctrl_clr(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP);
/* Wait for the hardware to halt */
- do {
- if (vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
- XILINX_VDMA_DMASR_HALTED)
- break;
- } while (loop--);
+ err = xilinx_vdma_poll_timeout(chan, XILINX_VDMA_REG_DMASR, val,
+ (val & XILINX_VDMA_DMASR_HALTED), 0,
+ XILINX_VDMA_LOOP_COUNT);
- if (!loop) {
+ if (err) {
dev_err(chan->dev, "Cannot stop channel %p: %x\n",
chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR));
chan->err = true;
@@ -586,18 +579,17 @@ static void xilinx_vdma_halt(struct xilinx_vdma_chan *chan)
*/
static void xilinx_vdma_start(struct xilinx_vdma_chan *chan)
{
- int loop = XILINX_VDMA_LOOP_COUNT;
+ int err;
+ u32 val;
vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP);
/* Wait for the hardware to start */
- do {
- if (!(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
- XILINX_VDMA_DMASR_HALTED))
- break;
- } while (loop--);
+ err = xilinx_vdma_poll_timeout(chan, XILINX_VDMA_REG_DMASR, val,
+ !(val & XILINX_VDMA_DMASR_HALTED), 0,
+ XILINX_VDMA_LOOP_COUNT);
- if (!loop) {
+ if (err) {
dev_err(chan->dev, "Cannot start channel %p: %x\n",
chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR));
@@ -614,45 +606,39 @@ static void xilinx_vdma_start(struct xilinx_vdma_chan *chan)
static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan)
{
struct xilinx_vdma_config *config = &chan->config;
- struct xilinx_vdma_tx_descriptor *desc;
- unsigned long flags;
+ struct xilinx_vdma_tx_descriptor *desc, *tail_desc;
u32 reg;
- struct xilinx_vdma_tx_segment *head, *tail = NULL;
+ struct xilinx_vdma_tx_segment *tail_segment;
+ /* This function was invoked with lock held */
if (chan->err)
return;
- spin_lock_irqsave(&chan->lock, flags);
-
- /* There's already an active descriptor, bail out. */
- if (chan->active_desc)
- goto out_unlock;
-
if (list_empty(&chan->pending_list))
- goto out_unlock;
+ return;
desc = list_first_entry(&chan->pending_list,
struct xilinx_vdma_tx_descriptor, node);
+ tail_desc = list_last_entry(&chan->pending_list,
+ struct xilinx_vdma_tx_descriptor, node);
+
+ tail_segment = list_last_entry(&tail_desc->segments,
+ struct xilinx_vdma_tx_segment, node);
/* If it is SG mode and hardware is busy, cannot submit */
if (chan->has_sg && xilinx_vdma_is_running(chan) &&
!xilinx_vdma_is_idle(chan)) {
dev_dbg(chan->dev, "DMA controller still busy\n");
- goto out_unlock;
+ return;
}
/*
* If hardware is idle, then all descriptors on the running lists are
* done, start new transfers
*/
- if (chan->has_sg) {
- head = list_first_entry(&desc->segments,
- struct xilinx_vdma_tx_segment, node);
- tail = list_entry(desc->segments.prev,
- struct xilinx_vdma_tx_segment, node);
-
- vdma_ctrl_write(chan, XILINX_VDMA_REG_CURDESC, head->phys);
- }
+ if (chan->has_sg)
+ vdma_ctrl_write(chan, XILINX_VDMA_REG_CURDESC,
+ desc->async_tx.phys);
/* Configure the hardware using info in the config structure */
reg = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR);
@@ -662,6 +648,10 @@ static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan)
else
reg &= ~XILINX_VDMA_DMACR_FRAMECNT_EN;
+ /* Configure channel to allow number frame buffers */
+ vdma_ctrl_write(chan, XILINX_VDMA_REG_FRMSTORE,
+ chan->desc_pendingcount);
+
/*
* With SG, start with circular mode, so that BDs can be fetched.
* In direct register mode, if not parking, enable circular mode
@@ -690,16 +680,19 @@ static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan)
xilinx_vdma_start(chan);
if (chan->err)
- goto out_unlock;
+ return;
/* Start the transfer */
if (chan->has_sg) {
- vdma_ctrl_write(chan, XILINX_VDMA_REG_TAILDESC, tail->phys);
+ vdma_ctrl_write(chan, XILINX_VDMA_REG_TAILDESC,
+ tail_segment->phys);
} else {
struct xilinx_vdma_tx_segment *segment, *last = NULL;
int i = 0;
- list_for_each_entry(segment, &desc->segments, node) {
+ list_for_each_entry(desc, &chan->pending_list, node) {
+ segment = list_first_entry(&desc->segments,
+ struct xilinx_vdma_tx_segment, node);
vdma_desc_write(chan,
XILINX_VDMA_REG_START_ADDRESS(i++),
segment->hw.buf_addr);
@@ -707,7 +700,7 @@ static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan)
}
if (!last)
- goto out_unlock;
+ return;
/* HW expects these parameters to be same for one transaction */
vdma_desc_write(chan, XILINX_VDMA_REG_HSIZE, last->hw.hsize);
@@ -716,11 +709,8 @@ static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan)
vdma_desc_write(chan, XILINX_VDMA_REG_VSIZE, last->hw.vsize);
}
- list_del(&desc->node);
- chan->active_desc = desc;
-
-out_unlock:
- spin_unlock_irqrestore(&chan->lock, flags);
+ list_splice_tail_init(&chan->pending_list, &chan->active_list);
+ chan->desc_pendingcount = 0;
}
/**
@@ -730,8 +720,11 @@ out_unlock:
static void xilinx_vdma_issue_pending(struct dma_chan *dchan)
{
struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+ unsigned long flags;
+ spin_lock_irqsave(&chan->lock, flags);
xilinx_vdma_start_transfer(chan);
+ spin_unlock_irqrestore(&chan->lock, flags);
}
/**
@@ -742,24 +735,17 @@ static void xilinx_vdma_issue_pending(struct dma_chan *dchan)
*/
static void xilinx_vdma_complete_descriptor(struct xilinx_vdma_chan *chan)
{
- struct xilinx_vdma_tx_descriptor *desc;
- unsigned long flags;
+ struct xilinx_vdma_tx_descriptor *desc, *next;
- spin_lock_irqsave(&chan->lock, flags);
+ /* This function was invoked with lock held */
+ if (list_empty(&chan->active_list))
+ return;
- desc = chan->active_desc;
- if (!desc) {
- dev_dbg(chan->dev, "no running descriptors\n");
- goto out_unlock;
+ list_for_each_entry_safe(desc, next, &chan->active_list, node) {
+ list_del(&desc->node);
+ dma_cookie_complete(&desc->async_tx);
+ list_add_tail(&desc->node, &chan->done_list);
}
-
- dma_cookie_complete(&desc->async_tx);
- list_add_tail(&desc->node, &chan->done_list);
-
- chan->active_desc = NULL;
-
-out_unlock:
- spin_unlock_irqrestore(&chan->lock, flags);
}
/**
@@ -770,21 +756,17 @@ out_unlock:
*/
static int xilinx_vdma_reset(struct xilinx_vdma_chan *chan)
{
- int loop = XILINX_VDMA_LOOP_COUNT;
+ int err;
u32 tmp;
vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RESET);
- tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) &
- XILINX_VDMA_DMACR_RESET;
-
/* Wait for the hardware to finish reset */
- do {
- tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) &
- XILINX_VDMA_DMACR_RESET;
- } while (loop-- && tmp);
+ err = xilinx_vdma_poll_timeout(chan, XILINX_VDMA_REG_DMACR, tmp,
+ !(tmp & XILINX_VDMA_DMACR_RESET), 0,
+ XILINX_VDMA_LOOP_COUNT);
- if (!loop) {
+ if (err) {
dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR),
vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR));
@@ -793,7 +775,7 @@ static int xilinx_vdma_reset(struct xilinx_vdma_chan *chan)
chan->err = false;
- return 0;
+ return err;
}
/**
@@ -870,8 +852,10 @@ static irqreturn_t xilinx_vdma_irq_handler(int irq, void *data)
}
if (status & XILINX_VDMA_DMASR_FRM_CNT_IRQ) {
+ spin_lock(&chan->lock);
xilinx_vdma_complete_descriptor(chan);
xilinx_vdma_start_transfer(chan);
+ spin_unlock(&chan->lock);
}
tasklet_schedule(&chan->tasklet);
@@ -879,6 +863,44 @@ static irqreturn_t xilinx_vdma_irq_handler(int irq, void *data)
}
/**
+ * append_desc_queue - Queuing descriptor
+ * @chan: Driver specific dma channel
+ * @desc: dma transaction descriptor
+ */
+static void append_desc_queue(struct xilinx_vdma_chan *chan,
+ struct xilinx_vdma_tx_descriptor *desc)
+{
+ struct xilinx_vdma_tx_segment *tail_segment;
+ struct xilinx_vdma_tx_descriptor *tail_desc;
+
+ if (list_empty(&chan->pending_list))
+ goto append;
+
+ /*
+ * Add the hardware descriptor to the chain of hardware descriptors
+ * that already exists in memory.
+ */
+ tail_desc = list_last_entry(&chan->pending_list,
+ struct xilinx_vdma_tx_descriptor, node);
+ tail_segment = list_last_entry(&tail_desc->segments,
+ struct xilinx_vdma_tx_segment, node);
+ tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
+
+ /*
+ * Add the software descriptor and all children to the list
+ * of pending transactions
+ */
+append:
+ list_add_tail(&desc->node, &chan->pending_list);
+ chan->desc_pendingcount++;
+
+ if (unlikely(chan->desc_pendingcount > chan->num_frms)) {
+ dev_dbg(chan->dev, "desc pendingcount is too high\n");
+ chan->desc_pendingcount = chan->num_frms;
+ }
+}
+
+/**
* xilinx_vdma_tx_submit - Submit DMA transaction
* @tx: Async transaction descriptor
*
@@ -906,11 +928,8 @@ static dma_cookie_t xilinx_vdma_tx_submit(struct dma_async_tx_descriptor *tx)
cookie = dma_cookie_assign(tx);
- /* Append the transaction to the pending transactions queue. */
- list_add_tail(&desc->node, &chan->pending_list);
-
- /* Free the allocated desc */
- chan->allocated_desc = NULL;
+ /* Put this transaction onto the tail of the pending queue */
+ append_desc_queue(chan, desc);
spin_unlock_irqrestore(&chan->lock, flags);
@@ -973,13 +992,6 @@ xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan,
else
hw->buf_addr = xt->src_start;
- /* Link the previous next descriptor to current */
- if (!list_empty(&desc->segments)) {
- prev = list_last_entry(&desc->segments,
- struct xilinx_vdma_tx_segment, node);
- prev->hw.next_desc = segment->phys;
- }
-
/* Insert the segment into the descriptor segments list. */
list_add_tail(&segment->node, &desc->segments);
@@ -988,7 +1000,7 @@ xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan,
/* Link the last hardware descriptor with the first. */
segment = list_first_entry(&desc->segments,
struct xilinx_vdma_tx_segment, node);
- prev->hw.next_desc = segment->phys;
+ desc->async_tx.phys = segment->phys;
return &desc->async_tx;
@@ -1127,10 +1139,12 @@ static int xilinx_vdma_chan_probe(struct xilinx_vdma_device *xdev,
chan->dev = xdev->dev;
chan->xdev = xdev;
chan->has_sg = xdev->has_sg;
+ chan->desc_pendingcount = 0x0;
spin_lock_init(&chan->lock);
INIT_LIST_HEAD(&chan->pending_list);
INIT_LIST_HEAD(&chan->done_list);
+ INIT_LIST_HEAD(&chan->active_list);
/* Retrieve the channel properties from the device tree */
has_dre = of_property_read_bool(node, "xlnx,include-dre");
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index ef25000a5bc6..37755e63cc28 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -367,14 +367,30 @@ config EDAC_OCTEON_PCI
Support for error detection and correction on the
Cavium Octeon family of SOCs.
-config EDAC_ALTERA_MC
- bool "Altera SDRAM Memory Controller EDAC"
+config EDAC_ALTERA
+ bool "Altera SOCFPGA ECC"
depends on EDAC_MM_EDAC=y && ARCH_SOCFPGA
help
Support for error detection and correction on the
- Altera SDRAM memory controller. Note that the
- preloader must initialize the SDRAM before loading
- the kernel.
+ Altera SOCs. This must be selected for SDRAM ECC.
+ Note that the preloader must initialize the SDRAM
+ before loading the kernel.
+
+config EDAC_ALTERA_L2C
+ bool "Altera L2 Cache ECC"
+ depends on EDAC_ALTERA=y
+ select CACHE_L2X0
+ help
+ Support for error detection and correction on the
+ Altera L2 cache Memory for Altera SoCs. This option
+ requires L2 cache so it will force that selection.
+
+config EDAC_ALTERA_OCRAM
+ bool "Altera On-Chip RAM ECC"
+ depends on EDAC_ALTERA=y && SRAM && GENERIC_ALLOCATOR
+ help
+ Support for error detection and correction on the
+ Altera On-Chip RAM Memory for Altera SoCs.
config EDAC_SYNOPSYS
tristate "Synopsys DDR Memory Controller"
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index be163e20fe56..f9e4a3e0e6e9 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -67,6 +67,6 @@ obj-$(CONFIG_EDAC_OCTEON_L2C) += octeon_edac-l2c.o
obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o
obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o
-obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o
+obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o
obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 929640981d8a..63e42098726d 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1,5 +1,5 @@
/*
- * Copyright Altera Corporation (C) 2014-2015. All rights reserved.
+ * Copyright Altera Corporation (C) 2014-2016. All rights reserved.
* Copyright 2011-2012 Calxeda, Inc.
*
* This program is free software; you can redistribute it and/or modify it
@@ -17,8 +17,10 @@
* Adapted from the highbank_mc_edac driver.
*/
+#include <asm/cacheflush.h>
#include <linux/ctype.h>
#include <linux/edac.h>
+#include <linux/genalloc.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
@@ -34,6 +36,7 @@
#define EDAC_MOD_STR "altera_edac"
#define EDAC_VERSION "1"
+#define EDAC_DEVICE "Altera"
static const struct altr_sdram_prv_data c5_data = {
.ecc_ctrl_offset = CV_CTLCFG_OFST,
@@ -75,6 +78,31 @@ static const struct altr_sdram_prv_data a10_data = {
.ue_set_mask = A10_DIAGINT_TDERRA_MASK,
};
+/************************** EDAC Device Defines **************************/
+
+/* OCRAM ECC Management Group Defines */
+#define ALTR_MAN_GRP_OCRAM_ECC_OFFSET 0x04
+#define ALTR_OCR_ECC_EN BIT(0)
+#define ALTR_OCR_ECC_INJS BIT(1)
+#define ALTR_OCR_ECC_INJD BIT(2)
+#define ALTR_OCR_ECC_SERR BIT(3)
+#define ALTR_OCR_ECC_DERR BIT(4)
+
+/* L2 ECC Management Group Defines */
+#define ALTR_MAN_GRP_L2_ECC_OFFSET 0x00
+#define ALTR_L2_ECC_EN BIT(0)
+#define ALTR_L2_ECC_INJS BIT(1)
+#define ALTR_L2_ECC_INJD BIT(2)
+
+#define ALTR_UE_TRIGGER_CHAR 'U' /* Trigger for UE */
+#define ALTR_TRIGGER_READ_WRD_CNT 32 /* Line size x 4 */
+#define ALTR_TRIG_OCRAM_BYTE_SIZE 128 /* Line size x 4 */
+#define ALTR_TRIG_L2C_BYTE_SIZE 4096 /* Full Page */
+
+/*********************** EDAC Memory Controller Functions ****************/
+
+/* The SDRAM controller uses the EDAC Memory Controller framework. */
+
static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id)
{
struct mem_ctl_info *mci = dev_id;
@@ -504,6 +532,466 @@ static struct platform_driver altr_sdram_edac_driver = {
module_platform_driver(altr_sdram_edac_driver);
+/************************* EDAC Parent Probe *************************/
+
+static const struct of_device_id altr_edac_device_of_match[];
+
+static const struct of_device_id altr_edac_of_match[] = {
+ { .compatible = "altr,socfpga-ecc-manager" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, altr_edac_of_match);
+
+static int altr_edac_probe(struct platform_device *pdev)
+{
+ of_platform_populate(pdev->dev.of_node, altr_edac_device_of_match,
+ NULL, &pdev->dev);
+ return 0;
+}
+
+static struct platform_driver altr_edac_driver = {
+ .probe = altr_edac_probe,
+ .driver = {
+ .name = "socfpga_ecc_manager",
+ .of_match_table = altr_edac_of_match,
+ },
+};
+module_platform_driver(altr_edac_driver);
+
+/************************* EDAC Device Functions *************************/
+
+/*
+ * EDAC Device Functions (shared between various IPs).
+ * The discrete memories use the EDAC Device framework. The probe
+ * and error handling functions are very similar between memories
+ * so they are shared. The memory allocation and freeing for EDAC
+ * trigger testing are different for each memory.
+ */
+
+const struct edac_device_prv_data ocramecc_data;
+const struct edac_device_prv_data l2ecc_data;
+
+struct edac_device_prv_data {
+ int (*setup)(struct platform_device *pdev, void __iomem *base);
+ int ce_clear_mask;
+ int ue_clear_mask;
+ char dbgfs_name[20];
+ void * (*alloc_mem)(size_t size, void **other);
+ void (*free_mem)(void *p, size_t size, void *other);
+ int ecc_enable_mask;
+ int ce_set_mask;
+ int ue_set_mask;
+ int trig_alloc_sz;
+};
+
+struct altr_edac_device_dev {
+ void __iomem *base;
+ int sb_irq;
+ int db_irq;
+ const struct edac_device_prv_data *data;
+ struct dentry *debugfs_dir;
+ char *edac_dev_name;
+};
+
+static irqreturn_t altr_edac_device_handler(int irq, void *dev_id)
+{
+ irqreturn_t ret_value = IRQ_NONE;
+ struct edac_device_ctl_info *dci = dev_id;
+ struct altr_edac_device_dev *drvdata = dci->pvt_info;
+ const struct edac_device_prv_data *priv = drvdata->data;
+
+ if (irq == drvdata->sb_irq) {
+ if (priv->ce_clear_mask)
+ writel(priv->ce_clear_mask, drvdata->base);
+ edac_device_handle_ce(dci, 0, 0, drvdata->edac_dev_name);
+ ret_value = IRQ_HANDLED;
+ } else if (irq == drvdata->db_irq) {
+ if (priv->ue_clear_mask)
+ writel(priv->ue_clear_mask, drvdata->base);
+ edac_device_handle_ue(dci, 0, 0, drvdata->edac_dev_name);
+ panic("\nEDAC:ECC_DEVICE[Uncorrectable errors]\n");
+ ret_value = IRQ_HANDLED;
+ } else {
+ WARN_ON(1);
+ }
+
+ return ret_value;
+}
+
+static ssize_t altr_edac_device_trig(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+
+{
+ u32 *ptemp, i, error_mask;
+ int result = 0;
+ u8 trig_type;
+ unsigned long flags;
+ struct edac_device_ctl_info *edac_dci = file->private_data;
+ struct altr_edac_device_dev *drvdata = edac_dci->pvt_info;
+ const struct edac_device_prv_data *priv = drvdata->data;
+ void *generic_ptr = edac_dci->dev;
+
+ if (!user_buf || get_user(trig_type, user_buf))
+ return -EFAULT;
+
+ if (!priv->alloc_mem)
+ return -ENOMEM;
+
+ /*
+ * Note that generic_ptr is initialized to the device * but in
+ * some alloc_functions, this is overridden and returns data.
+ */
+ ptemp = priv->alloc_mem(priv->trig_alloc_sz, &generic_ptr);
+ if (!ptemp) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Inject: Buffer Allocation error\n");
+ return -ENOMEM;
+ }
+
+ if (trig_type == ALTR_UE_TRIGGER_CHAR)
+ error_mask = priv->ue_set_mask;
+ else
+ error_mask = priv->ce_set_mask;
+
+ edac_printk(KERN_ALERT, EDAC_DEVICE,
+ "Trigger Error Mask (0x%X)\n", error_mask);
+
+ local_irq_save(flags);
+ /* write ECC corrupted data out. */
+ for (i = 0; i < (priv->trig_alloc_sz / sizeof(*ptemp)); i++) {
+ /* Read data so we're in the correct state */
+ rmb();
+ if (ACCESS_ONCE(ptemp[i]))
+ result = -1;
+ /* Toggle Error bit (it is latched), leave ECC enabled */
+ writel(error_mask, drvdata->base);
+ writel(priv->ecc_enable_mask, drvdata->base);
+ ptemp[i] = i;
+ }
+ /* Ensure it has been written out */
+ wmb();
+ local_irq_restore(flags);
+
+ if (result)
+ edac_printk(KERN_ERR, EDAC_DEVICE, "Mem Not Cleared\n");
+
+ /* Read out written data. ECC error caused here */
+ for (i = 0; i < ALTR_TRIGGER_READ_WRD_CNT; i++)
+ if (ACCESS_ONCE(ptemp[i]) != i)
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Read doesn't match written data\n");
+
+ if (priv->free_mem)
+ priv->free_mem(ptemp, priv->trig_alloc_sz, generic_ptr);
+
+ return count;
+}
+
+static const struct file_operations altr_edac_device_inject_fops = {
+ .open = simple_open,
+ .write = altr_edac_device_trig,
+ .llseek = generic_file_llseek,
+};
+
+static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci,
+ const struct edac_device_prv_data *priv)
+{
+ struct altr_edac_device_dev *drvdata = edac_dci->pvt_info;
+
+ if (!IS_ENABLED(CONFIG_EDAC_DEBUG))
+ return;
+
+ drvdata->debugfs_dir = edac_debugfs_create_dir(drvdata->edac_dev_name);
+ if (!drvdata->debugfs_dir)
+ return;
+
+ if (!edac_debugfs_create_file(priv->dbgfs_name, S_IWUSR,
+ drvdata->debugfs_dir, edac_dci,
+ &altr_edac_device_inject_fops))
+ debugfs_remove_recursive(drvdata->debugfs_dir);
+}
+
+static const struct of_device_id altr_edac_device_of_match[] = {
+#ifdef CONFIG_EDAC_ALTERA_L2C
+ { .compatible = "altr,socfpga-l2-ecc", .data = (void *)&l2ecc_data },
+#endif
+#ifdef CONFIG_EDAC_ALTERA_OCRAM
+ { .compatible = "altr,socfpga-ocram-ecc",
+ .data = (void *)&ocramecc_data },
+#endif
+ {},
+};
+MODULE_DEVICE_TABLE(of, altr_edac_device_of_match);
+
+/*
+ * altr_edac_device_probe()
+ * This is a generic EDAC device driver that will support
+ * various Altera memory devices such as the L2 cache ECC and
+ * OCRAM ECC as well as the memories for other peripherals.
+ * Module specific initialization is done by passing the
+ * function index in the device tree.
+ */
+static int altr_edac_device_probe(struct platform_device *pdev)
+{
+ struct edac_device_ctl_info *dci;
+ struct altr_edac_device_dev *drvdata;
+ struct resource *r;
+ int res = 0;
+ struct device_node *np = pdev->dev.of_node;
+ char *ecc_name = (char *)np->name;
+ static int dev_instance;
+
+ if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Unable to open devm\n");
+ return -ENOMEM;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Unable to get mem resource\n");
+ res = -ENODEV;
+ goto fail;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
+ dev_name(&pdev->dev))) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "%s:Error requesting mem region\n", ecc_name);
+ res = -EBUSY;
+ goto fail;
+ }
+
+ dci = edac_device_alloc_ctl_info(sizeof(*drvdata), ecc_name,
+ 1, ecc_name, 1, 0, NULL, 0,
+ dev_instance++);
+
+ if (!dci) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "%s: Unable to allocate EDAC device\n", ecc_name);
+ res = -ENOMEM;
+ goto fail;
+ }
+
+ drvdata = dci->pvt_info;
+ dci->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dci);
+ drvdata->edac_dev_name = ecc_name;
+
+ drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+ if (!drvdata->base)
+ goto fail1;
+
+ /* Get driver specific data for this EDAC device */
+ drvdata->data = of_match_node(altr_edac_device_of_match, np)->data;
+
+ /* Check specific dependencies for the module */
+ if (drvdata->data->setup) {
+ res = drvdata->data->setup(pdev, drvdata->base);
+ if (res)
+ goto fail1;
+ }
+
+ drvdata->sb_irq = platform_get_irq(pdev, 0);
+ res = devm_request_irq(&pdev->dev, drvdata->sb_irq,
+ altr_edac_device_handler,
+ 0, dev_name(&pdev->dev), dci);
+ if (res)
+ goto fail1;
+
+ drvdata->db_irq = platform_get_irq(pdev, 1);
+ res = devm_request_irq(&pdev->dev, drvdata->db_irq,
+ altr_edac_device_handler,
+ 0, dev_name(&pdev->dev), dci);
+ if (res)
+ goto fail1;
+
+ dci->mod_name = "Altera ECC Manager";
+ dci->dev_name = drvdata->edac_dev_name;
+
+ res = edac_device_add_device(dci);
+ if (res)
+ goto fail1;
+
+ altr_create_edacdev_dbgfs(dci, drvdata->data);
+
+ devres_close_group(&pdev->dev, NULL);
+
+ return 0;
+
+fail1:
+ edac_device_free_ctl_info(dci);
+fail:
+ devres_release_group(&pdev->dev, NULL);
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "%s:Error setting up EDAC device: %d\n", ecc_name, res);
+
+ return res;
+}
+
+static int altr_edac_device_remove(struct platform_device *pdev)
+{
+ struct edac_device_ctl_info *dci = platform_get_drvdata(pdev);
+ struct altr_edac_device_dev *drvdata = dci->pvt_info;
+
+ debugfs_remove_recursive(drvdata->debugfs_dir);
+ edac_device_del_device(&pdev->dev);
+ edac_device_free_ctl_info(dci);
+
+ return 0;
+}
+
+static struct platform_driver altr_edac_device_driver = {
+ .probe = altr_edac_device_probe,
+ .remove = altr_edac_device_remove,
+ .driver = {
+ .name = "altr_edac_device",
+ .of_match_table = altr_edac_device_of_match,
+ },
+};
+module_platform_driver(altr_edac_device_driver);
+
+/*********************** OCRAM EDAC Device Functions *********************/
+
+#ifdef CONFIG_EDAC_ALTERA_OCRAM
+
+static void *ocram_alloc_mem(size_t size, void **other)
+{
+ struct device_node *np;
+ struct gen_pool *gp;
+ void *sram_addr;
+
+ np = of_find_compatible_node(NULL, NULL, "altr,socfpga-ocram-ecc");
+ if (!np)
+ return NULL;
+
+ gp = of_gen_pool_get(np, "iram", 0);
+ of_node_put(np);
+ if (!gp)
+ return NULL;
+
+ sram_addr = (void *)gen_pool_alloc(gp, size);
+ if (!sram_addr)
+ return NULL;
+
+ memset(sram_addr, 0, size);
+ /* Ensure data is written out */
+ wmb();
+
+ /* Remember this handle for freeing later */
+ *other = gp;
+
+ return sram_addr;
+}
+
+static void ocram_free_mem(void *p, size_t size, void *other)
+{
+ gen_pool_free((struct gen_pool *)other, (u32)p, size);
+}
+
+/*
+ * altr_ocram_check_deps()
+ * Test for OCRAM cache ECC dependencies upon entry because
+ * platform specific startup should have initialized the
+ * On-Chip RAM memory and enabled the ECC.
+ * Can't turn on ECC here because accessing un-initialized
+ * memory will cause CE/UE errors possibly causing an ABORT.
+ */
+static int altr_ocram_check_deps(struct platform_device *pdev,
+ void __iomem *base)
+{
+ if (readl(base) & ALTR_OCR_ECC_EN)
+ return 0;
+
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "OCRAM: No ECC present or ECC disabled.\n");
+ return -ENODEV;
+}
+
+const struct edac_device_prv_data ocramecc_data = {
+ .setup = altr_ocram_check_deps,
+ .ce_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_SERR),
+ .ue_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_DERR),
+ .dbgfs_name = "altr_ocram_trigger",
+ .alloc_mem = ocram_alloc_mem,
+ .free_mem = ocram_free_mem,
+ .ecc_enable_mask = ALTR_OCR_ECC_EN,
+ .ce_set_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_INJS),
+ .ue_set_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_INJD),
+ .trig_alloc_sz = ALTR_TRIG_OCRAM_BYTE_SIZE,
+};
+
+#endif /* CONFIG_EDAC_ALTERA_OCRAM */
+
+/********************* L2 Cache EDAC Device Functions ********************/
+
+#ifdef CONFIG_EDAC_ALTERA_L2C
+
+static void *l2_alloc_mem(size_t size, void **other)
+{
+ struct device *dev = *other;
+ void *ptemp = devm_kzalloc(dev, size, GFP_KERNEL);
+
+ if (!ptemp)
+ return NULL;
+
+ /* Make sure everything is written out */
+ wmb();
+
+ /*
+ * Clean all cache levels up to LoC (includes L2)
+ * This ensures the corrupted data is written into
+ * L2 cache for readback test (which causes ECC error).
+ */
+ flush_cache_all();
+
+ return ptemp;
+}
+
+static void l2_free_mem(void *p, size_t size, void *other)
+{
+ struct device *dev = other;
+
+ if (dev && p)
+ devm_kfree(dev, p);
+}
+
+/*
+ * altr_l2_check_deps()
+ * Test for L2 cache ECC dependencies upon entry because
+ * platform specific startup should have initialized the L2
+ * memory and enabled the ECC.
+ * Bail if ECC is not enabled.
+ * Note that L2 Cache Enable is forced at build time.
+ */
+static int altr_l2_check_deps(struct platform_device *pdev,
+ void __iomem *base)
+{
+ if (readl(base) & ALTR_L2_ECC_EN)
+ return 0;
+
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "L2: No ECC present, or ECC disabled\n");
+ return -ENODEV;
+}
+
+const struct edac_device_prv_data l2ecc_data = {
+ .setup = altr_l2_check_deps,
+ .ce_clear_mask = 0,
+ .ue_clear_mask = 0,
+ .dbgfs_name = "altr_l2_trigger",
+ .alloc_mem = l2_alloc_mem,
+ .free_mem = l2_free_mem,
+ .ecc_enable_mask = ALTR_L2_ECC_EN,
+ .ce_set_mask = (ALTR_L2_ECC_EN | ALTR_L2_ECC_INJS),
+ .ue_set_mask = (ALTR_L2_ECC_EN | ALTR_L2_ECC_INJD),
+ .trig_alloc_sz = ALTR_TRIG_L2C_BYTE_SIZE,
+};
+
+#endif /* CONFIG_EDAC_ALTERA_L2C */
+
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Thor Thayer");
-MODULE_DESCRIPTION("EDAC Driver for Altera SDRAM Controller");
+MODULE_DESCRIPTION("EDAC Driver for Altera Memories");
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 9eee13ef83a5..d87a47547ba5 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1452,7 +1452,7 @@ static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
u64 chan_off;
u64 dram_base = get_dram_base(pvt, range);
u64 hole_off = f10_dhar_offset(pvt);
- u64 dct_sel_base_off = (pvt->dct_sel_hi & 0xFFFFFC00) << 16;
+ u64 dct_sel_base_off = (u64)(pvt->dct_sel_hi & 0xFFFFFC00) << 16;
if (hi_rng) {
/*
diff --git a/drivers/edac/debugfs.c b/drivers/edac/debugfs.c
index 54d2f668cb0a..92dbb7e2320c 100644
--- a/drivers/edac/debugfs.c
+++ b/drivers/edac/debugfs.c
@@ -53,7 +53,7 @@ int __init edac_debugfs_init(void)
void edac_debugfs_exit(void)
{
- debugfs_remove(edac_debugfs);
+ debugfs_remove_recursive(edac_debugfs);
}
int edac_create_debugfs_nodes(struct mem_ctl_info *mci)
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 8adfc167c2e3..1472f48c8ac6 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -535,60 +535,21 @@ static void edac_mc_workq_function(struct work_struct *work_req)
mutex_lock(&mem_ctls_mutex);
- /* if this control struct has movd to offline state, we are done */
- if (mci->op_state == OP_OFFLINE) {
+ if (mci->op_state != OP_RUNNING_POLL) {
mutex_unlock(&mem_ctls_mutex);
return;
}
- /* Only poll controllers that are running polled and have a check */
- if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL))
+ if (edac_mc_assert_error_check_and_clear())
mci->edac_check(mci);
mutex_unlock(&mem_ctls_mutex);
- /* Reschedule */
+ /* Queue ourselves again. */
edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec()));
}
/*
- * edac_mc_workq_setup
- * initialize a workq item for this mci
- * passing in the new delay period in msec
- *
- * locking model:
- *
- * called with the mem_ctls_mutex held
- */
-static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
-{
- edac_dbg(0, "\n");
-
- /* if this instance is not in the POLL state, then simply return */
- if (mci->op_state != OP_RUNNING_POLL)
- return;
-
- INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
-
- edac_queue_work(&mci->work, msecs_to_jiffies(msec));
-}
-
-/*
- * edac_mc_workq_teardown
- * stop the workq processing on this mci
- *
- * locking model:
- *
- * called WITHOUT lock held
- */
-static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
-{
- mci->op_state = OP_OFFLINE;
-
- edac_stop_work(&mci->work);
-}
-
-/*
* edac_mc_reset_delay_period(unsigned long value)
*
* user space has updated our poll period value, need to
@@ -771,12 +732,12 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
goto fail1;
}
- /* If there IS a check routine, then we are running POLLED */
- if (mci->edac_check != NULL) {
- /* This instance is NOW RUNNING */
+ if (mci->edac_check) {
mci->op_state = OP_RUNNING_POLL;
- edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
+ INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+ edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec()));
+
} else {
mci->op_state = OP_RUNNING_INTERRUPT;
}
@@ -823,15 +784,16 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
return NULL;
}
+ /* mark MCI offline: */
+ mci->op_state = OP_OFFLINE;
+
if (!del_mc_from_global_list(mci))
edac_mc_owner = NULL;
- mutex_unlock(&mem_ctls_mutex);
- /* flush workq processes */
- edac_mc_workq_teardown(mci);
+ mutex_unlock(&mem_ctls_mutex);
- /* marking MCI offline */
- mci->op_state = OP_OFFLINE;
+ if (mci->edac_check)
+ edac_stop_work(&mci->work);
/* remove from sysfs */
edac_remove_sysfs_mci_device(mci);
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
index 99685388d3fb..8f2f2899a7a2 100644
--- a/drivers/edac/edac_pci.c
+++ b/drivers/edac/edac_pci.c
@@ -195,55 +195,24 @@ static void edac_pci_workq_function(struct work_struct *work_req)
mutex_lock(&edac_pci_ctls_mutex);
- if (pci->op_state == OP_RUNNING_POLL) {
- /* we might be in POLL mode, but there may NOT be a poll func
- */
- if ((pci->edac_check != NULL) && edac_pci_get_check_errors())
- pci->edac_check(pci);
-
- /* if we are on a one second period, then use round */
- msec = edac_pci_get_poll_msec();
- if (msec == 1000)
- delay = round_jiffies_relative(msecs_to_jiffies(msec));
- else
- delay = msecs_to_jiffies(msec);
-
- /* Reschedule only if we are in POLL mode */
- edac_queue_work(&pci->work, delay);
+ if (pci->op_state != OP_RUNNING_POLL) {
+ mutex_unlock(&edac_pci_ctls_mutex);
+ return;
}
- mutex_unlock(&edac_pci_ctls_mutex);
-}
-
-/*
- * edac_pci_workq_setup()
- * initialize a workq item for this edac_pci instance
- * passing in the new delay period in msec
- *
- * locking model:
- * called when 'edac_pci_ctls_mutex' is locked
- */
-static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
- unsigned int msec)
-{
- edac_dbg(0, "\n");
+ if (edac_pci_get_check_errors())
+ pci->edac_check(pci);
- INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
+ /* if we are on a one second period, then use round */
+ msec = edac_pci_get_poll_msec();
+ if (msec == 1000)
+ delay = round_jiffies_relative(msecs_to_jiffies(msec));
+ else
+ delay = msecs_to_jiffies(msec);
- edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec()));
-}
+ edac_queue_work(&pci->work, delay);
-/*
- * edac_pci_workq_teardown()
- * stop the workq processing on this edac_pci instance
- */
-static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
-{
- edac_dbg(0, "\n");
-
- pci->op_state = OP_OFFLINE;
-
- edac_stop_work(&pci->work);
+ mutex_unlock(&edac_pci_ctls_mutex);
}
/*
@@ -289,10 +258,12 @@ int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
goto fail1;
}
- if (pci->edac_check != NULL) {
+ if (pci->edac_check) {
pci->op_state = OP_RUNNING_POLL;
- edac_pci_workq_setup(pci, 1000);
+ INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
+ edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec()));
+
} else {
pci->op_state = OP_RUNNING_INTERRUPT;
}
@@ -350,8 +321,8 @@ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
mutex_unlock(&edac_pci_ctls_mutex);
- /* stop the workq timer */
- edac_pci_workq_teardown(pci);
+ if (pci->edac_check)
+ edac_stop_work(&pci->work);
edac_printk(KERN_INFO, EDAC_PCI,
"Removed device %d for %s %s: DEV %s\n",
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index e3a945ce374b..49768c08ac07 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -147,6 +147,135 @@ static const char * const mc6_mce_desc[] = {
"Status Register File",
};
+/* Scalable MCA error strings */
+static const char * const f17h_ls_mce_desc[] = {
+ "Load queue parity",
+ "Store queue parity",
+ "Miss address buffer payload parity",
+ "L1 TLB parity",
+ "", /* reserved */
+ "DC tag error type 6",
+ "DC tag error type 1",
+ "Internal error type 1",
+ "Internal error type 2",
+ "Sys Read data error thread 0",
+ "Sys read data error thread 1",
+ "DC tag error type 2",
+ "DC data error type 1 (poison comsumption)",
+ "DC data error type 2",
+ "DC data error type 3",
+ "DC tag error type 4",
+ "L2 TLB parity",
+ "PDC parity error",
+ "DC tag error type 3",
+ "DC tag error type 5",
+ "L2 fill data error",
+};
+
+static const char * const f17h_if_mce_desc[] = {
+ "microtag probe port parity error",
+ "IC microtag or full tag multi-hit error",
+ "IC full tag parity",
+ "IC data array parity",
+ "Decoupling queue phys addr parity error",
+ "L0 ITLB parity error",
+ "L1 ITLB parity error",
+ "L2 ITLB parity error",
+ "BPQ snoop parity on Thread 0",
+ "BPQ snoop parity on Thread 1",
+ "L1 BTB multi-match error",
+ "L2 BTB multi-match error",
+};
+
+static const char * const f17h_l2_mce_desc[] = {
+ "L2M tag multi-way-hit error",
+ "L2M tag ECC error",
+ "L2M data ECC error",
+ "HW assert",
+};
+
+static const char * const f17h_de_mce_desc[] = {
+ "uop cache tag parity error",
+ "uop cache data parity error",
+ "Insn buffer parity error",
+ "Insn dispatch queue parity error",
+ "Fetch address FIFO parity",
+ "Patch RAM data parity",
+ "Patch RAM sequencer parity",
+ "uop buffer parity"
+};
+
+static const char * const f17h_ex_mce_desc[] = {
+ "Watchdog timeout error",
+ "Phy register file parity",
+ "Flag register file parity",
+ "Immediate displacement register file parity",
+ "Address generator payload parity",
+ "EX payload parity",
+ "Checkpoint queue parity",
+ "Retire dispatch queue parity",
+};
+
+static const char * const f17h_fp_mce_desc[] = {
+ "Physical register file parity",
+ "Freelist parity error",
+ "Schedule queue parity",
+ "NSQ parity error",
+ "Retire queue parity",
+ "Status register file parity",
+};
+
+static const char * const f17h_l3_mce_desc[] = {
+ "Shadow tag macro ECC error",
+ "Shadow tag macro multi-way-hit error",
+ "L3M tag ECC error",
+ "L3M tag multi-way-hit error",
+ "L3M data ECC error",
+ "XI parity, L3 fill done channel error",
+ "L3 victim queue parity",
+ "L3 HW assert",
+};
+
+static const char * const f17h_cs_mce_desc[] = {
+ "Illegal request from transport layer",
+ "Address violation",
+ "Security violation",
+ "Illegal response from transport layer",
+ "Unexpected response",
+ "Parity error on incoming request or probe response data",
+ "Parity error on incoming read response data",
+ "Atomic request parity",
+ "ECC error on probe filter access",
+};
+
+static const char * const f17h_pie_mce_desc[] = {
+ "HW assert",
+ "Internal PIE register security violation",
+ "Error on GMI link",
+ "Poison data written to internal PIE register",
+};
+
+static const char * const f17h_umc_mce_desc[] = {
+ "DRAM ECC error",
+ "Data poison error on DRAM",
+ "SDP parity error",
+ "Advanced peripheral bus error",
+ "Command/address parity error",
+ "Write data CRC error",
+};
+
+static const char * const f17h_pb_mce_desc[] = {
+ "Parameter Block RAM ECC error",
+};
+
+static const char * const f17h_psp_mce_desc[] = {
+ "PSP RAM ECC or parity error",
+};
+
+static const char * const f17h_smu_mce_desc[] = {
+ "SMU RAM ECC or parity error",
+};
+
static bool f12h_mc0_mce(u16 ec, u8 xec)
{
bool ret = false;
@@ -691,6 +820,177 @@ static void decode_mc6_mce(struct mce *m)
pr_emerg(HW_ERR "Corrupted MC6 MCE info?\n");
}
+static void decode_f17h_core_errors(const char *ip_name, u8 xec,
+ unsigned int mca_type)
+{
+ const char * const *error_desc_array;
+ size_t len;
+
+ pr_emerg(HW_ERR "%s Error: ", ip_name);
+
+ switch (mca_type) {
+ case SMCA_LS:
+ error_desc_array = f17h_ls_mce_desc;
+ len = ARRAY_SIZE(f17h_ls_mce_desc) - 1;
+
+ if (xec == 0x4) {
+ pr_cont("Unrecognized LS MCA error code.\n");
+ return;
+ }
+ break;
+
+ case SMCA_IF:
+ error_desc_array = f17h_if_mce_desc;
+ len = ARRAY_SIZE(f17h_if_mce_desc) - 1;
+ break;
+
+ case SMCA_L2_CACHE:
+ error_desc_array = f17h_l2_mce_desc;
+ len = ARRAY_SIZE(f17h_l2_mce_desc) - 1;
+ break;
+
+ case SMCA_DE:
+ error_desc_array = f17h_de_mce_desc;
+ len = ARRAY_SIZE(f17h_de_mce_desc) - 1;
+ break;
+
+ case SMCA_EX:
+ error_desc_array = f17h_ex_mce_desc;
+ len = ARRAY_SIZE(f17h_ex_mce_desc) - 1;
+ break;
+
+ case SMCA_FP:
+ error_desc_array = f17h_fp_mce_desc;
+ len = ARRAY_SIZE(f17h_fp_mce_desc) - 1;
+ break;
+
+ case SMCA_L3_CACHE:
+ error_desc_array = f17h_l3_mce_desc;
+ len = ARRAY_SIZE(f17h_l3_mce_desc) - 1;
+ break;
+
+ default:
+ pr_cont("Corrupted MCA core error info.\n");
+ return;
+ }
+
+ if (xec > len) {
+ pr_cont("Unrecognized %s MCA bank error code.\n",
+ amd_core_mcablock_names[mca_type]);
+ return;
+ }
+
+ pr_cont("%s.\n", error_desc_array[xec]);
+}
+
+static void decode_df_errors(u8 xec, unsigned int mca_type)
+{
+ const char * const *error_desc_array;
+ size_t len;
+
+ pr_emerg(HW_ERR "Data Fabric Error: ");
+
+ switch (mca_type) {
+ case SMCA_CS:
+ error_desc_array = f17h_cs_mce_desc;
+ len = ARRAY_SIZE(f17h_cs_mce_desc) - 1;
+ break;
+
+ case SMCA_PIE:
+ error_desc_array = f17h_pie_mce_desc;
+ len = ARRAY_SIZE(f17h_pie_mce_desc) - 1;
+ break;
+
+ default:
+ pr_cont("Corrupted MCA Data Fabric info.\n");
+ return;
+ }
+
+ if (xec > len) {
+ pr_cont("Unrecognized %s MCA bank error code.\n",
+ amd_df_mcablock_names[mca_type]);
+ return;
+ }
+
+ pr_cont("%s.\n", error_desc_array[xec]);
+}
+
+/* Decode errors according to Scalable MCA specification */
+static void decode_smca_errors(struct mce *m)
+{
+ u32 addr = MSR_AMD64_SMCA_MCx_IPID(m->bank);
+ unsigned int hwid, mca_type, i;
+ u8 xec = XEC(m->status, xec_mask);
+ const char * const *error_desc_array;
+ const char *ip_name;
+ u32 low, high;
+ size_t len;
+
+ if (rdmsr_safe(addr, &low, &high)) {
+ pr_emerg("Invalid IP block specified, error information is unreliable.\n");
+ return;
+ }
+
+ hwid = high & MCI_IPID_HWID;
+ mca_type = (high & MCI_IPID_MCATYPE) >> 16;
+
+ pr_emerg(HW_ERR "MC%d IPID value: 0x%08x%08x\n", m->bank, high, low);
+
+ /*
+ * Based on hwid and mca_type values, decode errors from respective IPs.
+ * Note: mca_type values make sense only in the context of an hwid.
+ */
+ for (i = 0; i < ARRAY_SIZE(amd_hwids); i++)
+ if (amd_hwids[i].hwid == hwid)
+ break;
+
+ switch (i) {
+ case SMCA_F17H_CORE:
+ ip_name = (mca_type == SMCA_L3_CACHE) ?
+ "L3 Cache" : "F17h Core";
+ return decode_f17h_core_errors(ip_name, xec, mca_type);
+ break;
+
+ case SMCA_DF:
+ return decode_df_errors(xec, mca_type);
+ break;
+
+ case SMCA_UMC:
+ error_desc_array = f17h_umc_mce_desc;
+ len = ARRAY_SIZE(f17h_umc_mce_desc) - 1;
+ break;
+
+ case SMCA_PB:
+ error_desc_array = f17h_pb_mce_desc;
+ len = ARRAY_SIZE(f17h_pb_mce_desc) - 1;
+ break;
+
+ case SMCA_PSP:
+ error_desc_array = f17h_psp_mce_desc;
+ len = ARRAY_SIZE(f17h_psp_mce_desc) - 1;
+ break;
+
+ case SMCA_SMU:
+ error_desc_array = f17h_smu_mce_desc;
+ len = ARRAY_SIZE(f17h_smu_mce_desc) - 1;
+ break;
+
+ default:
+ pr_emerg(HW_ERR "HWID:%d does not match any existing IPs.\n", hwid);
+ return;
+ }
+
+ ip_name = amd_hwids[i].name;
+ pr_emerg(HW_ERR "%s Error: ", ip_name);
+
+ if (xec > len) {
+ pr_cont("Unrecognized %s MCA bank error code.\n", ip_name);
+ return;
+ }
+
+ pr_cont("%s.\n", error_desc_array[xec]);
+}
+
static inline void amd_decode_err_code(u16 ec)
{
if (INT_ERROR(ec)) {
@@ -752,6 +1052,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
struct mce *m = (struct mce *)data;
struct cpuinfo_x86 *c = &cpu_data(m->extcpu);
int ecc;
+ u32 ebx = cpuid_ebx(0x80000007);
if (amd_filter_mce(m))
return NOTIFY_STOP;
@@ -769,11 +1070,20 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
- if (c->x86 == 0x15 || c->x86 == 0x16)
+ if (c->x86 >= 0x15)
pr_cont("|%s|%s",
((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
((m->status & MCI_STATUS_POISON) ? "Poison" : "-"));
+ if (!!(ebx & BIT(3))) {
+ u32 low, high;
+ u32 addr = MSR_AMD64_SMCA_MCx_CONFIG(m->bank);
+
+ if (!rdmsr_safe(addr, &low, &high) &&
+ (low & MCI_CONFIG_MCAX))
+ pr_cont("|%s", ((m->status & MCI_STATUS_TCC) ? "TCC" : "-"));
+ }
+
/* do the two bits[14:13] together */
ecc = (m->status >> 45) & 0x3;
if (ecc)
@@ -784,6 +1094,11 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
if (m->status & MCI_STATUS_ADDRV)
pr_emerg(HW_ERR "MC%d Error Address: 0x%016llx\n", m->bank, m->addr);
+ if (!!(ebx & BIT(3))) {
+ decode_smca_errors(m);
+ goto err_code;
+ }
+
if (!fam_ops)
goto err_code;
@@ -834,6 +1149,7 @@ static struct notifier_block amd_mce_dec_nb = {
static int __init mce_amd_init(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
+ u32 ebx;
if (c->x86_vendor != X86_VENDOR_AMD)
return -ENODEV;
@@ -888,10 +1204,18 @@ static int __init mce_amd_init(void)
fam_ops->mc2_mce = f16h_mc2_mce;
break;
+ case 0x17:
+ ebx = cpuid_ebx(0x80000007);
+ xec_mask = 0x3f;
+ if (!(ebx & BIT(3))) {
+ printk(KERN_WARNING "Decoding supported only on Scalable MCA processors.\n");
+ goto err_out;
+ }
+ break;
+
default:
printk(KERN_WARNING "Huh? What family is it: 0x%x?!\n", c->x86);
- kfree(fam_ops);
- fam_ops = NULL;
+ goto err_out;
}
pr_info("MCE: In-kernel MCE decoding enabled.\n");
@@ -899,6 +1223,11 @@ static int __init mce_amd_init(void)
mce_register_decode_chain(&amd_mce_dec_nb);
return 0;
+
+err_out:
+ kfree(fam_ops);
+ fam_ops = NULL;
+ return -EINVAL;
}
early_initcall(mce_amd_init);
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index b7139c160baf..ca63d0da8889 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -1244,7 +1244,7 @@ static struct platform_driver * const drivers[] = {
static int __init mpc85xx_mc_init(void)
{
int res = 0;
- u32 pvr = 0;
+ u32 __maybe_unused pvr = 0;
printk(KERN_INFO "Freescale(R) MPC85xx EDAC driver, "
"(C) 2006 Montavista Software\n");
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index e438ee5b433f..93f0d4120289 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -1574,7 +1574,7 @@ static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
for (cha = 0; cha < KNL_MAX_CHAS; cha++) {
if (knl_get_mc_route(target,
mc_route_reg[cha]) == channel
- && participants[channel]) {
+ && !participants[channel]) {
participant_count++;
participants[channel] = 1;
break;
@@ -1839,8 +1839,8 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
n_tads, gb, (mb*1000)/1024,
((u64)tmp_mb) << 20L,
- (u32)TAD_SOCK(reg),
- (u32)TAD_CH(reg),
+ (u32)(1 << TAD_SOCK(reg)),
+ (u32)TAD_CH(reg) + 1,
(u32)TAD_TGT0(reg),
(u32)TAD_TGT1(reg),
(u32)TAD_TGT2(reg),
@@ -2118,7 +2118,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
}
ch_way = TAD_CH(reg) + 1;
- sck_way = TAD_SOCK(reg) + 1;
+ sck_way = 1 << TAD_SOCK(reg);
if (ch_way == 3)
idx = addr >> 6;
@@ -2175,7 +2175,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
n_tads,
addr,
limit,
- (u32)TAD_SOCK(reg),
+ sck_way,
ch_way,
offset,
idx,
@@ -2190,18 +2190,12 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
offset, addr);
return -EINVAL;
}
- addr -= offset;
- /* Store the low bits [0:6] of the addr */
- ch_addr = addr & 0x7f;
- /* Remove socket wayness and remove 6 bits */
- addr >>= 6;
- addr = div_u64(addr, sck_xch);
-#if 0
- /* Divide by channel way */
- addr = addr / ch_way;
-#endif
- /* Recover the last 6 bits */
- ch_addr |= addr << 6;
+
+ ch_addr = addr - offset;
+ ch_addr >>= (6 + shiftup);
+ ch_addr /= ch_way * sck_way;
+ ch_addr <<= (6 + shiftup);
+ ch_addr |= addr & ((1 << (6 + shiftup)) - 1);
/*
* Step 3) Decode rank
diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c
index 41f876414a18..bf19b6e3bd12 100644
--- a/drivers/edac/xgene_edac.c
+++ b/drivers/edac/xgene_edac.c
@@ -61,6 +61,7 @@ struct xgene_edac {
struct regmap *mcba_map;
struct regmap *mcbb_map;
struct regmap *efuse_map;
+ struct regmap *rb_map;
void __iomem *pcp_csr;
spinlock_t lock;
struct dentry *dfs;
@@ -1057,7 +1058,7 @@ static bool xgene_edac_l3_promote_to_uc_err(u32 l3cesr, u32 l3celr)
case 0x041:
return true;
}
- } else if (L3C_ELR_ERRSYN(l3celr) == 9)
+ } else if (L3C_ELR_ERRWAY(l3celr) == 9)
return true;
return false;
@@ -1353,6 +1354,17 @@ static int xgene_edac_l3_remove(struct xgene_edac_dev_ctx *l3)
#define GLBL_MDED_ERRH 0x0848
#define GLBL_MDED_ERRHMASK 0x084c
+/* IO Bus Registers */
+#define RBCSR 0x0000
+#define STICKYERR_MASK BIT(0)
+#define RBEIR 0x0008
+#define AGENT_OFFLINE_ERR_MASK BIT(30)
+#define UNIMPL_RBPAGE_ERR_MASK BIT(29)
+#define WORD_ALIGNED_ERR_MASK BIT(28)
+#define PAGE_ACCESS_ERR_MASK BIT(27)
+#define WRITE_ACCESS_MASK BIT(26)
+#define RBERRADDR_RD(src) ((src) & 0x03FFFFFF)
+
static const char * const soc_mem_err_v1[] = {
"10GbE0",
"10GbE1",
@@ -1470,6 +1482,51 @@ static void xgene_edac_rb_report(struct edac_device_ctl_info *edac_dev)
u32 err_addr_hi;
u32 reg;
+ /* If the register bus resource isn't available, just skip it */
+ if (!ctx->edac->rb_map)
+ goto rb_skip;
+
+ /*
+ * Check RB access errors
+ * 1. Out of range
+ * 2. Un-implemented page
+ * 3. Un-aligned access
+ * 4. Offline slave IP
+ */
+ if (regmap_read(ctx->edac->rb_map, RBCSR, &reg))
+ return;
+ if (reg & STICKYERR_MASK) {
+ bool write;
+ u32 address;
+
+ dev_err(edac_dev->dev, "IOB bus access error(s)\n");
+ if (regmap_read(ctx->edac->rb_map, RBEIR, &reg))
+ return;
+ write = reg & WRITE_ACCESS_MASK ? 1 : 0;
+ address = RBERRADDR_RD(reg);
+ if (reg & AGENT_OFFLINE_ERR_MASK)
+ dev_err(edac_dev->dev,
+ "IOB bus %s access to offline agent error\n",
+ write ? "write" : "read");
+ if (reg & UNIMPL_RBPAGE_ERR_MASK)
+ dev_err(edac_dev->dev,
+ "IOB bus %s access to unimplemented page error\n",
+ write ? "write" : "read");
+ if (reg & WORD_ALIGNED_ERR_MASK)
+ dev_err(edac_dev->dev,
+ "IOB bus %s word aligned access error\n",
+ write ? "write" : "read");
+ if (reg & PAGE_ACCESS_ERR_MASK)
+ dev_err(edac_dev->dev,
+ "IOB bus %s to page out of range access error\n",
+ write ? "write" : "read");
+ if (regmap_write(ctx->edac->rb_map, RBEIR, 0))
+ return;
+ if (regmap_write(ctx->edac->rb_map, RBCSR, 0))
+ return;
+ }
+rb_skip:
+
/* IOB Bridge agent transaction error interrupt */
reg = readl(ctx->dev_csr + IOBBATRANSERRINTSTS);
if (!reg)
@@ -1852,6 +1909,17 @@ static int xgene_edac_probe(struct platform_device *pdev)
goto out_err;
}
+ /*
+ * NOTE: The register bus resource is optional for compatibility
+ * reason.
+ */
+ edac->rb_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "regmap-rb");
+ if (IS_ERR(edac->rb_map)) {
+ dev_warn(edac->dev, "missing syscon regmap rb\n");
+ edac->rb_map = NULL;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
edac->pcp_csr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(edac->pcp_csr)) {
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index c121d01a5cd6..1d8e0a57bd51 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -185,7 +185,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
break;
};
- mutex_lock(&arizona->dapm->card->dapm_mutex);
+ snd_soc_dapm_mutex_lock(arizona->dapm);
arizona->hpdet_clamp = clamp;
@@ -227,7 +227,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
ret);
}
- mutex_unlock(&arizona->dapm->card->dapm_mutex);
+ snd_soc_dapm_mutex_unlock(arizona->dapm);
}
static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index 279ff8f6637d..d023789f0fda 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -126,7 +126,7 @@ static int gpio_extcon_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&data->work, gpio_extcon_work);
/*
- * Request the interrput of gpio to detect whether external connector
+ * Request the interrupt of gpio to detect whether external connector
* is attached or detached.
*/
ret = devm_request_any_context_irq(&pdev->dev, data->irq,
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index b30ab97ce75f..852a7112f451 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -150,6 +150,7 @@ enum max14577_muic_acc_type {
static const unsigned int max14577_extcon_cable[] = {
EXTCON_USB,
+ EXTCON_CHG_USB_SDP,
EXTCON_CHG_USB_DCP,
EXTCON_CHG_USB_FAST,
EXTCON_CHG_USB_SLOW,
@@ -454,6 +455,8 @@ static int max14577_muic_chg_handler(struct max14577_muic_info *info)
return ret;
extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP,
+ attached);
break;
case MAX14577_CHARGER_TYPE_DEDICATED_CHG:
extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP,
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index fdf8f5d4d4e9..f17cb76b567c 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -204,6 +204,7 @@ enum max77693_muic_acc_type {
static const unsigned int max77693_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
+ EXTCON_CHG_USB_SDP,
EXTCON_CHG_USB_DCP,
EXTCON_CHG_USB_FAST,
EXTCON_CHG_USB_SLOW,
@@ -512,8 +513,11 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
break;
case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
dock_id = EXTCON_DOCK;
- if (!attached)
+ if (!attached) {
extcon_set_cable_state_(info->edev, EXTCON_USB, false);
+ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP,
+ false);
+ }
break;
default:
dev_err(info->dev, "failed to detect %s dock device\n",
@@ -601,6 +605,8 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
if (ret < 0)
return ret;
extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP,
+ attached);
break;
case MAX77693_MUIC_GND_MHL:
case MAX77693_MUIC_GND_MHL_VB:
@@ -830,6 +836,8 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
*/
extcon_set_cable_state_(info->edev, EXTCON_USB,
attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP,
+ attached);
if (!cable_attached)
extcon_set_cable_state_(info->edev, EXTCON_DOCK,
@@ -899,6 +907,8 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
extcon_set_cable_state_(info->edev, EXTCON_USB,
attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP,
+ attached);
break;
case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
/* Only TA cable */
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index 74dfb7f4f277..b188bd650efa 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -122,6 +122,7 @@ enum max77843_muic_charger_type {
static const unsigned int max77843_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
+ EXTCON_CHG_USB_SDP,
EXTCON_CHG_USB_DCP,
EXTCON_CHG_USB_CDP,
EXTCON_CHG_USB_FAST,
@@ -486,6 +487,8 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info)
return ret;
extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP,
+ attached);
break;
case MAX77843_MUIC_CHG_DOWNSTREAM:
ret = max77843_muic_set_path(info,
@@ -803,7 +806,7 @@ static int max77843_muic_probe(struct platform_device *pdev)
/* Clear IRQ bits before request IRQs */
ret = regmap_bulk_read(max77843->regmap_muic,
MAX77843_MUIC_REG_INT1, info->status,
- MAX77843_MUIC_IRQ_NUM);
+ MAX77843_MUIC_STATUS_NUM);
if (ret) {
dev_err(&pdev->dev, "Failed to Clear IRQ bits\n");
goto err_muic_irq;
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
index b2b13b3dce14..9a89320d09a8 100644
--- a/drivers/extcon/extcon-max8997.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -148,6 +148,7 @@ struct max8997_muic_info {
static const unsigned int max8997_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
+ EXTCON_CHG_USB_SDP,
EXTCON_CHG_USB_DCP,
EXTCON_CHG_USB_FAST,
EXTCON_CHG_USB_SLOW,
@@ -334,6 +335,8 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info,
break;
case MAX8997_USB_DEVICE:
extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP,
+ attached);
break;
default:
dev_err(info->dev, "failed to detect %s usb cable\n",
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index 93c30a885740..841a4b586395 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -216,11 +216,23 @@ static int palmas_usb_probe(struct platform_device *pdev)
return PTR_ERR(palmas_usb->id_gpiod);
}
+ palmas_usb->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus",
+ GPIOD_IN);
+ if (IS_ERR(palmas_usb->vbus_gpiod)) {
+ dev_err(&pdev->dev, "failed to get vbus gpio\n");
+ return PTR_ERR(palmas_usb->vbus_gpiod);
+ }
+
if (palmas_usb->enable_id_detection && palmas_usb->id_gpiod) {
palmas_usb->enable_id_detection = false;
palmas_usb->enable_gpio_id_detection = true;
}
+ if (palmas_usb->enable_vbus_detection && palmas_usb->vbus_gpiod) {
+ palmas_usb->enable_vbus_detection = false;
+ palmas_usb->enable_gpio_vbus_detection = true;
+ }
+
if (palmas_usb->enable_gpio_id_detection) {
u32 debounce;
@@ -266,7 +278,7 @@ static int palmas_usb_probe(struct platform_device *pdev)
palmas_usb->id_irq,
NULL, palmas_id_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
- IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ IRQF_ONESHOT,
"palmas_usb_id", palmas_usb);
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
@@ -304,13 +316,47 @@ static int palmas_usb_probe(struct platform_device *pdev)
palmas_usb->vbus_irq, NULL,
palmas_vbus_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
- IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ IRQF_ONESHOT,
"palmas_usb_vbus", palmas_usb);
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
palmas_usb->vbus_irq, status);
return status;
}
+ } else if (palmas_usb->enable_gpio_vbus_detection) {
+ /* remux GPIO_1 as VBUSDET */
+ status = palmas_update_bits(palmas,
+ PALMAS_PU_PD_OD_BASE,
+ PALMAS_PRIMARY_SECONDARY_PAD1,
+ PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK,
+ (1 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT));
+ if (status < 0) {
+ dev_err(&pdev->dev, "can't remux GPIO1\n");
+ return status;
+ }
+
+ palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data,
+ PALMAS_VBUS_OTG_IRQ);
+ palmas_usb->gpio_vbus_irq = gpiod_to_irq(palmas_usb->vbus_gpiod);
+ if (palmas_usb->gpio_vbus_irq < 0) {
+ dev_err(&pdev->dev, "failed to get vbus irq\n");
+ return palmas_usb->gpio_vbus_irq;
+ }
+ status = devm_request_threaded_irq(&pdev->dev,
+ palmas_usb->gpio_vbus_irq,
+ NULL,
+ palmas_vbus_irq_handler,
+ IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT |
+ IRQF_EARLY_RESUME,
+ "palmas_usb_vbus",
+ palmas_usb);
+ if (status < 0) {
+ dev_err(&pdev->dev,
+ "failed to request handler for vbus irq\n");
+ return status;
+ }
}
palmas_enable_irq(palmas_usb);
@@ -337,6 +383,8 @@ static int palmas_usb_suspend(struct device *dev)
if (device_may_wakeup(dev)) {
if (palmas_usb->enable_vbus_detection)
enable_irq_wake(palmas_usb->vbus_irq);
+ if (palmas_usb->enable_gpio_vbus_detection)
+ enable_irq_wake(palmas_usb->gpio_vbus_irq);
if (palmas_usb->enable_id_detection)
enable_irq_wake(palmas_usb->id_irq);
if (palmas_usb->enable_gpio_id_detection)
@@ -352,6 +400,8 @@ static int palmas_usb_resume(struct device *dev)
if (device_may_wakeup(dev)) {
if (palmas_usb->enable_vbus_detection)
disable_irq_wake(palmas_usb->vbus_irq);
+ if (palmas_usb->enable_gpio_vbus_detection)
+ disable_irq_wake(palmas_usb->gpio_vbus_irq);
if (palmas_usb->enable_id_detection)
disable_irq_wake(palmas_usb->id_irq);
if (palmas_usb->enable_gpio_id_detection)
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
index e1bb82809bef..97e074d70eca 100644
--- a/drivers/extcon/extcon-rt8973a.c
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -93,6 +93,7 @@ static struct reg_data rt8973a_reg_data[] = {
static const unsigned int rt8973a_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
+ EXTCON_CHG_USB_SDP,
EXTCON_CHG_USB_DCP,
EXTCON_JIG,
EXTCON_NONE,
@@ -398,6 +399,9 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info,
/* Change the state of external accessory */
extcon_set_cable_state_(info->edev, id, attached);
+ if (id == EXTCON_USB)
+ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP,
+ attached);
return 0;
}
@@ -663,7 +667,7 @@ MODULE_DEVICE_TABLE(of, rt8973a_dt_match);
#ifdef CONFIG_PM_SLEEP
static int rt8973a_muic_suspend(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct rt8973a_muic_info *info = i2c_get_clientdata(i2c);
enable_irq_wake(info->irq);
@@ -673,7 +677,7 @@ static int rt8973a_muic_suspend(struct device *dev)
static int rt8973a_muic_resume(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct rt8973a_muic_info *info = i2c_get_clientdata(i2c);
disable_irq_wake(info->irq);
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index 7aac3cc7efd7..df769a17e736 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -95,6 +95,7 @@ static struct reg_data sm5502_reg_data[] = {
static const unsigned int sm5502_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
+ EXTCON_CHG_USB_SDP,
EXTCON_CHG_USB_DCP,
EXTCON_NONE,
};
@@ -411,6 +412,9 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
/* Change the state of external accessory */
extcon_set_cable_state_(info->edev, id, attached);
+ if (id == EXTCON_USB)
+ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP,
+ attached);
return 0;
}
@@ -655,7 +659,7 @@ MODULE_DEVICE_TABLE(of, sm5502_dt_match);
#ifdef CONFIG_PM_SLEEP
static int sm5502_muic_suspend(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct sm5502_muic_info *info = i2c_get_clientdata(i2c);
enable_irq_wake(info->irq);
@@ -665,7 +669,7 @@ static int sm5502_muic_suspend(struct device *dev)
static int sm5502_muic_resume(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct sm5502_muic_info *info = i2c_get_clientdata(i2c);
disable_irq_wake(info->irq);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 49a3a1185bb6..6664f1108c7c 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -161,6 +161,26 @@ config RASPBERRYPI_FIRMWARE
This option enables support for communicating with the firmware on the
Raspberry Pi.
+config FW_CFG_SYSFS
+ tristate "QEMU fw_cfg device support in sysfs"
+ depends on SYSFS && (ARM || ARM64 || PPC_PMAC || SPARC || X86)
+ depends on HAS_IOPORT_MAP
+ default n
+ help
+ Say Y or M here to enable the exporting of the QEMU firmware
+ configuration (fw_cfg) file entries via sysfs. Entries are
+ found under /sys/firmware/fw_cfg when this option is enabled
+ and loaded.
+
+config FW_CFG_SYSFS_CMDLINE
+ bool "QEMU fw_cfg device parameter parsing"
+ depends on FW_CFG_SYSFS
+ help
+ Allow the qemu_fw_cfg device to be initialized via the kernel
+ command line or using a module parameter.
+ WARNING: Using incorrect parameters (base address in particular)
+ may crash your system.
+
config QCOM_SCM
bool
depends on ARM || ARM64
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 48dd4175297e..474bada56fcd 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
+obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 756eca8c4cf8..10e6774ab2a2 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -221,7 +221,7 @@ sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
}
if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
- efivar_validate(name, data, size) == false) {
+ efivar_validate(vendor, name, data, size) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
@@ -447,7 +447,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
}
if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
- efivar_validate(name, data, size) == false) {
+ efivar_validate(new_var->VendorGuid, name, data,
+ size) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
@@ -540,38 +541,30 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
static int
efivar_create_sysfs_entry(struct efivar_entry *new_var)
{
- int i, short_name_size;
+ int short_name_size;
char *short_name;
- unsigned long variable_name_size;
- efi_char16_t *variable_name;
+ unsigned long utf8_name_size;
+ efi_char16_t *variable_name = new_var->var.VariableName;
int ret;
- variable_name = new_var->var.VariableName;
- variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
-
/*
- * Length of the variable bytes in ASCII, plus the '-' separator,
+ * Length of the variable bytes in UTF8, plus the '-' separator,
* plus the GUID, plus trailing NUL
*/
- short_name_size = variable_name_size / sizeof(efi_char16_t)
- + 1 + EFI_VARIABLE_GUID_LEN + 1;
-
- short_name = kzalloc(short_name_size, GFP_KERNEL);
+ utf8_name_size = ucs2_utf8size(variable_name);
+ short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1;
+ short_name = kmalloc(short_name_size, GFP_KERNEL);
if (!short_name)
return -ENOMEM;
- /* Convert Unicode to normal chars (assume top bits are 0),
- ala UTF-8 */
- for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
- short_name[i] = variable_name[i] & 0xFF;
- }
+ ucs2_as_utf8(short_name, variable_name, short_name_size);
+
/* This is ugly, but necessary to separate one vendor's
private variables from another's. */
-
- *(short_name + strlen(short_name)) = '-';
+ short_name[utf8_name_size] = '-';
efi_guid_to_str(&new_var->var.VendorGuid,
- short_name + strlen(short_name));
+ short_name + utf8_name_size + 1);
new_var->kobj.kset = efivars_kset;
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index 70a0fb10517f..7f2ea21c730d 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -165,67 +165,133 @@ validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer,
}
struct variable_validate {
+ efi_guid_t vendor;
char *name;
bool (*validate)(efi_char16_t *var_name, int match, u8 *data,
unsigned long len);
};
+/*
+ * This is the list of variables we need to validate, as well as the
+ * whitelist for what we think is safe not to default to immutable.
+ *
+ * If it has a validate() method that's not NULL, it'll go into the
+ * validation routine. If not, it is assumed valid, but still used for
+ * whitelisting.
+ *
+ * Note that it's sorted by {vendor,name}, but globbed names must come after
+ * any other name with the same prefix.
+ */
static const struct variable_validate variable_validate[] = {
- { "BootNext", validate_uint16 },
- { "BootOrder", validate_boot_order },
- { "DriverOrder", validate_boot_order },
- { "Boot*", validate_load_option },
- { "Driver*", validate_load_option },
- { "ConIn", validate_device_path },
- { "ConInDev", validate_device_path },
- { "ConOut", validate_device_path },
- { "ConOutDev", validate_device_path },
- { "ErrOut", validate_device_path },
- { "ErrOutDev", validate_device_path },
- { "Timeout", validate_uint16 },
- { "Lang", validate_ascii_string },
- { "PlatformLang", validate_ascii_string },
- { "", NULL },
+ { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 },
+ { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order },
+ { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option },
+ { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order },
+ { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option },
+ { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path },
+ { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path },
+ { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path },
+ { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path },
+ { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path },
+ { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path },
+ { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string },
+ { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL },
+ { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string },
+ { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 },
+ { LINUX_EFI_CRASH_GUID, "*", NULL },
+ { NULL_GUID, "", NULL },
};
+static bool
+variable_matches(const char *var_name, size_t len, const char *match_name,
+ int *match)
+{
+ for (*match = 0; ; (*match)++) {
+ char c = match_name[*match];
+ char u = var_name[*match];
+
+ /* Wildcard in the matching name means we've matched */
+ if (c == '*')
+ return true;
+
+ /* Case sensitive match */
+ if (!c && *match == len)
+ return true;
+
+ if (c != u)
+ return false;
+
+ if (!c)
+ return true;
+ }
+ return true;
+}
+
bool
-efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len)
+efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
+ unsigned long data_size)
{
int i;
- u16 *unicode_name = var_name;
+ unsigned long utf8_size;
+ u8 *utf8_name;
- for (i = 0; variable_validate[i].validate != NULL; i++) {
- const char *name = variable_validate[i].name;
- int match;
+ utf8_size = ucs2_utf8size(var_name);
+ utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL);
+ if (!utf8_name)
+ return false;
- for (match = 0; ; match++) {
- char c = name[match];
- u16 u = unicode_name[match];
+ ucs2_as_utf8(utf8_name, var_name, utf8_size);
+ utf8_name[utf8_size] = '\0';
- /* All special variables are plain ascii */
- if (u > 127)
- return true;
+ for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
+ const char *name = variable_validate[i].name;
+ int match = 0;
- /* Wildcard in the matching name means we've matched */
- if (c == '*')
- return variable_validate[i].validate(var_name,
- match, data, len);
+ if (efi_guidcmp(vendor, variable_validate[i].vendor))
+ continue;
- /* Case sensitive match */
- if (c != u)
+ if (variable_matches(utf8_name, utf8_size+1, name, &match)) {
+ if (variable_validate[i].validate == NULL)
break;
-
- /* Reached the end of the string while matching */
- if (!c)
- return variable_validate[i].validate(var_name,
- match, data, len);
+ kfree(utf8_name);
+ return variable_validate[i].validate(var_name, match,
+ data, data_size);
}
}
-
+ kfree(utf8_name);
return true;
}
EXPORT_SYMBOL_GPL(efivar_validate);
+bool
+efivar_variable_is_removable(efi_guid_t vendor, const char *var_name,
+ size_t len)
+{
+ int i;
+ bool found = false;
+ int match = 0;
+
+ /*
+ * Check if our variable is in the validated variables list
+ */
+ for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
+ if (efi_guidcmp(variable_validate[i].vendor, vendor))
+ continue;
+
+ if (variable_matches(var_name, len,
+ variable_validate[i].name, &match)) {
+ found = true;
+ break;
+ }
+ }
+
+ /*
+ * If it's in our list, it is removable.
+ */
+ return found;
+}
+EXPORT_SYMBOL_GPL(efivar_variable_is_removable);
+
static efi_status_t
check_var_size(u32 attributes, unsigned long size)
{
@@ -852,7 +918,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
*set = false;
- if (efivar_validate(name, data, *size) == false)
+ if (efivar_validate(*vendor, name, data, *size) == false)
return -EINVAL;
/*
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index 72791232e46b..81037e5fe301 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -319,6 +319,9 @@ static ssize_t ibft_attr_show_nic(void *data, int type, char *buf)
val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
str += sprintf(str, "%pI4", &val);
break;
+ case ISCSI_BOOT_ETH_PREFIX_LEN:
+ str += sprintf(str, "%d\n", nic->subnet_mask_prefix);
+ break;
case ISCSI_BOOT_ETH_ORIGIN:
str += sprintf(str, "%d\n", nic->origin);
break;
@@ -460,6 +463,7 @@ static umode_t ibft_check_nic_for(void *data, int type)
if (address_not_null(nic->ip_addr))
rc = S_IRUGO;
break;
+ case ISCSI_BOOT_ETH_PREFIX_LEN:
case ISCSI_BOOT_ETH_SUBNET_MASK:
if (nic->subnet_mask_prefix)
rc = S_IRUGO;
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
new file mode 100644
index 000000000000..fedbff55a7f3
--- /dev/null
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -0,0 +1,751 @@
+/*
+ * drivers/firmware/qemu_fw_cfg.c
+ *
+ * Copyright 2015 Carnegie Mellon University
+ *
+ * Expose entries from QEMU's firmware configuration (fw_cfg) device in
+ * sysfs (read-only, under "/sys/firmware/qemu_fw_cfg/...").
+ *
+ * The fw_cfg device may be instantiated via either an ACPI node (on x86
+ * and select subsets of aarch64), a Device Tree node (on arm), or using
+ * a kernel module (or command line) parameter with the following syntax:
+ *
+ * [fw_cfg.]ioport=<size>@<base>[:<ctrl_off>:<data_off>]
+ * or
+ * [fw_cfg.]mmio=<size>@<base>[:<ctrl_off>:<data_off>]
+ *
+ * where:
+ * <size> := size of ioport or mmio range
+ * <base> := physical base address of ioport or mmio range
+ * <ctrl_off> := (optional) offset of control register
+ * <data_off> := (optional) offset of data register
+ *
+ * e.g.:
+ * fw_cfg.ioport=2@0x510:0:1 (the default on x86)
+ * or
+ * fw_cfg.mmio=0xA@0x9020000:8:0 (the default on arm)
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+MODULE_AUTHOR("Gabriel L. Somlo <somlo@cmu.edu>");
+MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
+MODULE_LICENSE("GPL");
+
+/* selector key values for "well-known" fw_cfg entries */
+#define FW_CFG_SIGNATURE 0x00
+#define FW_CFG_ID 0x01
+#define FW_CFG_FILE_DIR 0x19
+
+/* size in bytes of fw_cfg signature */
+#define FW_CFG_SIG_SIZE 4
+
+/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
+#define FW_CFG_MAX_FILE_PATH 56
+
+/* fw_cfg file directory entry type */
+struct fw_cfg_file {
+ u32 size;
+ u16 select;
+ u16 reserved;
+ char name[FW_CFG_MAX_FILE_PATH];
+};
+
+/* fw_cfg device i/o register addresses */
+static bool fw_cfg_is_mmio;
+static phys_addr_t fw_cfg_p_base;
+static resource_size_t fw_cfg_p_size;
+static void __iomem *fw_cfg_dev_base;
+static void __iomem *fw_cfg_reg_ctrl;
+static void __iomem *fw_cfg_reg_data;
+
+/* atomic access to fw_cfg device (potentially slow i/o, so using mutex) */
+static DEFINE_MUTEX(fw_cfg_dev_lock);
+
+/* pick appropriate endianness for selector key */
+static inline u16 fw_cfg_sel_endianness(u16 key)
+{
+ return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);
+}
+
+/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
+static inline void fw_cfg_read_blob(u16 key,
+ void *buf, loff_t pos, size_t count)
+{
+ mutex_lock(&fw_cfg_dev_lock);
+ iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+ while (pos-- > 0)
+ ioread8(fw_cfg_reg_data);
+ ioread8_rep(fw_cfg_reg_data, buf, count);
+ mutex_unlock(&fw_cfg_dev_lock);
+}
+
+/* clean up fw_cfg device i/o */
+static void fw_cfg_io_cleanup(void)
+{
+ if (fw_cfg_is_mmio) {
+ iounmap(fw_cfg_dev_base);
+ release_mem_region(fw_cfg_p_base, fw_cfg_p_size);
+ } else {
+ ioport_unmap(fw_cfg_dev_base);
+ release_region(fw_cfg_p_base, fw_cfg_p_size);
+ }
+}
+
+/* arch-specific ctrl & data register offsets are not available in ACPI, DT */
+#if !(defined(FW_CFG_CTRL_OFF) && defined(FW_CFG_DATA_OFF))
+# if (defined(CONFIG_ARM) || defined(CONFIG_ARM64))
+# define FW_CFG_CTRL_OFF 0x08
+# define FW_CFG_DATA_OFF 0x00
+# elif (defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC32)) /* ppc/mac,sun4m */
+# define FW_CFG_CTRL_OFF 0x00
+# define FW_CFG_DATA_OFF 0x02
+# elif (defined(CONFIG_X86) || defined(CONFIG_SPARC64)) /* x86, sun4u */
+# define FW_CFG_CTRL_OFF 0x00
+# define FW_CFG_DATA_OFF 0x01
+# else
+# warning "QEMU FW_CFG may not be available on this architecture!"
+# define FW_CFG_CTRL_OFF 0x00
+# define FW_CFG_DATA_OFF 0x01
+# endif
+#endif
+
+/* initialize fw_cfg device i/o from platform data */
+static int fw_cfg_do_platform_probe(struct platform_device *pdev)
+{
+ char sig[FW_CFG_SIG_SIZE];
+ struct resource *range, *ctrl, *data;
+
+ /* acquire i/o range details */
+ fw_cfg_is_mmio = false;
+ range = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!range) {
+ fw_cfg_is_mmio = true;
+ range = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!range)
+ return -EINVAL;
+ }
+ fw_cfg_p_base = range->start;
+ fw_cfg_p_size = resource_size(range);
+
+ if (fw_cfg_is_mmio) {
+ if (!request_mem_region(fw_cfg_p_base,
+ fw_cfg_p_size, "fw_cfg_mem"))
+ return -EBUSY;
+ fw_cfg_dev_base = ioremap(fw_cfg_p_base, fw_cfg_p_size);
+ if (!fw_cfg_dev_base) {
+ release_mem_region(fw_cfg_p_base, fw_cfg_p_size);
+ return -EFAULT;
+ }
+ } else {
+ if (!request_region(fw_cfg_p_base,
+ fw_cfg_p_size, "fw_cfg_io"))
+ return -EBUSY;
+ fw_cfg_dev_base = ioport_map(fw_cfg_p_base, fw_cfg_p_size);
+ if (!fw_cfg_dev_base) {
+ release_region(fw_cfg_p_base, fw_cfg_p_size);
+ return -EFAULT;
+ }
+ }
+
+ /* were custom register offsets provided (e.g. on the command line)? */
+ ctrl = platform_get_resource_byname(pdev, IORESOURCE_REG, "ctrl");
+ data = platform_get_resource_byname(pdev, IORESOURCE_REG, "data");
+ if (ctrl && data) {
+ fw_cfg_reg_ctrl = fw_cfg_dev_base + ctrl->start;
+ fw_cfg_reg_data = fw_cfg_dev_base + data->start;
+ } else {
+ /* use architecture-specific offsets */
+ fw_cfg_reg_ctrl = fw_cfg_dev_base + FW_CFG_CTRL_OFF;
+ fw_cfg_reg_data = fw_cfg_dev_base + FW_CFG_DATA_OFF;
+ }
+
+ /* verify fw_cfg device signature */
+ fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);
+ if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
+ fw_cfg_io_cleanup();
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
+static u32 fw_cfg_rev;
+
+static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf)
+{
+ return sprintf(buf, "%u\n", fw_cfg_rev);
+}
+
+static const struct {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *k, struct attribute *a, char *buf);
+} fw_cfg_rev_attr = {
+ .attr = { .name = "rev", .mode = S_IRUSR },
+ .show = fw_cfg_showrev,
+};
+
+/* fw_cfg_sysfs_entry type */
+struct fw_cfg_sysfs_entry {
+ struct kobject kobj;
+ struct fw_cfg_file f;
+ struct list_head list;
+};
+
+/* get fw_cfg_sysfs_entry from kobject member */
+static inline struct fw_cfg_sysfs_entry *to_entry(struct kobject *kobj)
+{
+ return container_of(kobj, struct fw_cfg_sysfs_entry, kobj);
+}
+
+/* fw_cfg_sysfs_attribute type */
+struct fw_cfg_sysfs_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct fw_cfg_sysfs_entry *entry, char *buf);
+};
+
+/* get fw_cfg_sysfs_attribute from attribute member */
+static inline struct fw_cfg_sysfs_attribute *to_attr(struct attribute *attr)
+{
+ return container_of(attr, struct fw_cfg_sysfs_attribute, attr);
+}
+
+/* global cache of fw_cfg_sysfs_entry objects */
+static LIST_HEAD(fw_cfg_entry_cache);
+
+/* kobjects removed lazily by kernel, mutual exclusion needed */
+static DEFINE_SPINLOCK(fw_cfg_cache_lock);
+
+static inline void fw_cfg_sysfs_cache_enlist(struct fw_cfg_sysfs_entry *entry)
+{
+ spin_lock(&fw_cfg_cache_lock);
+ list_add_tail(&entry->list, &fw_cfg_entry_cache);
+ spin_unlock(&fw_cfg_cache_lock);
+}
+
+static inline void fw_cfg_sysfs_cache_delist(struct fw_cfg_sysfs_entry *entry)
+{
+ spin_lock(&fw_cfg_cache_lock);
+ list_del(&entry->list);
+ spin_unlock(&fw_cfg_cache_lock);
+}
+
+static void fw_cfg_sysfs_cache_cleanup(void)
+{
+ struct fw_cfg_sysfs_entry *entry, *next;
+
+ list_for_each_entry_safe(entry, next, &fw_cfg_entry_cache, list) {
+ /* will end up invoking fw_cfg_sysfs_cache_delist()
+ * via each object's release() method (i.e. destructor)
+ */
+ kobject_put(&entry->kobj);
+ }
+}
+
+/* default_attrs: per-entry attributes and show methods */
+
+#define FW_CFG_SYSFS_ATTR(_attr) \
+struct fw_cfg_sysfs_attribute fw_cfg_sysfs_attr_##_attr = { \
+ .attr = { .name = __stringify(_attr), .mode = S_IRUSR }, \
+ .show = fw_cfg_sysfs_show_##_attr, \
+}
+
+static ssize_t fw_cfg_sysfs_show_size(struct fw_cfg_sysfs_entry *e, char *buf)
+{
+ return sprintf(buf, "%u\n", e->f.size);
+}
+
+static ssize_t fw_cfg_sysfs_show_key(struct fw_cfg_sysfs_entry *e, char *buf)
+{
+ return sprintf(buf, "%u\n", e->f.select);
+}
+
+static ssize_t fw_cfg_sysfs_show_name(struct fw_cfg_sysfs_entry *e, char *buf)
+{
+ return sprintf(buf, "%s\n", e->f.name);
+}
+
+static FW_CFG_SYSFS_ATTR(size);
+static FW_CFG_SYSFS_ATTR(key);
+static FW_CFG_SYSFS_ATTR(name);
+
+static struct attribute *fw_cfg_sysfs_entry_attrs[] = {
+ &fw_cfg_sysfs_attr_size.attr,
+ &fw_cfg_sysfs_attr_key.attr,
+ &fw_cfg_sysfs_attr_name.attr,
+ NULL,
+};
+
+/* sysfs_ops: find fw_cfg_[entry, attribute] and call appropriate show method */
+static ssize_t fw_cfg_sysfs_attr_show(struct kobject *kobj, struct attribute *a,
+ char *buf)
+{
+ struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
+ struct fw_cfg_sysfs_attribute *attr = to_attr(a);
+
+ return attr->show(entry, buf);
+}
+
+static const struct sysfs_ops fw_cfg_sysfs_attr_ops = {
+ .show = fw_cfg_sysfs_attr_show,
+};
+
+/* release: destructor, to be called via kobject_put() */
+static void fw_cfg_sysfs_release_entry(struct kobject *kobj)
+{
+ struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
+
+ fw_cfg_sysfs_cache_delist(entry);
+ kfree(entry);
+}
+
+/* kobj_type: ties together all properties required to register an entry */
+static struct kobj_type fw_cfg_sysfs_entry_ktype = {
+ .default_attrs = fw_cfg_sysfs_entry_attrs,
+ .sysfs_ops = &fw_cfg_sysfs_attr_ops,
+ .release = fw_cfg_sysfs_release_entry,
+};
+
+/* raw-read method and attribute */
+static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t count)
+{
+ struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
+
+ if (pos > entry->f.size)
+ return -EINVAL;
+
+ if (count > entry->f.size - pos)
+ count = entry->f.size - pos;
+
+ fw_cfg_read_blob(entry->f.select, buf, pos, count);
+ return count;
+}
+
+static struct bin_attribute fw_cfg_sysfs_attr_raw = {
+ .attr = { .name = "raw", .mode = S_IRUSR },
+ .read = fw_cfg_sysfs_read_raw,
+};
+
+/*
+ * Create a kset subdirectory matching each '/' delimited dirname token
+ * in 'name', starting with sysfs kset/folder 'dir'; At the end, create
+ * a symlink directed at the given 'target'.
+ * NOTE: We do this on a best-effort basis, since 'name' is not guaranteed
+ * to be a well-behaved path name. Whenever a symlink vs. kset directory
+ * name collision occurs, the kernel will issue big scary warnings while
+ * refusing to add the offending link or directory. We follow up with our
+ * own, slightly less scary error messages explaining the situation :)
+ */
+static int fw_cfg_build_symlink(struct kset *dir,
+ struct kobject *target, const char *name)
+{
+ int ret;
+ struct kset *subdir;
+ struct kobject *ko;
+ char *name_copy, *p, *tok;
+
+ if (!dir || !target || !name || !*name)
+ return -EINVAL;
+
+ /* clone a copy of name for parsing */
+ name_copy = p = kstrdup(name, GFP_KERNEL);
+ if (!name_copy)
+ return -ENOMEM;
+
+ /* create folders for each dirname token, then symlink for basename */
+ while ((tok = strsep(&p, "/")) && *tok) {
+
+ /* last (basename) token? If so, add symlink here */
+ if (!p || !*p) {
+ ret = sysfs_create_link(&dir->kobj, target, tok);
+ break;
+ }
+
+ /* does the current dir contain an item named after tok ? */
+ ko = kset_find_obj(dir, tok);
+ if (ko) {
+ /* drop reference added by kset_find_obj */
+ kobject_put(ko);
+
+ /* ko MUST be a kset - we're about to use it as one ! */
+ if (ko->ktype != dir->kobj.ktype) {
+ ret = -EINVAL;
+ break;
+ }
+
+ /* descend into already existing subdirectory */
+ dir = to_kset(ko);
+ } else {
+ /* create new subdirectory kset */
+ subdir = kzalloc(sizeof(struct kset), GFP_KERNEL);
+ if (!subdir) {
+ ret = -ENOMEM;
+ break;
+ }
+ subdir->kobj.kset = dir;
+ subdir->kobj.ktype = dir->kobj.ktype;
+ ret = kobject_set_name(&subdir->kobj, "%s", tok);
+ if (ret) {
+ kfree(subdir);
+ break;
+ }
+ ret = kset_register(subdir);
+ if (ret) {
+ kfree(subdir);
+ break;
+ }
+
+ /* descend into newly created subdirectory */
+ dir = subdir;
+ }
+ }
+
+ /* we're done with cloned copy of name */
+ kfree(name_copy);
+ return ret;
+}
+
+/* recursively unregister fw_cfg/by_name/ kset directory tree */
+static void fw_cfg_kset_unregister_recursive(struct kset *kset)
+{
+ struct kobject *k, *next;
+
+ list_for_each_entry_safe(k, next, &kset->list, entry)
+ /* all set members are ksets too, but check just in case... */
+ if (k->ktype == kset->kobj.ktype)
+ fw_cfg_kset_unregister_recursive(to_kset(k));
+
+ /* symlinks are cleanly and automatically removed with the directory */
+ kset_unregister(kset);
+}
+
+/* kobjects & kset representing top-level, by_key, and by_name folders */
+static struct kobject *fw_cfg_top_ko;
+static struct kobject *fw_cfg_sel_ko;
+static struct kset *fw_cfg_fname_kset;
+
+/* register an individual fw_cfg file */
+static int fw_cfg_register_file(const struct fw_cfg_file *f)
+{
+ int err;
+ struct fw_cfg_sysfs_entry *entry;
+
+ /* allocate new entry */
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ /* set file entry information */
+ memcpy(&entry->f, f, sizeof(struct fw_cfg_file));
+
+ /* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */
+ err = kobject_init_and_add(&entry->kobj, &fw_cfg_sysfs_entry_ktype,
+ fw_cfg_sel_ko, "%d", entry->f.select);
+ if (err)
+ goto err_register;
+
+ /* add raw binary content access */
+ err = sysfs_create_bin_file(&entry->kobj, &fw_cfg_sysfs_attr_raw);
+ if (err)
+ goto err_add_raw;
+
+ /* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
+ fw_cfg_build_symlink(fw_cfg_fname_kset, &entry->kobj, entry->f.name);
+
+ /* success, add entry to global cache */
+ fw_cfg_sysfs_cache_enlist(entry);
+ return 0;
+
+err_add_raw:
+ kobject_del(&entry->kobj);
+err_register:
+ kfree(entry);
+ return err;
+}
+
+/* iterate over all fw_cfg directory entries, registering each one */
+static int fw_cfg_register_dir_entries(void)
+{
+ int ret = 0;
+ u32 count, i;
+ struct fw_cfg_file *dir;
+ size_t dir_size;
+
+ fw_cfg_read_blob(FW_CFG_FILE_DIR, &count, 0, sizeof(count));
+ count = be32_to_cpu(count);
+ dir_size = count * sizeof(struct fw_cfg_file);
+
+ dir = kmalloc(dir_size, GFP_KERNEL);
+ if (!dir)
+ return -ENOMEM;
+
+ fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
+
+ for (i = 0; i < count; i++) {
+ dir[i].size = be32_to_cpu(dir[i].size);
+ dir[i].select = be16_to_cpu(dir[i].select);
+ ret = fw_cfg_register_file(&dir[i]);
+ if (ret)
+ break;
+ }
+
+ kfree(dir);
+ return ret;
+}
+
+/* unregister top-level or by_key folder */
+static inline void fw_cfg_kobj_cleanup(struct kobject *kobj)
+{
+ kobject_del(kobj);
+ kobject_put(kobj);
+}
+
+static int fw_cfg_sysfs_probe(struct platform_device *pdev)
+{
+ int err;
+
+ /* NOTE: If we supported multiple fw_cfg devices, we'd first create
+ * a subdirectory named after e.g. pdev->id, then hang per-device
+ * by_key (and by_name) subdirectories underneath it. However, only
+ * one fw_cfg device exist system-wide, so if one was already found
+ * earlier, we might as well stop here.
+ */
+ if (fw_cfg_sel_ko)
+ return -EBUSY;
+
+ /* create by_key and by_name subdirs of /sys/firmware/qemu_fw_cfg/ */
+ err = -ENOMEM;
+ fw_cfg_sel_ko = kobject_create_and_add("by_key", fw_cfg_top_ko);
+ if (!fw_cfg_sel_ko)
+ goto err_sel;
+ fw_cfg_fname_kset = kset_create_and_add("by_name", NULL, fw_cfg_top_ko);
+ if (!fw_cfg_fname_kset)
+ goto err_name;
+
+ /* initialize fw_cfg device i/o from platform data */
+ err = fw_cfg_do_platform_probe(pdev);
+ if (err)
+ goto err_probe;
+
+ /* get revision number, add matching top-level attribute */
+ fw_cfg_read_blob(FW_CFG_ID, &fw_cfg_rev, 0, sizeof(fw_cfg_rev));
+ fw_cfg_rev = le32_to_cpu(fw_cfg_rev);
+ err = sysfs_create_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr);
+ if (err)
+ goto err_rev;
+
+ /* process fw_cfg file directory entry, registering each file */
+ err = fw_cfg_register_dir_entries();
+ if (err)
+ goto err_dir;
+
+ /* success */
+ pr_debug("fw_cfg: loaded.\n");
+ return 0;
+
+err_dir:
+ fw_cfg_sysfs_cache_cleanup();
+ sysfs_remove_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr);
+err_rev:
+ fw_cfg_io_cleanup();
+err_probe:
+ fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset);
+err_name:
+ fw_cfg_kobj_cleanup(fw_cfg_sel_ko);
+err_sel:
+ return err;
+}
+
+static int fw_cfg_sysfs_remove(struct platform_device *pdev)
+{
+ pr_debug("fw_cfg: unloading.\n");
+ fw_cfg_sysfs_cache_cleanup();
+ fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset);
+ fw_cfg_kobj_cleanup(fw_cfg_sel_ko);
+ fw_cfg_io_cleanup();
+ return 0;
+}
+
+static const struct of_device_id fw_cfg_sysfs_mmio_match[] = {
+ { .compatible = "qemu,fw-cfg-mmio", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
+ { "QEMU0002", },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
+#endif
+
+static struct platform_driver fw_cfg_sysfs_driver = {
+ .probe = fw_cfg_sysfs_probe,
+ .remove = fw_cfg_sysfs_remove,
+ .driver = {
+ .name = "fw_cfg",
+ .of_match_table = fw_cfg_sysfs_mmio_match,
+ .acpi_match_table = ACPI_PTR(fw_cfg_sysfs_acpi_match),
+ },
+};
+
+#ifdef CONFIG_FW_CFG_SYSFS_CMDLINE
+
+static struct platform_device *fw_cfg_cmdline_dev;
+
+/* this probably belongs in e.g. include/linux/types.h,
+ * but right now we are the only ones doing it...
+ */
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+#define __PHYS_ADDR_PREFIX "ll"
+#else
+#define __PHYS_ADDR_PREFIX ""
+#endif
+
+/* use special scanf/printf modifier for phys_addr_t, resource_size_t */
+#define PH_ADDR_SCAN_FMT "@%" __PHYS_ADDR_PREFIX "i%n" \
+ ":%" __PHYS_ADDR_PREFIX "i" \
+ ":%" __PHYS_ADDR_PREFIX "i%n"
+
+#define PH_ADDR_PR_1_FMT "0x%" __PHYS_ADDR_PREFIX "x@" \
+ "0x%" __PHYS_ADDR_PREFIX "x"
+
+#define PH_ADDR_PR_3_FMT PH_ADDR_PR_1_FMT \
+ ":%" __PHYS_ADDR_PREFIX "u" \
+ ":%" __PHYS_ADDR_PREFIX "u"
+
+static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
+{
+ struct resource res[3] = {};
+ char *str;
+ phys_addr_t base;
+ resource_size_t size, ctrl_off, data_off;
+ int processed, consumed = 0;
+
+ /* only one fw_cfg device can exist system-wide, so if one
+ * was processed on the command line already, we might as
+ * well stop here.
+ */
+ if (fw_cfg_cmdline_dev) {
+ /* avoid leaking previously registered device */
+ platform_device_unregister(fw_cfg_cmdline_dev);
+ return -EINVAL;
+ }
+
+ /* consume "<size>" portion of command line argument */
+ size = memparse(arg, &str);
+
+ /* get "@<base>[:<ctrl_off>:<data_off>]" chunks */
+ processed = sscanf(str, PH_ADDR_SCAN_FMT,
+ &base, &consumed,
+ &ctrl_off, &data_off, &consumed);
+
+ /* sscanf() must process precisely 1 or 3 chunks:
+ * <base> is mandatory, optionally followed by <ctrl_off>
+ * and <data_off>;
+ * there must be no extra characters after the last chunk,
+ * so str[consumed] must be '\0'.
+ */
+ if (str[consumed] ||
+ (processed != 1 && processed != 3))
+ return -EINVAL;
+
+ res[0].start = base;
+ res[0].end = base + size - 1;
+ res[0].flags = !strcmp(kp->name, "mmio") ? IORESOURCE_MEM :
+ IORESOURCE_IO;
+
+ /* insert register offsets, if provided */
+ if (processed > 1) {
+ res[1].name = "ctrl";
+ res[1].start = ctrl_off;
+ res[1].flags = IORESOURCE_REG;
+ res[2].name = "data";
+ res[2].start = data_off;
+ res[2].flags = IORESOURCE_REG;
+ }
+
+ /* "processed" happens to nicely match the number of resources
+ * we need to pass in to this platform device.
+ */
+ fw_cfg_cmdline_dev = platform_device_register_simple("fw_cfg",
+ PLATFORM_DEVID_NONE, res, processed);
+ if (IS_ERR(fw_cfg_cmdline_dev))
+ return PTR_ERR(fw_cfg_cmdline_dev);
+
+ return 0;
+}
+
+static int fw_cfg_cmdline_get(char *buf, const struct kernel_param *kp)
+{
+ /* stay silent if device was not configured via the command
+ * line, or if the parameter name (ioport/mmio) doesn't match
+ * the device setting
+ */
+ if (!fw_cfg_cmdline_dev ||
+ (!strcmp(kp->name, "mmio") ^
+ (fw_cfg_cmdline_dev->resource[0].flags == IORESOURCE_MEM)))
+ return 0;
+
+ switch (fw_cfg_cmdline_dev->num_resources) {
+ case 1:
+ return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_1_FMT,
+ resource_size(&fw_cfg_cmdline_dev->resource[0]),
+ fw_cfg_cmdline_dev->resource[0].start);
+ case 3:
+ return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_3_FMT,
+ resource_size(&fw_cfg_cmdline_dev->resource[0]),
+ fw_cfg_cmdline_dev->resource[0].start,
+ fw_cfg_cmdline_dev->resource[1].start,
+ fw_cfg_cmdline_dev->resource[2].start);
+ }
+
+ /* Should never get here */
+ WARN(1, "Unexpected number of resources: %d\n",
+ fw_cfg_cmdline_dev->num_resources);
+ return 0;
+}
+
+static const struct kernel_param_ops fw_cfg_cmdline_param_ops = {
+ .set = fw_cfg_cmdline_set,
+ .get = fw_cfg_cmdline_get,
+};
+
+device_param_cb(ioport, &fw_cfg_cmdline_param_ops, NULL, S_IRUSR);
+device_param_cb(mmio, &fw_cfg_cmdline_param_ops, NULL, S_IRUSR);
+
+#endif /* CONFIG_FW_CFG_SYSFS_CMDLINE */
+
+static int __init fw_cfg_sysfs_init(void)
+{
+ /* create /sys/firmware/qemu_fw_cfg/ top level directory */
+ fw_cfg_top_ko = kobject_create_and_add("qemu_fw_cfg", firmware_kobj);
+ if (!fw_cfg_top_ko)
+ return -ENOMEM;
+
+ return platform_driver_register(&fw_cfg_sysfs_driver);
+}
+
+static void __exit fw_cfg_sysfs_exit(void)
+{
+ platform_driver_unregister(&fw_cfg_sysfs_driver);
+
+#ifdef CONFIG_FW_CFG_SYSFS_CMDLINE
+ platform_device_unregister(fw_cfg_cmdline_dev);
+#endif
+
+ /* clean up /sys/firmware/qemu_fw_cfg/ */
+ fw_cfg_kobj_cleanup(fw_cfg_top_ko);
+}
+
+module_init(fw_cfg_sysfs_init);
+module_exit(fw_cfg_sysfs_exit);
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index cf41440aff91..d9ab0cd1d205 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -196,6 +196,44 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
return 0;
}
+static void gpio_rcar_irq_bus_lock(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+
+ pm_runtime_get_sync(&p->pdev->dev);
+}
+
+static void gpio_rcar_irq_bus_sync_unlock(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+
+ pm_runtime_put(&p->pdev->dev);
+}
+
+
+static int gpio_rcar_irq_request_resources(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+ int error;
+
+ error = pm_runtime_get_sync(&p->pdev->dev);
+ if (error < 0)
+ return error;
+
+ return 0;
+}
+
+static void gpio_rcar_irq_release_resources(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+
+ pm_runtime_put(&p->pdev->dev);
+}
+
static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
{
struct gpio_rcar_priv *p = dev_id;
@@ -450,6 +488,10 @@ static int gpio_rcar_probe(struct platform_device *pdev)
irq_chip->irq_unmask = gpio_rcar_irq_enable;
irq_chip->irq_set_type = gpio_rcar_irq_set_type;
irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
+ irq_chip->irq_bus_lock = gpio_rcar_irq_bus_lock;
+ irq_chip->irq_bus_sync_unlock = gpio_rcar_irq_bus_sync_unlock;
+ irq_chip->irq_request_resources = gpio_rcar_irq_request_resources;
+ irq_chip->irq_release_resources = gpio_rcar_irq_release_resources;
irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
ret = gpiochip_add_data(gpio_chip, p);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index 89c3dd62ba21..119cdc2c43e7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -77,7 +77,7 @@ void amdgpu_connector_hotplug(struct drm_connector *connector)
} else if (amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
/* Don't try to start link training before we
* have the dpcd */
- if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
+ if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
return;
/* set it to OFF so that drm_helper_connector_dpms()
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index acd066d0a805..1846d65b7285 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -72,8 +72,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
struct drm_crtc *crtc = &amdgpuCrtc->base;
unsigned long flags;
- unsigned i;
- int vpos, hpos, stat, min_udelay;
+ unsigned i, repcnt = 4;
+ int vpos, hpos, stat, min_udelay = 0;
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
amdgpu_flip_wait_fence(adev, &work->excl);
@@ -96,7 +96,7 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
* In practice this won't execute very often unless on very fast
* machines because the time window for this to happen is very small.
*/
- for (;;) {
+ while (amdgpuCrtc->enabled && --repcnt) {
/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
* start in hpos, and to the "fudged earlier" vblank start in
* vpos.
@@ -112,12 +112,24 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
break;
/* Sleep at least until estimated real start of hw vblank */
- spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+ if (min_udelay > vblank->framedur_ns / 2000) {
+ /* Don't wait ridiculously long - something is wrong */
+ repcnt = 0;
+ break;
+ }
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
usleep_range(min_udelay, 2 * min_udelay);
spin_lock_irqsave(&crtc->dev->event_lock, flags);
};
+ if (!repcnt)
+ DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
+ "framedur %d, linedur %d, stat %d, vpos %d, "
+ "hpos %d\n", work->crtc_id, min_udelay,
+ vblank->framedur_ns / 1000,
+ vblank->linedur_ns / 1000, stat, vpos, hpos);
+
/* do the flip (mmio) */
adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
/* set the flip status */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 7380f782cd14..d20c2a8929cb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -596,7 +596,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
break;
}
ttm_eu_backoff_reservation(&ticket, &list);
- if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE))
+ if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) &&
+ !amdgpu_vm_debug)
amdgpu_gem_va_update_vm(adev, bo_va, args->operation);
drm_gem_object_unreference_unlocked(gobj);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
index 7d8d84eaea4a..95a4a25d8df9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -113,6 +113,10 @@ static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
+ if ((adev->flags & AMD_IS_PX) &&
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+ return snprintf(buf, PAGE_SIZE, "off\n");
+
if (adev->pp_enabled) {
enum amd_dpm_forced_level level;
@@ -140,6 +144,11 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
enum amdgpu_dpm_forced_level level;
int ret = 0;
+ /* Can't force performance level when the card is off */
+ if ((adev->flags & AMD_IS_PX) &&
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+ return -EINVAL;
+
if (strncmp("low", buf, strlen("low")) == 0) {
level = AMDGPU_DPM_FORCED_LEVEL_LOW;
} else if (strncmp("high", buf, strlen("high")) == 0) {
@@ -157,6 +166,7 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
mutex_lock(&adev->pm.mutex);
if (adev->pm.dpm.thermal_active) {
count = -EINVAL;
+ mutex_unlock(&adev->pm.mutex);
goto fail;
}
ret = amdgpu_dpm_force_performance_level(adev, level);
@@ -167,8 +177,6 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
mutex_unlock(&adev->pm.mutex);
}
fail:
- mutex_unlock(&adev->pm.mutex);
-
return count;
}
@@ -182,8 +190,14 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
char *buf)
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
+ struct drm_device *ddev = adev->ddev;
int temp;
+ /* Can't get temperature when the card is off */
+ if ((adev->flags & AMD_IS_PX) &&
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+ return -EINVAL;
+
if (!adev->pp_enabled && !adev->pm.funcs->get_temperature)
temp = 0;
else
@@ -634,11 +648,6 @@ force:
/* update display watermarks based on new power state */
amdgpu_display_bandwidth_update(adev);
- /* update displays */
- amdgpu_dpm_display_configuration_changed(adev);
-
- adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
- adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
/* wait for the rings to drain */
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
@@ -655,6 +664,12 @@ force:
amdgpu_dpm_post_set_power_state(adev);
+ /* update displays */
+ amdgpu_dpm_display_configuration_changed(adev);
+
+ adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
+ adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
+
if (adev->pm.funcs->force_performance_level) {
if (adev->pm.dpm.thermal_active) {
enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
@@ -847,12 +862,16 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct amdgpu_device *adev = dev->dev_private;
+ struct drm_device *ddev = adev->ddev;
if (!adev->pm.dpm_enabled) {
seq_printf(m, "dpm not enabled\n");
return 0;
}
- if (adev->pp_enabled) {
+ if ((adev->flags & AMD_IS_PX) &&
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
+ seq_printf(m, "PX asic powered off\n");
+ } else if (adev->pp_enabled) {
amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
} else {
mutex_lock(&adev->pm.mutex);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
index b9d0d55f6b47..3cb6d6c413c7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
@@ -143,8 +143,10 @@ static int amdgpu_pp_late_init(void *handle)
adev->powerplay.pp_handle);
#ifdef CONFIG_DRM_AMD_POWERPLAY
- if (adev->pp_enabled)
+ if (adev->pp_enabled) {
amdgpu_pm_sysfs_init(adev);
+ amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_COMPLETE_INIT, NULL, NULL);
+ }
#endif
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 6442a06d6fdc..1cbb16e15307 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -712,7 +712,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm)
0, PAGE_SIZE,
PCI_DMA_BIDIRECTIONAL);
if (pci_dma_mapping_error(adev->pdev, gtt->ttm.dma_address[i])) {
- while (--i) {
+ while (i--) {
pci_unmap_page(adev->pdev, gtt->ttm.dma_address[i],
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
gtt->ttm.dma_address[i] = 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
index 21aacc1f45c1..bf731e9f643e 100644
--- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
@@ -265,15 +265,27 @@ static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector
unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
unsigned lane_num, i, max_pix_clock;
- for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
- for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
- max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+ if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) ==
+ ENCODER_OBJECT_ID_NUTMEG) {
+ for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+ max_pix_clock = (lane_num * 270000 * 8) / bpp;
if (max_pix_clock >= pix_clock) {
*dp_lanes = lane_num;
- *dp_rate = link_rates[i];
+ *dp_rate = 270000;
return 0;
}
}
+ } else {
+ for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+ for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
+ max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+ if (max_pix_clock >= pix_clock) {
+ *dp_lanes = lane_num;
+ *dp_rate = link_rates[i];
+ return 0;
+ }
+ }
+ }
}
return -EINVAL;
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
index 9056355309d1..e7ef2261ff4a 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
@@ -2202,8 +2202,7 @@ static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate)
AMD_PG_STATE_GATE);
cz_enable_vce_dpm(adev, false);
- /* TODO: to figure out why vce can't be poweroff. */
- /* cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerOFF); */
+ cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerOFF);
pi->vce_power_gated = true;
} else {
cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerON);
@@ -2226,10 +2225,8 @@ static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate)
}
} else { /*pi->caps_vce_pg*/
cz_update_vce_dpm(adev);
- cz_enable_vce_dpm(adev, true);
+ cz_enable_vce_dpm(adev, !gate);
}
-
- return;
}
const struct amd_ip_funcs cz_dpm_ip_funcs = {
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
index 7732059ae30f..06602df707f8 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -3628,6 +3628,19 @@ static void gfx_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
unsigned vm_id, uint64_t pd_addr)
{
int usepfp = (ring->type == AMDGPU_RING_TYPE_GFX);
+ uint32_t seq = ring->fence_drv.sync_seq;
+ uint64_t addr = ring->fence_drv.gpu_addr;
+
+ amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+ amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */
+ WAIT_REG_MEM_FUNCTION(3) | /* equal */
+ WAIT_REG_MEM_ENGINE(usepfp))); /* pfp or me */
+ amdgpu_ring_write(ring, addr & 0xfffffffc);
+ amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+ amdgpu_ring_write(ring, seq);
+ amdgpu_ring_write(ring, 0xffffffff);
+ amdgpu_ring_write(ring, 4); /* poll interval */
+
if (usepfp) {
/* synce CE with ME to prevent CE fetch CEIB before context switch done */
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 8f8ec37ecd88..7086ac17abee 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -4809,7 +4809,8 @@ static void gfx_v8_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */
- WAIT_REG_MEM_FUNCTION(3))); /* equal */
+ WAIT_REG_MEM_FUNCTION(3) | /* equal */
+ WAIT_REG_MEM_ENGINE(usepfp))); /* pfp or me */
amdgpu_ring_write(ring, addr & 0xfffffffc);
amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
amdgpu_ring_write(ring, seq);
@@ -4995,7 +4996,7 @@ static int gfx_v8_0_set_priv_reg_fault_state(struct amdgpu_device *adev,
case AMDGPU_IRQ_STATE_ENABLE:
cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
- PRIV_REG_INT_ENABLE, 0);
+ PRIV_REG_INT_ENABLE, 1);
WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
break;
default:
diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
index aa67244a77ae..589599f66fcc 100644
--- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
@@ -402,8 +402,11 @@ int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, void *input,
data.requested_ui_label = power_state_convert(ps);
ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
+ break;
}
- break;
+ case AMD_PP_EVENT_COMPLETE_INIT:
+ ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
+ break;
default:
break;
}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
index 83be3cf210e0..6b52c78cb404 100644
--- a/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
@@ -165,6 +165,7 @@ const struct action_chain resume_action_chain = {
};
static const pem_event_action *complete_init_event[] = {
+ unblock_adjust_power_state_tasks,
adjust_power_state_tasks,
enable_gfx_clock_gating_tasks,
enable_gfx_voltage_island_power_gating_tasks,
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
index 52a3efc97f05..46410e3c7349 100644
--- a/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
@@ -31,7 +31,7 @@
static int pem_init(struct pp_eventmgr *eventmgr)
{
int result = 0;
- struct pem_event_data event_data;
+ struct pem_event_data event_data = { {0} };
/* Initialize PowerPlay feature info */
pem_init_feature_info(eventmgr);
@@ -52,7 +52,7 @@ static int pem_init(struct pp_eventmgr *eventmgr)
static void pem_fini(struct pp_eventmgr *eventmgr)
{
- struct pem_event_data event_data;
+ struct pem_event_data event_data = { {0} };
pem_uninit_featureInfo(eventmgr);
pem_unregister_interrupts(eventmgr);
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
index ad7700822a1c..ff08ce41bde9 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
@@ -226,7 +226,7 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
}
} else {
cz_dpm_update_vce_dpm(hwmgr);
- cz_enable_disable_vce_dpm(hwmgr, true);
+ cz_enable_disable_vce_dpm(hwmgr, !bgate);
return 0;
}
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index 9759009d1da3..b1480acbb3c3 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -227,7 +227,7 @@ static int ast_get_dram_info(struct drm_device *dev)
} while (ast_read32(ast, 0x10000) != 0x01);
data = ast_read32(ast, 0x10004);
- if (data & 0x400)
+ if (data & 0x40)
ast->dram_bus_width = 16;
else
ast->dram_bus_width = 32;
diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c
index 7f1a3604b19f..b332b4d3b0e2 100644
--- a/drivers/gpu/drm/bochs/bochs_drv.c
+++ b/drivers/gpu/drm/bochs/bochs_drv.c
@@ -182,8 +182,8 @@ static const struct pci_device_id bochs_pci_tbl[] = {
{
.vendor = 0x1234,
.device = 0x1111,
- .subvendor = 0x1af4,
- .subdevice = 0x1100,
+ .subvendor = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
+ .subdevice = PCI_SUBDEVICE_ID_QEMU,
.driver_data = BOCHS_QEMU_STDVGA,
},
{
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
index b1619e29a564..7bc394ec9fb3 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -33,8 +33,9 @@ static struct drm_driver driver;
/* only bind to the cirrus chip in qemu */
static const struct pci_device_id pciidlist[] = {
- { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, 0x1af4, 0x1100, 0,
- 0, 0 },
+ { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
+ PCI_SUBVENDOR_ID_REDHAT_QUMRANET, PCI_SUBDEVICE_ID_QEMU,
+ 0, 0, 0 },
{ PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, PCI_VENDOR_ID_XEN,
0x0001, 0, 0, 0 },
{0,}
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3f74193885f1..9a7b44616b55 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -65,8 +65,6 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
*/
state->allow_modeset = true;
- state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector);
-
state->crtcs = kcalloc(dev->mode_config.num_crtc,
sizeof(*state->crtcs), GFP_KERNEL);
if (!state->crtcs)
@@ -83,16 +81,6 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
sizeof(*state->plane_states), GFP_KERNEL);
if (!state->plane_states)
goto fail;
- state->connectors = kcalloc(state->num_connector,
- sizeof(*state->connectors),
- GFP_KERNEL);
- if (!state->connectors)
- goto fail;
- state->connector_states = kcalloc(state->num_connector,
- sizeof(*state->connector_states),
- GFP_KERNEL);
- if (!state->connector_states)
- goto fail;
state->dev = dev;
@@ -823,19 +811,27 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
index = drm_connector_index(connector);
- /*
- * Construction of atomic state updates can race with a connector
- * hot-add which might overflow. In this case flip the table and just
- * restart the entire ioctl - no one is fast enough to livelock a cpu
- * with physical hotplug events anyway.
- *
- * Note that we only grab the indexes once we have the right lock to
- * prevent hotplug/unplugging of connectors. So removal is no problem,
- * at most the array is a bit too large.
- */
if (index >= state->num_connector) {
- DRM_DEBUG_ATOMIC("Hot-added connector would overflow state array, restarting\n");
- return ERR_PTR(-EAGAIN);
+ struct drm_connector **c;
+ struct drm_connector_state **cs;
+ int alloc = max(index + 1, config->num_connector);
+
+ c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL);
+ if (!c)
+ return ERR_PTR(-ENOMEM);
+
+ state->connectors = c;
+ memset(&state->connectors[state->num_connector], 0,
+ sizeof(*state->connectors) * (alloc - state->num_connector));
+
+ cs = krealloc(state->connector_states, alloc * sizeof(*state->connector_states), GFP_KERNEL);
+ if (!cs)
+ return ERR_PTR(-ENOMEM);
+
+ state->connector_states = cs;
+ memset(&state->connector_states[state->num_connector], 0,
+ sizeof(*state->connector_states) * (alloc - state->num_connector));
+ state->num_connector = alloc;
}
if (state->connector_states[index])
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 7c523060a076..4f2d3e161593 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1493,7 +1493,7 @@ void drm_atomic_helper_swap_state(struct drm_device *dev,
{
int i;
- for (i = 0; i < dev->mode_config.num_connector; i++) {
+ for (i = 0; i < state->num_connector; i++) {
struct drm_connector *connector = state->connectors[i];
if (!connector)
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index d40bab29747e..f6191215b2cb 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -918,12 +918,19 @@ int drm_connector_init(struct drm_device *dev,
connector->base.properties = &connector->properties;
connector->dev = dev;
connector->funcs = funcs;
+
+ connector->connector_id = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL);
+ if (connector->connector_id < 0) {
+ ret = connector->connector_id;
+ goto out_put;
+ }
+
connector->connector_type = connector_type;
connector->connector_type_id =
ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
if (connector->connector_type_id < 0) {
ret = connector->connector_type_id;
- goto out_put;
+ goto out_put_id;
}
connector->name =
kasprintf(GFP_KERNEL, "%s-%d",
@@ -931,7 +938,7 @@ int drm_connector_init(struct drm_device *dev,
connector->connector_type_id);
if (!connector->name) {
ret = -ENOMEM;
- goto out_put;
+ goto out_put_type_id;
}
INIT_LIST_HEAD(&connector->probed_modes);
@@ -959,7 +966,12 @@ int drm_connector_init(struct drm_device *dev,
}
connector->debugfs_entry = NULL;
-
+out_put_type_id:
+ if (ret)
+ ida_remove(connector_ida, connector->connector_type_id);
+out_put_id:
+ if (ret)
+ ida_remove(&config->connector_ida, connector->connector_id);
out_put:
if (ret)
drm_mode_object_put(dev, &connector->base);
@@ -996,6 +1008,9 @@ void drm_connector_cleanup(struct drm_connector *connector)
ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
connector->connector_type_id);
+ ida_remove(&dev->mode_config.connector_ida,
+ connector->connector_id);
+
kfree(connector->display_info.bus_formats);
drm_mode_object_put(dev, &connector->base);
kfree(connector->name);
@@ -1013,32 +1028,6 @@ void drm_connector_cleanup(struct drm_connector *connector)
EXPORT_SYMBOL(drm_connector_cleanup);
/**
- * drm_connector_index - find the index of a registered connector
- * @connector: connector to find index for
- *
- * Given a registered connector, return the index of that connector within a DRM
- * device's list of connectors.
- */
-unsigned int drm_connector_index(struct drm_connector *connector)
-{
- unsigned int index = 0;
- struct drm_connector *tmp;
- struct drm_mode_config *config = &connector->dev->mode_config;
-
- WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
-
- drm_for_each_connector(tmp, connector->dev) {
- if (tmp == connector)
- return index;
-
- index++;
- }
-
- BUG();
-}
-EXPORT_SYMBOL(drm_connector_index);
-
-/**
* drm_connector_register - register a connector
* @connector: the connector to register
*
@@ -5789,6 +5778,7 @@ void drm_mode_config_init(struct drm_device *dev)
INIT_LIST_HEAD(&dev->mode_config.plane_list);
idr_init(&dev->mode_config.crtc_idr);
idr_init(&dev->mode_config.tile_idr);
+ ida_init(&dev->mode_config.connector_ida);
drm_modeset_lock_all(dev);
drm_mode_create_standard_properties(dev);
@@ -5869,6 +5859,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
crtc->funcs->destroy(crtc);
}
+ ida_destroy(&dev->mode_config.connector_ida);
idr_destroy(&dev->mode_config.tile_idr);
idr_destroy(&dev->mode_config.crtc_idr);
drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 8ae13de272c4..27fbd79d0daf 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -1159,11 +1159,13 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
drm_dp_put_port(port);
goto out;
}
-
- drm_mode_connector_set_tile_property(port->connector);
-
+ if (port->port_num >= DP_MST_LOGICAL_PORT_0) {
+ port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
+ drm_mode_connector_set_tile_property(port->connector);
+ }
(*mstb->mgr->cbs->register_connector)(port->connector);
}
+
out:
/* put reference to this port */
drm_dp_put_port(port);
@@ -1188,8 +1190,8 @@ static void drm_dp_update_port(struct drm_dp_mst_branch *mstb,
port->ddps = conn_stat->displayport_device_plug_status;
if (old_ddps != port->ddps) {
- dowork = true;
if (port->ddps) {
+ dowork = true;
} else {
port->available_pbn = 0;
}
@@ -1294,13 +1296,8 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m
if (port->input)
continue;
- if (!port->ddps) {
- if (port->cached_edid) {
- kfree(port->cached_edid);
- port->cached_edid = NULL;
- }
+ if (!port->ddps)
continue;
- }
if (!port->available_pbn)
drm_dp_send_enum_path_resources(mgr, mstb, port);
@@ -1311,12 +1308,6 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m
drm_dp_check_and_send_link_address(mgr, mstb_child);
drm_dp_put_mst_branch_device(mstb_child);
}
- } else if (port->pdt == DP_PEER_DEVICE_SST_SINK ||
- port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV) {
- if (!port->cached_edid) {
- port->cached_edid =
- drm_get_edid(port->connector, &port->aux.ddc);
- }
}
}
}
@@ -1336,8 +1327,6 @@ static void drm_dp_mst_link_probe_work(struct work_struct *work)
drm_dp_check_and_send_link_address(mgr, mstb);
drm_dp_put_mst_branch_device(mstb);
}
-
- (*mgr->cbs->hotplug)(mgr);
}
static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
@@ -1597,6 +1586,7 @@ static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) {
drm_dp_add_port(mstb, mgr->dev, &txmsg->reply.u.link_addr.ports[i]);
}
+ (*mgr->cbs->hotplug)(mgr);
}
} else {
mstb->link_address_sent = false;
@@ -2293,6 +2283,8 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
drm_dp_update_port(mstb, &msg.u.conn_stat);
DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type);
+ (*mgr->cbs->hotplug)(mgr);
+
} else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) {
drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);
if (!mstb)
@@ -2379,6 +2371,10 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector
case DP_PEER_DEVICE_SST_SINK:
status = connector_status_connected;
+ /* for logical ports - cache the EDID */
+ if (port->port_num >= 8 && !port->cached_edid) {
+ port->cached_edid = drm_get_edid(connector, &port->aux.ddc);
+ }
break;
case DP_PEER_DEVICE_DP_LEGACY_CONV:
if (port->ldps)
@@ -2433,7 +2429,10 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
if (port->cached_edid)
edid = drm_edid_duplicate(port->cached_edid);
-
+ else {
+ edid = drm_get_edid(connector, &port->aux.ddc);
+ drm_mode_connector_set_tile_property(connector);
+ }
port->has_audio = drm_detect_monitor_audio(edid);
drm_dp_put_port(port);
return edid;
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
index e5df53b6e229..1f500a1b9969 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -109,8 +109,8 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
if (IS_ERR(cma_obj))
return cma_obj;
- cma_obj->vaddr = dma_alloc_writecombine(drm->dev, size,
- &cma_obj->paddr, GFP_KERNEL | __GFP_NOWARN);
+ cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr,
+ GFP_KERNEL | __GFP_NOWARN);
if (!cma_obj->vaddr) {
dev_err(drm->dev, "failed to allocate buffer with size %zu\n",
size);
@@ -192,8 +192,8 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
cma_obj = to_drm_gem_cma_obj(gem_obj);
if (cma_obj->vaddr) {
- dma_free_writecombine(gem_obj->dev->dev, cma_obj->base.size,
- cma_obj->vaddr, cma_obj->paddr);
+ dma_free_wc(gem_obj->dev->dev, cma_obj->base.size,
+ cma_obj->vaddr, cma_obj->paddr);
} else if (gem_obj->import_attach) {
drm_prime_gem_destroy(gem_obj, cma_obj->sgt);
}
@@ -324,9 +324,8 @@ static int drm_gem_cma_mmap_obj(struct drm_gem_cma_object *cma_obj,
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_pgoff = 0;
- ret = dma_mmap_writecombine(cma_obj->base.dev->dev, vma,
- cma_obj->vaddr, cma_obj->paddr,
- vma->vm_end - vma->vm_start);
+ ret = dma_mmap_wc(cma_obj->base.dev->dev, vma, cma_obj->vaddr,
+ cma_obj->paddr, vma->vm_end - vma->vm_start);
if (ret)
drm_gem_vm_close(vma);
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index d12a4efa651b..1fe14579e8c9 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -224,6 +224,64 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0;
}
+ /*
+ * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset
+ * interval? If so then vblank irqs keep running and it will likely
+ * happen that the hardware vblank counter is not trustworthy as it
+ * might reset at some point in that interval and vblank timestamps
+ * are not trustworthy either in that interval. Iow. this can result
+ * in a bogus diff >> 1 which must be avoided as it would cause
+ * random large forward jumps of the software vblank counter.
+ */
+ if (diff > 1 && (vblank->inmodeset & 0x2)) {
+ DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u"
+ " due to pre-modeset.\n", pipe, diff);
+ diff = 1;
+ }
+
+ /*
+ * FIMXE: Need to replace this hack with proper seqlocks.
+ *
+ * Restrict the bump of the software vblank counter to a safe maximum
+ * value of +1 whenever there is the possibility that concurrent readers
+ * of vblank timestamps could be active at the moment, as the current
+ * implementation of the timestamp caching and updating is not safe
+ * against concurrent readers for calls to store_vblank() with a bump
+ * of anything but +1. A bump != 1 would very likely return corrupted
+ * timestamps to userspace, because the same slot in the cache could
+ * be concurrently written by store_vblank() and read by one of those
+ * readers without the read-retry logic detecting the collision.
+ *
+ * Concurrent readers can exist when we are called from the
+ * drm_vblank_off() or drm_vblank_on() functions and other non-vblank-
+ * irq callers. However, all those calls to us are happening with the
+ * vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount
+ * can't increase while we are executing. Therefore a zero refcount at
+ * this point is safe for arbitrary counter bumps if we are called
+ * outside vblank irq, a non-zero count is not 100% safe. Unfortunately
+ * we must also accept a refcount of 1, as whenever we are called from
+ * drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and
+ * we must let that one pass through in order to not lose vblank counts
+ * during vblank irq off - which would completely defeat the whole
+ * point of this routine.
+ *
+ * Whenever we are called from vblank irq, we have to assume concurrent
+ * readers exist or can show up any time during our execution, even if
+ * the refcount is currently zero, as vblank irqs are usually only
+ * enabled due to the presence of readers, and because when we are called
+ * from vblank irq we can't hold the vbl_lock to protect us from sudden
+ * bumps in vblank refcount. Therefore also restrict bumps to +1 when
+ * called from vblank irq.
+ */
+ if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 ||
+ (flags & DRM_CALLED_FROM_VBLIRQ))) {
+ DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u "
+ "refcount %u, vblirq %u\n", pipe, diff,
+ atomic_read(&vblank->refcount),
+ (flags & DRM_CALLED_FROM_VBLIRQ) != 0);
+ diff = 1;
+ }
+
DRM_DEBUG_VBL("updating vblank count on crtc %u:"
" current=%u, diff=%u, hw=%u hw_last=%u\n",
pipe, vblank->count, diff, cur_vblank, vblank->last);
@@ -1316,7 +1374,13 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe)
spin_lock_irqsave(&dev->event_lock, irqflags);
spin_lock(&dev->vbl_lock);
- vblank_disable_and_save(dev, pipe);
+ DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
+ pipe, vblank->enabled, vblank->inmodeset);
+
+ /* Avoid redundant vblank disables without previous drm_vblank_on(). */
+ if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset)
+ vblank_disable_and_save(dev, pipe);
+
wake_up(&vblank->queue);
/*
@@ -1418,6 +1482,9 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
return;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
+ pipe, vblank->enabled, vblank->inmodeset);
+
/* Drop our private "prevent drm_vblank_get" refcount */
if (vblank->inmodeset) {
atomic_dec(&vblank->refcount);
@@ -1430,8 +1497,7 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
* re-enable interrupts if there are users left, or the
* user wishes vblank interrupts to be enabled all the time.
*/
- if (atomic_read(&vblank->refcount) != 0 ||
- (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0))
+ if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0)
WARN_ON(drm_vblank_enable(dev, pipe));
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
@@ -1526,6 +1592,7 @@ void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe)
if (vblank->inmodeset) {
spin_lock_irqsave(&dev->vbl_lock, irqflags);
dev->vblank_disable_allowed = true;
+ drm_reset_vblank_timestamp(dev, pipe);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
if (vblank->inmodeset & 0x2)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index a33162cf4f4c..3c1ce44483d9 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1113,8 +1113,8 @@ struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size,
if (!cmdbuf)
return NULL;
- cmdbuf->vaddr = dma_alloc_writecombine(gpu->dev, size, &cmdbuf->paddr,
- GFP_KERNEL);
+ cmdbuf->vaddr = dma_alloc_wc(gpu->dev, size, &cmdbuf->paddr,
+ GFP_KERNEL);
if (!cmdbuf->vaddr) {
kfree(cmdbuf);
return NULL;
@@ -1128,8 +1128,8 @@ struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size,
void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
{
- dma_free_writecombine(cmdbuf->gpu->dev, cmdbuf->size,
- cmdbuf->vaddr, cmdbuf->paddr);
+ dma_free_wc(cmdbuf->gpu->dev, cmdbuf->size, cmdbuf->vaddr,
+ cmdbuf->paddr);
kfree(cmdbuf);
}
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 83efca941388..f17d39279596 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -1,6 +1,6 @@
config DRM_EXYNOS
tristate "DRM Support for Samsung SoC EXYNOS Series"
- depends on OF && DRM && (PLAT_SAMSUNG || ARCH_MULTIPLATFORM)
+ depends on OF && DRM && (ARCH_S3C64XX || ARCH_EXYNOS || ARCH_MULTIPLATFORM)
select DRM_KMS_HELPER
select DRM_KMS_FB_HELPER
select FB_CFB_FILLRECT
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index 1bf6a21130c7..162ab93e99cb 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -93,7 +93,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return -EPERM;
- if (test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
+ if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
val = VIDINTCON0_INTEN;
if (ctx->out_type == IFTYPE_I80)
val |= VIDINTCON0_FRAMEDONE;
@@ -402,8 +402,6 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
decon_enable_vblank(ctx->crtc);
decon_commit(ctx->crtc);
-
- set_bit(BIT_SUSPENDED, &ctx->flags);
}
static void decon_disable(struct exynos_drm_crtc *crtc)
@@ -582,9 +580,9 @@ out:
static int exynos5433_decon_suspend(struct device *dev)
{
struct decon_context *ctx = dev_get_drvdata(dev);
- int i;
+ int i = ARRAY_SIZE(decon_clks_name);
- for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++)
+ while (--i >= 0)
clk_disable_unprepare(ctx->clks[i]);
return 0;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index e977a81af2e6..26e81d191f56 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1782,6 +1782,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
bridge = of_drm_find_bridge(dsi->bridge_node);
if (bridge) {
+ encoder->bridge = bridge;
drm_bridge_attach(drm_dev, bridge);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index f6118baa8e3e..8baabd813ff5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -50,7 +50,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
if (vm_size > exynos_gem->size)
return -EINVAL;
- ret = dma_mmap_attrs(helper->dev->dev, vma, exynos_gem->pages,
+ ret = dma_mmap_attrs(helper->dev->dev, vma, exynos_gem->cookie,
exynos_gem->dma_addr, exynos_gem->size,
&exynos_gem->dma_attrs);
if (ret < 0) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index c747824f3c98..8a4f4a0211d0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -1723,7 +1723,7 @@ static int fimc_probe(struct platform_device *pdev)
goto err_put_clk;
}
- DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv);
+ DRM_DEBUG_KMS("id[%d]ippdrv[%p]\n", ctx->id, ippdrv);
spin_lock_init(&ctx->lock);
platform_set_drvdata(pdev, ctx);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index c17efdb238a6..8dfe6e113a88 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -1166,7 +1166,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
goto err_free_event;
}
- cmd = (struct drm_exynos_g2d_cmd *)(uint32_t)req->cmd;
+ cmd = (struct drm_exynos_g2d_cmd *)(unsigned long)req->cmd;
if (copy_from_user(cmdlist->data + cmdlist->last,
(void __user *)cmd,
@@ -1184,7 +1184,8 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
if (req->cmd_buf_nr) {
struct drm_exynos_g2d_cmd *cmd_buf;
- cmd_buf = (struct drm_exynos_g2d_cmd *)(uint32_t)req->cmd_buf;
+ cmd_buf = (struct drm_exynos_g2d_cmd *)
+ (unsigned long)req->cmd_buf;
if (copy_from_user(cmdlist->data + cmdlist->last,
(void __user *)cmd_buf,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 32358c5e3db4..26b5e4bd55b6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -218,7 +218,7 @@ static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,
return ERR_PTR(ret);
}
- DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
+ DRM_DEBUG_KMS("created file object = %p\n", obj->filp);
return exynos_gem;
}
@@ -335,7 +335,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem,
if (vm_size > exynos_gem->size)
return -EINVAL;
- ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem->pages,
+ ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem->cookie,
exynos_gem->dma_addr, exynos_gem->size,
&exynos_gem->dma_attrs);
if (ret < 0) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 7aecd23cfa11..5d20da8f957e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -1723,7 +1723,7 @@ static int gsc_probe(struct platform_device *pdev)
return ret;
}
- DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv);
+ DRM_DEBUG_KMS("id[%d]ippdrv[%p]\n", ctx->id, ippdrv);
mutex_init(&ctx->lock);
platform_set_drvdata(pdev, ctx);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index 67d24236e745..95eeb9116f10 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -208,7 +208,7 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id)
* e.g PAUSE state, queue buf, command control.
*/
list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
- DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv);
+ DRM_DEBUG_KMS("count[%d]ippdrv[%p]\n", count++, ippdrv);
mutex_lock(&ippdrv->cmd_lock);
list_for_each_entry(c_node, &ippdrv->cmd_list, list) {
@@ -388,8 +388,8 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
}
property->prop_id = ret;
- DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[0x%x]\n",
- property->prop_id, property->cmd, (int)ippdrv);
+ DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[%p]\n",
+ property->prop_id, property->cmd, ippdrv);
/* stored property information and ippdrv in private data */
c_node->property = *property;
@@ -518,7 +518,7 @@ static int ipp_put_mem_node(struct drm_device *drm_dev,
{
int i;
- DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
+ DRM_DEBUG_KMS("node[%p]\n", m_node);
if (!m_node) {
DRM_ERROR("invalid dequeue node.\n");
@@ -562,7 +562,7 @@ static struct drm_exynos_ipp_mem_node
m_node->buf_id = qbuf->buf_id;
INIT_LIST_HEAD(&m_node->list);
- DRM_DEBUG_KMS("m_node[0x%x]ops_id[%d]\n", (int)m_node, qbuf->ops_id);
+ DRM_DEBUG_KMS("m_node[%p]ops_id[%d]\n", m_node, qbuf->ops_id);
DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]\n", qbuf->prop_id, m_node->buf_id);
for_each_ipp_planar(i) {
@@ -582,8 +582,8 @@ static struct drm_exynos_ipp_mem_node
buf_info->handles[i] = qbuf->handle[i];
buf_info->base[i] = *addr;
- DRM_DEBUG_KMS("i[%d]base[0x%x]hd[0x%lx]\n", i,
- buf_info->base[i], buf_info->handles[i]);
+ DRM_DEBUG_KMS("i[%d]base[%pad]hd[0x%lx]\n", i,
+ &buf_info->base[i], buf_info->handles[i]);
}
}
@@ -664,7 +664,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,
mutex_lock(&c_node->event_lock);
list_for_each_entry_safe(e, te, &c_node->event_list, base.link) {
- DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e);
+ DRM_DEBUG_KMS("count[%d]e[%p]\n", count++, e);
/*
* qbuf == NULL condition means all event deletion.
@@ -755,7 +755,7 @@ static struct drm_exynos_ipp_mem_node
/* find memory node from memory list */
list_for_each_entry(m_node, head, list) {
- DRM_DEBUG_KMS("count[%d]m_node[0x%x]\n", count++, (int)m_node);
+ DRM_DEBUG_KMS("count[%d]m_node[%p]\n", count++, m_node);
/* compare buffer id */
if (m_node->buf_id == qbuf->buf_id)
@@ -772,7 +772,7 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
struct exynos_drm_ipp_ops *ops = NULL;
int ret = 0;
- DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
+ DRM_DEBUG_KMS("node[%p]\n", m_node);
if (!m_node) {
DRM_ERROR("invalid queue node.\n");
@@ -1237,7 +1237,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
m_node = list_first_entry(head,
struct drm_exynos_ipp_mem_node, list);
- DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node);
+ DRM_DEBUG_KMS("m_node[%p]\n", m_node);
ret = ipp_set_mem_node(ippdrv, c_node, m_node);
if (ret) {
@@ -1610,8 +1610,8 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
}
ippdrv->prop_list.ipp_id = ret;
- DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n",
- count++, (int)ippdrv, ret);
+ DRM_DEBUG_KMS("count[%d]ippdrv[%p]ipp_id[%d]\n",
+ count++, ippdrv, ret);
/* store parent device for node */
ippdrv->parent_dev = dev;
@@ -1668,7 +1668,7 @@ static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev,
file_priv->ipp_dev = dev;
- DRM_DEBUG_KMS("done priv[0x%x]\n", (int)dev);
+ DRM_DEBUG_KMS("done priv[%p]\n", dev);
return 0;
}
@@ -1685,8 +1685,8 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,
mutex_lock(&ippdrv->cmd_lock);
list_for_each_entry_safe(c_node, tc_node,
&ippdrv->cmd_list, list) {
- DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n",
- count++, (int)ippdrv);
+ DRM_DEBUG_KMS("count[%d]ippdrv[%p]\n",
+ count++, ippdrv);
if (c_node->filp == file) {
/*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index 4eaef36aec5a..9869d70e9e54 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/clk.h>
+#include <linux/component.h>
#include <drm/drmP.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -306,9 +307,9 @@ exit:
return ret;
}
-void mic_disable(struct drm_bridge *bridge) { }
+static void mic_disable(struct drm_bridge *bridge) { }
-void mic_post_disable(struct drm_bridge *bridge)
+static void mic_post_disable(struct drm_bridge *bridge)
{
struct exynos_mic *mic = bridge->driver_private;
int i;
@@ -328,7 +329,7 @@ already_disabled:
mutex_unlock(&mic_mutex);
}
-void mic_pre_enable(struct drm_bridge *bridge)
+static void mic_pre_enable(struct drm_bridge *bridge)
{
struct exynos_mic *mic = bridge->driver_private;
int ret, i;
@@ -371,11 +372,35 @@ already_enabled:
mutex_unlock(&mic_mutex);
}
-void mic_enable(struct drm_bridge *bridge) { }
+static void mic_enable(struct drm_bridge *bridge) { }
-void mic_destroy(struct drm_bridge *bridge)
+static const struct drm_bridge_funcs mic_bridge_funcs = {
+ .disable = mic_disable,
+ .post_disable = mic_post_disable,
+ .pre_enable = mic_pre_enable,
+ .enable = mic_enable,
+};
+
+static int exynos_mic_bind(struct device *dev, struct device *master,
+ void *data)
{
- struct exynos_mic *mic = bridge->driver_private;
+ struct exynos_mic *mic = dev_get_drvdata(dev);
+ int ret;
+
+ mic->bridge.funcs = &mic_bridge_funcs;
+ mic->bridge.of_node = dev->of_node;
+ mic->bridge.driver_private = mic;
+ ret = drm_bridge_add(&mic->bridge);
+ if (ret)
+ DRM_ERROR("mic: Failed to add MIC to the global bridge list\n");
+
+ return ret;
+}
+
+static void exynos_mic_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct exynos_mic *mic = dev_get_drvdata(dev);
int i;
mutex_lock(&mic_mutex);
@@ -387,16 +412,16 @@ void mic_destroy(struct drm_bridge *bridge)
already_disabled:
mutex_unlock(&mic_mutex);
+
+ drm_bridge_remove(&mic->bridge);
}
-static const struct drm_bridge_funcs mic_bridge_funcs = {
- .disable = mic_disable,
- .post_disable = mic_post_disable,
- .pre_enable = mic_pre_enable,
- .enable = mic_enable,
+static const struct component_ops exynos_mic_component_ops = {
+ .bind = exynos_mic_bind,
+ .unbind = exynos_mic_unbind,
};
-int exynos_mic_probe(struct platform_device *pdev)
+static int exynos_mic_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct exynos_mic *mic;
@@ -435,17 +460,8 @@ int exynos_mic_probe(struct platform_device *pdev)
goto err;
}
- mic->bridge.funcs = &mic_bridge_funcs;
- mic->bridge.of_node = dev->of_node;
- mic->bridge.driver_private = mic;
- ret = drm_bridge_add(&mic->bridge);
- if (ret) {
- DRM_ERROR("mic: Failed to add MIC to the global bridge list\n");
- goto err;
- }
-
for (i = 0; i < NUM_CLKS; i++) {
- mic->clks[i] = of_clk_get_by_name(dev->of_node, clk_names[i]);
+ mic->clks[i] = devm_clk_get(dev, clk_names[i]);
if (IS_ERR(mic->clks[i])) {
DRM_ERROR("mic: Failed to get clock (%s)\n",
clk_names[i]);
@@ -454,7 +470,10 @@ int exynos_mic_probe(struct platform_device *pdev)
}
}
+ platform_set_drvdata(pdev, mic);
+
DRM_DEBUG_KMS("MIC has been probed\n");
+ return component_add(dev, &exynos_mic_component_ops);
err:
return ret;
@@ -462,14 +481,7 @@ err:
static int exynos_mic_remove(struct platform_device *pdev)
{
- struct exynos_mic *mic = platform_get_drvdata(pdev);
- int i;
-
- drm_bridge_remove(&mic->bridge);
-
- for (i = NUM_CLKS - 1; i > -1; i--)
- clk_put(mic->clks[i]);
-
+ component_del(&pdev->dev, &exynos_mic_component_ops);
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index bea0f7826d30..ce59f4443394 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -754,7 +754,7 @@ static int rotator_probe(struct platform_device *pdev)
goto err_ippdrv_register;
}
- DRM_DEBUG_KMS("ippdrv[0x%x]\n", (int)ippdrv);
+ DRM_DEBUG_KMS("ippdrv[%p]\n", ippdrv);
platform_set_drvdata(pdev, rot);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 62ac4e5fa51d..b605bd7395ec 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -223,7 +223,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
}
}
-static int vidi_show_connection(struct device *dev,
+static ssize_t vidi_show_connection(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct vidi_context *ctx = dev_get_drvdata(dev);
@@ -238,7 +238,7 @@ static int vidi_show_connection(struct device *dev,
return rc;
}
-static int vidi_store_connection(struct device *dev,
+static ssize_t vidi_store_connection(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
@@ -294,7 +294,9 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
}
if (vidi->connection) {
- struct edid *raw_edid = (struct edid *)(uint32_t)vidi->edid;
+ struct edid *raw_edid;
+
+ raw_edid = (struct edid *)(unsigned long)vidi->edid;
if (!drm_edid_is_valid(raw_edid)) {
DRM_DEBUG_KMS("edid data is invalid.\n");
return -EINVAL;
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 34e38749a817..f8ee740c0e26 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -1382,8 +1382,16 @@ static void tda998x_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
+static int tda998x_connector_dpms(struct drm_connector *connector, int mode)
+{
+ if (drm_core_check_feature(connector->dev, DRIVER_ATOMIC))
+ return drm_atomic_helper_connector_dpms(connector, mode);
+ else
+ return drm_helper_connector_dpms(connector, mode);
+}
+
static const struct drm_connector_funcs tda998x_connector_funcs = {
- .dpms = drm_atomic_helper_connector_dpms,
+ .dpms = tda998x_connector_dpms,
.reset = drm_atomic_helper_connector_reset,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = tda998x_connector_detect,
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 0fc38bb7276c..cf39ed3133d6 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -825,8 +825,11 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
}
for_each_pipe(dev_priv, pipe) {
- if (!intel_display_power_is_enabled(dev_priv,
- POWER_DOMAIN_PIPE(pipe))) {
+ enum intel_display_power_domain power_domain;
+
+ power_domain = POWER_DOMAIN_PIPE(pipe);
+ if (!intel_display_power_get_if_enabled(dev_priv,
+ power_domain)) {
seq_printf(m, "Pipe %c power disabled\n",
pipe_name(pipe));
continue;
@@ -840,6 +843,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
seq_printf(m, "Pipe %c IER:\t%08x\n",
pipe_name(pipe),
I915_READ(GEN8_DE_PIPE_IER(pipe)));
+
+ intel_display_power_put(dev_priv, power_domain);
}
seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
@@ -3985,6 +3990,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
struct intel_crtc *crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev,
pipe));
+ enum intel_display_power_domain power_domain;
u32 val = 0; /* shut up gcc */
int ret;
@@ -3995,7 +4001,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
if (pipe_crc->source && source)
return -EINVAL;
- if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PIPE(pipe))) {
+ power_domain = POWER_DOMAIN_PIPE(pipe);
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) {
DRM_DEBUG_KMS("Trying to capture CRC while pipe is off\n");
return -EIO;
}
@@ -4012,7 +4019,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
ret = ivb_pipe_crc_ctl_reg(dev, pipe, &source, &val);
if (ret != 0)
- return ret;
+ goto out;
/* none -> real source transition */
if (source) {
@@ -4024,8 +4031,10 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
entries = kcalloc(INTEL_PIPE_CRC_ENTRIES_NR,
sizeof(pipe_crc->entries[0]),
GFP_KERNEL);
- if (!entries)
- return -ENOMEM;
+ if (!entries) {
+ ret = -ENOMEM;
+ goto out;
+ }
/*
* When IPS gets enabled, the pipe CRC changes. Since IPS gets
@@ -4081,7 +4090,12 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
hsw_enable_ips(crtc);
}
- return 0;
+ ret = 0;
+
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
/*
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f0f75d7c0d94..b0847b915545 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -751,6 +751,7 @@ struct intel_csr {
uint32_t mmio_count;
i915_reg_t mmioaddr[8];
uint32_t mmiodata[8];
+ uint32_t dc_state;
};
#define DEV_INFO_FOR_EACH_FLAG(func, sep) \
@@ -1988,6 +1989,9 @@ enum hdmi_force_audio {
#define I915_GTT_OFFSET_NONE ((u32)-1)
struct drm_i915_gem_object_ops {
+ unsigned int flags;
+#define I915_GEM_OBJECT_HAS_STRUCT_PAGE 0x1
+
/* Interface between the GEM object and its backing storage.
* get_pages() is called once prior to the use of the associated set
* of pages before to binding them into the GTT, and put_pages() is
@@ -2003,6 +2007,7 @@ struct drm_i915_gem_object_ops {
*/
int (*get_pages)(struct drm_i915_gem_object *);
void (*put_pages)(struct drm_i915_gem_object *);
+
int (*dmabuf_export)(struct drm_i915_gem_object *);
void (*release)(struct drm_i915_gem_object *);
};
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index ddc21d4b388d..bb44bad15403 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4425,6 +4425,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
}
static const struct drm_i915_gem_object_ops i915_gem_object_ops = {
+ .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE,
.get_pages = i915_gem_object_get_pages_gtt,
.put_pages = i915_gem_object_put_pages_gtt,
};
@@ -5261,7 +5262,7 @@ i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, int n)
struct page *page;
/* Only default objects have per-page dirty tracking */
- if (WARN_ON(obj->ops != &i915_gem_object_ops))
+ if (WARN_ON((obj->ops->flags & I915_GEM_OBJECT_HAS_STRUCT_PAGE) == 0))
return NULL;
page = i915_gem_object_get_page(obj, n);
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
index 19fb0bddc1cd..59e45b3a6937 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -789,9 +789,10 @@ i915_gem_userptr_dmabuf_export(struct drm_i915_gem_object *obj)
}
static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = {
- .dmabuf_export = i915_gem_userptr_dmabuf_export,
+ .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE,
.get_pages = i915_gem_userptr_get_pages,
.put_pages = i915_gem_userptr_put_pages,
+ .dmabuf_export = i915_gem_userptr_dmabuf_export,
.release = i915_gem_userptr_release,
};
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 007ae83a4086..4897728713f6 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3287,19 +3287,20 @@ enum skl_disp_power_wells {
#define PORT_HOTPLUG_STAT _MMIO(dev_priv->info.display_mmio_offset + 0x61114)
/*
- * HDMI/DP bits are gen4+
+ * HDMI/DP bits are g4x+
*
* WARNING: Bspec for hpd status bits on gen4 seems to be completely confused.
* Please check the detailed lore in the commit message for for experimental
* evidence.
*/
-#define PORTD_HOTPLUG_LIVE_STATUS_G4X (1 << 29)
+/* Bspec says GM45 should match G4X/VLV/CHV, but reality disagrees */
+#define PORTD_HOTPLUG_LIVE_STATUS_GM45 (1 << 29)
+#define PORTC_HOTPLUG_LIVE_STATUS_GM45 (1 << 28)
+#define PORTB_HOTPLUG_LIVE_STATUS_GM45 (1 << 27)
+/* G4X/VLV/CHV DP/HDMI bits again match Bspec */
+#define PORTD_HOTPLUG_LIVE_STATUS_G4X (1 << 27)
#define PORTC_HOTPLUG_LIVE_STATUS_G4X (1 << 28)
-#define PORTB_HOTPLUG_LIVE_STATUS_G4X (1 << 27)
-/* VLV DP/HDMI bits again match Bspec */
-#define PORTD_HOTPLUG_LIVE_STATUS_VLV (1 << 27)
-#define PORTC_HOTPLUG_LIVE_STATUS_VLV (1 << 28)
-#define PORTB_HOTPLUG_LIVE_STATUS_VLV (1 << 29)
+#define PORTB_HOTPLUG_LIVE_STATUS_G4X (1 << 29)
#define PORTD_HOTPLUG_INT_STATUS (3 << 21)
#define PORTD_HOTPLUG_INT_LONG_PULSE (2 << 21)
#define PORTD_HOTPLUG_INT_SHORT_PULSE (1 << 21)
@@ -7514,7 +7515,7 @@ enum skl_disp_power_wells {
#define DPLL_CFGCR2_PDIV_7 (4<<2)
#define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3)
-#define DPLL_CFGCR1(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR2)
+#define DPLL_CFGCR1(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR1)
#define DPLL_CFGCR2(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR2, _DPLL2_CFGCR2)
/* BXT display engine PLL */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index a2aa09ce3202..a8af594fbd00 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -49,7 +49,7 @@ static void i915_save_display(struct drm_device *dev)
dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS);
dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS);
dev_priv->regfile.savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR);
- } else if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
+ } else if (INTEL_INFO(dev)->gen <= 4) {
dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS);
dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
@@ -84,7 +84,7 @@ static void i915_restore_display(struct drm_device *dev)
I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR);
I915_WRITE(PCH_PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
- } else if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
+ } else if (INTEL_INFO(dev)->gen <= 4) {
I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS);
I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
I915_WRITE(PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR);
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 31f6d212fb1b..30f921421b0c 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -527,6 +527,8 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
mutex_lock(&dev_priv->av_mutex);
intel_dig_port->audio_connector = connector;
+ /* referred in audio callbacks */
+ dev_priv->dig_port_map[port] = intel_encoder;
mutex_unlock(&dev_priv->av_mutex);
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
@@ -554,6 +556,7 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
mutex_lock(&dev_priv->av_mutex);
intel_dig_port->audio_connector = NULL;
+ dev_priv->dig_port_map[port] = NULL;
mutex_unlock(&dev_priv->av_mutex);
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 9c89df1af036..a7b4a524fadd 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -71,22 +71,29 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
struct intel_crt *crt = intel_encoder_to_crt(encoder);
enum intel_display_power_domain power_domain;
u32 tmp;
+ bool ret;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_is_enabled(dev_priv, power_domain))
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
+ ret = false;
+
tmp = I915_READ(crt->adpa_reg);
if (!(tmp & ADPA_DAC_ENABLE))
- return false;
+ goto out;
if (HAS_PCH_CPT(dev))
*pipe = PORT_TO_PIPE_CPT(tmp);
else
*pipe = PORT_TO_PIPE(tmp);
- return true;
+ ret = true;
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
static unsigned int intel_crt_get_flags(struct intel_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index 9bb63a85997a..647d85e77c2f 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -240,6 +240,8 @@ void intel_csr_load_program(struct drm_i915_private *dev_priv)
I915_WRITE(dev_priv->csr.mmioaddr[i],
dev_priv->csr.mmiodata[i]);
}
+
+ dev_priv->csr.dc_state = 0;
}
static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e6408e5583d7..084d5586585d 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1589,7 +1589,8 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
wrpll_params.central_freq;
- } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
+ } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+ intel_encoder->type == INTEL_OUTPUT_DP_MST) {
switch (crtc_state->port_clock / 2) {
case 81000:
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
@@ -1968,13 +1969,16 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
enum transcoder cpu_transcoder;
enum intel_display_power_domain power_domain;
uint32_t tmp;
+ bool ret;
power_domain = intel_display_port_power_domain(intel_encoder);
- if (!intel_display_power_is_enabled(dev_priv, power_domain))
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
- if (!intel_encoder->get_hw_state(intel_encoder, &pipe))
- return false;
+ if (!intel_encoder->get_hw_state(intel_encoder, &pipe)) {
+ ret = false;
+ goto out;
+ }
if (port == PORT_A)
cpu_transcoder = TRANSCODER_EDP;
@@ -1986,23 +1990,33 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
switch (tmp & TRANS_DDI_MODE_SELECT_MASK) {
case TRANS_DDI_MODE_SELECT_HDMI:
case TRANS_DDI_MODE_SELECT_DVI:
- return (type == DRM_MODE_CONNECTOR_HDMIA);
+ ret = type == DRM_MODE_CONNECTOR_HDMIA;
+ break;
case TRANS_DDI_MODE_SELECT_DP_SST:
- if (type == DRM_MODE_CONNECTOR_eDP)
- return true;
- return (type == DRM_MODE_CONNECTOR_DisplayPort);
+ ret = type == DRM_MODE_CONNECTOR_eDP ||
+ type == DRM_MODE_CONNECTOR_DisplayPort;
+ break;
+
case TRANS_DDI_MODE_SELECT_DP_MST:
/* if the transcoder is in MST state then
* connector isn't connected */
- return false;
+ ret = false;
+ break;
case TRANS_DDI_MODE_SELECT_FDI:
- return (type == DRM_MODE_CONNECTOR_VGA);
+ ret = type == DRM_MODE_CONNECTOR_VGA;
+ break;
default:
- return false;
+ ret = false;
+ break;
}
+
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
@@ -2014,15 +2028,18 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
enum intel_display_power_domain power_domain;
u32 tmp;
int i;
+ bool ret;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_is_enabled(dev_priv, power_domain))
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
+ ret = false;
+
tmp = I915_READ(DDI_BUF_CTL(port));
if (!(tmp & DDI_BUF_CTL_ENABLE))
- return false;
+ goto out;
if (port == PORT_A) {
tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
@@ -2040,25 +2057,32 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
break;
}
- return true;
- } else {
- for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) {
- tmp = I915_READ(TRANS_DDI_FUNC_CTL(i));
+ ret = true;
- if ((tmp & TRANS_DDI_PORT_MASK)
- == TRANS_DDI_SELECT_PORT(port)) {
- if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_DP_MST)
- return false;
+ goto out;
+ }
- *pipe = i;
- return true;
- }
+ for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) {
+ tmp = I915_READ(TRANS_DDI_FUNC_CTL(i));
+
+ if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(port)) {
+ if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
+ TRANS_DDI_MODE_SELECT_DP_MST)
+ goto out;
+
+ *pipe = i;
+ ret = true;
+
+ goto out;
}
}
DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port));
- return false;
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
@@ -2507,12 +2531,14 @@ static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
{
uint32_t val;
- if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
val = I915_READ(WRPLL_CTL(pll->id));
hw_state->wrpll = val;
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
return val & WRPLL_PLL_ENABLE;
}
@@ -2522,12 +2548,14 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
{
uint32_t val;
- if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
val = I915_READ(SPLL_CTL);
hw_state->spll = val;
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
return val & SPLL_PLL_ENABLE;
}
@@ -2644,16 +2672,19 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
uint32_t val;
unsigned int dpll;
const struct skl_dpll_regs *regs = skl_dpll_regs;
+ bool ret;
- if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
+ ret = false;
+
/* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
dpll = pll->id + 1;
val = I915_READ(regs[pll->id].ctl);
if (!(val & LCPLL_PLL_ENABLE))
- return false;
+ goto out;
val = I915_READ(DPLL_CTRL1);
hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f;
@@ -2663,8 +2694,12 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
}
+ ret = true;
- return true;
+out:
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+ return ret;
}
static void skl_shared_dplls_init(struct drm_i915_private *dev_priv)
@@ -2931,13 +2966,16 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
{
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
uint32_t val;
+ bool ret;
- if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
+ ret = false;
+
val = I915_READ(BXT_PORT_PLL_ENABLE(port));
if (!(val & PORT_PLL_ENABLE))
- return false;
+ goto out;
hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
@@ -2984,7 +3022,12 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
- return true;
+ ret = true;
+
+out:
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+ return ret;
}
static void bxt_shared_dplls_init(struct drm_i915_private *dev_priv)
@@ -3119,11 +3162,15 @@ bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
{
u32 temp;
- if (intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
+ if (intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
temp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
+
if (temp & AUDIO_OUTPUT_ENABLE(intel_crtc->pipe))
return true;
}
+
return false;
}
@@ -3311,7 +3358,6 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
intel_encoder->get_config = intel_ddi_get_config;
intel_dig_port->port = port;
- dev_priv->dig_port_map[port] = intel_encoder;
intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
(DDI_BUF_PORT_REVERSAL |
DDI_A_4_LANES);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5feb65725c04..46947fffd599 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1351,18 +1351,21 @@ void assert_pipe(struct drm_i915_private *dev_priv,
bool cur_state;
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
pipe);
+ enum intel_display_power_domain power_domain;
/* if we need the pipe quirk it must be always on */
if ((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
(pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
state = true;
- if (!intel_display_power_is_enabled(dev_priv,
- POWER_DOMAIN_TRANSCODER(cpu_transcoder))) {
- cur_state = false;
- } else {
+ power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
+ if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
u32 val = I915_READ(PIPECONF(cpu_transcoder));
cur_state = !!(val & PIPECONF_ENABLE);
+
+ intel_display_power_put(dev_priv, power_domain);
+ } else {
+ cur_state = false;
}
I915_STATE_WARN(cur_state != state,
@@ -8171,18 +8174,22 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ enum intel_display_power_domain power_domain;
uint32_t tmp;
+ bool ret;
- if (!intel_display_power_is_enabled(dev_priv,
- POWER_DOMAIN_PIPE(crtc->pipe)))
+ power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+ ret = false;
+
tmp = I915_READ(PIPECONF(crtc->pipe));
if (!(tmp & PIPECONF_ENABLE))
- return false;
+ goto out;
if (IS_G4X(dev) || IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
switch (tmp & PIPECONF_BPC_MASK) {
@@ -8262,7 +8269,12 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
pipe_config->base.adjusted_mode.crtc_clock =
pipe_config->port_clock / pipe_config->pixel_multiplier;
- return true;
+ ret = true;
+
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
static void ironlake_init_pch_refclk(struct drm_device *dev)
@@ -9366,18 +9378,21 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ enum intel_display_power_domain power_domain;
uint32_t tmp;
+ bool ret;
- if (!intel_display_power_is_enabled(dev_priv,
- POWER_DOMAIN_PIPE(crtc->pipe)))
+ power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+ ret = false;
tmp = I915_READ(PIPECONF(crtc->pipe));
if (!(tmp & PIPECONF_ENABLE))
- return false;
+ goto out;
switch (tmp & PIPECONF_BPC_MASK) {
case PIPECONF_6BPC:
@@ -9440,7 +9455,12 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
ironlake_get_pfit_config(crtc, pipe_config);
- return true;
+ ret = true;
+
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
@@ -9950,12 +9970,17 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- enum intel_display_power_domain pfit_domain;
+ enum intel_display_power_domain power_domain;
+ unsigned long power_domain_mask;
uint32_t tmp;
+ bool ret;
- if (!intel_display_power_is_enabled(dev_priv,
- POWER_DOMAIN_PIPE(crtc->pipe)))
+ power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
+ power_domain_mask = BIT(power_domain);
+
+ ret = false;
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
pipe_config->shared_dpll = DPLL_ID_PRIVATE;
@@ -9982,13 +10007,14 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
pipe_config->cpu_transcoder = TRANSCODER_EDP;
}
- if (!intel_display_power_is_enabled(dev_priv,
- POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder)))
- return false;
+ power_domain = POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder);
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+ goto out;
+ power_domain_mask |= BIT(power_domain);
tmp = I915_READ(PIPECONF(pipe_config->cpu_transcoder));
if (!(tmp & PIPECONF_ENABLE))
- return false;
+ goto out;
haswell_get_ddi_port_state(crtc, pipe_config);
@@ -9998,14 +10024,14 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
skl_init_scalers(dev, crtc, pipe_config);
}
- pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
-
if (INTEL_INFO(dev)->gen >= 9) {
pipe_config->scaler_state.scaler_id = -1;
pipe_config->scaler_state.scaler_users &= ~(1 << SKL_CRTC_INDEX);
}
- if (intel_display_power_is_enabled(dev_priv, pfit_domain)) {
+ power_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
+ if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
+ power_domain_mask |= BIT(power_domain);
if (INTEL_INFO(dev)->gen >= 9)
skylake_get_pfit_config(crtc, pipe_config);
else
@@ -10023,7 +10049,13 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
pipe_config->pixel_multiplier = 1;
}
- return true;
+ ret = true;
+
+out:
+ for_each_power_domain(power_domain, power_domain_mask)
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
static void i845_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
@@ -13630,7 +13662,7 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
{
uint32_t val;
- if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
val = I915_READ(PCH_DPLL(pll->id));
@@ -13638,6 +13670,8 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
return val & DPLL_VCO_ENABLE;
}
@@ -15568,10 +15602,12 @@ void i915_redisable_vga(struct drm_device *dev)
* level, just check if the power well is enabled instead of trying to
* follow the "don't touch the power well if we don't need it" policy
* the rest of the driver uses. */
- if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_VGA))
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_VGA))
return;
i915_redisable_vga_power_on(dev);
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
}
static bool primary_get_hw_state(struct intel_plane *plane)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 796e3d313cb9..cdc2c15873dc 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2362,15 +2362,18 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private;
enum intel_display_power_domain power_domain;
u32 tmp;
+ bool ret;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_is_enabled(dev_priv, power_domain))
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
+ ret = false;
+
tmp = I915_READ(intel_dp->output_reg);
if (!(tmp & DP_PORT_EN))
- return false;
+ goto out;
if (IS_GEN7(dev) && port == PORT_A) {
*pipe = PORT_TO_PIPE_CPT(tmp);
@@ -2381,7 +2384,9 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
u32 trans_dp = I915_READ(TRANS_DP_CTL(p));
if (TRANS_DP_PIPE_TO_PORT(trans_dp) == port) {
*pipe = p;
- return true;
+ ret = true;
+
+ goto out;
}
}
@@ -2393,7 +2398,12 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
*pipe = PORT_TO_PIPE(tmp);
}
- return true;
+ ret = true;
+
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
static void intel_dp_get_config(struct intel_encoder *encoder,
@@ -4493,20 +4503,20 @@ static bool g4x_digital_port_connected(struct drm_i915_private *dev_priv,
return I915_READ(PORT_HOTPLUG_STAT) & bit;
}
-static bool vlv_digital_port_connected(struct drm_i915_private *dev_priv,
- struct intel_digital_port *port)
+static bool gm45_digital_port_connected(struct drm_i915_private *dev_priv,
+ struct intel_digital_port *port)
{
u32 bit;
switch (port->port) {
case PORT_B:
- bit = PORTB_HOTPLUG_LIVE_STATUS_VLV;
+ bit = PORTB_HOTPLUG_LIVE_STATUS_GM45;
break;
case PORT_C:
- bit = PORTC_HOTPLUG_LIVE_STATUS_VLV;
+ bit = PORTC_HOTPLUG_LIVE_STATUS_GM45;
break;
case PORT_D:
- bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
+ bit = PORTD_HOTPLUG_LIVE_STATUS_GM45;
break;
default:
MISSING_CASE(port->port);
@@ -4558,8 +4568,8 @@ bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
return cpt_digital_port_connected(dev_priv, port);
else if (IS_BROXTON(dev_priv))
return bxt_digital_port_connected(dev_priv, port);
- else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- return vlv_digital_port_connected(dev_priv, port);
+ else if (IS_GM45(dev_priv))
+ return gm45_digital_port_connected(dev_priv, port);
else
return g4x_digital_port_connected(dev_priv, port);
}
@@ -6035,7 +6045,6 @@ intel_dp_init(struct drm_device *dev,
}
intel_dig_port->port = port;
- dev_priv->dig_port_map[port] = intel_encoder;
intel_dig_port->dp.output_reg = output_reg;
intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 88887938e0bf..0b8eefc2acc5 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -215,27 +215,46 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
}
}
-static void
-intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+/*
+ * Pick training pattern for channel equalization. Training Pattern 3 for HBR2
+ * or 1.2 devices that support it, Training Pattern 2 otherwise.
+ */
+static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
{
- bool channel_eq = false;
- int tries, cr_tries;
- uint32_t training_pattern = DP_TRAINING_PATTERN_2;
+ u32 training_pattern = DP_TRAINING_PATTERN_2;
+ bool source_tps3, sink_tps3;
/*
- * Training Pattern 3 for HBR2 or 1.2 devices that support it.
- *
* Intel platforms that support HBR2 also support TPS3. TPS3 support is
- * also mandatory for downstream devices that support HBR2.
+ * also mandatory for downstream devices that support HBR2. However, not
+ * all sinks follow the spec.
*
* Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is
- * supported but still not enabled.
+ * supported in source but still not enabled.
*/
- if (intel_dp_source_supports_hbr2(intel_dp) &&
- drm_dp_tps3_supported(intel_dp->dpcd))
+ source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
+ sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
+
+ if (source_tps3 && sink_tps3) {
training_pattern = DP_TRAINING_PATTERN_3;
- else if (intel_dp->link_rate == 540000)
- DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n");
+ } else if (intel_dp->link_rate == 540000) {
+ if (!source_tps3)
+ DRM_DEBUG_KMS("5.4 Gbps link rate without source HBR2/TPS3 support\n");
+ if (!sink_tps3)
+ DRM_DEBUG_KMS("5.4 Gbps link rate without sink TPS3 support\n");
+ }
+
+ return training_pattern;
+}
+
+static void
+intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+{
+ bool channel_eq = false;
+ int tries, cr_tries;
+ u32 training_pattern;
+
+ training_pattern = intel_dp_training_pattern(intel_dp);
/* channel equalization */
if (!intel_dp_set_link_train(intel_dp,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ea5415851c6e..df7f3cb66056 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1428,6 +1428,8 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
void intel_display_power_get(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
+bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
+ enum intel_display_power_domain domain);
void intel_display_power_put(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
@@ -1514,6 +1516,7 @@ enable_rpm_wakeref_asserts(struct drm_i915_private *dev_priv)
enable_rpm_wakeref_asserts(dev_priv)
void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
+bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv);
void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 44742fa2f616..0193c62a53ef 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -664,13 +664,16 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
struct drm_device *dev = encoder->base.dev;
enum intel_display_power_domain power_domain;
enum port port;
+ bool ret;
DRM_DEBUG_KMS("\n");
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_is_enabled(dev_priv, power_domain))
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
+ ret = false;
+
/* XXX: this only works for one DSI output */
for_each_dsi_port(port, intel_dsi->ports) {
i915_reg_t ctrl_reg = IS_BROXTON(dev) ?
@@ -691,12 +694,16 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
if (dpi_enabled || (func & CMD_MODE_DATA_WIDTH_MASK)) {
if (I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY) {
*pipe = port == PORT_A ? PIPE_A : PIPE_B;
- return true;
+ ret = true;
+
+ goto out;
}
}
}
+out:
+ intel_display_power_put(dev_priv, power_domain);
- return false;
+ return ret;
}
static void intel_dsi_get_config(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
index a5e99ac305da..e8113ad65477 100644
--- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
+++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
@@ -204,10 +204,28 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
struct drm_device *dev = intel_dsi->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ if (dev_priv->vbt.dsi.seq_version >= 3)
+ data++;
+
gpio = *data++;
/* pull up/down */
- action = *data++;
+ action = *data++ & 1;
+
+ if (gpio >= ARRAY_SIZE(gtable)) {
+ DRM_DEBUG_KMS("unknown gpio %u\n", gpio);
+ goto out;
+ }
+
+ if (!IS_VALLEYVIEW(dev_priv)) {
+ DRM_DEBUG_KMS("GPIO element not supported on this platform\n");
+ goto out;
+ }
+
+ if (dev_priv->vbt.dsi.seq_version >= 3) {
+ DRM_DEBUG_KMS("GPIO element v3 not supported\n");
+ goto out;
+ }
function = gtable[gpio].function_reg;
pad = gtable[gpio].pad_reg;
@@ -226,6 +244,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
vlv_gpio_nc_write(dev_priv, pad, val);
mutex_unlock(&dev_priv->sb_lock);
+out:
return data;
}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 4a77639a489d..616108c4bc3e 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -880,15 +880,18 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
enum intel_display_power_domain power_domain;
u32 tmp;
+ bool ret;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_is_enabled(dev_priv, power_domain))
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
+ ret = false;
+
tmp = I915_READ(intel_hdmi->hdmi_reg);
if (!(tmp & SDVO_ENABLE))
- return false;
+ goto out;
if (HAS_PCH_CPT(dev))
*pipe = PORT_TO_PIPE_CPT(tmp);
@@ -897,7 +900,12 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
else
*pipe = PORT_TO_PIPE(tmp);
- return true;
+ ret = true;
+
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
static void intel_hdmi_get_config(struct intel_encoder *encoder,
@@ -2146,7 +2154,6 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
void intel_hdmi_init(struct drm_device *dev,
i915_reg_t hdmi_reg, enum port port)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_digital_port *intel_dig_port;
struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector;
@@ -2215,7 +2222,6 @@ void intel_hdmi_init(struct drm_device *dev,
intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
intel_dig_port->port = port;
- dev_priv->dig_port_map[port] = intel_encoder;
intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 25254b5c1ac5..52fbe530fc9e 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -664,6 +664,12 @@ int intel_setup_gmbus(struct drm_device *dev)
bus->adapter.algo = &gmbus_algorithm;
+ /*
+ * We wish to retry with bit banging
+ * after a timed out GMBUS attempt.
+ */
+ bus->adapter.retries = 1;
+
/* By default use a conservative clock rate */
bus->reg0 = pin | GMBUS_RATE_100KHZ;
@@ -683,7 +689,7 @@ int intel_setup_gmbus(struct drm_device *dev)
return 0;
err:
- while (--pin) {
+ while (pin--) {
if (!intel_gmbus_is_valid_pin(dev_priv, pin))
continue;
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 0da0240caf81..bc04d8d29acb 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -75,22 +75,30 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
enum intel_display_power_domain power_domain;
u32 tmp;
+ bool ret;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_is_enabled(dev_priv, power_domain))
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
return false;
+ ret = false;
+
tmp = I915_READ(lvds_encoder->reg);
if (!(tmp & LVDS_PORT_EN))
- return false;
+ goto out;
if (HAS_PCH_CPT(dev))
*pipe = PORT_TO_PIPE_CPT(tmp);
else
*pipe = PORT_TO_PIPE(tmp);
- return true;
+ ret = true;
+
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
}
static void intel_lvds_get_config(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index eb5fa05cf476..b28c29f20e75 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -1783,16 +1783,20 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
const struct intel_plane_state *pstate,
uint32_t mem_value)
{
- int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0;
+ /*
+ * We treat the cursor plane as always-on for the purposes of watermark
+ * calculation. Until we have two-stage watermark programming merged,
+ * this is necessary to avoid flickering.
+ */
+ int cpp = 4;
+ int width = pstate->visible ? pstate->base.crtc_w : 64;
- if (!cstate->base.active || !pstate->visible)
+ if (!cstate->base.active)
return 0;
return ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
cstate->base.adjusted_mode.crtc_htotal,
- drm_rect_width(&pstate->dst),
- bpp,
- mem_value);
+ width, cpp, mem_value);
}
/* Only for WM_LP. */
@@ -2825,7 +2829,10 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
memset(ddb, 0, sizeof(*ddb));
for_each_pipe(dev_priv, pipe) {
- if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PIPE(pipe)))
+ enum intel_display_power_domain power_domain;
+
+ power_domain = POWER_DOMAIN_PIPE(pipe);
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
continue;
for_each_plane(dev_priv, pipe, plane) {
@@ -2837,6 +2844,8 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
val = I915_READ(CUR_BUF_CFG(pipe));
skl_ddb_entry_init_from_hw(&ddb->plane[pipe][PLANE_CURSOR],
val);
+
+ intel_display_power_put(dev_priv, power_domain);
}
}
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index ddbdbffe829a..4f43d9b32e66 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -470,6 +470,43 @@ static void gen9_set_dc_state_debugmask_memory_up(
}
}
+static void gen9_write_dc_state(struct drm_i915_private *dev_priv,
+ u32 state)
+{
+ int rewrites = 0;
+ int rereads = 0;
+ u32 v;
+
+ I915_WRITE(DC_STATE_EN, state);
+
+ /* It has been observed that disabling the dc6 state sometimes
+ * doesn't stick and dmc keeps returning old value. Make sure
+ * the write really sticks enough times and also force rewrite until
+ * we are confident that state is exactly what we want.
+ */
+ do {
+ v = I915_READ(DC_STATE_EN);
+
+ if (v != state) {
+ I915_WRITE(DC_STATE_EN, state);
+ rewrites++;
+ rereads = 0;
+ } else if (rereads++ > 5) {
+ break;
+ }
+
+ } while (rewrites < 100);
+
+ if (v != state)
+ DRM_ERROR("Writing dc state to 0x%x failed, now 0x%x\n",
+ state, v);
+
+ /* Most of the times we need one retry, avoid spam */
+ if (rewrites > 1)
+ DRM_DEBUG_KMS("Rewrote dc state to 0x%x %d times\n",
+ state, rewrites);
+}
+
static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state)
{
uint32_t val;
@@ -494,10 +531,18 @@ static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state)
val = I915_READ(DC_STATE_EN);
DRM_DEBUG_KMS("Setting DC state from %02x to %02x\n",
val & mask, state);
+
+ /* Check if DMC is ignoring our DC state requests */
+ if ((val & mask) != dev_priv->csr.dc_state)
+ DRM_ERROR("DC state mismatch (0x%x -> 0x%x)\n",
+ dev_priv->csr.dc_state, val & mask);
+
val &= ~mask;
val |= state;
- I915_WRITE(DC_STATE_EN, val);
- POSTING_READ(DC_STATE_EN);
+
+ gen9_write_dc_state(dev_priv, val);
+
+ dev_priv->csr.dc_state = val & mask;
}
void bxt_enable_dc9(struct drm_i915_private *dev_priv)
@@ -1442,6 +1487,22 @@ static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv,
chv_set_pipe_power_well(dev_priv, power_well, false);
}
+static void
+__intel_display_power_get_domain(struct drm_i915_private *dev_priv,
+ enum intel_display_power_domain domain)
+{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ struct i915_power_well *power_well;
+ int i;
+
+ for_each_power_well(i, power_well, BIT(domain), power_domains) {
+ if (!power_well->count++)
+ intel_power_well_enable(dev_priv, power_well);
+ }
+
+ power_domains->domain_use_count[domain]++;
+}
+
/**
* intel_display_power_get - grab a power domain reference
* @dev_priv: i915 device instance
@@ -1457,24 +1518,53 @@ static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv,
void intel_display_power_get(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain)
{
- struct i915_power_domains *power_domains;
- struct i915_power_well *power_well;
- int i;
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
intel_runtime_pm_get(dev_priv);
- power_domains = &dev_priv->power_domains;
+ mutex_lock(&power_domains->lock);
+
+ __intel_display_power_get_domain(dev_priv, domain);
+
+ mutex_unlock(&power_domains->lock);
+}
+
+/**
+ * intel_display_power_get_if_enabled - grab a reference for an enabled display power domain
+ * @dev_priv: i915 device instance
+ * @domain: power domain to reference
+ *
+ * This function grabs a power domain reference for @domain and ensures that the
+ * power domain and all its parents are powered up. Therefore users should only
+ * grab a reference to the innermost power domain they need.
+ *
+ * Any power domain reference obtained by this function must have a symmetric
+ * call to intel_display_power_put() to release the reference again.
+ */
+bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
+ enum intel_display_power_domain domain)
+{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ bool is_enabled;
+
+ if (!intel_runtime_pm_get_if_in_use(dev_priv))
+ return false;
mutex_lock(&power_domains->lock);
- for_each_power_well(i, power_well, BIT(domain), power_domains) {
- if (!power_well->count++)
- intel_power_well_enable(dev_priv, power_well);
+ if (__intel_display_power_is_enabled(dev_priv, domain)) {
+ __intel_display_power_get_domain(dev_priv, domain);
+ is_enabled = true;
+ } else {
+ is_enabled = false;
}
- power_domains->domain_use_count[domain]++;
-
mutex_unlock(&power_domains->lock);
+
+ if (!is_enabled)
+ intel_runtime_pm_put(dev_priv);
+
+ return is_enabled;
}
/**
@@ -2213,15 +2303,15 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
*/
void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
{
- if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
- skl_display_core_uninit(dev_priv);
-
/*
* Even if power well support was disabled we still want to disable
* power wells while we are system suspended.
*/
if (!i915.disable_power_well)
intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+ skl_display_core_uninit(dev_priv);
}
/**
@@ -2246,6 +2336,41 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
}
/**
+ * intel_runtime_pm_get_if_in_use - grab a runtime pm reference if device in use
+ * @dev_priv: i915 device instance
+ *
+ * This function grabs a device-level runtime pm reference if the device is
+ * already in use and ensures that it is powered up.
+ *
+ * Any runtime pm reference obtained by this function must have a symmetric
+ * call to intel_runtime_pm_put() to release the reference again.
+ */
+bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
+{
+ struct drm_device *dev = dev_priv->dev;
+ struct device *device = &dev->pdev->dev;
+
+ if (IS_ENABLED(CONFIG_PM)) {
+ int ret = pm_runtime_get_if_in_use(device);
+
+ /*
+ * In cases runtime PM is disabled by the RPM core and we get
+ * an -EINVAL return value we are not supposed to call this
+ * function, since the power state is undefined. This applies
+ * atm to the late/early system suspend/resume handlers.
+ */
+ WARN_ON_ONCE(ret < 0);
+ if (ret <= 0)
+ return false;
+ }
+
+ atomic_inc(&dev_priv->pm.wakeref_count);
+ assert_rpm_wakelock_held(dev_priv);
+
+ return true;
+}
+
+/**
* intel_runtime_pm_get_noresume - grab a runtime pm reference
* @dev_priv: i915 device instance
*
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 30a57185bdb4..287226311413 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -64,6 +64,7 @@ static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
/* Start DC channel and DI after IDMAC */
ipu_dc_enable_channel(ipu_crtc->dc);
ipu_di_enable(ipu_crtc->di);
+ drm_crtc_vblank_on(&ipu_crtc->base);
ipu_crtc->enabled = 1;
}
@@ -80,6 +81,7 @@ static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
ipu_di_disable(ipu_crtc->di);
ipu_plane_disable(ipu_crtc->plane[0]);
ipu_dc_disable(ipu);
+ drm_crtc_vblank_off(&ipu_crtc->base);
ipu_crtc->enabled = 0;
}
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 591ba2f1ae03..26bb1b626fe3 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -42,6 +42,7 @@ static const uint32_t ipu_plane_formats[] = {
DRM_FORMAT_YVYU,
DRM_FORMAT_YUV420,
DRM_FORMAT_YVU420,
+ DRM_FORMAT_RGB565,
};
int ipu_plane_irq(struct ipu_plane *ipu_plane)
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 78f520d05de9..e3acc35e3805 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -1520,7 +1520,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
DMA_BIDIRECTIONAL);
if (dma_mapping_error(pdev, addr)) {
- while (--i) {
+ while (i--) {
dma_unmap_page(pdev, ttm_dma->dma_address[i],
PAGE_SIZE, DMA_BIDIRECTIONAL);
ttm_dma->dma_address[i] = 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 24be27d3cd18..20935eb2a09e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -635,10 +635,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
nv_crtc->lut.depth = 0;
}
- /* Make sure that drm and hw vblank irqs get resumed if needed. */
- for (head = 0; head < dev->mode_config.num_crtc; head++)
- drm_vblank_on(dev, head);
-
/* This should ensure we don't hit a locking problem when someone
* wakes us up via a connector. We should never go into suspend
* while the display is on anyways.
@@ -648,6 +644,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
drm_helper_resume_force_mode(dev);
+ /* Make sure that drm and hw vblank irqs get resumed if needed. */
+ for (head = 0; head < dev->mode_config.num_crtc; head++)
+ drm_vblank_on(dev, head);
+
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c
index 8a70cec59bcd..2dfe58af12e4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_platform.c
+++ b/drivers/gpu/drm/nouveau/nouveau_platform.c
@@ -24,7 +24,7 @@
static int nouveau_platform_probe(struct platform_device *pdev)
{
const struct nvkm_device_tegra_func *func;
- struct nvkm_device *device;
+ struct nvkm_device *device = NULL;
struct drm_device *drm;
int ret;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
index 7f8a42721eb2..e7e581d6a8ff 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
@@ -252,32 +252,40 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL)))
return -ENOMEM;
- *pdevice = &tdev->device;
+
tdev->func = func;
tdev->pdev = pdev;
tdev->irq = -1;
tdev->vdd = devm_regulator_get(&pdev->dev, "vdd");
- if (IS_ERR(tdev->vdd))
- return PTR_ERR(tdev->vdd);
+ if (IS_ERR(tdev->vdd)) {
+ ret = PTR_ERR(tdev->vdd);
+ goto free;
+ }
tdev->rst = devm_reset_control_get(&pdev->dev, "gpu");
- if (IS_ERR(tdev->rst))
- return PTR_ERR(tdev->rst);
+ if (IS_ERR(tdev->rst)) {
+ ret = PTR_ERR(tdev->rst);
+ goto free;
+ }
tdev->clk = devm_clk_get(&pdev->dev, "gpu");
- if (IS_ERR(tdev->clk))
- return PTR_ERR(tdev->clk);
+ if (IS_ERR(tdev->clk)) {
+ ret = PTR_ERR(tdev->clk);
+ goto free;
+ }
tdev->clk_pwr = devm_clk_get(&pdev->dev, "pwr");
- if (IS_ERR(tdev->clk_pwr))
- return PTR_ERR(tdev->clk_pwr);
+ if (IS_ERR(tdev->clk_pwr)) {
+ ret = PTR_ERR(tdev->clk_pwr);
+ goto free;
+ }
nvkm_device_tegra_probe_iommu(tdev);
ret = nvkm_device_tegra_power_up(tdev);
if (ret)
- return ret;
+ goto remove;
tdev->gpu_speedo = tegra_sku_info.gpu_speedo_value;
ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev,
@@ -285,9 +293,19 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
cfg, dbg, detect, mmio, subdev_mask,
&tdev->device);
if (ret)
- return ret;
+ goto powerdown;
+
+ *pdevice = &tdev->device;
return 0;
+
+powerdown:
+ nvkm_device_tegra_power_down(tdev);
+remove:
+ nvkm_device_tegra_remove_iommu(tdev);
+free:
+ kfree(tdev);
+ return ret;
}
#else
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
index 74e2f7c6c07e..9688970eca47 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
@@ -328,6 +328,7 @@ nvkm_dp_train(struct work_struct *w)
.outp = outp,
}, *dp = &_dp;
u32 datarate = 0;
+ u8 pwr;
int ret;
if (!outp->base.info.location && disp->func->sor.magic)
@@ -355,6 +356,15 @@ nvkm_dp_train(struct work_struct *w)
/* disable link interrupt handling during link training */
nvkm_notify_put(&outp->irq);
+ /* ensure sink is not in a low-power state */
+ if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) {
+ if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
+ pwr &= ~DPCD_SC00_SET_POWER;
+ pwr |= DPCD_SC00_SET_POWER_D0;
+ nvkm_wraux(outp->aux, DPCD_SC00, &pwr, 1);
+ }
+ }
+
/* enable down-spreading and execute pre-train script from vbios */
dp_link_train_init(dp, outp->dpcd[3] & 0x01);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
index 9596290329c7..6e10c5e0ef11 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
@@ -71,5 +71,11 @@
#define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c
#define DPCD_LS0C_LANE0_POST_CURSOR2 0x03
+/* DPCD Sink Control */
+#define DPCD_SC00 0x00600
+#define DPCD_SC00_SET_POWER 0x03
+#define DPCD_SC00_SET_POWER_D0 0x01
+#define DPCD_SC00_SET_POWER_D3 0x03
+
void nvkm_dp_train(struct work_struct *);
#endif
diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
index dfebdc4aa0f2..85dfe3674b41 100644
--- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
+++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
@@ -573,10 +573,9 @@ static int omap_dmm_remove(struct platform_device *dev)
kfree(omap_dmm->engines);
if (omap_dmm->refill_va)
- dma_free_writecombine(omap_dmm->dev,
- REFILL_BUFFER_SIZE * omap_dmm->num_engines,
- omap_dmm->refill_va,
- omap_dmm->refill_pa);
+ dma_free_wc(omap_dmm->dev,
+ REFILL_BUFFER_SIZE * omap_dmm->num_engines,
+ omap_dmm->refill_va, omap_dmm->refill_pa);
if (omap_dmm->dummy_page)
__free_page(omap_dmm->dummy_page);
@@ -701,9 +700,9 @@ static int omap_dmm_probe(struct platform_device *dev)
omap_dmm->dummy_pa = page_to_phys(omap_dmm->dummy_page);
/* alloc refill memory */
- omap_dmm->refill_va = dma_alloc_writecombine(&dev->dev,
- REFILL_BUFFER_SIZE * omap_dmm->num_engines,
- &omap_dmm->refill_pa, GFP_KERNEL);
+ omap_dmm->refill_va = dma_alloc_wc(&dev->dev,
+ REFILL_BUFFER_SIZE * omap_dmm->num_engines,
+ &omap_dmm->refill_pa, GFP_KERNEL);
if (!omap_dmm->refill_va) {
dev_err(&dev->dev, "could not allocate refill memory\n");
goto fail;
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index 8495a1a4b617..359b0d7e8ef7 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -1330,8 +1330,8 @@ void omap_gem_free_object(struct drm_gem_object *obj)
omap_gem_detach_pages(obj);
if (!is_shmem(obj)) {
- dma_free_writecombine(dev->dev, obj->size,
- omap_obj->vaddr, omap_obj->paddr);
+ dma_free_wc(dev->dev, obj->size, omap_obj->vaddr,
+ omap_obj->paddr);
} else if (omap_obj->vaddr) {
vunmap(omap_obj->vaddr);
}
@@ -1395,8 +1395,8 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
/* attempt to allocate contiguous memory if we don't
* have DMM for remappign discontiguous buffers
*/
- omap_obj->vaddr = dma_alloc_writecombine(dev->dev, size,
- &omap_obj->paddr, GFP_KERNEL);
+ omap_obj->vaddr = dma_alloc_wc(dev->dev, size,
+ &omap_obj->paddr, GFP_KERNEL);
if (!omap_obj->vaddr) {
kfree(omap_obj);
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index 2ae8577497ca..7c2e78201ead 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -168,7 +168,8 @@ static int qxl_process_single_command(struct qxl_device *qdev,
cmd->command_size))
return -EFAULT;
- reloc_info = kmalloc(sizeof(struct qxl_reloc_info) * cmd->relocs_num, GFP_KERNEL);
+ reloc_info = kmalloc_array(cmd->relocs_num,
+ sizeof(struct qxl_reloc_info), GFP_KERNEL);
if (!reloc_info)
return -ENOMEM;
diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c
index 3d031b50a8fd..9f029dda1f07 100644
--- a/drivers/gpu/drm/qxl/qxl_prime.c
+++ b/drivers/gpu/drm/qxl/qxl_prime.c
@@ -68,5 +68,5 @@ int qxl_gem_prime_mmap(struct drm_gem_object *obj,
struct vm_area_struct *area)
{
WARN_ONCE(1, "not implemented");
- return ENOSYS;
+ return -ENOSYS;
}
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 44ee72e04df9..6af832545bc5 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -315,15 +315,27 @@ int radeon_dp_get_dp_link_config(struct drm_connector *connector,
unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
unsigned lane_num, i, max_pix_clock;
- for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
- for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
- max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+ if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
+ ENCODER_OBJECT_ID_NUTMEG) {
+ for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+ max_pix_clock = (lane_num * 270000 * 8) / bpp;
if (max_pix_clock >= pix_clock) {
*dp_lanes = lane_num;
- *dp_rate = link_rates[i];
+ *dp_rate = 270000;
return 0;
}
}
+ } else {
+ for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+ for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
+ max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+ if (max_pix_clock >= pix_clock) {
+ *dp_lanes = lane_num;
+ *dp_rate = link_rates[i];
+ return 0;
+ }
+ }
+ }
}
return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index a9b01bcf7d0a..432480ff9d22 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -34,7 +34,6 @@
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/prom.h>
-#include <asm/pci-bridge.h>
#endif /* CONFIG_PPC_PMAC */
/* from radeon_legacy_encoder.c */
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 902b59cebac5..4197ca1bb1e4 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1744,7 +1744,6 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
}
drm_kms_helper_poll_enable(dev);
- drm_helper_hpd_irq_event(dev);
/* set the power state here in case we are a PX system or headless */
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 298ea1c453c3..2d9196a447fd 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -403,7 +403,8 @@ static void radeon_flip_work_func(struct work_struct *__work)
struct drm_crtc *crtc = &radeon_crtc->base;
unsigned long flags;
int r;
- int vpos, hpos, stat, min_udelay;
+ int vpos, hpos, stat, min_udelay = 0;
+ unsigned repcnt = 4;
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
down_read(&rdev->exclusive_lock);
@@ -454,7 +455,7 @@ static void radeon_flip_work_func(struct work_struct *__work)
* In practice this won't execute very often unless on very fast
* machines because the time window for this to happen is very small.
*/
- for (;;) {
+ while (radeon_crtc->enabled && --repcnt) {
/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
* start in hpos, and to the "fudged earlier" vblank start in
* vpos.
@@ -470,12 +471,24 @@ static void radeon_flip_work_func(struct work_struct *__work)
break;
/* Sleep at least until estimated real start of hw vblank */
- spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+ if (min_udelay > vblank->framedur_ns / 2000) {
+ /* Don't wait ridiculously long - something is wrong */
+ repcnt = 0;
+ break;
+ }
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
usleep_range(min_udelay, 2 * min_udelay);
spin_lock_irqsave(&crtc->dev->event_lock, flags);
};
+ if (!repcnt)
+ DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
+ "framedur %d, linedur %d, stat %d, vpos %d, "
+ "hpos %d\n", work->crtc_id, min_udelay,
+ vblank->framedur_ns / 1000,
+ vblank->linedur_ns / 1000, stat, vpos, hpos);
+
/* do the flip (mmio) */
radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 460c8f2989da..7a98823bacd1 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -276,8 +276,12 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
if (rdev->irq.installed) {
for (i = 0; i < rdev->num_crtc; i++) {
if (rdev->pm.active_crtcs & (1 << i)) {
- rdev->pm.req_vblank |= (1 << i);
- drm_vblank_get(rdev->ddev, i);
+ /* This can fail if a modeset is in progress */
+ if (drm_vblank_get(rdev->ddev, i) == 0)
+ rdev->pm.req_vblank |= (1 << i);
+ else
+ DRM_DEBUG_DRIVER("crtc %d no vblank, can glitch\n",
+ i);
}
}
}
@@ -1078,10 +1082,6 @@ force:
/* update displays */
radeon_dpm_display_configuration_changed(rdev);
- rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
- rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
- rdev->pm.dpm.single_display = single_display;
-
/* wait for the rings to drain */
for (i = 0; i < RADEON_NUM_RINGS; i++) {
struct radeon_ring *ring = &rdev->ring[i];
@@ -1097,6 +1097,10 @@ force:
radeon_dpm_post_set_power_state(rdev);
+ rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+ rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+ rdev->pm.dpm.single_display = single_display;
+
if (rdev->asic->dpm.force_performance_level) {
if (rdev->pm.dpm.thermal_active) {
enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index e34307459e50..e06ac546a90f 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -758,7 +758,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
0, PAGE_SIZE,
PCI_DMA_BIDIRECTIONAL);
if (pci_dma_mapping_error(rdev->pdev, gtt->ttm.dma_address[i])) {
- while (--i) {
+ while (i--) {
pci_unmap_page(rdev->pdev, gtt->ttm.dma_address[i],
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
gtt->ttm.dma_address[i] = 0;
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index 807863106b8d..bd736ace3f81 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -157,17 +157,15 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
cursor->height = src_h;
if (cursor->pixmap.base)
- dma_free_writecombine(cursor->dev,
- cursor->pixmap.size,
- cursor->pixmap.base,
- cursor->pixmap.paddr);
+ dma_free_wc(cursor->dev, cursor->pixmap.size,
+ cursor->pixmap.base, cursor->pixmap.paddr);
cursor->pixmap.size = cursor->width * cursor->height;
- cursor->pixmap.base = dma_alloc_writecombine(cursor->dev,
- cursor->pixmap.size,
- &cursor->pixmap.paddr,
- GFP_KERNEL | GFP_DMA);
+ cursor->pixmap.base = dma_alloc_wc(cursor->dev,
+ cursor->pixmap.size,
+ &cursor->pixmap.paddr,
+ GFP_KERNEL | GFP_DMA);
if (!cursor->pixmap.base) {
DRM_ERROR("Failed to allocate memory for pixmap\n");
return;
@@ -252,8 +250,8 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
/* Allocate clut buffer */
size = 0x100 * sizeof(unsigned short);
- cursor->clut = dma_alloc_writecombine(dev, size, &cursor->clut_paddr,
- GFP_KERNEL | GFP_DMA);
+ cursor->clut = dma_alloc_wc(dev, size, &cursor->clut_paddr,
+ GFP_KERNEL | GFP_DMA);
if (!cursor->clut) {
DRM_ERROR("Failed to allocate memory for cursor clut\n");
@@ -286,7 +284,7 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
return &cursor->plane.drm_plane;
err_plane:
- dma_free_writecombine(dev, size, cursor->clut, cursor->clut_paddr);
+ dma_free_wc(dev, size, cursor->clut, cursor->clut_paddr);
err_clut:
devm_kfree(dev, cursor);
return NULL;
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index f9a1d92c9d95..514551c857bb 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -312,8 +312,7 @@ static void sti_gdp_init(struct sti_gdp *gdp)
/* Allocate all the nodes within a single memory page */
size = sizeof(struct sti_gdp_node) *
GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK;
- base = dma_alloc_writecombine(gdp->dev,
- size, &dma_addr, GFP_KERNEL | GFP_DMA);
+ base = dma_alloc_wc(gdp->dev, size, &dma_addr, GFP_KERNEL | GFP_DMA);
if (!base) {
DRM_ERROR("Failed to allocate memory for GDP node\n");
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index 43861b52261d..1d3c3d029603 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -617,9 +617,9 @@ static void sti_hqvdp_init(struct sti_hqvdp *hqvdp)
/* Allocate memory for the VDP commands */
size = NB_VDP_CMD * sizeof(struct sti_hqvdp_cmd);
- hqvdp->hqvdp_cmd = dma_alloc_writecombine(hqvdp->dev, size,
- &hqvdp->hqvdp_cmd_paddr,
- GFP_KERNEL | GFP_DMA);
+ hqvdp->hqvdp_cmd = dma_alloc_wc(hqvdp->dev, size,
+ &hqvdp->hqvdp_cmd_paddr,
+ GFP_KERNEL | GFP_DMA);
if (!hqvdp->hqvdp_cmd) {
DRM_ERROR("Failed to allocate memory for VDP cmd\n");
return;
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 33add93b4ed9..3b0d8c392b70 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -175,8 +175,7 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo)
sg_free_table(bo->sgt);
kfree(bo->sgt);
} else if (bo->vaddr) {
- dma_free_writecombine(drm->dev, bo->gem.size, bo->vaddr,
- bo->paddr);
+ dma_free_wc(drm->dev, bo->gem.size, bo->vaddr, bo->paddr);
}
}
@@ -233,8 +232,8 @@ static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo)
} else {
size_t size = bo->gem.size;
- bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr,
- GFP_KERNEL | __GFP_NOWARN);
+ bo->vaddr = dma_alloc_wc(drm->dev, size, &bo->paddr,
+ GFP_KERNEL | __GFP_NOWARN);
if (!bo->vaddr) {
dev_err(drm->dev,
"failed to allocate buffer of size %zu\n",
@@ -472,8 +471,8 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_pgoff = 0;
- ret = dma_mmap_writecombine(gem->dev->dev, vma, bo->vaddr,
- bo->paddr, gem->size);
+ ret = dma_mmap_wc(gem->dev->dev, vma, bo->vaddr, bo->paddr,
+ gem->size);
if (ret) {
drm_gem_vm_close(vma);
return ret;
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index 18dfe3ec9a62..034ef2de9037 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -215,7 +215,7 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size,
struct drm_gem_cma_object *cma_obj;
if (size == 0)
- return NULL;
+ return ERR_PTR(-EINVAL);
/* First, try to get a vc4_bo from the kernel BO cache. */
if (from_cache) {
@@ -237,7 +237,7 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size,
if (IS_ERR(cma_obj)) {
DRM_ERROR("Failed to allocate from CMA:\n");
vc4_bo_stats_dump(vc4);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
}
@@ -259,8 +259,8 @@ int vc4_dumb_create(struct drm_file *file_priv,
args->size = args->pitch * args->height;
bo = vc4_bo_create(dev, args->size, false);
- if (!bo)
- return -ENOMEM;
+ if (IS_ERR(bo))
+ return PTR_ERR(bo);
ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
drm_gem_object_unreference_unlocked(&bo->base.base);
@@ -398,9 +398,8 @@ int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_pgoff = 0;
- ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma,
- bo->base.vaddr, bo->base.paddr,
- vma->vm_end - vma->vm_start);
+ ret = dma_mmap_wc(bo->base.base.dev->dev, vma, bo->base.vaddr,
+ bo->base.paddr, vma->vm_end - vma->vm_start);
if (ret)
drm_gem_vm_close(vma);
@@ -443,8 +442,8 @@ int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
* get zeroed, and that might leak data between users.
*/
bo = vc4_bo_create(dev, args->size, false);
- if (!bo)
- return -ENOMEM;
+ if (IS_ERR(bo))
+ return PTR_ERR(bo);
ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
drm_gem_object_unreference_unlocked(&bo->base.base);
@@ -496,8 +495,8 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
}
bo = vc4_bo_create(dev, args->size, true);
- if (!bo)
- return -ENOMEM;
+ if (IS_ERR(bo))
+ return PTR_ERR(bo);
ret = copy_from_user(bo->base.vaddr,
(void __user *)(uintptr_t)args->data,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 080865ec2bae..51a63330d4f8 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -91,8 +91,12 @@ struct vc4_dev {
struct vc4_bo *overflow_mem;
struct work_struct overflow_mem_work;
+ int power_refcount;
+
+ /* Mutex controlling the power refcount. */
+ struct mutex power_lock;
+
struct {
- uint32_t last_ct0ca, last_ct1ca;
struct timer_list timer;
struct work_struct reset_work;
} hangcheck;
@@ -142,6 +146,7 @@ struct vc4_seqno_cb {
};
struct vc4_v3d {
+ struct vc4_dev *vc4;
struct platform_device *pdev;
void __iomem *regs;
};
@@ -192,6 +197,11 @@ struct vc4_exec_info {
/* Sequence number for this bin/render job. */
uint64_t seqno;
+ /* Last current addresses the hardware was processing when the
+ * hangcheck timer checked on us.
+ */
+ uint32_t last_ct0ca, last_ct1ca;
+
/* Kernel-space copy of the ioctl arguments */
struct drm_vc4_submit_cl *args;
@@ -434,7 +444,6 @@ void vc4_plane_async_set_fb(struct drm_plane *plane,
extern struct platform_driver vc4_v3d_driver;
int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused);
int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused);
-int vc4_v3d_set_power(struct vc4_dev *vc4, bool on);
/* vc4_validate.c */
int
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 48ce30a6f4b5..202aa1544acc 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -228,8 +229,16 @@ vc4_reset(struct drm_device *dev)
struct vc4_dev *vc4 = to_vc4_dev(dev);
DRM_INFO("Resetting GPU.\n");
- vc4_v3d_set_power(vc4, false);
- vc4_v3d_set_power(vc4, true);
+
+ mutex_lock(&vc4->power_lock);
+ if (vc4->power_refcount) {
+ /* Power the device off and back on the by dropping the
+ * reference on runtime PM.
+ */
+ pm_runtime_put_sync_suspend(&vc4->v3d->pdev->dev);
+ pm_runtime_get_sync(&vc4->v3d->pdev->dev);
+ }
+ mutex_unlock(&vc4->power_lock);
vc4_irq_reset(dev);
@@ -257,10 +266,17 @@ vc4_hangcheck_elapsed(unsigned long data)
struct drm_device *dev = (struct drm_device *)data;
struct vc4_dev *vc4 = to_vc4_dev(dev);
uint32_t ct0ca, ct1ca;
+ unsigned long irqflags;
+ struct vc4_exec_info *exec;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ exec = vc4_first_job(vc4);
/* If idle, we can stop watching for hangs. */
- if (list_empty(&vc4->job_list))
+ if (!exec) {
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
return;
+ }
ct0ca = V3D_READ(V3D_CTNCA(0));
ct1ca = V3D_READ(V3D_CTNCA(1));
@@ -268,14 +284,16 @@ vc4_hangcheck_elapsed(unsigned long data)
/* If we've made any progress in execution, rearm the timer
* and wait.
*/
- if (ct0ca != vc4->hangcheck.last_ct0ca ||
- ct1ca != vc4->hangcheck.last_ct1ca) {
- vc4->hangcheck.last_ct0ca = ct0ca;
- vc4->hangcheck.last_ct1ca = ct1ca;
+ if (ct0ca != exec->last_ct0ca || ct1ca != exec->last_ct1ca) {
+ exec->last_ct0ca = ct0ca;
+ exec->last_ct1ca = ct1ca;
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
vc4_queue_hangcheck(dev);
return;
}
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+
/* We've gone too long with no progress, reset. This has to
* be done from a work struct, since resetting can sleep and
* this timer hook isn't allowed to.
@@ -340,12 +358,7 @@ vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns,
finish_wait(&vc4->job_wait_queue, &wait);
trace_vc4_wait_for_seqno_end(dev, seqno);
- if (ret && ret != -ERESTARTSYS) {
- DRM_ERROR("timeout waiting for render thread idle\n");
- return ret;
- }
-
- return 0;
+ return ret;
}
static void
@@ -578,9 +591,9 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
}
bo = vc4_bo_create(dev, exec_size, true);
- if (!bo) {
+ if (IS_ERR(bo)) {
DRM_ERROR("Couldn't allocate BO for binning\n");
- ret = -ENOMEM;
+ ret = PTR_ERR(bo);
goto fail;
}
exec->exec_bo = &bo->base;
@@ -617,6 +630,7 @@ fail:
static void
vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
unsigned i;
/* Need the struct lock for drm_gem_object_unreference(). */
@@ -635,6 +649,11 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
}
mutex_unlock(&dev->struct_mutex);
+ mutex_lock(&vc4->power_lock);
+ if (--vc4->power_refcount == 0)
+ pm_runtime_put(&vc4->v3d->pdev->dev);
+ mutex_unlock(&vc4->power_lock);
+
kfree(exec);
}
@@ -746,6 +765,9 @@ vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
struct drm_gem_object *gem_obj;
struct vc4_bo *bo;
+ if (args->pad != 0)
+ return -EINVAL;
+
gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (!gem_obj) {
DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
@@ -772,7 +794,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct drm_vc4_submit_cl *args = data;
struct vc4_exec_info *exec;
- int ret;
+ int ret = 0;
if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) {
DRM_ERROR("Unknown flags: 0x%02x\n", args->flags);
@@ -785,6 +807,15 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
return -ENOMEM;
}
+ mutex_lock(&vc4->power_lock);
+ if (vc4->power_refcount++ == 0)
+ ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
+ mutex_unlock(&vc4->power_lock);
+ if (ret < 0) {
+ kfree(exec);
+ return ret;
+ }
+
exec->args = args;
INIT_LIST_HEAD(&exec->unref_list);
@@ -839,6 +870,8 @@ vc4_gem_init(struct drm_device *dev)
(unsigned long)dev);
INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
+
+ mutex_init(&vc4->power_lock);
}
void
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index b68060e758db..78a21357fb2d 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -57,7 +57,7 @@ vc4_overflow_mem_work(struct work_struct *work)
struct vc4_bo *bo;
bo = vc4_bo_create(dev, 256 * 1024, true);
- if (!bo) {
+ if (IS_ERR(bo)) {
DRM_ERROR("Couldn't allocate binner overflow mem\n");
return;
}
diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c
index 8a2a312e2c1b..0f12418725e5 100644
--- a/drivers/gpu/drm/vc4/vc4_render_cl.c
+++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
@@ -316,20 +316,11 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec,
size += xtiles * ytiles * loop_body_size;
setup->rcl = &vc4_bo_create(dev, size, true)->base;
- if (!setup->rcl)
- return -ENOMEM;
+ if (IS_ERR(setup->rcl))
+ return PTR_ERR(setup->rcl);
list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
&exec->unref_list);
- rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
- rcl_u32(setup,
- (setup->color_write ? (setup->color_write->paddr +
- args->color_write.offset) :
- 0));
- rcl_u16(setup, args->width);
- rcl_u16(setup, args->height);
- rcl_u16(setup, args->color_write.bits);
-
/* The tile buffer gets cleared when the previous tile is stored. If
* the clear values changed between frames, then the tile buffer has
* stale clear values in it, so we have to do a store in None mode (no
@@ -349,6 +340,15 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec,
rcl_u32(setup, 0); /* no address, since we're in None mode */
}
+ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
+ rcl_u32(setup,
+ (setup->color_write ? (setup->color_write->paddr +
+ args->color_write.offset) :
+ 0));
+ rcl_u16(setup, args->width);
+ rcl_u16(setup, args->height);
+ rcl_u16(setup, args->color_write.bits);
+
for (y = min_y_tile; y <= max_y_tile; y++) {
for (x = min_x_tile; x <= max_x_tile; x++) {
bool first = (x == min_x_tile && y == min_y_tile);
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index 314ff71db978..31de5d17bc85 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -17,6 +17,7 @@
*/
#include "linux/component.h"
+#include "linux/pm_runtime.h"
#include "vc4_drv.h"
#include "vc4_regs.h"
@@ -144,18 +145,6 @@ int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
}
#endif /* CONFIG_DEBUG_FS */
-int
-vc4_v3d_set_power(struct vc4_dev *vc4, bool on)
-{
- /* XXX: This interface is needed for GPU reset, and the way to
- * do it is to turn our power domain off and back on. We
- * can't just reset from within the driver, because the reset
- * bits are in the power domain's register area, and get set
- * during the poweron process.
- */
- return 0;
-}
-
static void vc4_v3d_init_hw(struct drm_device *dev)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
@@ -167,6 +156,29 @@ static void vc4_v3d_init_hw(struct drm_device *dev)
V3D_WRITE(V3D_VPMBASE, 0);
}
+#ifdef CONFIG_PM
+static int vc4_v3d_runtime_suspend(struct device *dev)
+{
+ struct vc4_v3d *v3d = dev_get_drvdata(dev);
+ struct vc4_dev *vc4 = v3d->vc4;
+
+ vc4_irq_uninstall(vc4->dev);
+
+ return 0;
+}
+
+static int vc4_v3d_runtime_resume(struct device *dev)
+{
+ struct vc4_v3d *v3d = dev_get_drvdata(dev);
+ struct vc4_dev *vc4 = v3d->vc4;
+
+ vc4_v3d_init_hw(vc4->dev);
+ vc4_irq_postinstall(vc4->dev);
+
+ return 0;
+}
+#endif
+
static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -179,6 +191,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
if (!v3d)
return -ENOMEM;
+ dev_set_drvdata(dev, v3d);
+
v3d->pdev = pdev;
v3d->regs = vc4_ioremap_regs(pdev, 0);
@@ -186,6 +200,7 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
return PTR_ERR(v3d->regs);
vc4->v3d = v3d;
+ v3d->vc4 = vc4;
if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) {
DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n",
@@ -207,6 +222,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
return ret;
}
+ pm_runtime_enable(dev);
+
return 0;
}
@@ -216,6 +233,8 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
struct drm_device *drm = dev_get_drvdata(master);
struct vc4_dev *vc4 = to_vc4_dev(drm);
+ pm_runtime_disable(dev);
+
drm_irq_uninstall(drm);
/* Disable the binner's overflow memory address, so the next
@@ -228,6 +247,10 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
vc4->v3d = NULL;
}
+static const struct dev_pm_ops vc4_v3d_pm_ops = {
+ SET_RUNTIME_PM_OPS(vc4_v3d_runtime_suspend, vc4_v3d_runtime_resume, NULL)
+};
+
static const struct component_ops vc4_v3d_ops = {
.bind = vc4_v3d_bind,
.unbind = vc4_v3d_unbind,
@@ -255,5 +278,6 @@ struct platform_driver vc4_v3d_driver = {
.driver = {
.name = "vc4_v3d",
.of_match_table = vc4_v3d_dt_match,
+ .pm = &vc4_v3d_pm_ops,
},
};
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c
index e26d9f6face3..24c2c746e8f3 100644
--- a/drivers/gpu/drm/vc4/vc4_validate.c
+++ b/drivers/gpu/drm/vc4/vc4_validate.c
@@ -401,8 +401,8 @@ validate_tile_binning_config(VALIDATE_ARGS)
tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size,
true);
exec->tile_bo = &tile_bo->base;
- if (!exec->tile_bo)
- return -ENOMEM;
+ if (IS_ERR(exec->tile_bo))
+ return PTR_ERR(exec->tile_bo);
list_add_tail(&tile_bo->unref_head, &exec->unref_list);
/* tile alloc address. */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index db082bea8daf..c5a1a08b0449 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -563,6 +563,8 @@ static void vmw_sou_connector_destroy(struct drm_connector *connector)
static const struct drm_connector_funcs vmw_sou_connector_funcs = {
.dpms = vmw_du_connector_dpms,
+ .detect = vmw_du_connector_detect,
+ .fill_modes = vmw_du_connector_fill_modes,
.set_property = vmw_du_connector_set_property,
.destroy = vmw_sou_connector_destroy,
};
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index da462afcb225..dd2dbb9746ce 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -18,6 +18,7 @@
#include <linux/host1x.h>
#include <linux/of.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include "bus.h"
#include "dev.h"
@@ -394,6 +395,7 @@ static int host1x_device_add(struct host1x *host1x,
device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
device->dev.dma_mask = &device->dev.coherent_dma_mask;
dev_set_name(&device->dev, "%s", driver->driver.name);
+ of_dma_configure(&device->dev, host1x->dev->of_node);
device->dev.release = host1x_device_release;
device->dev.bus = &host1x_bus_type;
device->dev.parent = host1x->dev;
diff --git a/drivers/gpu/host1x/cdma.c b/drivers/gpu/host1x/cdma.c
index 5a8c8d55317a..a18db4d5347c 100644
--- a/drivers/gpu/host1x/cdma.c
+++ b/drivers/gpu/host1x/cdma.c
@@ -52,8 +52,8 @@ static void host1x_pushbuffer_destroy(struct push_buffer *pb)
struct host1x *host1x = cdma_to_host1x(cdma);
if (pb->phys != 0)
- dma_free_writecombine(host1x->dev, pb->size_bytes + 4,
- pb->mapped, pb->phys);
+ dma_free_wc(host1x->dev, pb->size_bytes + 4, pb->mapped,
+ pb->phys);
pb->mapped = NULL;
pb->phys = 0;
@@ -76,8 +76,8 @@ static int host1x_pushbuffer_init(struct push_buffer *pb)
pb->pos = 0;
/* allocate and map pushbuffer memory */
- pb->mapped = dma_alloc_writecombine(host1x->dev, pb->size_bytes + 4,
- &pb->phys, GFP_KERNEL);
+ pb->mapped = dma_alloc_wc(host1x->dev, pb->size_bytes + 4, &pb->phys,
+ GFP_KERNEL);
if (!pb->mapped)
goto fail;
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 314bf3718cc7..ff348690df94 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -23,6 +23,7 @@
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/dma-mapping.h>
#define CREATE_TRACE_POINTS
#include <trace/events/host1x.h>
@@ -68,6 +69,7 @@ static const struct host1x_info host1x01_info = {
.nb_bases = 8,
.init = host1x01_init,
.sync_offset = 0x3000,
+ .dma_mask = DMA_BIT_MASK(32),
};
static const struct host1x_info host1x02_info = {
@@ -77,6 +79,7 @@ static const struct host1x_info host1x02_info = {
.nb_bases = 12,
.init = host1x02_init,
.sync_offset = 0x3000,
+ .dma_mask = DMA_BIT_MASK(32),
};
static const struct host1x_info host1x04_info = {
@@ -86,6 +89,7 @@ static const struct host1x_info host1x04_info = {
.nb_bases = 64,
.init = host1x04_init,
.sync_offset = 0x2100,
+ .dma_mask = DMA_BIT_MASK(34),
};
static const struct host1x_info host1x05_info = {
@@ -95,6 +99,7 @@ static const struct host1x_info host1x05_info = {
.nb_bases = 64,
.init = host1x05_init,
.sync_offset = 0x2100,
+ .dma_mask = DMA_BIT_MASK(34),
};
static struct of_device_id host1x_of_match[] = {
@@ -148,6 +153,8 @@ static int host1x_probe(struct platform_device *pdev)
if (IS_ERR(host->regs))
return PTR_ERR(host->regs);
+ dma_set_mask_and_coherent(host->dev, host->info->dma_mask);
+
if (host->info->init) {
err = host->info->init(host);
if (err)
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
index 0b6e8e9629c5..dace124994bb 100644
--- a/drivers/gpu/host1x/dev.h
+++ b/drivers/gpu/host1x/dev.h
@@ -96,6 +96,7 @@ struct host1x_info {
int nb_mlocks; /* host1x: number of mlocks */
int (*init)(struct host1x *); /* initialize per SoC ops */
int sync_offset;
+ u64 dma_mask; /* mask of addressable memory */
};
struct host1x {
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
index 63bd63f3c7df..defa7995f213 100644
--- a/drivers/gpu/host1x/job.c
+++ b/drivers/gpu/host1x/job.c
@@ -467,9 +467,8 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev)
size += g->words * sizeof(u32);
}
- job->gather_copy_mapped = dma_alloc_writecombine(dev, size,
- &job->gather_copy,
- GFP_KERNEL);
+ job->gather_copy_mapped = dma_alloc_wc(dev, size, &job->gather_copy,
+ GFP_KERNEL);
if (!job->gather_copy_mapped) {
job->gather_copy_mapped = NULL;
return -ENOMEM;
@@ -578,9 +577,8 @@ void host1x_job_unpin(struct host1x_job *job)
job->num_unpins = 0;
if (job->gather_copy_size)
- dma_free_writecombine(job->channel->dev, job->gather_copy_size,
- job->gather_copy_mapped,
- job->gather_copy);
+ dma_free_wc(job->channel->dev, job->gather_copy_size,
+ job->gather_copy_mapped, job->gather_copy);
}
EXPORT_SYMBOL(host1x_job_unpin);
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index f2e13eb8339f..e00db3f510dd 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -1050,6 +1050,17 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
const struct ipu_platform_reg *reg = &client_reg[i];
struct platform_device *pdev;
+ struct device_node *of_node;
+
+ /* Associate subdevice with the corresponding port node */
+ of_node = of_graph_get_port_by_id(dev->of_node, i);
+ if (!of_node) {
+ dev_info(dev,
+ "no port@%d node in %s, not using %s%d\n",
+ i, dev->of_node->full_name,
+ (i / 2) ? "DI" : "CSI", i % 2);
+ continue;
+ }
pdev = platform_device_alloc(reg->name, id++);
if (!pdev) {
@@ -1057,17 +1068,9 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
goto err_register;
}
+ pdev->dev.of_node = of_node;
pdev->dev.parent = dev;
- /* Associate subdevice with the corresponding port node */
- pdev->dev.of_node = of_graph_get_port_by_id(dev->of_node, i);
- if (!pdev->dev.of_node) {
- dev_err(dev, "missing port@%d node in %s\n", i,
- dev->of_node->full_name);
- ret = -ENODEV;
- goto err_register;
- }
-
ret = platform_device_add_data(pdev, &reg->pdata,
sizeof(reg->pdata));
if (!ret)
@@ -1289,10 +1292,6 @@ static int ipu_probe(struct platform_device *pdev)
ipu->irq_sync = irq_sync;
ipu->irq_err = irq_err;
- ret = ipu_irq_init(ipu);
- if (ret)
- goto out_failed_irq;
-
ret = device_reset(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "failed to reset: %d\n", ret);
@@ -1302,6 +1301,10 @@ static int ipu_probe(struct platform_device *pdev)
if (ret)
goto out_failed_reset;
+ ret = ipu_irq_init(ipu);
+ if (ret)
+ goto out_failed_irq;
+
/* Set MCU_T to divide MCU access window into 2 */
ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
IPU_DISP_GEN);
@@ -1324,9 +1327,9 @@ static int ipu_probe(struct platform_device *pdev)
failed_add_clients:
ipu_submodules_exit(ipu);
failed_submodules_init:
-out_failed_reset:
ipu_irq_exit(ipu);
out_failed_irq:
+out_failed_reset:
clk_disable_unprepare(ipu->clk);
return ret;
}
diff --git a/drivers/hsi/clients/nokia-modem.c b/drivers/hsi/clients/nokia-modem.c
index 7f82c911ad74..c000780d931f 100644
--- a/drivers/hsi/clients/nokia-modem.c
+++ b/drivers/hsi/clients/nokia-modem.c
@@ -281,6 +281,8 @@ static int nokia_modem_remove(struct device *dev)
#ifdef CONFIG_OF
static const struct of_device_id nokia_modem_of_match[] = {
{ .compatible = "nokia,n900-modem", },
+ { .compatible = "nokia,n950-modem", },
+ { .compatible = "nokia,n9-modem", },
{},
};
MODULE_DEVICE_TABLE(of, nokia_modem_of_match);
diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c
index a38af68cf326..6595d2091268 100644
--- a/drivers/hsi/clients/ssi_protocol.c
+++ b/drivers/hsi/clients/ssi_protocol.c
@@ -521,13 +521,7 @@ static void ssip_start_rx(struct hsi_client *cl)
* high transition. Therefore we need to ignore the sencond UP event.
*/
if ((ssi->main_state != ACTIVE) || (ssi->recv_state == RECV_READY)) {
- if (ssi->main_state == INIT) {
- ssi->main_state = HANDSHAKE;
- spin_unlock(&ssi->lock);
- ssip_send_bootinfo_req_cmd(cl);
- } else {
- spin_unlock(&ssi->lock);
- }
+ spin_unlock(&ssi->lock);
return;
}
ssip_set_rxstate(ssi, RECV_READY);
@@ -671,6 +665,7 @@ static void ssip_rx_bootinforeq(struct hsi_client *cl, u32 cmd)
ssip_error(cl);
/* Fall through */
case INIT:
+ case HANDSHAKE:
spin_lock(&ssi->lock);
ssi->main_state = HANDSHAKE;
if (!ssi->waketest) {
@@ -688,9 +683,6 @@ static void ssip_rx_bootinforeq(struct hsi_client *cl, u32 cmd)
msg->complete = ssip_release_cmd;
hsi_async_write(cl, msg);
break;
- case HANDSHAKE:
- /* Ignore */
- break;
default:
dev_dbg(&cl->device, "Wrong state M(%d)\n", ssi->main_state);
break;
@@ -939,9 +931,11 @@ static int ssip_pn_open(struct net_device *dev)
ssi->waketest = 1;
ssi_waketest(cl, 1); /* FIXME: To be removed */
}
- ssi->main_state = INIT;
+ ssi->main_state = HANDSHAKE;
spin_unlock_bh(&ssi->lock);
+ ssip_send_bootinfo_req_cmd(cl);
+
return 0;
}
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 1161d68a1863..56dd261f7142 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -219,6 +219,21 @@ error0:
}
EXPORT_SYMBOL_GPL(vmbus_open);
+/* Used for Hyper-V Socket: a guest client's connect() to the host */
+int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id,
+ const uuid_le *shv_host_servie_id)
+{
+ struct vmbus_channel_tl_connect_request conn_msg;
+
+ memset(&conn_msg, 0, sizeof(conn_msg));
+ conn_msg.header.msgtype = CHANNELMSG_TL_CONNECT_REQUEST;
+ conn_msg.guest_endpoint_id = *shv_guest_servie_id;
+ conn_msg.host_service_id = *shv_host_servie_id;
+
+ return vmbus_post_msg(&conn_msg, sizeof(conn_msg));
+}
+EXPORT_SYMBOL_GPL(vmbus_send_tl_connect_request);
+
/*
* create_gpadl_header - Creates a gpadl for the specified buffer
*/
@@ -624,6 +639,7 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
u64 aligned_data = 0;
int ret;
bool signal = false;
+ bool lock = channel->acquire_ring_lock;
int num_vecs = ((bufferlen != 0) ? 3 : 1);
@@ -643,7 +659,7 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs,
- &signal);
+ &signal, lock);
/*
* Signalling the host is conditional on many factors:
@@ -659,6 +675,9 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
* If we cannot write to the ring-buffer; signal the host
* even if we may not have written anything. This is a rare
* enough condition that it should not matter.
+ * NOTE: in this case, the hvsock channel is an exception, because
+ * it looks the host side's hvsock implementation has a throttling
+ * mechanism which can hurt the performance otherwise.
*/
if (channel->signal_policy)
@@ -666,7 +685,8 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
else
kick_q = true;
- if (((ret == 0) && kick_q && signal) || (ret))
+ if (((ret == 0) && kick_q && signal) ||
+ (ret && !is_hvsock_channel(channel)))
vmbus_setevent(channel);
return ret;
@@ -719,6 +739,7 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
+ bool lock = channel->acquire_ring_lock;
if (pagecount > MAX_PAGE_BUFFER_COUNT)
return -EINVAL;
@@ -755,7 +776,8 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
- ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
+ &signal, lock);
/*
* Signalling the host is conditional on many factors:
@@ -818,6 +840,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
+ bool lock = channel->acquire_ring_lock;
packetlen = desc_size + bufferlen;
packetlen_aligned = ALIGN(packetlen, sizeof(u64));
@@ -837,7 +860,8 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
- ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
+ &signal, lock);
if (ret == 0 && signal)
vmbus_setevent(channel);
@@ -862,6 +886,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
+ bool lock = channel->acquire_ring_lock;
u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
multi_pagebuffer->len);
@@ -900,7 +925,8 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
- ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
+ &signal, lock);
if (ret == 0 && signal)
vmbus_setevent(channel);
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 1c1ad47042c5..38b682bab85a 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -28,12 +28,127 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/completion.h>
+#include <linux/delay.h>
#include <linux/hyperv.h>
#include "hyperv_vmbus.h"
-static void init_vp_index(struct vmbus_channel *channel,
- const uuid_le *type_guid);
+static void init_vp_index(struct vmbus_channel *channel, u16 dev_type);
+
+static const struct vmbus_device vmbus_devs[] = {
+ /* IDE */
+ { .dev_type = HV_IDE,
+ HV_IDE_GUID,
+ .perf_device = true,
+ },
+
+ /* SCSI */
+ { .dev_type = HV_SCSI,
+ HV_SCSI_GUID,
+ .perf_device = true,
+ },
+
+ /* Fibre Channel */
+ { .dev_type = HV_FC,
+ HV_SYNTHFC_GUID,
+ .perf_device = true,
+ },
+
+ /* Synthetic NIC */
+ { .dev_type = HV_NIC,
+ HV_NIC_GUID,
+ .perf_device = true,
+ },
+
+ /* Network Direct */
+ { .dev_type = HV_ND,
+ HV_ND_GUID,
+ .perf_device = true,
+ },
+
+ /* PCIE */
+ { .dev_type = HV_PCIE,
+ HV_PCIE_GUID,
+ .perf_device = true,
+ },
+
+ /* Synthetic Frame Buffer */
+ { .dev_type = HV_FB,
+ HV_SYNTHVID_GUID,
+ .perf_device = false,
+ },
+
+ /* Synthetic Keyboard */
+ { .dev_type = HV_KBD,
+ HV_KBD_GUID,
+ .perf_device = false,
+ },
+
+ /* Synthetic MOUSE */
+ { .dev_type = HV_MOUSE,
+ HV_MOUSE_GUID,
+ .perf_device = false,
+ },
+
+ /* KVP */
+ { .dev_type = HV_KVP,
+ HV_KVP_GUID,
+ .perf_device = false,
+ },
+
+ /* Time Synch */
+ { .dev_type = HV_TS,
+ HV_TS_GUID,
+ .perf_device = false,
+ },
+
+ /* Heartbeat */
+ { .dev_type = HV_HB,
+ HV_HEART_BEAT_GUID,
+ .perf_device = false,
+ },
+
+ /* Shutdown */
+ { .dev_type = HV_SHUTDOWN,
+ HV_SHUTDOWN_GUID,
+ .perf_device = false,
+ },
+
+ /* File copy */
+ { .dev_type = HV_FCOPY,
+ HV_FCOPY_GUID,
+ .perf_device = false,
+ },
+
+ /* Backup */
+ { .dev_type = HV_BACKUP,
+ HV_VSS_GUID,
+ .perf_device = false,
+ },
+
+ /* Dynamic Memory */
+ { .dev_type = HV_DM,
+ HV_DM_GUID,
+ .perf_device = false,
+ },
+
+ /* Unknown GUID */
+ { .dev_type = HV_UNKOWN,
+ .perf_device = false,
+ },
+};
+
+static u16 hv_get_dev_type(const uuid_le *guid)
+{
+ u16 i;
+
+ for (i = HV_IDE; i < HV_UNKOWN; i++) {
+ if (!uuid_le_cmp(*guid, vmbus_devs[i].guid))
+ return i;
+ }
+ pr_info("Unknown GUID: %pUl\n", guid);
+ return i;
+}
/**
* vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
@@ -144,6 +259,7 @@ static struct vmbus_channel *alloc_channel(void)
return NULL;
channel->id = atomic_inc_return(&chan_num);
+ channel->acquire_ring_lock = true;
spin_lock_init(&channel->inbound_lock);
spin_lock_init(&channel->lock);
@@ -195,6 +311,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
vmbus_release_relid(relid);
BUG_ON(!channel->rescind);
+ BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
if (channel->target_cpu != get_cpu()) {
put_cpu();
@@ -206,9 +323,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
}
if (channel->primary_channel == NULL) {
- mutex_lock(&vmbus_connection.channel_mutex);
list_del(&channel->listentry);
- mutex_unlock(&vmbus_connection.channel_mutex);
primary_channel = channel;
} else {
@@ -251,6 +366,8 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
struct vmbus_channel *channel;
bool fnew = true;
unsigned long flags;
+ u16 dev_type;
+ int ret;
/* Make sure this is a new offer */
mutex_lock(&vmbus_connection.channel_mutex);
@@ -288,7 +405,9 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
goto err_free_chan;
}
- init_vp_index(newchannel, &newchannel->offermsg.offer.if_type);
+ dev_type = hv_get_dev_type(&newchannel->offermsg.offer.if_type);
+
+ init_vp_index(newchannel, dev_type);
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
@@ -325,12 +444,17 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
if (!newchannel->device_obj)
goto err_deq_chan;
+ newchannel->device_obj->device_id = dev_type;
/*
* Add the new device to the bus. This will kick off device-driver
* binding which eventually invokes the device driver's AddDevice()
* method.
*/
- if (vmbus_device_register(newchannel->device_obj) != 0) {
+ mutex_lock(&vmbus_connection.channel_mutex);
+ ret = vmbus_device_register(newchannel->device_obj);
+ mutex_unlock(&vmbus_connection.channel_mutex);
+
+ if (ret != 0) {
pr_err("unable to add child device object (relid %d)\n",
newchannel->offermsg.child_relid);
kfree(newchannel->device_obj);
@@ -358,37 +482,6 @@ err_free_chan:
free_channel(newchannel);
}
-enum {
- IDE = 0,
- SCSI,
- FC,
- NIC,
- ND_NIC,
- PCIE,
- MAX_PERF_CHN,
-};
-
-/*
- * This is an array of device_ids (device types) that are performance critical.
- * We attempt to distribute the interrupt load for these devices across
- * all available CPUs.
- */
-static const struct hv_vmbus_device_id hp_devs[] = {
- /* IDE */
- { HV_IDE_GUID, },
- /* Storage - SCSI */
- { HV_SCSI_GUID, },
- /* Storage - FC */
- { HV_SYNTHFC_GUID, },
- /* Network */
- { HV_NIC_GUID, },
- /* NetworkDirect Guest RDMA */
- { HV_ND_GUID, },
- /* PCI Express Pass Through */
- { HV_PCIE_GUID, },
-};
-
-
/*
* We use this state to statically distribute the channel interrupt load.
*/
@@ -405,22 +498,15 @@ static int next_numa_node_id;
* For pre-win8 hosts or non-performance critical channels we assign the
* first CPU in the first NUMA node.
*/
-static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_guid)
+static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
{
u32 cur_cpu;
- int i;
- bool perf_chn = false;
+ bool perf_chn = vmbus_devs[dev_type].perf_device;
struct vmbus_channel *primary = channel->primary_channel;
int next_node;
struct cpumask available_mask;
struct cpumask *alloced_mask;
- for (i = IDE; i < MAX_PERF_CHN; i++) {
- if (!uuid_le_cmp(*type_guid, hp_devs[i].guid)) {
- perf_chn = true;
- break;
- }
- }
if ((vmbus_proto_version == VERSION_WS2008) ||
(vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) {
/*
@@ -469,6 +555,17 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
cpumask_of_node(primary->numa_node));
cur_cpu = -1;
+
+ /*
+ * Normally Hyper-V host doesn't create more subchannels than there
+ * are VCPUs on the node but it is possible when not all present VCPUs
+ * on the node are initialized by guest. Clear the alloced_cpus_in_node
+ * to start over.
+ */
+ if (cpumask_equal(&primary->alloced_cpus_in_node,
+ cpumask_of_node(primary->numa_node)))
+ cpumask_clear(&primary->alloced_cpus_in_node);
+
while (true) {
cur_cpu = cpumask_next(cur_cpu, &available_mask);
if (cur_cpu >= nr_cpu_ids) {
@@ -498,6 +595,32 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
channel->target_vp = hv_context.vp_index[cur_cpu];
}
+static void vmbus_wait_for_unload(void)
+{
+ int cpu = smp_processor_id();
+ void *page_addr = hv_context.synic_message_page[cpu];
+ struct hv_message *msg = (struct hv_message *)page_addr +
+ VMBUS_MESSAGE_SINT;
+ struct vmbus_channel_message_header *hdr;
+ bool unloaded = false;
+
+ while (1) {
+ if (READ_ONCE(msg->header.message_type) == HVMSG_NONE) {
+ mdelay(10);
+ continue;
+ }
+
+ hdr = (struct vmbus_channel_message_header *)msg->u.payload;
+ if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE)
+ unloaded = true;
+
+ vmbus_signal_eom(msg);
+
+ if (unloaded)
+ break;
+ }
+}
+
/*
* vmbus_unload_response - Handler for the unload response.
*/
@@ -510,7 +633,7 @@ static void vmbus_unload_response(struct vmbus_channel_message_header *hdr)
complete(&vmbus_connection.unload_event);
}
-void vmbus_initiate_unload(void)
+void vmbus_initiate_unload(bool crash)
{
struct vmbus_channel_message_header hdr;
@@ -523,7 +646,14 @@ void vmbus_initiate_unload(void)
hdr.msgtype = CHANNELMSG_UNLOAD;
vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header));
- wait_for_completion(&vmbus_connection.unload_event);
+ /*
+ * vmbus_initiate_unload() is also called on crash and the crash can be
+ * happening in an interrupt context, where scheduling is impossible.
+ */
+ if (!crash)
+ wait_for_completion(&vmbus_connection.unload_event);
+ else
+ vmbus_wait_for_unload();
}
/*
@@ -592,6 +722,8 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
struct device *dev;
rescind = (struct vmbus_channel_rescind_offer *)hdr;
+
+ mutex_lock(&vmbus_connection.channel_mutex);
channel = relid2channel(rescind->child_relid);
if (channel == NULL) {
@@ -600,7 +732,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
* vmbus_process_offer(), we have already invoked
* vmbus_release_relid() on error.
*/
- return;
+ goto out;
}
spin_lock_irqsave(&channel->lock, flags);
@@ -608,6 +740,10 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
spin_unlock_irqrestore(&channel->lock, flags);
if (channel->device_obj) {
+ if (channel->chn_rescind_callback) {
+ channel->chn_rescind_callback(channel);
+ goto out;
+ }
/*
* We will have to unregister this device from the
* driver core.
@@ -621,7 +757,24 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
hv_process_channel_removal(channel,
channel->offermsg.child_relid);
}
+
+out:
+ mutex_unlock(&vmbus_connection.channel_mutex);
+}
+
+void vmbus_hvsock_device_unregister(struct vmbus_channel *channel)
+{
+ mutex_lock(&vmbus_connection.channel_mutex);
+
+ BUG_ON(!is_hvsock_channel(channel));
+
+ channel->rescind = true;
+ vmbus_device_unregister(channel->device_obj);
+
+ mutex_unlock(&vmbus_connection.channel_mutex);
}
+EXPORT_SYMBOL_GPL(vmbus_hvsock_device_unregister);
+
/*
* vmbus_onoffers_delivered -
@@ -825,6 +978,10 @@ struct vmbus_channel_message_table_entry
{CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response},
{CHANNELMSG_UNLOAD, 0, NULL},
{CHANNELMSG_UNLOAD_RESPONSE, 1, vmbus_unload_response},
+ {CHANNELMSG_18, 0, NULL},
+ {CHANNELMSG_19, 0, NULL},
+ {CHANNELMSG_20, 0, NULL},
+ {CHANNELMSG_TL_CONNECT_REQUEST, 0, NULL},
};
/*
@@ -973,3 +1130,10 @@ bool vmbus_are_subchannels_present(struct vmbus_channel *primary)
return ret;
}
EXPORT_SYMBOL_GPL(vmbus_are_subchannels_present);
+
+void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel,
+ void (*chn_rescind_cb)(struct vmbus_channel *))
+{
+ channel->chn_rescind_callback = chn_rescind_cb;
+}
+EXPORT_SYMBOL_GPL(vmbus_set_chn_rescind_callback);
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 3dc5a9c7fad6..d02f1373dd98 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -88,8 +88,16 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
* This has been the behavior pre-win8. This is not
* perf issue and having all channel messages delivered on CPU 0
* would be ok.
+ * For post win8 hosts, we support receiving channel messagges on
+ * all the CPUs. This is needed for kexec to work correctly where
+ * the CPU attempting to connect may not be CPU 0.
*/
- msg->target_vcpu = 0;
+ if (version >= VERSION_WIN8_1) {
+ msg->target_vcpu = hv_context.vp_index[get_cpu()];
+ put_cpu();
+ } else {
+ msg->target_vcpu = 0;
+ }
/*
* Add to list before we send the request since we may
@@ -236,7 +244,7 @@ void vmbus_disconnect(void)
/*
* First send the unload request to the host.
*/
- vmbus_initiate_unload();
+ vmbus_initiate_unload(false);
if (vmbus_connection.work_queue) {
drain_workqueue(vmbus_connection.work_queue);
@@ -288,7 +296,8 @@ struct vmbus_channel *relid2channel(u32 relid)
struct list_head *cur, *tmp;
struct vmbus_channel *cur_sc;
- mutex_lock(&vmbus_connection.channel_mutex);
+ BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
+
list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (channel->offermsg.child_relid == relid) {
found_channel = channel;
@@ -307,7 +316,6 @@ struct vmbus_channel *relid2channel(u32 relid)
}
}
}
- mutex_unlock(&vmbus_connection.channel_mutex);
return found_channel;
}
@@ -474,7 +482,7 @@ int vmbus_post_msg(void *buffer, size_t buflen)
/*
* vmbus_set_event - Send an event notification to the parent
*/
-int vmbus_set_event(struct vmbus_channel *channel)
+void vmbus_set_event(struct vmbus_channel *channel)
{
u32 child_relid = channel->offermsg.child_relid;
@@ -485,5 +493,5 @@ int vmbus_set_event(struct vmbus_channel *channel)
(child_relid >> 5));
}
- return hv_signal_event(channel->sig_event);
+ hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL);
}
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 11bca51ef5ff..a1c086ba3b9a 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -204,6 +204,8 @@ int hv_init(void)
sizeof(int) * NR_CPUS);
memset(hv_context.event_dpc, 0,
sizeof(void *) * NR_CPUS);
+ memset(hv_context.msg_dpc, 0,
+ sizeof(void *) * NR_CPUS);
memset(hv_context.clk_evt, 0,
sizeof(void *) * NR_CPUS);
@@ -295,8 +297,14 @@ void hv_cleanup(void)
* Cleanup the TSC page based CS.
*/
if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
- clocksource_change_rating(&hyperv_cs_tsc, 10);
- clocksource_unregister(&hyperv_cs_tsc);
+ /*
+ * Crash can happen in an interrupt context and unregistering
+ * a clocksource is impossible and redundant in this case.
+ */
+ if (!oops_in_progress) {
+ clocksource_change_rating(&hyperv_cs_tsc, 10);
+ clocksource_unregister(&hyperv_cs_tsc);
+ }
hypercall_msr.as_uint64 = 0;
wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
@@ -337,22 +345,6 @@ int hv_post_message(union hv_connection_id connection_id,
return status & 0xFFFF;
}
-
-/*
- * hv_signal_event -
- * Signal an event on the specified connection using the hypervisor event IPC.
- *
- * This involves a hypercall.
- */
-int hv_signal_event(void *con_id)
-{
- u64 status;
-
- status = hv_do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL);
-
- return status & 0xFFFF;
-}
-
static int hv_ce_set_next_event(unsigned long delta,
struct clock_event_device *evt)
{
@@ -425,6 +417,13 @@ int hv_synic_alloc(void)
}
tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
+ hv_context.msg_dpc[cpu] = kmalloc(size, GFP_ATOMIC);
+ if (hv_context.msg_dpc[cpu] == NULL) {
+ pr_err("Unable to allocate event dpc\n");
+ goto err;
+ }
+ tasklet_init(hv_context.msg_dpc[cpu], vmbus_on_msg_dpc, cpu);
+
hv_context.clk_evt[cpu] = kzalloc(ced_size, GFP_ATOMIC);
if (hv_context.clk_evt[cpu] == NULL) {
pr_err("Unable to allocate clock event device\n");
@@ -466,6 +465,7 @@ err:
static void hv_synic_free_cpu(int cpu)
{
kfree(hv_context.event_dpc[cpu]);
+ kfree(hv_context.msg_dpc[cpu]);
kfree(hv_context.clk_evt[cpu]);
if (hv_context.synic_event_page[cpu])
free_page((unsigned long)hv_context.synic_event_page[cpu]);
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index c37a71e13de0..23c70799ad8a 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -251,7 +251,6 @@ void hv_fcopy_onchannelcallback(void *context)
*/
fcopy_transaction.recv_len = recvlen;
- fcopy_transaction.recv_channel = channel;
fcopy_transaction.recv_req_id = requestid;
fcopy_transaction.fcopy_msg = fcopy_msg;
@@ -317,6 +316,7 @@ static void fcopy_on_reset(void)
int hv_fcopy_init(struct hv_util_service *srv)
{
recv_buffer = srv->recv_buffer;
+ fcopy_transaction.recv_channel = srv->channel;
/*
* When this driver loads, the user level daemon that
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index d4ab81bcd515..9b9b370fe22a 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -639,7 +639,6 @@ void hv_kvp_onchannelcallback(void *context)
*/
kvp_transaction.recv_len = recvlen;
- kvp_transaction.recv_channel = channel;
kvp_transaction.recv_req_id = requestid;
kvp_transaction.kvp_msg = kvp_msg;
@@ -688,6 +687,7 @@ int
hv_kvp_init(struct hv_util_service *srv)
{
recv_buffer = srv->recv_buffer;
+ kvp_transaction.recv_channel = srv->channel;
/*
* When this driver loads, the user level daemon that
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 67def4a831c8..3fba14e88f03 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -263,7 +263,6 @@ void hv_vss_onchannelcallback(void *context)
*/
vss_transaction.recv_len = recvlen;
- vss_transaction.recv_channel = channel;
vss_transaction.recv_req_id = requestid;
vss_transaction.msg = (struct hv_vss_msg *)vss_msg;
@@ -337,6 +336,7 @@ hv_vss_init(struct hv_util_service *srv)
return -ENOTSUPP;
}
recv_buffer = srv->recv_buffer;
+ vss_transaction.recv_channel = srv->channel;
/*
* When this driver loads, the user level daemon that
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 7994ec2e4151..d5acaa2d8e61 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -322,6 +322,7 @@ static int util_probe(struct hv_device *dev,
srv->recv_buffer = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
if (!srv->recv_buffer)
return -ENOMEM;
+ srv->channel = dev->channel;
if (srv->util_init) {
ret = srv->util_init(srv);
if (ret) {
diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c
index 4f42c0e20c20..9a9983fa4531 100644
--- a/drivers/hv/hv_utils_transport.c
+++ b/drivers/hv/hv_utils_transport.c
@@ -310,6 +310,9 @@ struct hvutil_transport *hvutil_transport_init(const char *name,
return hvt;
err_free_hvt:
+ spin_lock(&hvt_list_lock);
+ list_del(&hvt->list);
+ spin_unlock(&hvt_list_lock);
kfree(hvt);
return NULL;
}
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 4ebc796b4f33..12321b93a756 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -256,12 +256,6 @@ struct hv_monitor_page {
u8 rsvdz4[1984];
};
-/* Declare the various hypercall operations. */
-enum hv_call_code {
- HVCALL_POST_MESSAGE = 0x005c,
- HVCALL_SIGNAL_EVENT = 0x005d,
-};
-
/* Definition of the hv_post_message hypercall input structure. */
struct hv_input_post_message {
union hv_connection_id connectionid;
@@ -449,10 +443,11 @@ struct hv_context {
u32 vp_index[NR_CPUS];
/*
* Starting with win8, we can take channel interrupts on any CPU;
- * we will manage the tasklet that handles events on a per CPU
+ * we will manage the tasklet that handles events messages on a per CPU
* basis.
*/
struct tasklet_struct *event_dpc[NR_CPUS];
+ struct tasklet_struct *msg_dpc[NR_CPUS];
/*
* To optimize the mapping of relid to channel, maintain
* per-cpu list of the channels based on their CPU affinity.
@@ -501,8 +496,6 @@ extern int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type,
void *payload, size_t payload_size);
-extern int hv_signal_event(void *con_id);
-
extern int hv_synic_alloc(void);
extern void hv_synic_free(void);
@@ -531,7 +524,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
struct kvec *kv_list,
- u32 kv_count, bool *signal);
+ u32 kv_count, bool *signal, bool lock);
int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
void *buffer, u32 buflen, u32 *buffer_actual_len,
@@ -626,6 +619,30 @@ struct vmbus_channel_message_table_entry {
extern struct vmbus_channel_message_table_entry
channel_message_table[CHANNELMSG_COUNT];
+/* Free the message slot and signal end-of-message if required */
+static inline void vmbus_signal_eom(struct hv_message *msg)
+{
+ msg->header.message_type = HVMSG_NONE;
+
+ /*
+ * Make sure the write to MessageType (ie set to
+ * HVMSG_NONE) happens before we read the
+ * MessagePending and EOMing. Otherwise, the EOMing
+ * will not deliver any more messages since there is
+ * no empty slot
+ */
+ mb();
+
+ if (msg->header.message_flags.msg_pending) {
+ /*
+ * This will cause message queue rescan to
+ * possibly deliver another msg from the
+ * hypervisor
+ */
+ wrmsrl(HV_X64_MSR_EOM, 0);
+ }
+}
+
/* General vmbus interface */
struct hv_device *vmbus_device_create(const uuid_le *type,
@@ -650,9 +667,10 @@ void vmbus_disconnect(void);
int vmbus_post_msg(void *buffer, size_t buflen);
-int vmbus_set_event(struct vmbus_channel *channel);
+void vmbus_set_event(struct vmbus_channel *channel);
void vmbus_on_event(unsigned long data);
+void vmbus_on_msg_dpc(unsigned long data);
int hv_kvp_init(struct hv_util_service *);
void hv_kvp_deinit(void);
@@ -665,7 +683,7 @@ void hv_vss_onchannelcallback(void *);
int hv_fcopy_init(struct hv_util_service *);
void hv_fcopy_deinit(void);
void hv_fcopy_onchannelcallback(void *);
-void vmbus_initiate_unload(void);
+void vmbus_initiate_unload(bool crash);
static inline void hv_poll_channel(struct vmbus_channel *channel,
void (*cb)(void *))
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index b53702ce692f..5613e2b5cff7 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -314,7 +314,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
/* Write to the ring buffer. */
int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
- struct kvec *kv_list, u32 kv_count, bool *signal)
+ struct kvec *kv_list, u32 kv_count, bool *signal, bool lock)
{
int i = 0;
u32 bytes_avail_towrite;
@@ -324,14 +324,15 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
u32 next_write_location;
u32 old_write;
u64 prev_indices = 0;
- unsigned long flags;
+ unsigned long flags = 0;
for (i = 0; i < kv_count; i++)
totalbytes_towrite += kv_list[i].iov_len;
totalbytes_towrite += sizeof(u64);
- spin_lock_irqsave(&outring_info->ring_lock, flags);
+ if (lock)
+ spin_lock_irqsave(&outring_info->ring_lock, flags);
hv_get_ringbuffer_availbytes(outring_info,
&bytes_avail_toread,
@@ -343,7 +344,8 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
* is empty since the read index == write index.
*/
if (bytes_avail_towrite <= totalbytes_towrite) {
- spin_unlock_irqrestore(&outring_info->ring_lock, flags);
+ if (lock)
+ spin_unlock_irqrestore(&outring_info->ring_lock, flags);
return -EAGAIN;
}
@@ -374,7 +376,8 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
hv_set_next_write_location(outring_info, next_write_location);
- spin_unlock_irqrestore(&outring_info->ring_lock, flags);
+ if (lock)
+ spin_unlock_irqrestore(&outring_info->ring_lock, flags);
*signal = hv_need_to_signal(old_write, outring_info);
return 0;
@@ -388,7 +391,6 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
u32 bytes_avail_toread;
u32 next_read_location = 0;
u64 prev_indices = 0;
- unsigned long flags;
struct vmpacket_descriptor desc;
u32 offset;
u32 packetlen;
@@ -397,7 +399,6 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
if (buflen <= 0)
return -EINVAL;
- spin_lock_irqsave(&inring_info->ring_lock, flags);
*buffer_actual_len = 0;
*requestid = 0;
@@ -412,7 +413,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
* No error is set when there is even no header, drivers are
* supposed to analyze buffer_actual_len.
*/
- goto out_unlock;
+ return ret;
}
next_read_location = hv_get_next_read_location(inring_info);
@@ -425,15 +426,11 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
*buffer_actual_len = packetlen;
*requestid = desc.trans_id;
- if (bytes_avail_toread < packetlen + offset) {
- ret = -EAGAIN;
- goto out_unlock;
- }
+ if (bytes_avail_toread < packetlen + offset)
+ return -EAGAIN;
- if (packetlen > buflen) {
- ret = -ENOBUFS;
- goto out_unlock;
- }
+ if (packetlen > buflen)
+ return -ENOBUFS;
next_read_location =
hv_get_next_readlocation_withoffset(inring_info, offset);
@@ -460,7 +457,5 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
*signal = hv_need_to_signal_on_read(bytes_avail_towrite, inring_info);
-out_unlock:
- spin_unlock_irqrestore(&inring_info->ring_lock, flags);
return ret;
}
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 328e4c3808e0..64713ff47e36 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -45,7 +45,6 @@
static struct acpi_device *hv_acpi_dev;
-static struct tasklet_struct msg_dpc;
static struct completion probe_event;
@@ -477,6 +476,24 @@ static ssize_t channel_vp_mapping_show(struct device *dev,
}
static DEVICE_ATTR_RO(channel_vp_mapping);
+static ssize_t vendor_show(struct device *dev,
+ struct device_attribute *dev_attr,
+ char *buf)
+{
+ struct hv_device *hv_dev = device_to_hv_device(dev);
+ return sprintf(buf, "0x%x\n", hv_dev->vendor_id);
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t device_show(struct device *dev,
+ struct device_attribute *dev_attr,
+ char *buf)
+{
+ struct hv_device *hv_dev = device_to_hv_device(dev);
+ return sprintf(buf, "0x%x\n", hv_dev->device_id);
+}
+static DEVICE_ATTR_RO(device);
+
/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
static struct attribute *vmbus_attrs[] = {
&dev_attr_id.attr,
@@ -502,6 +519,8 @@ static struct attribute *vmbus_attrs[] = {
&dev_attr_in_read_bytes_avail.attr,
&dev_attr_in_write_bytes_avail.attr,
&dev_attr_channel_vp_mapping.attr,
+ &dev_attr_vendor.attr,
+ &dev_attr_device.attr,
NULL,
};
ATTRIBUTE_GROUPS(vmbus);
@@ -562,6 +581,10 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
struct hv_driver *drv = drv_to_hv_drv(driver);
struct hv_device *hv_dev = device_to_hv_device(device);
+ /* The hv_sock driver handles all hv_sock offers. */
+ if (is_hvsock_channel(hv_dev->channel))
+ return drv->hvsock;
+
if (hv_vmbus_get_id(drv->id_table, &hv_dev->dev_type))
return 1;
@@ -685,28 +708,10 @@ static void hv_process_timer_expiration(struct hv_message *msg, int cpu)
if (dev->event_handler)
dev->event_handler(dev);
- msg->header.message_type = HVMSG_NONE;
-
- /*
- * Make sure the write to MessageType (ie set to
- * HVMSG_NONE) happens before we read the
- * MessagePending and EOMing. Otherwise, the EOMing
- * will not deliver any more messages since there is
- * no empty slot
- */
- mb();
-
- if (msg->header.message_flags.msg_pending) {
- /*
- * This will cause message queue rescan to
- * possibly deliver another msg from the
- * hypervisor
- */
- wrmsrl(HV_X64_MSR_EOM, 0);
- }
+ vmbus_signal_eom(msg);
}
-static void vmbus_on_msg_dpc(unsigned long data)
+void vmbus_on_msg_dpc(unsigned long data)
{
int cpu = smp_processor_id();
void *page_addr = hv_context.synic_message_page[cpu];
@@ -716,52 +721,32 @@ static void vmbus_on_msg_dpc(unsigned long data)
struct vmbus_channel_message_table_entry *entry;
struct onmessage_work_context *ctx;
- while (1) {
- if (msg->header.message_type == HVMSG_NONE)
- /* no msg */
- break;
+ if (msg->header.message_type == HVMSG_NONE)
+ /* no msg */
+ return;
- hdr = (struct vmbus_channel_message_header *)msg->u.payload;
+ hdr = (struct vmbus_channel_message_header *)msg->u.payload;
- if (hdr->msgtype >= CHANNELMSG_COUNT) {
- WARN_ONCE(1, "unknown msgtype=%d\n", hdr->msgtype);
- goto msg_handled;
- }
+ if (hdr->msgtype >= CHANNELMSG_COUNT) {
+ WARN_ONCE(1, "unknown msgtype=%d\n", hdr->msgtype);
+ goto msg_handled;
+ }
- entry = &channel_message_table[hdr->msgtype];
- if (entry->handler_type == VMHT_BLOCKING) {
- ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
- if (ctx == NULL)
- continue;
+ entry = &channel_message_table[hdr->msgtype];
+ if (entry->handler_type == VMHT_BLOCKING) {
+ ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+ if (ctx == NULL)
+ return;
- INIT_WORK(&ctx->work, vmbus_onmessage_work);
- memcpy(&ctx->msg, msg, sizeof(*msg));
+ INIT_WORK(&ctx->work, vmbus_onmessage_work);
+ memcpy(&ctx->msg, msg, sizeof(*msg));
- queue_work(vmbus_connection.work_queue, &ctx->work);
- } else
- entry->message_handler(hdr);
+ queue_work(vmbus_connection.work_queue, &ctx->work);
+ } else
+ entry->message_handler(hdr);
msg_handled:
- msg->header.message_type = HVMSG_NONE;
-
- /*
- * Make sure the write to MessageType (ie set to
- * HVMSG_NONE) happens before we read the
- * MessagePending and EOMing. Otherwise, the EOMing
- * will not deliver any more messages since there is
- * no empty slot
- */
- mb();
-
- if (msg->header.message_flags.msg_pending) {
- /*
- * This will cause message queue rescan to
- * possibly deliver another msg from the
- * hypervisor
- */
- wrmsrl(HV_X64_MSR_EOM, 0);
- }
- }
+ vmbus_signal_eom(msg);
}
static void vmbus_isr(void)
@@ -814,7 +799,7 @@ static void vmbus_isr(void)
if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
hv_process_timer_expiration(msg, cpu);
else
- tasklet_schedule(&msg_dpc);
+ tasklet_schedule(hv_context.msg_dpc[cpu]);
}
}
@@ -838,8 +823,6 @@ static int vmbus_bus_init(void)
return ret;
}
- tasklet_init(&msg_dpc, vmbus_on_msg_dpc, 0);
-
ret = bus_register(&hv_bus);
if (ret)
goto err_cleanup;
@@ -957,6 +940,7 @@ struct hv_device *vmbus_device_create(const uuid_le *type,
memcpy(&child_device_obj->dev_type, type, sizeof(uuid_le));
memcpy(&child_device_obj->dev_instance, instance,
sizeof(uuid_le));
+ child_device_obj->vendor_id = 0x1414; /* MSFT vendor ID */
return child_device_obj;
@@ -1268,7 +1252,7 @@ static void hv_kexec_handler(void)
int cpu;
hv_synic_clockevents_cleanup();
- vmbus_initiate_unload();
+ vmbus_initiate_unload(false);
for_each_online_cpu(cpu)
smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
hv_cleanup();
@@ -1276,7 +1260,7 @@ static void hv_kexec_handler(void)
static void hv_crash_handler(struct pt_regs *regs)
{
- vmbus_initiate_unload();
+ vmbus_initiate_unload(true);
/*
* In crash handler we can't schedule synic cleanup for all CPUs,
* doing the cleanup for current CPU only. This should be sufficient
@@ -1334,7 +1318,8 @@ static void __exit vmbus_exit(void)
hv_synic_clockevents_cleanup();
vmbus_disconnect();
hv_remove_vmbus_irq();
- tasklet_kill(&msg_dpc);
+ for_each_online_cpu(cpu)
+ tasklet_kill(hv_context.msg_dpc[cpu]);
vmbus_free_channels();
if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
unregister_die_notifier(&hyperv_die_block);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 60fb80bd353d..5c2d13a687aa 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -685,6 +685,20 @@ config SENSORS_LTC2945
This driver can also be built as a module. If so, the module will
be called ltc2945.
+config SENSORS_LTC2990
+ tristate "Linear Technology LTC2990 (current monitoring mode only)"
+ depends on I2C
+ help
+ If you say yes here you get support for Linear Technology LTC2990
+ I2C System Monitor. The LTC2990 supports a combination of voltage,
+ current and temperature monitoring, but in addition to the Vcc supply
+ voltage and chip temperature, this driver currently only supports
+ reading two currents by measuring two differential voltages across
+ series resistors.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc2990.
+
config SENSORS_LTC4151
tristate "Linear Technology LTC4151"
depends on I2C
@@ -1127,7 +1141,7 @@ config SENSORS_NTC_THERMISTOR
Currently, this driver supports
NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, NCP15WL333,
- and NCP03WF104 from Murata and B57330V2103 from EPCOS.
+ NCP03WF104 and NCP15XH103 from Murata and B57330V2103 from EPCOS.
This driver can also be built as a module. If so, the module
will be called ntc-thermistor.
@@ -1176,6 +1190,21 @@ config SENSORS_NCT7904
This driver can also be built as a module. If so, the module
will be called nct7904.
+config SENSORS_NSA320
+ tristate "ZyXEL NSA320 and compatible fan speed and temperature sensors"
+ depends on GPIOLIB && OF
+ depends on MACH_KIRKWOOD || COMPILE_TEST
+ help
+ If you say yes here you get support for hardware monitoring
+ for the ZyXEL NSA320 Media Server and other compatible devices
+ (probably the NSA325 and some NSA310 variants).
+
+ The sensor data is taken from a Holtek HT46R065 microcontroller
+ connected to GPIO lines.
+
+ This driver can also be built as a module. If so, the module
+ will be called nsa320-hwmon.
+
config SENSORS_PCF8591
tristate "Philips PCF8591 ADC/DAC"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 30c94df31465..58cc3acba7e7 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -100,6 +100,7 @@ obj-$(CONFIG_SENSORS_LM95234) += lm95234.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o
+obj-$(CONFIG_SENSORS_LTC2990) += ltc2990.o
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o
@@ -123,6 +124,7 @@ obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o
obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o
obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o
obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o
+obj-$(CONFIG_SENSORS_NSA320) += nsa320-hwmon.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
@@ -149,7 +151,7 @@ obj-$(CONFIG_SENSORS_TMP103) += tmp103.o
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
-obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress.o
+obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o
obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
index f155b8380481..2b3105c8aed3 100644
--- a/drivers/hwmon/ads1015.c
+++ b/drivers/hwmon/ads1015.c
@@ -126,7 +126,7 @@ static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel,
struct ads1015_data *data = i2c_get_clientdata(client);
unsigned int pga = data->channel_data[channel].pga;
int fullscale = fullscale_table[pga];
- const unsigned mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
+ const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
return DIV_ROUND_CLOSEST(reg * fullscale, mask);
}
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 82de3deeb18a..685568b1236d 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -406,16 +406,11 @@ static int gpio_fan_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct gpio_fan_data *fan_data = cdev->devdata;
- int r;
if (!fan_data)
return -EINVAL;
- r = get_fan_speed_index(fan_data);
- if (r < 0)
- return r;
-
- *state = r;
+ *state = fan_data->speed_index;
return 0;
}
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 17ae2eb26ce2..b550ba5fa58a 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -67,6 +67,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
enum iio_chan_type type;
struct iio_channel *channels;
const char *name = "iio_hwmon";
+ char *sname;
if (dev->of_node && dev->of_node->name)
name = dev->of_node->name;
@@ -144,7 +145,15 @@ static int iio_hwmon_probe(struct platform_device *pdev)
st->attr_group.attrs = st->attrs;
st->groups[0] = &st->attr_group;
- st->hwmon_dev = hwmon_device_register_with_groups(dev, name, st,
+
+ sname = devm_kstrdup(dev, name, GFP_KERNEL);
+ if (!sname) {
+ ret = -ENOMEM;
+ goto error_release_channels;
+ }
+
+ strreplace(sname, '-', '_');
+ st->hwmon_dev = hwmon_device_register_with_groups(dev, sname, st,
st->groups);
if (IS_ERR(st->hwmon_dev)) {
ret = PTR_ERR(st->hwmon_dev);
diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c
new file mode 100644
index 000000000000..8f8fe059ab48
--- /dev/null
+++ b/drivers/hwmon/ltc2990.c
@@ -0,0 +1,161 @@
+/*
+ * Driver for Linear Technology LTC2990 power monitor
+ *
+ * Copyright (C) 2014 Topic Embedded Products
+ * Author: Mike Looijmans <mike.looijmans@topic.nl>
+ *
+ * License: GPLv2
+ *
+ * This driver assumes the chip is wired as a dual current monitor, and
+ * reports the voltage drop across two series resistors. It also reports
+ * the chip's internal temperature and Vcc power supply voltage.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#define LTC2990_STATUS 0x00
+#define LTC2990_CONTROL 0x01
+#define LTC2990_TRIGGER 0x02
+#define LTC2990_TINT_MSB 0x04
+#define LTC2990_V1_MSB 0x06
+#define LTC2990_V2_MSB 0x08
+#define LTC2990_V3_MSB 0x0A
+#define LTC2990_V4_MSB 0x0C
+#define LTC2990_VCC_MSB 0x0E
+
+#define LTC2990_CONTROL_KELVIN BIT(7)
+#define LTC2990_CONTROL_SINGLE BIT(6)
+#define LTC2990_CONTROL_MEASURE_ALL (0x3 << 3)
+#define LTC2990_CONTROL_MODE_CURRENT 0x06
+#define LTC2990_CONTROL_MODE_VOLTAGE 0x07
+
+/* convert raw register value to sign-extended integer in 16-bit range */
+static int ltc2990_voltage_to_int(int raw)
+{
+ if (raw & BIT(14))
+ return -(0x4000 - (raw & 0x3FFF)) << 2;
+ else
+ return (raw & 0x3FFF) << 2;
+}
+
+/* Return the converted value from the given register in uV or mC */
+static int ltc2990_get_value(struct i2c_client *i2c, u8 reg, int *result)
+{
+ int val;
+
+ val = i2c_smbus_read_word_swapped(i2c, reg);
+ if (unlikely(val < 0))
+ return val;
+
+ switch (reg) {
+ case LTC2990_TINT_MSB:
+ /* internal temp, 0.0625 degrees/LSB, 13-bit */
+ val = (val & 0x1FFF) << 3;
+ *result = (val * 1000) >> 7;
+ break;
+ case LTC2990_V1_MSB:
+ case LTC2990_V3_MSB:
+ /* Vx-Vy, 19.42uV/LSB. Depends on mode. */
+ *result = ltc2990_voltage_to_int(val) * 1942 / (4 * 100);
+ break;
+ case LTC2990_VCC_MSB:
+ /* Vcc, 305.18μV/LSB, 2.5V offset */
+ *result = (ltc2990_voltage_to_int(val) * 30518 /
+ (4 * 100 * 1000)) + 2500;
+ break;
+ default:
+ return -EINVAL; /* won't happen, keep compiler happy */
+ }
+
+ return 0;
+}
+
+static ssize_t ltc2990_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int value;
+ int ret;
+
+ ret = ltc2990_get_value(dev_get_drvdata(dev), attr->index, &value);
+ if (unlikely(ret < 0))
+ return ret;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL,
+ LTC2990_TINT_MSB);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL,
+ LTC2990_V1_MSB);
+static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL,
+ LTC2990_V3_MSB);
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL,
+ LTC2990_VCC_MSB);
+
+static struct attribute *ltc2990_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr2_input.dev_attr.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(ltc2990);
+
+static int ltc2990_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct device *hwmon_dev;
+
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ /* Setup continuous mode, current monitor */
+ ret = i2c_smbus_write_byte_data(i2c, LTC2990_CONTROL,
+ LTC2990_CONTROL_MEASURE_ALL |
+ LTC2990_CONTROL_MODE_CURRENT);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Error: Failed to set control mode.\n");
+ return ret;
+ }
+ /* Trigger once to start continuous conversion */
+ ret = i2c_smbus_write_byte_data(i2c, LTC2990_TRIGGER, 1);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Error: Failed to start acquisition.\n");
+ return ret;
+ }
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(&i2c->dev,
+ i2c->name,
+ i2c,
+ ltc2990_groups);
+
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc2990_i2c_id[] = {
+ { "ltc2990", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ltc2990_i2c_id);
+
+static struct i2c_driver ltc2990_i2c_driver = {
+ .driver = {
+ .name = "ltc2990",
+ },
+ .probe = ltc2990_i2c_probe,
+ .id_table = ltc2990_i2c_id,
+};
+
+module_i2c_driver(ltc2990_i2c_driver);
+
+MODULE_DESCRIPTION("LTC2990 Sensor Driver");
+MODULE_AUTHOR("Topic Embedded Products");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/nsa320-hwmon.c b/drivers/hwmon/nsa320-hwmon.c
new file mode 100644
index 000000000000..0517a265741f
--- /dev/null
+++ b/drivers/hwmon/nsa320-hwmon.c
@@ -0,0 +1,215 @@
+/*
+ * drivers/hwmon/nsa320-hwmon.c
+ *
+ * ZyXEL NSA320 Media Servers
+ * hardware monitoring
+ *
+ * Copyright (C) 2016 Adam Baker <linux@baker-net.org.uk>
+ * based on a board file driver
+ * Copyright (C) 2012 Peter Schildmann <linux@schildmann.info>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+/* Tests for error return values rely upon this value being < 0x80 */
+#define MAGIC_NUMBER 0x55
+
+/*
+ * The Zyxel hwmon MCU is a Holtek HT46R065 that is factory programmed
+ * to perform temperature and fan speed monitoring. It is read by taking
+ * the active pin low. The 32 bit output word is then clocked onto the
+ * data line. The MSB of the data word is a magic nuber to indicate it
+ * has been read correctly, the next byte is the fan speed (in hundreds
+ * of RPM) and the last two bytes are the temperature (in tenths of a
+ * degree)
+ */
+
+struct nsa320_hwmon {
+ struct mutex update_lock; /* lock GPIO operations */
+ unsigned long last_updated; /* jiffies */
+ unsigned long mcu_data;
+ struct gpio_desc *act;
+ struct gpio_desc *clk;
+ struct gpio_desc *data;
+};
+
+enum nsa320_inputs {
+ NSA320_TEMP = 0,
+ NSA320_FAN = 1,
+};
+
+static const char * const nsa320_input_names[] = {
+ [NSA320_TEMP] = "System Temperature",
+ [NSA320_FAN] = "Chassis Fan",
+};
+
+/*
+ * Although this protocol looks similar to SPI the long delay
+ * between the active (aka chip select) signal and the shorter
+ * delay between clock pulses are needed for reliable operation.
+ * The delays provided are taken from the manufacturer kernel,
+ * testing suggest they probably incorporate a reasonable safety
+ * margin. (The single device tested became unreliable if the
+ * delay was reduced to 1/10th of this value.)
+ */
+static s32 nsa320_hwmon_update(struct device *dev)
+{
+ u32 mcu_data;
+ u32 mask;
+ struct nsa320_hwmon *hwmon = dev_get_drvdata(dev);
+
+ mutex_lock(&hwmon->update_lock);
+
+ mcu_data = hwmon->mcu_data;
+
+ if (time_after(jiffies, hwmon->last_updated + HZ) || mcu_data == 0) {
+ gpiod_set_value(hwmon->act, 1);
+ msleep(100);
+
+ mcu_data = 0;
+ for (mask = BIT(31); mask; mask >>= 1) {
+ gpiod_set_value(hwmon->clk, 0);
+ usleep_range(100, 200);
+ gpiod_set_value(hwmon->clk, 1);
+ usleep_range(100, 200);
+ if (gpiod_get_value(hwmon->data))
+ mcu_data |= mask;
+ }
+
+ gpiod_set_value(hwmon->act, 0);
+ dev_dbg(dev, "Read raw MCU data %08x\n", mcu_data);
+
+ if ((mcu_data >> 24) != MAGIC_NUMBER) {
+ dev_dbg(dev, "Read invalid MCU data %08x\n", mcu_data);
+ mcu_data = -EIO;
+ } else {
+ hwmon->mcu_data = mcu_data;
+ hwmon->last_updated = jiffies;
+ }
+ }
+
+ mutex_unlock(&hwmon->update_lock);
+
+ return mcu_data;
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int channel = to_sensor_dev_attr(attr)->index;
+
+ return sprintf(buf, "%s\n", nsa320_input_names[channel]);
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ s32 mcu_data = nsa320_hwmon_update(dev);
+
+ if (mcu_data < 0)
+ return mcu_data;
+
+ return sprintf(buf, "%d\n", (mcu_data & 0xffff) * 100);
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ s32 mcu_data = nsa320_hwmon_update(dev);
+
+ if (mcu_data < 0)
+ return mcu_data;
+
+ return sprintf(buf, "%d\n", ((mcu_data & 0xff0000) >> 16) * 100);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, NSA320_TEMP);
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, show_label, NULL, NSA320_FAN);
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL);
+
+static struct attribute *nsa320_attrs[] = {
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ &dev_attr_temp1_input.attr,
+ &sensor_dev_attr_fan1_label.dev_attr.attr,
+ &dev_attr_fan1_input.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(nsa320);
+
+static const struct of_device_id of_nsa320_hwmon_match[] = {
+ { .compatible = "zyxel,nsa320-mcu", },
+ { },
+};
+
+static int nsa320_hwmon_probe(struct platform_device *pdev)
+{
+ struct nsa320_hwmon *hwmon;
+ struct device *classdev;
+
+ hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
+ if (!hwmon)
+ return -ENOMEM;
+
+ /* Look up the GPIO pins to use */
+ hwmon->act = devm_gpiod_get(&pdev->dev, "act", GPIOD_OUT_LOW);
+ if (IS_ERR(hwmon->act))
+ return PTR_ERR(hwmon->act);
+
+ hwmon->clk = devm_gpiod_get(&pdev->dev, "clk", GPIOD_OUT_HIGH);
+ if (IS_ERR(hwmon->clk))
+ return PTR_ERR(hwmon->clk);
+
+ hwmon->data = devm_gpiod_get(&pdev->dev, "data", GPIOD_IN);
+ if (IS_ERR(hwmon->data))
+ return PTR_ERR(hwmon->data);
+
+ mutex_init(&hwmon->update_lock);
+
+ classdev = devm_hwmon_device_register_with_groups(&pdev->dev,
+ "nsa320", hwmon, nsa320_groups);
+
+ return PTR_ERR_OR_ZERO(classdev);
+
+}
+
+/* All allocations use devres so remove() is not needed. */
+
+static struct platform_driver nsa320_hwmon_driver = {
+ .probe = nsa320_hwmon_probe,
+ .driver = {
+ .name = "nsa320-hwmon",
+ .of_match_table = of_match_ptr(of_nsa320_hwmon_match),
+ },
+};
+
+module_platform_driver(nsa320_hwmon_driver);
+
+MODULE_DEVICE_TABLE(of, of_nsa320_hwmon_match);
+MODULE_AUTHOR("Peter Schildmann <linux@schildmann.info>");
+MODULE_AUTHOR("Adam Baker <linux@baker-net.org.uk>");
+MODULE_DESCRIPTION("NSA320 Hardware Monitoring");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:nsa320-hwmon");
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index feed30646d91..faa6e8dfbaaf 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -54,6 +54,7 @@ static const struct platform_device_id ntc_thermistor_id[] = {
{ "ncp15wl333", TYPE_NCPXXWL333 },
{ "b57330v2103", TYPE_B57330V2103},
{ "ncp03wf104", TYPE_NCPXXWF104 },
+ { "ncp15xh103", TYPE_NCPXXXH103 },
{ },
};
@@ -173,6 +174,43 @@ static const struct ntc_compensation ncpXXwf104[] = {
{ .temp_c = 125, .ohm = 2522 },
};
+static const struct ntc_compensation ncpXXxh103[] = {
+ { .temp_c = -40, .ohm = 247565 },
+ { .temp_c = -35, .ohm = 181742 },
+ { .temp_c = -30, .ohm = 135128 },
+ { .temp_c = -25, .ohm = 101678 },
+ { .temp_c = -20, .ohm = 77373 },
+ { .temp_c = -15, .ohm = 59504 },
+ { .temp_c = -10, .ohm = 46222 },
+ { .temp_c = -5, .ohm = 36244 },
+ { .temp_c = 0, .ohm = 28674 },
+ { .temp_c = 5, .ohm = 22878 },
+ { .temp_c = 10, .ohm = 18399 },
+ { .temp_c = 15, .ohm = 14910 },
+ { .temp_c = 20, .ohm = 12169 },
+ { .temp_c = 25, .ohm = 10000 },
+ { .temp_c = 30, .ohm = 8271 },
+ { .temp_c = 35, .ohm = 6883 },
+ { .temp_c = 40, .ohm = 5762 },
+ { .temp_c = 45, .ohm = 4851 },
+ { .temp_c = 50, .ohm = 4105 },
+ { .temp_c = 55, .ohm = 3492 },
+ { .temp_c = 60, .ohm = 2985 },
+ { .temp_c = 65, .ohm = 2563 },
+ { .temp_c = 70, .ohm = 2211 },
+ { .temp_c = 75, .ohm = 1915 },
+ { .temp_c = 80, .ohm = 1666 },
+ { .temp_c = 85, .ohm = 1454 },
+ { .temp_c = 90, .ohm = 1275 },
+ { .temp_c = 95, .ohm = 1121 },
+ { .temp_c = 100, .ohm = 990 },
+ { .temp_c = 105, .ohm = 876 },
+ { .temp_c = 110, .ohm = 779 },
+ { .temp_c = 115, .ohm = 694 },
+ { .temp_c = 120, .ohm = 620 },
+ { .temp_c = 125, .ohm = 556 },
+};
+
/*
* The following compensation table is from the specification of EPCOS NTC
* Thermistors Datasheet
@@ -260,6 +298,8 @@ static const struct of_device_id ntc_match[] = {
.data = &ntc_thermistor_id[5]},
{ .compatible = "murata,ncp03wf104",
.data = &ntc_thermistor_id[6] },
+ { .compatible = "murata,ncp15xh103",
+ .data = &ntc_thermistor_id[7] },
/* Usage of vendor name "ntc" is deprecated */
{ .compatible = "ntc,ncp15wb473",
@@ -609,6 +649,10 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
data->comp = ncpXXwf104;
data->n_comp = ARRAY_SIZE(ncpXXwf104);
break;
+ case TYPE_NCPXXXH103:
+ data->comp = ncpXXxh103;
+ data->n_comp = ARRAY_SIZE(ncpXXxh103);
+ break;
default:
dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
pdev_id->driver_data, pdev_id->name);
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 7e5cc3d025ef..054d3d863802 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -31,8 +31,8 @@ config SENSORS_ADM1275
default n
help
If you say yes here you get hardware monitoring support for Analog
- Devices ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 Hot-Swap
- Controller and Digital Power Monitors.
+ Devices ADM1075, ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294
+ Hot-Swap Controller and Digital Power Monitors.
This driver can also be built as a module. If so, the module will
be called adm1275.
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
index 188af4c89f40..3baa4f4a8c5e 100644
--- a/drivers/hwmon/pmbus/adm1275.c
+++ b/drivers/hwmon/pmbus/adm1275.c
@@ -24,7 +24,7 @@
#include <linux/bitops.h>
#include "pmbus.h"
-enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 };
+enum chips { adm1075, adm1275, adm1276, adm1278, adm1293, adm1294 };
#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0)
#define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5)
@@ -41,6 +41,10 @@ enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 };
#define ADM1075_IRANGE_25 BIT(3)
#define ADM1075_IRANGE_MASK (BIT(3) | BIT(4))
+#define ADM1278_TEMP1_EN BIT(3)
+#define ADM1278_VIN_EN BIT(2)
+#define ADM1278_VOUT_EN BIT(1)
+
#define ADM1293_IRANGE_25 0
#define ADM1293_IRANGE_50 BIT(6)
#define ADM1293_IRANGE_100 BIT(7)
@@ -54,6 +58,7 @@ enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 };
#define ADM1293_VAUX_EN BIT(1)
+#define ADM1278_PEAK_TEMP 0xd7
#define ADM1275_IOUT_WARN2_LIMIT 0xd7
#define ADM1275_DEVICE_CONFIG 0xd8
@@ -80,6 +85,7 @@ struct adm1275_data {
bool have_iout_min;
bool have_pin_min;
bool have_pin_max;
+ bool have_temp_max;
struct pmbus_driver_info info;
};
@@ -113,6 +119,13 @@ static const struct coefficients adm1276_coefficients[] = {
[4] = { 2115, 0, -1 }, /* power, vrange not set */
};
+static const struct coefficients adm1278_coefficients[] = {
+ [0] = { 19599, 0, -2 }, /* voltage */
+ [1] = { 800, 20475, -1 }, /* current */
+ [2] = { 6123, 0, -2 }, /* power */
+ [3] = { 42, 31880, -1 }, /* temperature */
+};
+
static const struct coefficients adm1293_coefficients[] = {
[0] = { 3333, -1, 0 }, /* voltage, vrange 1.2V */
[1] = { 5552, -5, -1 }, /* voltage, vrange 7.4V */
@@ -196,6 +209,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
return -ENXIO;
ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN);
break;
+ case PMBUS_VIRT_READ_TEMP_MAX:
+ if (!data->have_temp_max)
+ return -ENXIO;
+ ret = pmbus_read_word_data(client, 0, ADM1278_PEAK_TEMP);
+ break;
case PMBUS_VIRT_RESET_IOUT_HISTORY:
case PMBUS_VIRT_RESET_VOUT_HISTORY:
case PMBUS_VIRT_RESET_VIN_HISTORY:
@@ -204,6 +222,10 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
if (!data->have_pin_max)
return -ENXIO;
break;
+ case PMBUS_VIRT_RESET_TEMP_HISTORY:
+ if (!data->have_temp_max)
+ return -ENXIO;
+ break;
default:
ret = -ENODATA;
break;
@@ -245,6 +267,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
ret = pmbus_write_word_data(client, 0,
ADM1293_PIN_MIN, 0);
break;
+ case PMBUS_VIRT_RESET_TEMP_HISTORY:
+ ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0);
+ break;
default:
ret = -ENODATA;
break;
@@ -312,6 +337,7 @@ static const struct i2c_device_id adm1275_id[] = {
{ "adm1075", adm1075 },
{ "adm1275", adm1275 },
{ "adm1276", adm1276 },
+ { "adm1278", adm1278 },
{ "adm1293", adm1293 },
{ "adm1294", adm1294 },
{ }
@@ -329,6 +355,7 @@ static int adm1275_probe(struct i2c_client *client,
const struct i2c_device_id *mid;
const struct coefficients *coefficients;
int vindex = -1, voindex = -1, cindex = -1, pindex = -1;
+ int tindex = -1;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA
@@ -386,6 +413,7 @@ static int adm1275_probe(struct i2c_client *client,
info->format[PSC_VOLTAGE_OUT] = direct;
info->format[PSC_CURRENT_OUT] = direct;
info->format[PSC_POWER] = direct;
+ info->format[PSC_TEMPERATURE] = direct;
info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
info->read_word_data = adm1275_read_word_data;
@@ -460,6 +488,27 @@ static int adm1275_probe(struct i2c_client *client,
info->func[0] |=
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
break;
+ case adm1278:
+ data->have_vout = true;
+ data->have_pin_max = true;
+ data->have_temp_max = true;
+
+ coefficients = adm1278_coefficients;
+ vindex = 0;
+ cindex = 1;
+ pindex = 2;
+ tindex = 3;
+
+ info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT;
+ if (config & ADM1278_TEMP1_EN)
+ info->func[0] |=
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+ if (config & ADM1278_VIN_EN)
+ info->func[0] |= PMBUS_HAVE_VIN;
+ if (config & ADM1278_VOUT_EN)
+ info->func[0] |=
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+ break;
case adm1293:
case adm1294:
data->have_iout_min = true;
@@ -537,6 +586,11 @@ static int adm1275_probe(struct i2c_client *client,
info->b[PSC_POWER] = coefficients[pindex].b;
info->R[PSC_POWER] = coefficients[pindex].R;
}
+ if (tindex >= 0) {
+ info->m[PSC_TEMPERATURE] = coefficients[tindex].m;
+ info->b[PSC_TEMPERATURE] = coefficients[tindex].b;
+ info->R[PSC_TEMPERATURE] = coefficients[tindex].R;
+ }
return pmbus_do_probe(client, id, info);
}
diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress-hwmon.c
index 8ba419d343f8..8ba419d343f8 100644
--- a/drivers/hwmon/vexpress.c
+++ b/drivers/hwmon/vexpress-hwmon.c
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index c85935f3525a..db0541031c72 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -4,6 +4,7 @@
menuconfig CORESIGHT
bool "CoreSight Tracing Support"
select ARM_AMBA
+ select PERF_EVENTS
help
This framework provides a kernel interface for the CoreSight debug
and trace drivers to register themselves with. It's intended to build
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 99f8e5f6256e..cf8c6d689747 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -8,6 +8,8 @@ obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o
obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
coresight-replicator.o
-obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o
+obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o \
+ coresight-etm3x-sysfs.o \
+ coresight-etm-perf.o
obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o
obj-$(CONFIG_CORESIGHT_QCOM_REPLICATOR) += coresight-replicator-qcom.o
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index 77d0f9c1118d..acbce79934d6 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -1,5 +1,7 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
+ * Description: CoreSight Embedded Trace Buffer driver
+ *
* 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.
@@ -10,8 +12,8 @@
* GNU General Public License for more details.
*/
+#include <asm/local.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
@@ -27,6 +29,11 @@
#include <linux/coresight.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
+#include <linux/circ_buf.h>
+#include <linux/mm.h>
+#include <linux/perf_event.h>
+
+#include <asm/local.h>
#include "coresight-priv.h"
@@ -64,6 +71,26 @@
#define ETB_FRAME_SIZE_WORDS 4
/**
+ * struct cs_buffer - keep track of a recording session' specifics
+ * @cur: index of the current buffer
+ * @nr_pages: max number of pages granted to us
+ * @offset: offset within the current buffer
+ * @data_size: how much we collected in this run
+ * @lost: other than zero if we had a HW buffer wrap around
+ * @snapshot: is this run in snapshot mode
+ * @data_pages: a handle the ring buffer
+ */
+struct cs_buffers {
+ unsigned int cur;
+ unsigned int nr_pages;
+ unsigned long offset;
+ local_t data_size;
+ local_t lost;
+ bool snapshot;
+ void **data_pages;
+};
+
+/**
* struct etb_drvdata - specifics associated to an ETB component
* @base: memory mapped base address for this component.
* @dev: the device entity associated to this component.
@@ -71,10 +98,10 @@
* @csdev: component vitals needed by the framework.
* @miscdev: specifics to handle "/dev/xyz.etb" entry.
* @spinlock: only one at a time pls.
- * @in_use: synchronise user space access to etb buffer.
+ * @reading: synchronise user space access to etb buffer.
+ * @mode: this ETB is being used.
* @buf: area of memory where ETB buffer content gets sent.
* @buffer_depth: size of @buf.
- * @enable: this ETB is being used.
* @trigger_cntr: amount of words to store after a trigger.
*/
struct etb_drvdata {
@@ -84,10 +111,10 @@ struct etb_drvdata {
struct coresight_device *csdev;
struct miscdevice miscdev;
spinlock_t spinlock;
- atomic_t in_use;
+ local_t reading;
+ local_t mode;
u8 *buf;
u32 buffer_depth;
- bool enable;
u32 trigger_cntr;
};
@@ -132,18 +159,31 @@ static void etb_enable_hw(struct etb_drvdata *drvdata)
CS_LOCK(drvdata->base);
}
-static int etb_enable(struct coresight_device *csdev)
+static int etb_enable(struct coresight_device *csdev, u32 mode)
{
- struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ u32 val;
unsigned long flags;
+ struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- pm_runtime_get_sync(drvdata->dev);
+ val = local_cmpxchg(&drvdata->mode,
+ CS_MODE_DISABLED, mode);
+ /*
+ * When accessing from Perf, a HW buffer can be handled
+ * by a single trace entity. In sysFS mode many tracers
+ * can be logging to the same HW buffer.
+ */
+ if (val == CS_MODE_PERF)
+ return -EBUSY;
+
+ /* Nothing to do, the tracer is already enabled. */
+ if (val == CS_MODE_SYSFS)
+ goto out;
spin_lock_irqsave(&drvdata->spinlock, flags);
etb_enable_hw(drvdata);
- drvdata->enable = true;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+out:
dev_info(drvdata->dev, "ETB enabled\n");
return 0;
}
@@ -244,17 +284,225 @@ static void etb_disable(struct coresight_device *csdev)
spin_lock_irqsave(&drvdata->spinlock, flags);
etb_disable_hw(drvdata);
etb_dump_hw(drvdata);
- drvdata->enable = false;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
+ local_set(&drvdata->mode, CS_MODE_DISABLED);
dev_info(drvdata->dev, "ETB disabled\n");
}
+static void *etb_alloc_buffer(struct coresight_device *csdev, int cpu,
+ void **pages, int nr_pages, bool overwrite)
+{
+ int node;
+ struct cs_buffers *buf;
+
+ if (cpu == -1)
+ cpu = smp_processor_id();
+ node = cpu_to_node(cpu);
+
+ buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
+ if (!buf)
+ return NULL;
+
+ buf->snapshot = overwrite;
+ buf->nr_pages = nr_pages;
+ buf->data_pages = pages;
+
+ return buf;
+}
+
+static void etb_free_buffer(void *config)
+{
+ struct cs_buffers *buf = config;
+
+ kfree(buf);
+}
+
+static int etb_set_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *sink_config)
+{
+ int ret = 0;
+ unsigned long head;
+ struct cs_buffers *buf = sink_config;
+
+ /* wrap head around to the amount of space we have */
+ head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1);
+
+ /* find the page to write to */
+ buf->cur = head / PAGE_SIZE;
+
+ /* and offset within that page */
+ buf->offset = head % PAGE_SIZE;
+
+ local_set(&buf->data_size, 0);
+
+ return ret;
+}
+
+static unsigned long etb_reset_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *sink_config, bool *lost)
+{
+ unsigned long size = 0;
+ struct cs_buffers *buf = sink_config;
+
+ if (buf) {
+ /*
+ * In snapshot mode ->data_size holds the new address of the
+ * ring buffer's head. The size itself is the whole address
+ * range since we want the latest information.
+ */
+ if (buf->snapshot)
+ handle->head = local_xchg(&buf->data_size,
+ buf->nr_pages << PAGE_SHIFT);
+
+ /*
+ * Tell the tracer PMU how much we got in this run and if
+ * something went wrong along the way. Nobody else can use
+ * this cs_buffers instance until we are done. As such
+ * resetting parameters here and squaring off with the ring
+ * buffer API in the tracer PMU is fine.
+ */
+ *lost = !!local_xchg(&buf->lost, 0);
+ size = local_xchg(&buf->data_size, 0);
+ }
+
+ return size;
+}
+
+static void etb_update_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *sink_config)
+{
+ int i, cur;
+ u8 *buf_ptr;
+ u32 read_ptr, write_ptr, capacity;
+ u32 status, read_data, to_read;
+ unsigned long offset;
+ struct cs_buffers *buf = sink_config;
+ struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (!buf)
+ return;
+
+ capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS;
+
+ CS_UNLOCK(drvdata->base);
+ etb_disable_hw(drvdata);
+
+ /* unit is in words, not bytes */
+ read_ptr = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER);
+ write_ptr = readl_relaxed(drvdata->base + ETB_RAM_WRITE_POINTER);
+
+ /*
+ * Entries should be aligned to the frame size. If they are not
+ * go back to the last alignement point to give decoding tools a
+ * chance to fix things.
+ */
+ if (write_ptr % ETB_FRAME_SIZE_WORDS) {
+ dev_err(drvdata->dev,
+ "write_ptr: %lu not aligned to formatter frame size\n",
+ (unsigned long)write_ptr);
+
+ write_ptr &= ~(ETB_FRAME_SIZE_WORDS - 1);
+ local_inc(&buf->lost);
+ }
+
+ /*
+ * Get a hold of the status register and see if a wrap around
+ * has occurred. If so adjust things accordingly. Otherwise
+ * start at the beginning and go until the write pointer has
+ * been reached.
+ */
+ status = readl_relaxed(drvdata->base + ETB_STATUS_REG);
+ if (status & ETB_STATUS_RAM_FULL) {
+ local_inc(&buf->lost);
+ to_read = capacity;
+ read_ptr = write_ptr;
+ } else {
+ to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->buffer_depth);
+ to_read *= ETB_FRAME_SIZE_WORDS;
+ }
+
+ /*
+ * Make sure we don't overwrite data that hasn't been consumed yet.
+ * It is entirely possible that the HW buffer has more data than the
+ * ring buffer can currently handle. If so adjust the start address
+ * to take only the last traces.
+ *
+ * In snapshot mode we are looking to get the latest traces only and as
+ * such, we don't care about not overwriting data that hasn't been
+ * processed by user space.
+ */
+ if (!buf->snapshot && to_read > handle->size) {
+ u32 mask = ~(ETB_FRAME_SIZE_WORDS - 1);
+
+ /* The new read pointer must be frame size aligned */
+ to_read -= handle->size & mask;
+ /*
+ * Move the RAM read pointer up, keeping in mind that
+ * everything is in frame size units.
+ */
+ read_ptr = (write_ptr + drvdata->buffer_depth) -
+ to_read / ETB_FRAME_SIZE_WORDS;
+ /* Wrap around if need be*/
+ read_ptr &= ~(drvdata->buffer_depth - 1);
+ /* let the decoder know we've skipped ahead */
+ local_inc(&buf->lost);
+ }
+
+ /* finally tell HW where we want to start reading from */
+ writel_relaxed(read_ptr, drvdata->base + ETB_RAM_READ_POINTER);
+
+ cur = buf->cur;
+ offset = buf->offset;
+ for (i = 0; i < to_read; i += 4) {
+ buf_ptr = buf->data_pages[cur] + offset;
+ read_data = readl_relaxed(drvdata->base +
+ ETB_RAM_READ_DATA_REG);
+ *buf_ptr++ = read_data >> 0;
+ *buf_ptr++ = read_data >> 8;
+ *buf_ptr++ = read_data >> 16;
+ *buf_ptr++ = read_data >> 24;
+
+ offset += 4;
+ if (offset >= PAGE_SIZE) {
+ offset = 0;
+ cur++;
+ /* wrap around at the end of the buffer */
+ cur &= buf->nr_pages - 1;
+ }
+ }
+
+ /* reset ETB buffer for next run */
+ writel_relaxed(0x0, drvdata->base + ETB_RAM_READ_POINTER);
+ writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER);
+
+ /*
+ * In snapshot mode all we have to do is communicate to
+ * perf_aux_output_end() the address of the current head. In full
+ * trace mode the same function expects a size to move rb->aux_head
+ * forward.
+ */
+ if (buf->snapshot)
+ local_set(&buf->data_size, (cur * PAGE_SIZE) + offset);
+ else
+ local_add(to_read, &buf->data_size);
+
+ etb_enable_hw(drvdata);
+ CS_LOCK(drvdata->base);
+}
+
static const struct coresight_ops_sink etb_sink_ops = {
.enable = etb_enable,
.disable = etb_disable,
+ .alloc_buffer = etb_alloc_buffer,
+ .free_buffer = etb_free_buffer,
+ .set_buffer = etb_set_buffer,
+ .reset_buffer = etb_reset_buffer,
+ .update_buffer = etb_update_buffer,
};
static const struct coresight_ops etb_cs_ops = {
@@ -266,7 +514,7 @@ static void etb_dump(struct etb_drvdata *drvdata)
unsigned long flags;
spin_lock_irqsave(&drvdata->spinlock, flags);
- if (drvdata->enable) {
+ if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
etb_disable_hw(drvdata);
etb_dump_hw(drvdata);
etb_enable_hw(drvdata);
@@ -281,7 +529,7 @@ static int etb_open(struct inode *inode, struct file *file)
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
- if (atomic_cmpxchg(&drvdata->in_use, 0, 1))
+ if (local_cmpxchg(&drvdata->reading, 0, 1))
return -EBUSY;
dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
@@ -317,7 +565,7 @@ static int etb_release(struct inode *inode, struct file *file)
{
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
- atomic_set(&drvdata->in_use, 0);
+ local_set(&drvdata->reading, 0);
dev_dbg(drvdata->dev, "%s: released\n", __func__);
return 0;
@@ -489,15 +737,6 @@ err_misc_register:
return ret;
}
-static int etb_remove(struct amba_device *adev)
-{
- struct etb_drvdata *drvdata = amba_get_drvdata(adev);
-
- misc_deregister(&drvdata->miscdev);
- coresight_unregister(drvdata->csdev);
- return 0;
-}
-
#ifdef CONFIG_PM
static int etb_runtime_suspend(struct device *dev)
{
@@ -537,14 +776,10 @@ static struct amba_driver etb_driver = {
.name = "coresight-etb10",
.owner = THIS_MODULE,
.pm = &etb_dev_pm_ops,
+ .suppress_bind_attrs = true,
},
.probe = etb_probe,
- .remove = etb_remove,
.id_table = etb_ids,
};
-
-module_amba_driver(etb_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");
+builtin_amba_driver(etb_driver);
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
new file mode 100644
index 000000000000..755125f7917f
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * 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 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/coresight.h>
+#include <linux/coresight-pmu.h>
+#include <linux/cpumask.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include "coresight-priv.h"
+
+static struct pmu etm_pmu;
+static bool etm_perf_up;
+
+/**
+ * struct etm_event_data - Coresight specifics associated to an event
+ * @work: Handle to free allocated memory outside IRQ context.
+ * @mask: Hold the CPU(s) this event was set for.
+ * @snk_config: The sink configuration.
+ * @path: An array of path, each slot for one CPU.
+ */
+struct etm_event_data {
+ struct work_struct work;
+ cpumask_t mask;
+ void *snk_config;
+ struct list_head **path;
+};
+
+static DEFINE_PER_CPU(struct perf_output_handle, ctx_handle);
+static DEFINE_PER_CPU(struct coresight_device *, csdev_src);
+
+/* ETMv3.5/PTM's ETMCR is 'config' */
+PMU_FORMAT_ATTR(cycacc, "config:" __stringify(ETM_OPT_CYCACC));
+PMU_FORMAT_ATTR(timestamp, "config:" __stringify(ETM_OPT_TS));
+
+static struct attribute *etm_config_formats_attr[] = {
+ &format_attr_cycacc.attr,
+ &format_attr_timestamp.attr,
+ NULL,
+};
+
+static struct attribute_group etm_pmu_format_group = {
+ .name = "format",
+ .attrs = etm_config_formats_attr,
+};
+
+static const struct attribute_group *etm_pmu_attr_groups[] = {
+ &etm_pmu_format_group,
+ NULL,
+};
+
+static void etm_event_read(struct perf_event *event) {}
+
+static int etm_event_init(struct perf_event *event)
+{
+ if (event->attr.type != etm_pmu.type)
+ return -ENOENT;
+
+ return 0;
+}
+
+static void free_event_data(struct work_struct *work)
+{
+ int cpu;
+ cpumask_t *mask;
+ struct etm_event_data *event_data;
+ struct coresight_device *sink;
+
+ event_data = container_of(work, struct etm_event_data, work);
+ mask = &event_data->mask;
+ /*
+ * First deal with the sink configuration. See comment in
+ * etm_setup_aux() about why we take the first available path.
+ */
+ if (event_data->snk_config) {
+ cpu = cpumask_first(mask);
+ sink = coresight_get_sink(event_data->path[cpu]);
+ if (sink_ops(sink)->free_buffer)
+ sink_ops(sink)->free_buffer(event_data->snk_config);
+ }
+
+ for_each_cpu(cpu, mask) {
+ if (event_data->path[cpu])
+ coresight_release_path(event_data->path[cpu]);
+ }
+
+ kfree(event_data->path);
+ kfree(event_data);
+}
+
+static void *alloc_event_data(int cpu)
+{
+ int size;
+ cpumask_t *mask;
+ struct etm_event_data *event_data;
+
+ /* First get memory for the session's data */
+ event_data = kzalloc(sizeof(struct etm_event_data), GFP_KERNEL);
+ if (!event_data)
+ return NULL;
+
+ /* Make sure nothing disappears under us */
+ get_online_cpus();
+ size = num_online_cpus();
+
+ mask = &event_data->mask;
+ if (cpu != -1)
+ cpumask_set_cpu(cpu, mask);
+ else
+ cpumask_copy(mask, cpu_online_mask);
+ put_online_cpus();
+
+ /*
+ * Each CPU has a single path between source and destination. As such
+ * allocate an array using CPU numbers as indexes. That way a path
+ * for any CPU can easily be accessed at any given time. We proceed
+ * the same way for sessions involving a single CPU. The cost of
+ * unused memory when dealing with single CPU trace scenarios is small
+ * compared to the cost of searching through an optimized array.
+ */
+ event_data->path = kcalloc(size,
+ sizeof(struct list_head *), GFP_KERNEL);
+ if (!event_data->path) {
+ kfree(event_data);
+ return NULL;
+ }
+
+ return event_data;
+}
+
+static void etm_free_aux(void *data)
+{
+ struct etm_event_data *event_data = data;
+
+ schedule_work(&event_data->work);
+}
+
+static void *etm_setup_aux(int event_cpu, void **pages,
+ int nr_pages, bool overwrite)
+{
+ int cpu;
+ cpumask_t *mask;
+ struct coresight_device *sink;
+ struct etm_event_data *event_data = NULL;
+
+ event_data = alloc_event_data(event_cpu);
+ if (!event_data)
+ return NULL;
+
+ INIT_WORK(&event_data->work, free_event_data);
+
+ mask = &event_data->mask;
+
+ /* Setup the path for each CPU in a trace session */
+ for_each_cpu(cpu, mask) {
+ struct coresight_device *csdev;
+
+ csdev = per_cpu(csdev_src, cpu);
+ if (!csdev)
+ goto err;
+
+ /*
+ * Building a path doesn't enable it, it simply builds a
+ * list of devices from source to sink that can be
+ * referenced later when the path is actually needed.
+ */
+ event_data->path[cpu] = coresight_build_path(csdev);
+ if (!event_data->path[cpu])
+ goto err;
+ }
+
+ /*
+ * In theory nothing prevent tracers in a trace session from being
+ * associated with different sinks, nor having a sink per tracer. But
+ * until we have HW with this kind of topology and a way to convey
+ * sink assignement from the perf cmd line we need to assume tracers
+ * in a trace session are using the same sink. Therefore pick the sink
+ * found at the end of the first available path.
+ */
+ cpu = cpumask_first(mask);
+ /* Grab the sink at the end of the path */
+ sink = coresight_get_sink(event_data->path[cpu]);
+ if (!sink)
+ goto err;
+
+ if (!sink_ops(sink)->alloc_buffer)
+ goto err;
+
+ /* Get the AUX specific data from the sink buffer */
+ event_data->snk_config =
+ sink_ops(sink)->alloc_buffer(sink, cpu, pages,
+ nr_pages, overwrite);
+ if (!event_data->snk_config)
+ goto err;
+
+out:
+ return event_data;
+
+err:
+ etm_free_aux(event_data);
+ event_data = NULL;
+ goto out;
+}
+
+static void etm_event_start(struct perf_event *event, int flags)
+{
+ int cpu = smp_processor_id();
+ struct etm_event_data *event_data;
+ struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
+ struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
+
+ if (!csdev)
+ goto fail;
+
+ /*
+ * Deal with the ring buffer API and get a handle on the
+ * session's information.
+ */
+ event_data = perf_aux_output_begin(handle, event);
+ if (!event_data)
+ goto fail;
+
+ /* We need a sink, no need to continue without one */
+ sink = coresight_get_sink(event_data->path[cpu]);
+ if (WARN_ON_ONCE(!sink || !sink_ops(sink)->set_buffer))
+ goto fail_end_stop;
+
+ /* Configure the sink */
+ if (sink_ops(sink)->set_buffer(sink, handle,
+ event_data->snk_config))
+ goto fail_end_stop;
+
+ /* Nothing will happen without a path */
+ if (coresight_enable_path(event_data->path[cpu], CS_MODE_PERF))
+ goto fail_end_stop;
+
+ /* Tell the perf core the event is alive */
+ event->hw.state = 0;
+
+ /* Finally enable the tracer */
+ if (source_ops(csdev)->enable(csdev, &event->attr, CS_MODE_PERF))
+ goto fail_end_stop;
+
+out:
+ return;
+
+fail_end_stop:
+ perf_aux_output_end(handle, 0, true);
+fail:
+ event->hw.state = PERF_HES_STOPPED;
+ goto out;
+}
+
+static void etm_event_stop(struct perf_event *event, int mode)
+{
+ bool lost;
+ int cpu = smp_processor_id();
+ unsigned long size;
+ struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
+ struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
+ struct etm_event_data *event_data = perf_get_aux(handle);
+
+ if (event->hw.state == PERF_HES_STOPPED)
+ return;
+
+ if (!csdev)
+ return;
+
+ sink = coresight_get_sink(event_data->path[cpu]);
+ if (!sink)
+ return;
+
+ /* stop tracer */
+ source_ops(csdev)->disable(csdev);
+
+ /* tell the core */
+ event->hw.state = PERF_HES_STOPPED;
+
+ if (mode & PERF_EF_UPDATE) {
+ if (WARN_ON_ONCE(handle->event != event))
+ return;
+
+ /* update trace information */
+ if (!sink_ops(sink)->update_buffer)
+ return;
+
+ sink_ops(sink)->update_buffer(sink, handle,
+ event_data->snk_config);
+
+ if (!sink_ops(sink)->reset_buffer)
+ return;
+
+ size = sink_ops(sink)->reset_buffer(sink, handle,
+ event_data->snk_config,
+ &lost);
+
+ perf_aux_output_end(handle, size, lost);
+ }
+
+ /* Disabling the path make its elements available to other sessions */
+ coresight_disable_path(event_data->path[cpu]);
+}
+
+static int etm_event_add(struct perf_event *event, int mode)
+{
+ int ret = 0;
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (mode & PERF_EF_START) {
+ etm_event_start(event, 0);
+ if (hwc->state & PERF_HES_STOPPED)
+ ret = -EINVAL;
+ } else {
+ hwc->state = PERF_HES_STOPPED;
+ }
+
+ return ret;
+}
+
+static void etm_event_del(struct perf_event *event, int mode)
+{
+ etm_event_stop(event, PERF_EF_UPDATE);
+}
+
+int etm_perf_symlink(struct coresight_device *csdev, bool link)
+{
+ char entry[sizeof("cpu9999999")];
+ int ret = 0, cpu = source_ops(csdev)->cpu_id(csdev);
+ struct device *pmu_dev = etm_pmu.dev;
+ struct device *cs_dev = &csdev->dev;
+
+ sprintf(entry, "cpu%d", cpu);
+
+ if (!etm_perf_up)
+ return -EPROBE_DEFER;
+
+ if (link) {
+ ret = sysfs_create_link(&pmu_dev->kobj, &cs_dev->kobj, entry);
+ if (ret)
+ return ret;
+ per_cpu(csdev_src, cpu) = csdev;
+ } else {
+ sysfs_remove_link(&pmu_dev->kobj, entry);
+ per_cpu(csdev_src, cpu) = NULL;
+ }
+
+ return 0;
+}
+
+static int __init etm_perf_init(void)
+{
+ int ret;
+
+ etm_pmu.capabilities = PERF_PMU_CAP_EXCLUSIVE;
+
+ etm_pmu.attr_groups = etm_pmu_attr_groups;
+ etm_pmu.task_ctx_nr = perf_sw_context;
+ etm_pmu.read = etm_event_read;
+ etm_pmu.event_init = etm_event_init;
+ etm_pmu.setup_aux = etm_setup_aux;
+ etm_pmu.free_aux = etm_free_aux;
+ etm_pmu.start = etm_event_start;
+ etm_pmu.stop = etm_event_stop;
+ etm_pmu.add = etm_event_add;
+ etm_pmu.del = etm_event_del;
+
+ ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1);
+ if (ret == 0)
+ etm_perf_up = true;
+
+ return ret;
+}
+device_initcall(etm_perf_init);
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h
new file mode 100644
index 000000000000..87f5a134eb6f
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * 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 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CORESIGHT_ETM_PERF_H
+#define _CORESIGHT_ETM_PERF_H
+
+struct coresight_device;
+
+#ifdef CONFIG_CORESIGHT
+int etm_perf_symlink(struct coresight_device *csdev, bool link);
+
+#else
+static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
+{ return -EINVAL; }
+
+#endif /* CONFIG_CORESIGHT */
+
+#endif
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index b4481eb29304..51597cb2c08a 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -13,6 +13,7 @@
#ifndef _CORESIGHT_CORESIGHT_ETM_H
#define _CORESIGHT_CORESIGHT_ETM_H
+#include <asm/local.h>
#include <linux/spinlock.h>
#include "coresight-priv.h"
@@ -109,7 +110,10 @@
#define ETM_MODE_STALL BIT(2)
#define ETM_MODE_TIMESTAMP BIT(3)
#define ETM_MODE_CTXID BIT(4)
-#define ETM_MODE_ALL 0x1f
+#define ETM_MODE_ALL (ETM_MODE_EXCLUDE | ETM_MODE_CYCACC | \
+ ETM_MODE_STALL | ETM_MODE_TIMESTAMP | \
+ ETM_MODE_CTXID | ETM_MODE_EXCL_KERN | \
+ ETM_MODE_EXCL_USER)
#define ETM_SQR_MASK 0x3
#define ETM_TRACEID_MASK 0x3f
@@ -136,35 +140,16 @@
#define ETM_DEFAULT_EVENT_VAL (ETM_HARD_WIRE_RES_A | \
ETM_ADD_COMP_0 | \
ETM_EVENT_NOT_A)
+
/**
- * struct etm_drvdata - specifics associated to an ETM component
- * @base: memory mapped base address for this component.
- * @dev: the device entity associated to this component.
- * @atclk: optional clock for the core parts of the ETM.
- * @csdev: component vitals needed by the framework.
- * @spinlock: only one at a time pls.
- * @cpu: the cpu this component is affined to.
- * @port_size: port size as reported by ETMCR bit 4-6 and 21.
- * @arch: ETM/PTM version number.
- * @use_cpu14: true if management registers need to be accessed via CP14.
- * @enable: is this ETM/PTM currently tracing.
- * @sticky_enable: true if ETM base configuration has been done.
- * @boot_enable:true if we should start tracing at boot time.
- * @os_unlock: true if access to management registers is allowed.
- * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
- * @nr_cntr: Number of counters as found in ETMCCR bit 13-15.
- * @nr_ext_inp: Number of external input as found in ETMCCR bit 17-19.
- * @nr_ext_out: Number of external output as found in ETMCCR bit 20-22.
- * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
- * @etmccr: value of register ETMCCR.
- * @etmccer: value of register ETMCCER.
- * @traceid: value of the current ID for this component.
+ * struct etm_config - configuration information related to an ETM
* @mode: controls various modes supported by this ETM/PTM.
* @ctrl: used in conjunction with @mode.
* @trigger_event: setting for register ETMTRIGGER.
* @startstop_ctrl: setting for register ETMTSSCR.
* @enable_event: setting for register ETMTEEVR.
* @enable_ctrl1: setting for register ETMTECR1.
+ * @enable_ctrl2: setting for register ETMTECR2.
* @fifofull_level: setting for register ETMFFLR.
* @addr_idx: index for the address comparator selection.
* @addr_val: value for address comparator register.
@@ -189,36 +174,16 @@
* @ctxid_mask: mask applicable to all the context IDs.
* @sync_freq: Synchronisation frequency.
* @timestamp_event: Defines an event that requests the insertion
- of a timestamp into the trace stream.
+ * of a timestamp into the trace stream.
*/
-struct etm_drvdata {
- void __iomem *base;
- struct device *dev;
- struct clk *atclk;
- struct coresight_device *csdev;
- spinlock_t spinlock;
- int cpu;
- int port_size;
- u8 arch;
- bool use_cp14;
- bool enable;
- bool sticky_enable;
- bool boot_enable;
- bool os_unlock;
- u8 nr_addr_cmp;
- u8 nr_cntr;
- u8 nr_ext_inp;
- u8 nr_ext_out;
- u8 nr_ctxid_cmp;
- u32 etmccr;
- u32 etmccer;
- u32 traceid;
+struct etm_config {
u32 mode;
u32 ctrl;
u32 trigger_event;
u32 startstop_ctrl;
u32 enable_event;
u32 enable_ctrl1;
+ u32 enable_ctrl2;
u32 fifofull_level;
u8 addr_idx;
u32 addr_val[ETM_MAX_ADDR_CMP];
@@ -244,6 +209,56 @@ struct etm_drvdata {
u32 timestamp_event;
};
+/**
+ * struct etm_drvdata - specifics associated to an ETM component
+ * @base: memory mapped base address for this component.
+ * @dev: the device entity associated to this component.
+ * @atclk: optional clock for the core parts of the ETM.
+ * @csdev: component vitals needed by the framework.
+ * @spinlock: only one at a time pls.
+ * @cpu: the cpu this component is affined to.
+ * @port_size: port size as reported by ETMCR bit 4-6 and 21.
+ * @arch: ETM/PTM version number.
+ * @use_cpu14: true if management registers need to be accessed via CP14.
+ * @mode: this tracer's mode, i.e sysFS, Perf or disabled.
+ * @sticky_enable: true if ETM base configuration has been done.
+ * @boot_enable:true if we should start tracing at boot time.
+ * @os_unlock: true if access to management registers is allowed.
+ * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
+ * @nr_cntr: Number of counters as found in ETMCCR bit 13-15.
+ * @nr_ext_inp: Number of external input as found in ETMCCR bit 17-19.
+ * @nr_ext_out: Number of external output as found in ETMCCR bit 20-22.
+ * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
+ * @etmccr: value of register ETMCCR.
+ * @etmccer: value of register ETMCCER.
+ * @traceid: value of the current ID for this component.
+ * @config: structure holding configuration parameters.
+ */
+struct etm_drvdata {
+ void __iomem *base;
+ struct device *dev;
+ struct clk *atclk;
+ struct coresight_device *csdev;
+ spinlock_t spinlock;
+ int cpu;
+ int port_size;
+ u8 arch;
+ bool use_cp14;
+ local_t mode;
+ bool sticky_enable;
+ bool boot_enable;
+ bool os_unlock;
+ u8 nr_addr_cmp;
+ u8 nr_cntr;
+ u8 nr_ext_inp;
+ u8 nr_ext_out;
+ u8 nr_ctxid_cmp;
+ u32 etmccr;
+ u32 etmccer;
+ u32 traceid;
+ struct etm_config config;
+};
+
enum etm_addr_type {
ETM_ADDR_TYPE_NONE,
ETM_ADDR_TYPE_SINGLE,
@@ -251,4 +266,39 @@ enum etm_addr_type {
ETM_ADDR_TYPE_START,
ETM_ADDR_TYPE_STOP,
};
+
+static inline void etm_writel(struct etm_drvdata *drvdata,
+ u32 val, u32 off)
+{
+ if (drvdata->use_cp14) {
+ if (etm_writel_cp14(off, val)) {
+ dev_err(drvdata->dev,
+ "invalid CP14 access to ETM reg: %#x", off);
+ }
+ } else {
+ writel_relaxed(val, drvdata->base + off);
+ }
+}
+
+static inline unsigned int etm_readl(struct etm_drvdata *drvdata, u32 off)
+{
+ u32 val;
+
+ if (drvdata->use_cp14) {
+ if (etm_readl_cp14(off, &val)) {
+ dev_err(drvdata->dev,
+ "invalid CP14 access to ETM reg: %#x", off);
+ }
+ } else {
+ val = readl_relaxed(drvdata->base + off);
+ }
+
+ return val;
+}
+
+extern const struct attribute_group *coresight_etm_groups[];
+int etm_get_trace_id(struct etm_drvdata *drvdata);
+void etm_set_default(struct etm_config *config);
+void etm_config_trace_mode(struct etm_config *config);
+struct etm_config *get_etm_config(struct etm_drvdata *drvdata);
#endif
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
new file mode 100644
index 000000000000..cbb4046c1070
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -0,0 +1,1272 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * 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 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/sysfs.h>
+#include "coresight-etm.h"
+
+static ssize_t nr_addr_cmp_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ val = drvdata->nr_addr_cmp;
+ return sprintf(buf, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nr_addr_cmp);
+
+static ssize_t nr_cntr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ val = drvdata->nr_cntr;
+ return sprintf(buf, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nr_cntr);
+
+static ssize_t nr_ctxid_cmp_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ val = drvdata->nr_ctxid_cmp;
+ return sprintf(buf, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nr_ctxid_cmp);
+
+static ssize_t etmsr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags, val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ pm_runtime_get_sync(drvdata->dev);
+ spin_lock_irqsave(&drvdata->spinlock, flags);
+ CS_UNLOCK(drvdata->base);
+
+ val = etm_readl(drvdata, ETMSR);
+
+ CS_LOCK(drvdata->base);
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ pm_runtime_put(drvdata->dev);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(etmsr);
+
+static ssize_t reset_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int i, ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ if (val) {
+ spin_lock(&drvdata->spinlock);
+ memset(config, 0, sizeof(struct etm_config));
+ config->mode = ETM_MODE_EXCLUDE;
+ config->trigger_event = ETM_DEFAULT_EVENT_VAL;
+ for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+ config->addr_type[i] = ETM_ADDR_TYPE_NONE;
+ }
+
+ etm_set_default(config);
+ spin_unlock(&drvdata->spinlock);
+ }
+
+ return size;
+}
+static DEVICE_ATTR_WO(reset);
+
+static ssize_t mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->mode;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ config->mode = val & ETM_MODE_ALL;
+
+ if (config->mode & ETM_MODE_EXCLUDE)
+ config->enable_ctrl1 |= ETMTECR1_INC_EXC;
+ else
+ config->enable_ctrl1 &= ~ETMTECR1_INC_EXC;
+
+ if (config->mode & ETM_MODE_CYCACC)
+ config->ctrl |= ETMCR_CYC_ACC;
+ else
+ config->ctrl &= ~ETMCR_CYC_ACC;
+
+ if (config->mode & ETM_MODE_STALL) {
+ if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
+ dev_warn(drvdata->dev, "stall mode not supported\n");
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ config->ctrl |= ETMCR_STALL_MODE;
+ } else
+ config->ctrl &= ~ETMCR_STALL_MODE;
+
+ if (config->mode & ETM_MODE_TIMESTAMP) {
+ if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
+ dev_warn(drvdata->dev, "timestamp not supported\n");
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ config->ctrl |= ETMCR_TIMESTAMP_EN;
+ } else
+ config->ctrl &= ~ETMCR_TIMESTAMP_EN;
+
+ if (config->mode & ETM_MODE_CTXID)
+ config->ctrl |= ETMCR_CTXID_SIZE;
+ else
+ config->ctrl &= ~ETMCR_CTXID_SIZE;
+
+ if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER))
+ etm_config_trace_mode(config);
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+
+err_unlock:
+ spin_unlock(&drvdata->spinlock);
+ return ret;
+}
+static DEVICE_ATTR_RW(mode);
+
+static ssize_t trigger_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->trigger_event;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t trigger_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->trigger_event = val & ETM_EVENT_MASK;
+
+ return size;
+}
+static DEVICE_ATTR_RW(trigger_event);
+
+static ssize_t enable_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->enable_event;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t enable_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->enable_event = val & ETM_EVENT_MASK;
+
+ return size;
+}
+static DEVICE_ATTR_RW(enable_event);
+
+static ssize_t fifofull_level_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->fifofull_level;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t fifofull_level_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->fifofull_level = val;
+
+ return size;
+}
+static DEVICE_ATTR_RW(fifofull_level);
+
+static ssize_t addr_idx_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->addr_idx;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t addr_idx_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ if (val >= drvdata->nr_addr_cmp)
+ return -EINVAL;
+
+ /*
+ * Use spinlock to ensure index doesn't change while it gets
+ * dereferenced multiple times within a spinlock block elsewhere.
+ */
+ spin_lock(&drvdata->spinlock);
+ config->addr_idx = val;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(addr_idx);
+
+static ssize_t addr_single_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 idx;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->addr_idx;
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EINVAL;
+ }
+
+ val = config->addr_val[idx];
+ spin_unlock(&drvdata->spinlock);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t addr_single_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ u8 idx;
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->addr_idx;
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EINVAL;
+ }
+
+ config->addr_val[idx] = val;
+ config->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(addr_single);
+
+static ssize_t addr_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 idx;
+ unsigned long val1, val2;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->addr_idx;
+ if (idx % 2 != 0) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+ config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+ (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+ config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+
+ val1 = config->addr_val[idx];
+ val2 = config->addr_val[idx + 1];
+ spin_unlock(&drvdata->spinlock);
+
+ return sprintf(buf, "%#lx %#lx\n", val1, val2);
+}
+
+static ssize_t addr_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ u8 idx;
+ unsigned long val1, val2;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+ return -EINVAL;
+ /* Lower address comparator cannot have a higher address value */
+ if (val1 > val2)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->addr_idx;
+ if (idx % 2 != 0) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+ config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+ (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+ config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+
+ config->addr_val[idx] = val1;
+ config->addr_type[idx] = ETM_ADDR_TYPE_RANGE;
+ config->addr_val[idx + 1] = val2;
+ config->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
+ config->enable_ctrl1 |= (1 << (idx/2));
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(addr_range);
+
+static ssize_t addr_start_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 idx;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->addr_idx;
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+
+ val = config->addr_val[idx];
+ spin_unlock(&drvdata->spinlock);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t addr_start_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ u8 idx;
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->addr_idx;
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+
+ config->addr_val[idx] = val;
+ config->addr_type[idx] = ETM_ADDR_TYPE_START;
+ config->startstop_ctrl |= (1 << idx);
+ config->enable_ctrl1 |= BIT(25);
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(addr_start);
+
+static ssize_t addr_stop_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 idx;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->addr_idx;
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+
+ val = config->addr_val[idx];
+ spin_unlock(&drvdata->spinlock);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t addr_stop_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ u8 idx;
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->addr_idx;
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+
+ config->addr_val[idx] = val;
+ config->addr_type[idx] = ETM_ADDR_TYPE_STOP;
+ config->startstop_ctrl |= (1 << (idx + 16));
+ config->enable_ctrl1 |= ETMTECR1_START_STOP;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(addr_stop);
+
+static ssize_t addr_acctype_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ val = config->addr_acctype[config->addr_idx];
+ spin_unlock(&drvdata->spinlock);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t addr_acctype_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ config->addr_acctype[config->addr_idx] = val;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(addr_acctype);
+
+static ssize_t cntr_idx_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->cntr_idx;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t cntr_idx_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ if (val >= drvdata->nr_cntr)
+ return -EINVAL;
+ /*
+ * Use spinlock to ensure index doesn't change while it gets
+ * dereferenced multiple times within a spinlock block elsewhere.
+ */
+ spin_lock(&drvdata->spinlock);
+ config->cntr_idx = val;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(cntr_idx);
+
+static ssize_t cntr_rld_val_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ val = config->cntr_rld_val[config->cntr_idx];
+ spin_unlock(&drvdata->spinlock);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t cntr_rld_val_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ config->cntr_rld_val[config->cntr_idx] = val;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(cntr_rld_val);
+
+static ssize_t cntr_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ val = config->cntr_event[config->cntr_idx];
+ spin_unlock(&drvdata->spinlock);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t cntr_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ config->cntr_event[config->cntr_idx] = val & ETM_EVENT_MASK;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(cntr_event);
+
+static ssize_t cntr_rld_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ val = config->cntr_rld_event[config->cntr_idx];
+ spin_unlock(&drvdata->spinlock);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t cntr_rld_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ config->cntr_rld_event[config->cntr_idx] = val & ETM_EVENT_MASK;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(cntr_rld_event);
+
+static ssize_t cntr_val_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, ret = 0;
+ u32 val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ if (!local_read(&drvdata->mode)) {
+ spin_lock(&drvdata->spinlock);
+ for (i = 0; i < drvdata->nr_cntr; i++)
+ ret += sprintf(buf, "counter %d: %x\n",
+ i, config->cntr_val[i]);
+ spin_unlock(&drvdata->spinlock);
+ return ret;
+ }
+
+ for (i = 0; i < drvdata->nr_cntr; i++) {
+ val = etm_readl(drvdata, ETMCNTVRn(i));
+ ret += sprintf(buf, "counter %d: %x\n", i, val);
+ }
+
+ return ret;
+}
+
+static ssize_t cntr_val_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ config->cntr_val[config->cntr_idx] = val;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(cntr_val);
+
+static ssize_t seq_12_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->seq_12_event;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t seq_12_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->seq_12_event = val & ETM_EVENT_MASK;
+ return size;
+}
+static DEVICE_ATTR_RW(seq_12_event);
+
+static ssize_t seq_21_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->seq_21_event;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t seq_21_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->seq_21_event = val & ETM_EVENT_MASK;
+ return size;
+}
+static DEVICE_ATTR_RW(seq_21_event);
+
+static ssize_t seq_23_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->seq_23_event;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t seq_23_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->seq_23_event = val & ETM_EVENT_MASK;
+ return size;
+}
+static DEVICE_ATTR_RW(seq_23_event);
+
+static ssize_t seq_31_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->seq_31_event;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t seq_31_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->seq_31_event = val & ETM_EVENT_MASK;
+ return size;
+}
+static DEVICE_ATTR_RW(seq_31_event);
+
+static ssize_t seq_32_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->seq_32_event;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t seq_32_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->seq_32_event = val & ETM_EVENT_MASK;
+ return size;
+}
+static DEVICE_ATTR_RW(seq_32_event);
+
+static ssize_t seq_13_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->seq_13_event;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t seq_13_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->seq_13_event = val & ETM_EVENT_MASK;
+ return size;
+}
+static DEVICE_ATTR_RW(seq_13_event);
+
+static ssize_t seq_curr_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val, flags;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ if (!local_read(&drvdata->mode)) {
+ val = config->seq_curr_state;
+ goto out;
+ }
+
+ pm_runtime_get_sync(drvdata->dev);
+ spin_lock_irqsave(&drvdata->spinlock, flags);
+
+ CS_UNLOCK(drvdata->base);
+ val = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
+ CS_LOCK(drvdata->base);
+
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ pm_runtime_put(drvdata->dev);
+out:
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t seq_curr_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ if (val > ETM_SEQ_STATE_MAX_VAL)
+ return -EINVAL;
+
+ config->seq_curr_state = val;
+
+ return size;
+}
+static DEVICE_ATTR_RW(seq_curr_state);
+
+static ssize_t ctxid_idx_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->ctxid_idx;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t ctxid_idx_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ if (val >= drvdata->nr_ctxid_cmp)
+ return -EINVAL;
+
+ /*
+ * Use spinlock to ensure index doesn't change while it gets
+ * dereferenced multiple times within a spinlock block elsewhere.
+ */
+ spin_lock(&drvdata->spinlock);
+ config->ctxid_idx = val;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(ctxid_idx);
+
+static ssize_t ctxid_pid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ val = config->ctxid_vpid[config->ctxid_idx];
+ spin_unlock(&drvdata->spinlock);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t ctxid_pid_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long vpid, pid;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &vpid);
+ if (ret)
+ return ret;
+
+ pid = coresight_vpid_to_pid(vpid);
+
+ spin_lock(&drvdata->spinlock);
+ config->ctxid_pid[config->ctxid_idx] = pid;
+ config->ctxid_vpid[config->ctxid_idx] = vpid;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(ctxid_pid);
+
+static ssize_t ctxid_mask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->ctxid_mask;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t ctxid_mask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->ctxid_mask = val;
+ return size;
+}
+static DEVICE_ATTR_RW(ctxid_mask);
+
+static ssize_t sync_freq_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->sync_freq;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t sync_freq_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->sync_freq = val & ETM_SYNC_MASK;
+ return size;
+}
+static DEVICE_ATTR_RW(sync_freq);
+
+static ssize_t timestamp_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ val = config->timestamp_event;
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t timestamp_event_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etm_config *config = &drvdata->config;
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ config->timestamp_event = val & ETM_EVENT_MASK;
+ return size;
+}
+static DEVICE_ATTR_RW(timestamp_event);
+
+static ssize_t cpu_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ val = drvdata->cpu;
+ return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+
+}
+static DEVICE_ATTR_RO(cpu);
+
+static ssize_t traceid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ val = etm_get_trace_id(drvdata);
+
+ return sprintf(buf, "%#lx\n", val);
+}
+
+static ssize_t traceid_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ ret = kstrtoul(buf, 16, &val);
+ if (ret)
+ return ret;
+
+ drvdata->traceid = val & ETM_TRACEID_MASK;
+ return size;
+}
+static DEVICE_ATTR_RW(traceid);
+
+static struct attribute *coresight_etm_attrs[] = {
+ &dev_attr_nr_addr_cmp.attr,
+ &dev_attr_nr_cntr.attr,
+ &dev_attr_nr_ctxid_cmp.attr,
+ &dev_attr_etmsr.attr,
+ &dev_attr_reset.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_trigger_event.attr,
+ &dev_attr_enable_event.attr,
+ &dev_attr_fifofull_level.attr,
+ &dev_attr_addr_idx.attr,
+ &dev_attr_addr_single.attr,
+ &dev_attr_addr_range.attr,
+ &dev_attr_addr_start.attr,
+ &dev_attr_addr_stop.attr,
+ &dev_attr_addr_acctype.attr,
+ &dev_attr_cntr_idx.attr,
+ &dev_attr_cntr_rld_val.attr,
+ &dev_attr_cntr_event.attr,
+ &dev_attr_cntr_rld_event.attr,
+ &dev_attr_cntr_val.attr,
+ &dev_attr_seq_12_event.attr,
+ &dev_attr_seq_21_event.attr,
+ &dev_attr_seq_23_event.attr,
+ &dev_attr_seq_31_event.attr,
+ &dev_attr_seq_32_event.attr,
+ &dev_attr_seq_13_event.attr,
+ &dev_attr_seq_curr_state.attr,
+ &dev_attr_ctxid_idx.attr,
+ &dev_attr_ctxid_pid.attr,
+ &dev_attr_ctxid_mask.attr,
+ &dev_attr_sync_freq.attr,
+ &dev_attr_timestamp_event.attr,
+ &dev_attr_traceid.attr,
+ &dev_attr_cpu.attr,
+ NULL,
+};
+
+#define coresight_simple_func(name, offset) \
+static ssize_t name##_show(struct device *_dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct etm_drvdata *drvdata = dev_get_drvdata(_dev->parent); \
+ return scnprintf(buf, PAGE_SIZE, "0x%x\n", \
+ readl_relaxed(drvdata->base + offset)); \
+} \
+DEVICE_ATTR_RO(name)
+
+coresight_simple_func(etmccr, ETMCCR);
+coresight_simple_func(etmccer, ETMCCER);
+coresight_simple_func(etmscr, ETMSCR);
+coresight_simple_func(etmidr, ETMIDR);
+coresight_simple_func(etmcr, ETMCR);
+coresight_simple_func(etmtraceidr, ETMTRACEIDR);
+coresight_simple_func(etmteevr, ETMTEEVR);
+coresight_simple_func(etmtssvr, ETMTSSCR);
+coresight_simple_func(etmtecr1, ETMTECR1);
+coresight_simple_func(etmtecr2, ETMTECR2);
+
+static struct attribute *coresight_etm_mgmt_attrs[] = {
+ &dev_attr_etmccr.attr,
+ &dev_attr_etmccer.attr,
+ &dev_attr_etmscr.attr,
+ &dev_attr_etmidr.attr,
+ &dev_attr_etmcr.attr,
+ &dev_attr_etmtraceidr.attr,
+ &dev_attr_etmteevr.attr,
+ &dev_attr_etmtssvr.attr,
+ &dev_attr_etmtecr1.attr,
+ &dev_attr_etmtecr2.attr,
+ NULL,
+};
+
+static const struct attribute_group coresight_etm_group = {
+ .attrs = coresight_etm_attrs,
+};
+
+static const struct attribute_group coresight_etm_mgmt_group = {
+ .attrs = coresight_etm_mgmt_attrs,
+ .name = "mgmt",
+};
+
+const struct attribute_group *coresight_etm_groups[] = {
+ &coresight_etm_group,
+ &coresight_etm_mgmt_group,
+ NULL,
+};
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
index d630b7ece735..d83ab82672e4 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -1,5 +1,7 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
+ * Description: CoreSight Program Flow Trace driver
+ *
* 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.
@@ -11,7 +13,7 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
@@ -27,14 +29,21 @@
#include <linux/cpu.h>
#include <linux/of.h>
#include <linux/coresight.h>
+#include <linux/coresight-pmu.h>
#include <linux/amba/bus.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
+#include <linux/perf_event.h>
#include <asm/sections.h>
#include "coresight-etm.h"
+#include "coresight-etm-perf.h"
+/*
+ * Not really modular but using module_param is the easiest way to
+ * remain consistent with existing use cases for now.
+ */
static int boot_enable;
module_param_named(boot_enable, boot_enable, int, S_IRUGO);
@@ -42,45 +51,16 @@ module_param_named(boot_enable, boot_enable, int, S_IRUGO);
static int etm_count;
static struct etm_drvdata *etmdrvdata[NR_CPUS];
-static inline void etm_writel(struct etm_drvdata *drvdata,
- u32 val, u32 off)
-{
- if (drvdata->use_cp14) {
- if (etm_writel_cp14(off, val)) {
- dev_err(drvdata->dev,
- "invalid CP14 access to ETM reg: %#x", off);
- }
- } else {
- writel_relaxed(val, drvdata->base + off);
- }
-}
-
-static inline unsigned int etm_readl(struct etm_drvdata *drvdata, u32 off)
-{
- u32 val;
-
- if (drvdata->use_cp14) {
- if (etm_readl_cp14(off, &val)) {
- dev_err(drvdata->dev,
- "invalid CP14 access to ETM reg: %#x", off);
- }
- } else {
- val = readl_relaxed(drvdata->base + off);
- }
-
- return val;
-}
-
/*
* Memory mapped writes to clear os lock are not supported on some processors
* and OS lock must be unlocked before any memory mapped access on such
* processors, otherwise memory mapped reads/writes will be invalid.
*/
-static void etm_os_unlock(void *info)
+static void etm_os_unlock(struct etm_drvdata *drvdata)
{
- struct etm_drvdata *drvdata = (struct etm_drvdata *)info;
/* Writing any value to ETMOSLAR unlocks the trace registers */
etm_writel(drvdata, 0x0, ETMOSLAR);
+ drvdata->os_unlock = true;
isb();
}
@@ -215,36 +195,156 @@ static void etm_clr_prog(struct etm_drvdata *drvdata)
}
}
-static void etm_set_default(struct etm_drvdata *drvdata)
+void etm_set_default(struct etm_config *config)
{
int i;
- drvdata->trigger_event = ETM_DEFAULT_EVENT_VAL;
- drvdata->enable_event = ETM_HARD_WIRE_RES_A;
+ if (WARN_ON_ONCE(!config))
+ return;
- drvdata->seq_12_event = ETM_DEFAULT_EVENT_VAL;
- drvdata->seq_21_event = ETM_DEFAULT_EVENT_VAL;
- drvdata->seq_23_event = ETM_DEFAULT_EVENT_VAL;
- drvdata->seq_31_event = ETM_DEFAULT_EVENT_VAL;
- drvdata->seq_32_event = ETM_DEFAULT_EVENT_VAL;
- drvdata->seq_13_event = ETM_DEFAULT_EVENT_VAL;
- drvdata->timestamp_event = ETM_DEFAULT_EVENT_VAL;
+ /*
+ * Taken verbatim from the TRM:
+ *
+ * To trace all memory:
+ * set bit [24] in register 0x009, the ETMTECR1, to 1
+ * set all other bits in register 0x009, the ETMTECR1, to 0
+ * set all bits in register 0x007, the ETMTECR2, to 0
+ * set register 0x008, the ETMTEEVR, to 0x6F (TRUE).
+ */
+ config->enable_ctrl1 = BIT(24);
+ config->enable_ctrl2 = 0x0;
+ config->enable_event = ETM_HARD_WIRE_RES_A;
- for (i = 0; i < drvdata->nr_cntr; i++) {
- drvdata->cntr_rld_val[i] = 0x0;
- drvdata->cntr_event[i] = ETM_DEFAULT_EVENT_VAL;
- drvdata->cntr_rld_event[i] = ETM_DEFAULT_EVENT_VAL;
- drvdata->cntr_val[i] = 0x0;
+ config->trigger_event = ETM_DEFAULT_EVENT_VAL;
+ config->enable_event = ETM_HARD_WIRE_RES_A;
+
+ config->seq_12_event = ETM_DEFAULT_EVENT_VAL;
+ config->seq_21_event = ETM_DEFAULT_EVENT_VAL;
+ config->seq_23_event = ETM_DEFAULT_EVENT_VAL;
+ config->seq_31_event = ETM_DEFAULT_EVENT_VAL;
+ config->seq_32_event = ETM_DEFAULT_EVENT_VAL;
+ config->seq_13_event = ETM_DEFAULT_EVENT_VAL;
+ config->timestamp_event = ETM_DEFAULT_EVENT_VAL;
+
+ for (i = 0; i < ETM_MAX_CNTR; i++) {
+ config->cntr_rld_val[i] = 0x0;
+ config->cntr_event[i] = ETM_DEFAULT_EVENT_VAL;
+ config->cntr_rld_event[i] = ETM_DEFAULT_EVENT_VAL;
+ config->cntr_val[i] = 0x0;
}
- drvdata->seq_curr_state = 0x0;
- drvdata->ctxid_idx = 0x0;
- for (i = 0; i < drvdata->nr_ctxid_cmp; i++) {
- drvdata->ctxid_pid[i] = 0x0;
- drvdata->ctxid_vpid[i] = 0x0;
+ config->seq_curr_state = 0x0;
+ config->ctxid_idx = 0x0;
+ for (i = 0; i < ETM_MAX_CTXID_CMP; i++) {
+ config->ctxid_pid[i] = 0x0;
+ config->ctxid_vpid[i] = 0x0;
}
- drvdata->ctxid_mask = 0x0;
+ config->ctxid_mask = 0x0;
+}
+
+void etm_config_trace_mode(struct etm_config *config)
+{
+ u32 flags, mode;
+
+ mode = config->mode;
+
+ mode &= (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER);
+
+ /* excluding kernel AND user space doesn't make sense */
+ if (mode == (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER))
+ return;
+
+ /* nothing to do if neither flags are set */
+ if (!(mode & ETM_MODE_EXCL_KERN) && !(mode & ETM_MODE_EXCL_USER))
+ return;
+
+ flags = (1 << 0 | /* instruction execute */
+ 3 << 3 | /* ARM instruction */
+ 0 << 5 | /* No data value comparison */
+ 0 << 7 | /* No exact mach */
+ 0 << 8); /* Ignore context ID */
+
+ /* No need to worry about single address comparators. */
+ config->enable_ctrl2 = 0x0;
+
+ /* Bit 0 is address range comparator 1 */
+ config->enable_ctrl1 = ETMTECR1_ADDR_COMP_1;
+
+ /*
+ * On ETMv3.5:
+ * ETMACTRn[13,11] == Non-secure state comparison control
+ * ETMACTRn[12,10] == Secure state comparison control
+ *
+ * b00 == Match in all modes in this state
+ * b01 == Do not match in any more in this state
+ * b10 == Match in all modes excepts user mode in this state
+ * b11 == Match only in user mode in this state
+ */
+
+ /* Tracing in secure mode is not supported at this time */
+ flags |= (0 << 12 | 1 << 10);
+
+ if (mode & ETM_MODE_EXCL_USER) {
+ /* exclude user, match all modes except user mode */
+ flags |= (1 << 13 | 0 << 11);
+ } else {
+ /* exclude kernel, match only in user mode */
+ flags |= (1 << 13 | 1 << 11);
+ }
+
+ /*
+ * The ETMEEVR register is already set to "hard wire A". As such
+ * all there is to do is setup an address comparator that spans
+ * the entire address range and configure the state and mode bits.
+ */
+ config->addr_val[0] = (u32) 0x0;
+ config->addr_val[1] = (u32) ~0x0;
+ config->addr_acctype[0] = flags;
+ config->addr_acctype[1] = flags;
+ config->addr_type[0] = ETM_ADDR_TYPE_RANGE;
+ config->addr_type[1] = ETM_ADDR_TYPE_RANGE;
+}
+
+#define ETM3X_SUPPORTED_OPTIONS (ETMCR_CYC_ACC | ETMCR_TIMESTAMP_EN)
+
+static int etm_parse_event_config(struct etm_drvdata *drvdata,
+ struct perf_event_attr *attr)
+{
+ struct etm_config *config = &drvdata->config;
+
+ if (!attr)
+ return -EINVAL;
+
+ /* Clear configuration from previous run */
+ memset(config, 0, sizeof(struct etm_config));
+
+ if (attr->exclude_kernel)
+ config->mode = ETM_MODE_EXCL_KERN;
+
+ if (attr->exclude_user)
+ config->mode = ETM_MODE_EXCL_USER;
+
+ /* Always start from the default config */
+ etm_set_default(config);
+
+ /*
+ * By default the tracers are configured to trace the whole address
+ * range. Narrow the field only if requested by user space.
+ */
+ if (config->mode)
+ etm_config_trace_mode(config);
+
+ /*
+ * At this time only cycle accurate and timestamp options are
+ * available.
+ */
+ if (attr->config & ~ETM3X_SUPPORTED_OPTIONS)
+ return -EINVAL;
+
+ config->ctrl = attr->config;
+
+ return 0;
}
static void etm_enable_hw(void *info)
@@ -252,6 +352,7 @@ static void etm_enable_hw(void *info)
int i;
u32 etmcr;
struct etm_drvdata *drvdata = info;
+ struct etm_config *config = &drvdata->config;
CS_UNLOCK(drvdata->base);
@@ -265,65 +366,74 @@ static void etm_enable_hw(void *info)
etm_set_prog(drvdata);
etmcr = etm_readl(drvdata, ETMCR);
- etmcr &= (ETMCR_PWD_DWN | ETMCR_ETM_PRG);
+ /* Clear setting from a previous run if need be */
+ etmcr &= ~ETM3X_SUPPORTED_OPTIONS;
etmcr |= drvdata->port_size;
- etm_writel(drvdata, drvdata->ctrl | etmcr, ETMCR);
- etm_writel(drvdata, drvdata->trigger_event, ETMTRIGGER);
- etm_writel(drvdata, drvdata->startstop_ctrl, ETMTSSCR);
- etm_writel(drvdata, drvdata->enable_event, ETMTEEVR);
- etm_writel(drvdata, drvdata->enable_ctrl1, ETMTECR1);
- etm_writel(drvdata, drvdata->fifofull_level, ETMFFLR);
+ etmcr |= ETMCR_ETM_EN;
+ etm_writel(drvdata, config->ctrl | etmcr, ETMCR);
+ etm_writel(drvdata, config->trigger_event, ETMTRIGGER);
+ etm_writel(drvdata, config->startstop_ctrl, ETMTSSCR);
+ etm_writel(drvdata, config->enable_event, ETMTEEVR);
+ etm_writel(drvdata, config->enable_ctrl1, ETMTECR1);
+ etm_writel(drvdata, config->fifofull_level, ETMFFLR);
for (i = 0; i < drvdata->nr_addr_cmp; i++) {
- etm_writel(drvdata, drvdata->addr_val[i], ETMACVRn(i));
- etm_writel(drvdata, drvdata->addr_acctype[i], ETMACTRn(i));
+ etm_writel(drvdata, config->addr_val[i], ETMACVRn(i));
+ etm_writel(drvdata, config->addr_acctype[i], ETMACTRn(i));
}
for (i = 0; i < drvdata->nr_cntr; i++) {
- etm_writel(drvdata, drvdata->cntr_rld_val[i], ETMCNTRLDVRn(i));
- etm_writel(drvdata, drvdata->cntr_event[i], ETMCNTENRn(i));
- etm_writel(drvdata, drvdata->cntr_rld_event[i],
+ etm_writel(drvdata, config->cntr_rld_val[i], ETMCNTRLDVRn(i));
+ etm_writel(drvdata, config->cntr_event[i], ETMCNTENRn(i));
+ etm_writel(drvdata, config->cntr_rld_event[i],
ETMCNTRLDEVRn(i));
- etm_writel(drvdata, drvdata->cntr_val[i], ETMCNTVRn(i));
- }
- etm_writel(drvdata, drvdata->seq_12_event, ETMSQ12EVR);
- etm_writel(drvdata, drvdata->seq_21_event, ETMSQ21EVR);
- etm_writel(drvdata, drvdata->seq_23_event, ETMSQ23EVR);
- etm_writel(drvdata, drvdata->seq_31_event, ETMSQ31EVR);
- etm_writel(drvdata, drvdata->seq_32_event, ETMSQ32EVR);
- etm_writel(drvdata, drvdata->seq_13_event, ETMSQ13EVR);
- etm_writel(drvdata, drvdata->seq_curr_state, ETMSQR);
+ etm_writel(drvdata, config->cntr_val[i], ETMCNTVRn(i));
+ }
+ etm_writel(drvdata, config->seq_12_event, ETMSQ12EVR);
+ etm_writel(drvdata, config->seq_21_event, ETMSQ21EVR);
+ etm_writel(drvdata, config->seq_23_event, ETMSQ23EVR);
+ etm_writel(drvdata, config->seq_31_event, ETMSQ31EVR);
+ etm_writel(drvdata, config->seq_32_event, ETMSQ32EVR);
+ etm_writel(drvdata, config->seq_13_event, ETMSQ13EVR);
+ etm_writel(drvdata, config->seq_curr_state, ETMSQR);
for (i = 0; i < drvdata->nr_ext_out; i++)
etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i));
for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
- etm_writel(drvdata, drvdata->ctxid_pid[i], ETMCIDCVRn(i));
- etm_writel(drvdata, drvdata->ctxid_mask, ETMCIDCMR);
- etm_writel(drvdata, drvdata->sync_freq, ETMSYNCFR);
+ etm_writel(drvdata, config->ctxid_pid[i], ETMCIDCVRn(i));
+ etm_writel(drvdata, config->ctxid_mask, ETMCIDCMR);
+ etm_writel(drvdata, config->sync_freq, ETMSYNCFR);
/* No external input selected */
etm_writel(drvdata, 0x0, ETMEXTINSELR);
- etm_writel(drvdata, drvdata->timestamp_event, ETMTSEVR);
+ etm_writel(drvdata, config->timestamp_event, ETMTSEVR);
/* No auxiliary control selected */
etm_writel(drvdata, 0x0, ETMAUXCR);
etm_writel(drvdata, drvdata->traceid, ETMTRACEIDR);
/* No VMID comparator value selected */
etm_writel(drvdata, 0x0, ETMVMIDCVR);
- /* Ensures trace output is enabled from this ETM */
- etm_writel(drvdata, drvdata->ctrl | ETMCR_ETM_EN | etmcr, ETMCR);
-
etm_clr_prog(drvdata);
CS_LOCK(drvdata->base);
dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
}
-static int etm_trace_id(struct coresight_device *csdev)
+static int etm_cpu_id(struct coresight_device *csdev)
{
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ return drvdata->cpu;
+}
+
+int etm_get_trace_id(struct etm_drvdata *drvdata)
+{
unsigned long flags;
int trace_id = -1;
- if (!drvdata->enable)
+ if (!drvdata)
+ goto out;
+
+ if (!local_read(&drvdata->mode))
return drvdata->traceid;
- pm_runtime_get_sync(csdev->dev.parent);
+
+ pm_runtime_get_sync(drvdata->dev);
spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -332,17 +442,41 @@ static int etm_trace_id(struct coresight_device *csdev)
CS_LOCK(drvdata->base);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(csdev->dev.parent);
+ pm_runtime_put(drvdata->dev);
+out:
return trace_id;
+
+}
+
+static int etm_trace_id(struct coresight_device *csdev)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ return etm_get_trace_id(drvdata);
}
-static int etm_enable(struct coresight_device *csdev)
+static int etm_enable_perf(struct coresight_device *csdev,
+ struct perf_event_attr *attr)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
+ return -EINVAL;
+
+ /* Configure the tracer based on the session's specifics */
+ etm_parse_event_config(drvdata, attr);
+ /* And enable it */
+ etm_enable_hw(drvdata);
+
+ return 0;
+}
+
+static int etm_enable_sysfs(struct coresight_device *csdev)
{
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret;
- pm_runtime_get_sync(csdev->dev.parent);
spin_lock(&drvdata->spinlock);
/*
@@ -357,16 +491,45 @@ static int etm_enable(struct coresight_device *csdev)
goto err;
}
- drvdata->enable = true;
drvdata->sticky_enable = true;
-
spin_unlock(&drvdata->spinlock);
dev_info(drvdata->dev, "ETM tracing enabled\n");
return 0;
+
err:
spin_unlock(&drvdata->spinlock);
- pm_runtime_put(csdev->dev.parent);
+ return ret;
+}
+
+static int etm_enable(struct coresight_device *csdev,
+ struct perf_event_attr *attr, u32 mode)
+{
+ int ret;
+ u32 val;
+ struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
+
+ /* Someone is already using the tracer */
+ if (val)
+ return -EBUSY;
+
+ switch (mode) {
+ case CS_MODE_SYSFS:
+ ret = etm_enable_sysfs(csdev);
+ break;
+ case CS_MODE_PERF:
+ ret = etm_enable_perf(csdev, attr);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ /* The tracer didn't start */
+ if (ret)
+ local_set(&drvdata->mode, CS_MODE_DISABLED);
+
return ret;
}
@@ -374,18 +537,16 @@ static void etm_disable_hw(void *info)
{
int i;
struct etm_drvdata *drvdata = info;
+ struct etm_config *config = &drvdata->config;
CS_UNLOCK(drvdata->base);
etm_set_prog(drvdata);
- /* Program trace enable to low by using always false event */
- etm_writel(drvdata, ETM_HARD_WIRE_RES_A | ETM_EVENT_NOT_A, ETMTEEVR);
-
/* Read back sequencer and counters for post trace analysis */
- drvdata->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
+ config->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
for (i = 0; i < drvdata->nr_cntr; i++)
- drvdata->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));
+ config->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));
etm_set_pwrdwn(drvdata);
CS_LOCK(drvdata->base);
@@ -393,7 +554,28 @@ static void etm_disable_hw(void *info)
dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
}
-static void etm_disable(struct coresight_device *csdev)
+static void etm_disable_perf(struct coresight_device *csdev)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
+ return;
+
+ CS_UNLOCK(drvdata->base);
+
+ /* Setting the prog bit disables tracing immediately */
+ etm_set_prog(drvdata);
+
+ /*
+ * There is no way to know when the tracer will be used again so
+ * power down the tracer.
+ */
+ etm_set_pwrdwn(drvdata);
+
+ CS_LOCK(drvdata->base);
+}
+
+static void etm_disable_sysfs(struct coresight_device *csdev)
{
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -411,1235 +593,52 @@ static void etm_disable(struct coresight_device *csdev)
* ensures that register writes occur when cpu is powered.
*/
smp_call_function_single(drvdata->cpu, etm_disable_hw, drvdata, 1);
- drvdata->enable = false;
spin_unlock(&drvdata->spinlock);
put_online_cpus();
- pm_runtime_put(csdev->dev.parent);
dev_info(drvdata->dev, "ETM tracing disabled\n");
}
-static const struct coresight_ops_source etm_source_ops = {
- .trace_id = etm_trace_id,
- .enable = etm_enable,
- .disable = etm_disable,
-};
-
-static const struct coresight_ops etm_cs_ops = {
- .source_ops = &etm_source_ops,
-};
-
-static ssize_t nr_addr_cmp_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->nr_addr_cmp;
- return sprintf(buf, "%#lx\n", val);
-}
-static DEVICE_ATTR_RO(nr_addr_cmp);
-
-static ssize_t nr_cntr_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{ unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->nr_cntr;
- return sprintf(buf, "%#lx\n", val);
-}
-static DEVICE_ATTR_RO(nr_cntr);
-
-static ssize_t nr_ctxid_cmp_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->nr_ctxid_cmp;
- return sprintf(buf, "%#lx\n", val);
-}
-static DEVICE_ATTR_RO(nr_ctxid_cmp);
-
-static ssize_t etmsr_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long flags, val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- pm_runtime_get_sync(drvdata->dev);
- spin_lock_irqsave(&drvdata->spinlock, flags);
- CS_UNLOCK(drvdata->base);
-
- val = etm_readl(drvdata, ETMSR);
-
- CS_LOCK(drvdata->base);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
-
- return sprintf(buf, "%#lx\n", val);
-}
-static DEVICE_ATTR_RO(etmsr);
-
-static ssize_t reset_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int i, ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- if (val) {
- spin_lock(&drvdata->spinlock);
- drvdata->mode = ETM_MODE_EXCLUDE;
- drvdata->ctrl = 0x0;
- drvdata->trigger_event = ETM_DEFAULT_EVENT_VAL;
- drvdata->startstop_ctrl = 0x0;
- drvdata->addr_idx = 0x0;
- for (i = 0; i < drvdata->nr_addr_cmp; i++) {
- drvdata->addr_val[i] = 0x0;
- drvdata->addr_acctype[i] = 0x0;
- drvdata->addr_type[i] = ETM_ADDR_TYPE_NONE;
- }
- drvdata->cntr_idx = 0x0;
-
- etm_set_default(drvdata);
- spin_unlock(&drvdata->spinlock);
- }
-
- return size;
-}
-static DEVICE_ATTR_WO(reset);
-
-static ssize_t mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->mode;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- spin_lock(&drvdata->spinlock);
- drvdata->mode = val & ETM_MODE_ALL;
-
- if (drvdata->mode & ETM_MODE_EXCLUDE)
- drvdata->enable_ctrl1 |= ETMTECR1_INC_EXC;
- else
- drvdata->enable_ctrl1 &= ~ETMTECR1_INC_EXC;
-
- if (drvdata->mode & ETM_MODE_CYCACC)
- drvdata->ctrl |= ETMCR_CYC_ACC;
- else
- drvdata->ctrl &= ~ETMCR_CYC_ACC;
-
- if (drvdata->mode & ETM_MODE_STALL) {
- if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
- dev_warn(drvdata->dev, "stall mode not supported\n");
- ret = -EINVAL;
- goto err_unlock;
- }
- drvdata->ctrl |= ETMCR_STALL_MODE;
- } else
- drvdata->ctrl &= ~ETMCR_STALL_MODE;
-
- if (drvdata->mode & ETM_MODE_TIMESTAMP) {
- if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
- dev_warn(drvdata->dev, "timestamp not supported\n");
- ret = -EINVAL;
- goto err_unlock;
- }
- drvdata->ctrl |= ETMCR_TIMESTAMP_EN;
- } else
- drvdata->ctrl &= ~ETMCR_TIMESTAMP_EN;
-
- if (drvdata->mode & ETM_MODE_CTXID)
- drvdata->ctrl |= ETMCR_CTXID_SIZE;
- else
- drvdata->ctrl &= ~ETMCR_CTXID_SIZE;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-
-err_unlock:
- spin_unlock(&drvdata->spinlock);
- return ret;
-}
-static DEVICE_ATTR_RW(mode);
-
-static ssize_t trigger_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->trigger_event;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t trigger_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->trigger_event = val & ETM_EVENT_MASK;
-
- return size;
-}
-static DEVICE_ATTR_RW(trigger_event);
-
-static ssize_t enable_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->enable_event;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t enable_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->enable_event = val & ETM_EVENT_MASK;
-
- return size;
-}
-static DEVICE_ATTR_RW(enable_event);
-
-static ssize_t fifofull_level_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->fifofull_level;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t fifofull_level_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->fifofull_level = val;
-
- return size;
-}
-static DEVICE_ATTR_RW(fifofull_level);
-
-static ssize_t addr_idx_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->addr_idx;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t addr_idx_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- if (val >= drvdata->nr_addr_cmp)
- return -EINVAL;
-
- /*
- * Use spinlock to ensure index doesn't change while it gets
- * dereferenced multiple times within a spinlock block elsewhere.
- */
- spin_lock(&drvdata->spinlock);
- drvdata->addr_idx = val;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(addr_idx);
-
-static ssize_t addr_single_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- u8 idx;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
- spin_unlock(&drvdata->spinlock);
- return -EINVAL;
- }
-
- val = drvdata->addr_val[idx];
- spin_unlock(&drvdata->spinlock);
-
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t addr_single_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- u8 idx;
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
- spin_unlock(&drvdata->spinlock);
- return -EINVAL;
- }
-
- drvdata->addr_val[idx] = val;
- drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(addr_single);
-
-static ssize_t addr_range_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- u8 idx;
- unsigned long val1, val2;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- if (idx % 2 != 0) {
- spin_unlock(&drvdata->spinlock);
- return -EPERM;
- }
- if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
- drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
- (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
- drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
- spin_unlock(&drvdata->spinlock);
- return -EPERM;
- }
-
- val1 = drvdata->addr_val[idx];
- val2 = drvdata->addr_val[idx + 1];
- spin_unlock(&drvdata->spinlock);
-
- return sprintf(buf, "%#lx %#lx\n", val1, val2);
-}
-
-static ssize_t addr_range_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- u8 idx;
- unsigned long val1, val2;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
- return -EINVAL;
- /* Lower address comparator cannot have a higher address value */
- if (val1 > val2)
- return -EINVAL;
-
- spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- if (idx % 2 != 0) {
- spin_unlock(&drvdata->spinlock);
- return -EPERM;
- }
- if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
- drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
- (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
- drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
- spin_unlock(&drvdata->spinlock);
- return -EPERM;
- }
-
- drvdata->addr_val[idx] = val1;
- drvdata->addr_type[idx] = ETM_ADDR_TYPE_RANGE;
- drvdata->addr_val[idx + 1] = val2;
- drvdata->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
- drvdata->enable_ctrl1 |= (1 << (idx/2));
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(addr_range);
-
-static ssize_t addr_start_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- u8 idx;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
- spin_unlock(&drvdata->spinlock);
- return -EPERM;
- }
-
- val = drvdata->addr_val[idx];
- spin_unlock(&drvdata->spinlock);
-
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t addr_start_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- u8 idx;
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
- spin_unlock(&drvdata->spinlock);
- return -EPERM;
- }
-
- drvdata->addr_val[idx] = val;
- drvdata->addr_type[idx] = ETM_ADDR_TYPE_START;
- drvdata->startstop_ctrl |= (1 << idx);
- drvdata->enable_ctrl1 |= BIT(25);
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(addr_start);
-
-static ssize_t addr_stop_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- u8 idx;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
- spin_unlock(&drvdata->spinlock);
- return -EPERM;
- }
-
- val = drvdata->addr_val[idx];
- spin_unlock(&drvdata->spinlock);
-
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t addr_stop_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- u8 idx;
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
- spin_unlock(&drvdata->spinlock);
- return -EPERM;
- }
-
- drvdata->addr_val[idx] = val;
- drvdata->addr_type[idx] = ETM_ADDR_TYPE_STOP;
- drvdata->startstop_ctrl |= (1 << (idx + 16));
- drvdata->enable_ctrl1 |= ETMTECR1_START_STOP;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(addr_stop);
-
-static ssize_t addr_acctype_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- spin_lock(&drvdata->spinlock);
- val = drvdata->addr_acctype[drvdata->addr_idx];
- spin_unlock(&drvdata->spinlock);
-
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t addr_acctype_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- spin_lock(&drvdata->spinlock);
- drvdata->addr_acctype[drvdata->addr_idx] = val;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(addr_acctype);
-
-static ssize_t cntr_idx_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->cntr_idx;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t cntr_idx_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- if (val >= drvdata->nr_cntr)
- return -EINVAL;
- /*
- * Use spinlock to ensure index doesn't change while it gets
- * dereferenced multiple times within a spinlock block elsewhere.
- */
- spin_lock(&drvdata->spinlock);
- drvdata->cntr_idx = val;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(cntr_idx);
-
-static ssize_t cntr_rld_val_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- spin_lock(&drvdata->spinlock);
- val = drvdata->cntr_rld_val[drvdata->cntr_idx];
- spin_unlock(&drvdata->spinlock);
-
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t cntr_rld_val_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- spin_lock(&drvdata->spinlock);
- drvdata->cntr_rld_val[drvdata->cntr_idx] = val;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(cntr_rld_val);
-
-static ssize_t cntr_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- spin_lock(&drvdata->spinlock);
- val = drvdata->cntr_event[drvdata->cntr_idx];
- spin_unlock(&drvdata->spinlock);
-
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t cntr_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- spin_lock(&drvdata->spinlock);
- drvdata->cntr_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(cntr_event);
-
-static ssize_t cntr_rld_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- spin_lock(&drvdata->spinlock);
- val = drvdata->cntr_rld_event[drvdata->cntr_idx];
- spin_unlock(&drvdata->spinlock);
-
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t cntr_rld_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- spin_lock(&drvdata->spinlock);
- drvdata->cntr_rld_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(cntr_rld_event);
-
-static ssize_t cntr_val_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int i, ret = 0;
- u32 val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- if (!drvdata->enable) {
- spin_lock(&drvdata->spinlock);
- for (i = 0; i < drvdata->nr_cntr; i++)
- ret += sprintf(buf, "counter %d: %x\n",
- i, drvdata->cntr_val[i]);
- spin_unlock(&drvdata->spinlock);
- return ret;
- }
-
- for (i = 0; i < drvdata->nr_cntr; i++) {
- val = etm_readl(drvdata, ETMCNTVRn(i));
- ret += sprintf(buf, "counter %d: %x\n", i, val);
- }
-
- return ret;
-}
-
-static ssize_t cntr_val_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- spin_lock(&drvdata->spinlock);
- drvdata->cntr_val[drvdata->cntr_idx] = val;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(cntr_val);
-
-static ssize_t seq_12_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->seq_12_event;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t seq_12_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->seq_12_event = val & ETM_EVENT_MASK;
- return size;
-}
-static DEVICE_ATTR_RW(seq_12_event);
-
-static ssize_t seq_21_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->seq_21_event;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t seq_21_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->seq_21_event = val & ETM_EVENT_MASK;
- return size;
-}
-static DEVICE_ATTR_RW(seq_21_event);
-
-static ssize_t seq_23_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->seq_23_event;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t seq_23_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->seq_23_event = val & ETM_EVENT_MASK;
- return size;
-}
-static DEVICE_ATTR_RW(seq_23_event);
-
-static ssize_t seq_31_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->seq_31_event;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t seq_31_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->seq_31_event = val & ETM_EVENT_MASK;
- return size;
-}
-static DEVICE_ATTR_RW(seq_31_event);
-
-static ssize_t seq_32_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->seq_32_event;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t seq_32_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->seq_32_event = val & ETM_EVENT_MASK;
- return size;
-}
-static DEVICE_ATTR_RW(seq_32_event);
-
-static ssize_t seq_13_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->seq_13_event;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t seq_13_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->seq_13_event = val & ETM_EVENT_MASK;
- return size;
-}
-static DEVICE_ATTR_RW(seq_13_event);
-
-static ssize_t seq_curr_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val, flags;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- if (!drvdata->enable) {
- val = drvdata->seq_curr_state;
- goto out;
- }
-
- pm_runtime_get_sync(drvdata->dev);
- spin_lock_irqsave(&drvdata->spinlock, flags);
-
- CS_UNLOCK(drvdata->base);
- val = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
- CS_LOCK(drvdata->base);
-
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
-out:
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t seq_curr_state_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- if (val > ETM_SEQ_STATE_MAX_VAL)
- return -EINVAL;
-
- drvdata->seq_curr_state = val;
-
- return size;
-}
-static DEVICE_ATTR_RW(seq_curr_state);
-
-static ssize_t ctxid_idx_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->ctxid_idx;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t ctxid_idx_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
+static void etm_disable(struct coresight_device *csdev)
{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- if (val >= drvdata->nr_ctxid_cmp)
- return -EINVAL;
+ u32 mode;
+ struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
/*
- * Use spinlock to ensure index doesn't change while it gets
- * dereferenced multiple times within a spinlock block elsewhere.
+ * For as long as the tracer isn't disabled another entity can't
+ * change its status. As such we can read the status here without
+ * fearing it will change under us.
*/
- spin_lock(&drvdata->spinlock);
- drvdata->ctxid_idx = val;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(ctxid_idx);
-
-static ssize_t ctxid_pid_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- spin_lock(&drvdata->spinlock);
- val = drvdata->ctxid_vpid[drvdata->ctxid_idx];
- spin_unlock(&drvdata->spinlock);
+ mode = local_read(&drvdata->mode);
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t ctxid_pid_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long vpid, pid;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &vpid);
- if (ret)
- return ret;
-
- pid = coresight_vpid_to_pid(vpid);
-
- spin_lock(&drvdata->spinlock);
- drvdata->ctxid_pid[drvdata->ctxid_idx] = pid;
- drvdata->ctxid_vpid[drvdata->ctxid_idx] = vpid;
- spin_unlock(&drvdata->spinlock);
-
- return size;
-}
-static DEVICE_ATTR_RW(ctxid_pid);
-
-static ssize_t ctxid_mask_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->ctxid_mask;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t ctxid_mask_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->ctxid_mask = val;
- return size;
-}
-static DEVICE_ATTR_RW(ctxid_mask);
-
-static ssize_t sync_freq_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->sync_freq;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t sync_freq_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->sync_freq = val & ETM_SYNC_MASK;
- return size;
-}
-static DEVICE_ATTR_RW(sync_freq);
-
-static ssize_t timestamp_event_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->timestamp_event;
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t timestamp_event_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->timestamp_event = val & ETM_EVENT_MASK;
- return size;
-}
-static DEVICE_ATTR_RW(timestamp_event);
-
-static ssize_t cpu_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = drvdata->cpu;
- return scnprintf(buf, PAGE_SIZE, "%d\n", val);
-
-}
-static DEVICE_ATTR_RO(cpu);
-
-static ssize_t traceid_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned long val, flags;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- if (!drvdata->enable) {
- val = drvdata->traceid;
- goto out;
+ switch (mode) {
+ case CS_MODE_DISABLED:
+ break;
+ case CS_MODE_SYSFS:
+ etm_disable_sysfs(csdev);
+ break;
+ case CS_MODE_PERF:
+ etm_disable_perf(csdev);
+ break;
+ default:
+ WARN_ON_ONCE(mode);
+ return;
}
- pm_runtime_get_sync(drvdata->dev);
- spin_lock_irqsave(&drvdata->spinlock, flags);
- CS_UNLOCK(drvdata->base);
-
- val = (etm_readl(drvdata, ETMTRACEIDR) & ETM_TRACEID_MASK);
-
- CS_LOCK(drvdata->base);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
-out:
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t traceid_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- drvdata->traceid = val & ETM_TRACEID_MASK;
- return size;
+ if (mode)
+ local_set(&drvdata->mode, CS_MODE_DISABLED);
}
-static DEVICE_ATTR_RW(traceid);
-
-static struct attribute *coresight_etm_attrs[] = {
- &dev_attr_nr_addr_cmp.attr,
- &dev_attr_nr_cntr.attr,
- &dev_attr_nr_ctxid_cmp.attr,
- &dev_attr_etmsr.attr,
- &dev_attr_reset.attr,
- &dev_attr_mode.attr,
- &dev_attr_trigger_event.attr,
- &dev_attr_enable_event.attr,
- &dev_attr_fifofull_level.attr,
- &dev_attr_addr_idx.attr,
- &dev_attr_addr_single.attr,
- &dev_attr_addr_range.attr,
- &dev_attr_addr_start.attr,
- &dev_attr_addr_stop.attr,
- &dev_attr_addr_acctype.attr,
- &dev_attr_cntr_idx.attr,
- &dev_attr_cntr_rld_val.attr,
- &dev_attr_cntr_event.attr,
- &dev_attr_cntr_rld_event.attr,
- &dev_attr_cntr_val.attr,
- &dev_attr_seq_12_event.attr,
- &dev_attr_seq_21_event.attr,
- &dev_attr_seq_23_event.attr,
- &dev_attr_seq_31_event.attr,
- &dev_attr_seq_32_event.attr,
- &dev_attr_seq_13_event.attr,
- &dev_attr_seq_curr_state.attr,
- &dev_attr_ctxid_idx.attr,
- &dev_attr_ctxid_pid.attr,
- &dev_attr_ctxid_mask.attr,
- &dev_attr_sync_freq.attr,
- &dev_attr_timestamp_event.attr,
- &dev_attr_traceid.attr,
- &dev_attr_cpu.attr,
- NULL,
-};
-
-#define coresight_simple_func(name, offset) \
-static ssize_t name##_show(struct device *_dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct etm_drvdata *drvdata = dev_get_drvdata(_dev->parent); \
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", \
- readl_relaxed(drvdata->base + offset)); \
-} \
-DEVICE_ATTR_RO(name)
-
-coresight_simple_func(etmccr, ETMCCR);
-coresight_simple_func(etmccer, ETMCCER);
-coresight_simple_func(etmscr, ETMSCR);
-coresight_simple_func(etmidr, ETMIDR);
-coresight_simple_func(etmcr, ETMCR);
-coresight_simple_func(etmtraceidr, ETMTRACEIDR);
-coresight_simple_func(etmteevr, ETMTEEVR);
-coresight_simple_func(etmtssvr, ETMTSSCR);
-coresight_simple_func(etmtecr1, ETMTECR1);
-coresight_simple_func(etmtecr2, ETMTECR2);
-
-static struct attribute *coresight_etm_mgmt_attrs[] = {
- &dev_attr_etmccr.attr,
- &dev_attr_etmccer.attr,
- &dev_attr_etmscr.attr,
- &dev_attr_etmidr.attr,
- &dev_attr_etmcr.attr,
- &dev_attr_etmtraceidr.attr,
- &dev_attr_etmteevr.attr,
- &dev_attr_etmtssvr.attr,
- &dev_attr_etmtecr1.attr,
- &dev_attr_etmtecr2.attr,
- NULL,
-};
-static const struct attribute_group coresight_etm_group = {
- .attrs = coresight_etm_attrs,
-};
-
-
-static const struct attribute_group coresight_etm_mgmt_group = {
- .attrs = coresight_etm_mgmt_attrs,
- .name = "mgmt",
+static const struct coresight_ops_source etm_source_ops = {
+ .cpu_id = etm_cpu_id,
+ .trace_id = etm_trace_id,
+ .enable = etm_enable,
+ .disable = etm_disable,
};
-static const struct attribute_group *coresight_etm_groups[] = {
- &coresight_etm_group,
- &coresight_etm_mgmt_group,
- NULL,
+static const struct coresight_ops etm_cs_ops = {
+ .source_ops = &etm_source_ops,
};
static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
@@ -1658,7 +657,7 @@ static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
etmdrvdata[cpu]->os_unlock = true;
}
- if (etmdrvdata[cpu]->enable)
+ if (local_read(&etmdrvdata[cpu]->mode))
etm_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
@@ -1671,7 +670,7 @@ static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
case CPU_DYING:
spin_lock(&etmdrvdata[cpu]->spinlock);
- if (etmdrvdata[cpu]->enable)
+ if (local_read(&etmdrvdata[cpu]->mode))
etm_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
@@ -1707,6 +706,9 @@ static void etm_init_arch_data(void *info)
u32 etmccr;
struct etm_drvdata *drvdata = info;
+ /* Make sure all registers are accessible */
+ etm_os_unlock(drvdata);
+
CS_UNLOCK(drvdata->base);
/* First dummy read */
@@ -1743,40 +745,9 @@ static void etm_init_arch_data(void *info)
CS_LOCK(drvdata->base);
}
-static void etm_init_default_data(struct etm_drvdata *drvdata)
+static void etm_init_trace_id(struct etm_drvdata *drvdata)
{
- /*
- * A trace ID of value 0 is invalid, so let's start at some
- * random value that fits in 7 bits and will be just as good.
- */
- static int etm3x_traceid = 0x10;
-
- u32 flags = (1 << 0 | /* instruction execute*/
- 3 << 3 | /* ARM instruction */
- 0 << 5 | /* No data value comparison */
- 0 << 7 | /* No exact mach */
- 0 << 8 | /* Ignore context ID */
- 0 << 10); /* Security ignored */
-
- /*
- * Initial configuration only - guarantees sources handled by
- * this driver have a unique ID at startup time but not between
- * all other types of sources. For that we lean on the core
- * framework.
- */
- drvdata->traceid = etm3x_traceid++;
- drvdata->ctrl = (ETMCR_CYC_ACC | ETMCR_TIMESTAMP_EN);
- drvdata->enable_ctrl1 = ETMTECR1_ADDR_COMP_1;
- if (drvdata->nr_addr_cmp >= 2) {
- drvdata->addr_val[0] = (u32) _stext;
- drvdata->addr_val[1] = (u32) _etext;
- drvdata->addr_acctype[0] = flags;
- drvdata->addr_acctype[1] = flags;
- drvdata->addr_type[0] = ETM_ADDR_TYPE_RANGE;
- drvdata->addr_type[1] = ETM_ADDR_TYPE_RANGE;
- }
-
- etm_set_default(drvdata);
+ drvdata->traceid = coresight_get_trace_id(drvdata->cpu);
}
static int etm_probe(struct amba_device *adev, const struct amba_id *id)
@@ -1831,9 +802,6 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
get_online_cpus();
etmdrvdata[drvdata->cpu] = drvdata;
- if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, drvdata, 1))
- drvdata->os_unlock = true;
-
if (smp_call_function_single(drvdata->cpu,
etm_init_arch_data, drvdata, 1))
dev_err(dev, "ETM arch init failed\n");
@@ -1847,7 +815,9 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
ret = -EINVAL;
goto err_arch_supported;
}
- etm_init_default_data(drvdata);
+
+ etm_init_trace_id(drvdata);
+ etm_set_default(&drvdata->config);
desc->type = CORESIGHT_DEV_TYPE_SOURCE;
desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
@@ -1861,6 +831,12 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
goto err_arch_supported;
}
+ ret = etm_perf_symlink(drvdata->csdev, true);
+ if (ret) {
+ coresight_unregister(drvdata->csdev);
+ goto err_arch_supported;
+ }
+
pm_runtime_put(&adev->dev);
dev_info(dev, "%s initialized\n", (char *)id->data);
@@ -1877,17 +853,6 @@ err_arch_supported:
return ret;
}
-static int etm_remove(struct amba_device *adev)
-{
- struct etm_drvdata *drvdata = amba_get_drvdata(adev);
-
- coresight_unregister(drvdata->csdev);
- if (--etm_count == 0)
- unregister_hotcpu_notifier(&etm_cpu_notifier);
-
- return 0;
-}
-
#ifdef CONFIG_PM
static int etm_runtime_suspend(struct device *dev)
{
@@ -1948,13 +913,9 @@ static struct amba_driver etm_driver = {
.name = "coresight-etm3x",
.owner = THIS_MODULE,
.pm = &etm_dev_pm_ops,
+ .suppress_bind_attrs = true,
},
.probe = etm_probe,
- .remove = etm_remove,
.id_table = etm_ids,
};
-
-module_amba_driver(etm_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("CoreSight Program Flow Trace driver");
+builtin_amba_driver(etm_driver);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index a6707642bb23..1c59bd36834c 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -15,7 +15,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
-#include <linux/module.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/fs.h>
@@ -32,6 +31,7 @@
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
+#include <linux/perf_event.h>
#include <asm/sections.h>
#include "coresight-etm4x.h"
@@ -63,6 +63,13 @@ static bool etm4_arch_supported(u8 arch)
return true;
}
+static int etm4_cpu_id(struct coresight_device *csdev)
+{
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ return drvdata->cpu;
+}
+
static int etm4_trace_id(struct coresight_device *csdev)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -72,7 +79,6 @@ static int etm4_trace_id(struct coresight_device *csdev)
if (!drvdata->enable)
return drvdata->trcid;
- pm_runtime_get_sync(drvdata->dev);
spin_lock_irqsave(&drvdata->spinlock, flags);
CS_UNLOCK(drvdata->base);
@@ -81,7 +87,6 @@ static int etm4_trace_id(struct coresight_device *csdev)
CS_LOCK(drvdata->base);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
return trace_id;
}
@@ -182,12 +187,12 @@ static void etm4_enable_hw(void *info)
dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
}
-static int etm4_enable(struct coresight_device *csdev)
+static int etm4_enable(struct coresight_device *csdev,
+ struct perf_event_attr *attr, u32 mode)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret;
- pm_runtime_get_sync(drvdata->dev);
spin_lock(&drvdata->spinlock);
/*
@@ -207,7 +212,6 @@ static int etm4_enable(struct coresight_device *csdev)
return 0;
err:
spin_unlock(&drvdata->spinlock);
- pm_runtime_put(drvdata->dev);
return ret;
}
@@ -256,12 +260,11 @@ static void etm4_disable(struct coresight_device *csdev)
spin_unlock(&drvdata->spinlock);
put_online_cpus();
- pm_runtime_put(drvdata->dev);
-
dev_info(drvdata->dev, "ETM tracing disabled\n");
}
static const struct coresight_ops_source etm4_source_ops = {
+ .cpu_id = etm4_cpu_id,
.trace_id = etm4_trace_id,
.enable = etm4_enable,
.disable = etm4_disable,
@@ -2219,7 +2222,7 @@ static ssize_t name##_show(struct device *_dev, \
return scnprintf(buf, PAGE_SIZE, "0x%x\n", \
readl_relaxed(drvdata->base + offset)); \
} \
-DEVICE_ATTR_RO(name)
+static DEVICE_ATTR_RO(name)
coresight_simple_func(trcoslsr, TRCOSLSR);
coresight_simple_func(trcpdcr, TRCPDCR);
@@ -2684,17 +2687,6 @@ err_coresight_register:
return ret;
}
-static int etm4_remove(struct amba_device *adev)
-{
- struct etmv4_drvdata *drvdata = amba_get_drvdata(adev);
-
- coresight_unregister(drvdata->csdev);
- if (--etm4_count == 0)
- unregister_hotcpu_notifier(&etm4_cpu_notifier);
-
- return 0;
-}
-
static struct amba_id etm4_ids[] = {
{ /* ETM 4.0 - Qualcomm */
.id = 0x0003b95d,
@@ -2712,10 +2704,9 @@ static struct amba_id etm4_ids[] = {
static struct amba_driver etm4x_driver = {
.drv = {
.name = "coresight-etm4x",
+ .suppress_bind_attrs = true,
},
.probe = etm4_probe,
- .remove = etm4_remove,
.id_table = etm4_ids,
};
-
-module_amba_driver(etm4x_driver);
+builtin_amba_driver(etm4x_driver);
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 2e36bde7fcb4..0600ca30649d 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -1,5 +1,7 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
+ * Description: CoreSight Funnel driver
+ *
* 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.
@@ -11,7 +13,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
@@ -69,7 +70,6 @@ static int funnel_enable(struct coresight_device *csdev, int inport,
{
struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- pm_runtime_get_sync(drvdata->dev);
funnel_enable_hw(drvdata, inport);
dev_info(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
@@ -95,7 +95,6 @@ static void funnel_disable(struct coresight_device *csdev, int inport,
struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
funnel_disable_hw(drvdata, inport);
- pm_runtime_put(drvdata->dev);
dev_info(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
}
@@ -226,14 +225,6 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
}
-static int funnel_remove(struct amba_device *adev)
-{
- struct funnel_drvdata *drvdata = amba_get_drvdata(adev);
-
- coresight_unregister(drvdata->csdev);
- return 0;
-}
-
#ifdef CONFIG_PM
static int funnel_runtime_suspend(struct device *dev)
{
@@ -273,13 +264,9 @@ static struct amba_driver funnel_driver = {
.name = "coresight-funnel",
.owner = THIS_MODULE,
.pm = &funnel_dev_pm_ops,
+ .suppress_bind_attrs = true,
},
.probe = funnel_probe,
- .remove = funnel_remove,
.id_table = funnel_ids,
};
-
-module_amba_driver(funnel_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("CoreSight Funnel driver");
+builtin_amba_driver(funnel_driver);
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 62fcd98cc7cf..333eddaed339 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -34,6 +34,15 @@
#define TIMEOUT_US 100
#define BMVAL(val, lsb, msb) ((val & GENMASK(msb, lsb)) >> lsb)
+#define ETM_MODE_EXCL_KERN BIT(30)
+#define ETM_MODE_EXCL_USER BIT(31)
+
+enum cs_mode {
+ CS_MODE_DISABLED,
+ CS_MODE_SYSFS,
+ CS_MODE_PERF,
+};
+
static inline void CS_LOCK(void __iomem *addr)
{
do {
@@ -52,6 +61,12 @@ static inline void CS_UNLOCK(void __iomem *addr)
} while (0);
}
+void coresight_disable_path(struct list_head *path);
+int coresight_enable_path(struct list_head *path, u32 mode);
+struct coresight_device *coresight_get_sink(struct list_head *path);
+struct list_head *coresight_build_path(struct coresight_device *csdev);
+void coresight_release_path(struct list_head *path);
+
#ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
extern int etm_readl_cp14(u32 off, unsigned int *val);
extern int etm_writel_cp14(u32 off, u32 val);
diff --git a/drivers/hwtracing/coresight/coresight-replicator-qcom.c b/drivers/hwtracing/coresight/coresight-replicator-qcom.c
index 584059e9e866..700f710e4bfa 100644
--- a/drivers/hwtracing/coresight/coresight-replicator-qcom.c
+++ b/drivers/hwtracing/coresight/coresight-replicator-qcom.c
@@ -15,7 +15,6 @@
#include <linux/clk.h>
#include <linux/coresight.h>
#include <linux/device.h>
-#include <linux/module.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -48,8 +47,6 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
{
struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent);
- pm_runtime_get_sync(drvdata->dev);
-
CS_UNLOCK(drvdata->base);
/*
@@ -86,8 +83,6 @@ static void replicator_disable(struct coresight_device *csdev, int inport,
CS_LOCK(drvdata->base);
- pm_runtime_put(drvdata->dev);
-
dev_info(drvdata->dev, "REPLICATOR disabled\n");
}
@@ -156,15 +151,6 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
}
-static int replicator_remove(struct amba_device *adev)
-{
- struct replicator_state *drvdata = amba_get_drvdata(adev);
-
- pm_runtime_disable(&adev->dev);
- coresight_unregister(drvdata->csdev);
- return 0;
-}
-
#ifdef CONFIG_PM
static int replicator_runtime_suspend(struct device *dev)
{
@@ -206,10 +192,9 @@ static struct amba_driver replicator_driver = {
.drv = {
.name = "coresight-replicator-qcom",
.pm = &replicator_dev_pm_ops,
+ .suppress_bind_attrs = true,
},
.probe = replicator_probe,
- .remove = replicator_remove,
.id_table = replicator_ids,
};
-
-module_amba_driver(replicator_driver);
+builtin_amba_driver(replicator_driver);
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index 963ac197c253..4299c0569340 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -1,5 +1,7 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
+ * Description: CoreSight Replicator driver
+ *
* 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.
@@ -11,7 +13,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -41,7 +42,6 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
{
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- pm_runtime_get_sync(drvdata->dev);
dev_info(drvdata->dev, "REPLICATOR enabled\n");
return 0;
}
@@ -51,7 +51,6 @@ static void replicator_disable(struct coresight_device *csdev, int inport,
{
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- pm_runtime_put(drvdata->dev);
dev_info(drvdata->dev, "REPLICATOR disabled\n");
}
@@ -127,20 +126,6 @@ out_disable_pm:
return ret;
}
-static int replicator_remove(struct platform_device *pdev)
-{
- struct replicator_drvdata *drvdata = platform_get_drvdata(pdev);
-
- coresight_unregister(drvdata->csdev);
- pm_runtime_get_sync(&pdev->dev);
- if (!IS_ERR(drvdata->atclk))
- clk_disable_unprepare(drvdata->atclk);
- pm_runtime_put_noidle(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
- return 0;
-}
-
#ifdef CONFIG_PM
static int replicator_runtime_suspend(struct device *dev)
{
@@ -175,15 +160,11 @@ static const struct of_device_id replicator_match[] = {
static struct platform_driver replicator_driver = {
.probe = replicator_probe,
- .remove = replicator_remove,
.driver = {
.name = "coresight-replicator",
.of_match_table = replicator_match,
.pm = &replicator_dev_pm_ops,
+ .suppress_bind_attrs = true,
},
};
-
builtin_platform_driver(replicator_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("CoreSight Replicator driver");
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index a57c7ec1661f..1be191f5d39c 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -1,5 +1,7 @@
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
+ * Description: CoreSight Trace Memory Controller driver
+ *
* 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.
@@ -11,7 +13,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
@@ -124,7 +125,7 @@ struct tmc_drvdata {
bool reading;
char *buf;
dma_addr_t paddr;
- void __iomem *vaddr;
+ void *vaddr;
u32 size;
bool enable;
enum tmc_config_type config_type;
@@ -242,12 +243,9 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
{
unsigned long flags;
- pm_runtime_get_sync(drvdata->dev);
-
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
return -EBUSY;
}
@@ -268,7 +266,7 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
return 0;
}
-static int tmc_enable_sink(struct coresight_device *csdev)
+static int tmc_enable_sink(struct coresight_device *csdev, u32 mode)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -381,8 +379,6 @@ out:
drvdata->enable = false;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
-
dev_info(drvdata->dev, "TMC disabled\n");
}
@@ -766,23 +762,10 @@ err_misc_register:
err_devm_kzalloc:
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
dma_free_coherent(dev, drvdata->size,
- &drvdata->paddr, GFP_KERNEL);
+ drvdata->vaddr, drvdata->paddr);
return ret;
}
-static int tmc_remove(struct amba_device *adev)
-{
- struct tmc_drvdata *drvdata = amba_get_drvdata(adev);
-
- misc_deregister(&drvdata->miscdev);
- coresight_unregister(drvdata->csdev);
- if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
- dma_free_coherent(drvdata->dev, drvdata->size,
- &drvdata->paddr, GFP_KERNEL);
-
- return 0;
-}
-
static struct amba_id tmc_ids[] = {
{
.id = 0x0003b961,
@@ -795,13 +778,9 @@ static struct amba_driver tmc_driver = {
.drv = {
.name = "coresight-tmc",
.owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
},
.probe = tmc_probe,
- .remove = tmc_remove,
.id_table = tmc_ids,
};
-
-module_amba_driver(tmc_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("CoreSight Trace Memory Controller driver");
+builtin_amba_driver(tmc_driver);
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
index 7214efd10db5..8fb09d9237ab 100644
--- a/drivers/hwtracing/coresight/coresight-tpiu.c
+++ b/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -1,5 +1,7 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
+ * Description: CoreSight Trace Port Interface Unit driver
+ *
* 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.
@@ -11,7 +13,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -70,11 +71,10 @@ static void tpiu_enable_hw(struct tpiu_drvdata *drvdata)
CS_LOCK(drvdata->base);
}
-static int tpiu_enable(struct coresight_device *csdev)
+static int tpiu_enable(struct coresight_device *csdev, u32 mode)
{
struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- pm_runtime_get_sync(csdev->dev.parent);
tpiu_enable_hw(drvdata);
dev_info(drvdata->dev, "TPIU enabled\n");
@@ -98,7 +98,6 @@ static void tpiu_disable(struct coresight_device *csdev)
struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
tpiu_disable_hw(drvdata);
- pm_runtime_put(csdev->dev.parent);
dev_info(drvdata->dev, "TPIU disabled\n");
}
@@ -172,14 +171,6 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
}
-static int tpiu_remove(struct amba_device *adev)
-{
- struct tpiu_drvdata *drvdata = amba_get_drvdata(adev);
-
- coresight_unregister(drvdata->csdev);
- return 0;
-}
-
#ifdef CONFIG_PM
static int tpiu_runtime_suspend(struct device *dev)
{
@@ -223,13 +214,9 @@ static struct amba_driver tpiu_driver = {
.name = "coresight-tpiu",
.owner = THIS_MODULE,
.pm = &tpiu_dev_pm_ops,
+ .suppress_bind_attrs = true,
},
.probe = tpiu_probe,
- .remove = tpiu_remove,
.id_table = tpiu_ids,
};
-
-module_amba_driver(tpiu_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");
+builtin_amba_driver(tpiu_driver);
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 93738dfbf631..2ea5961092c1 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -11,7 +11,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
@@ -24,11 +23,28 @@
#include <linux/coresight.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include "coresight-priv.h"
static DEFINE_MUTEX(coresight_mutex);
+/**
+ * struct coresight_node - elements of a path, from source to sink
+ * @csdev: Address of an element.
+ * @link: hook to the list.
+ */
+struct coresight_node {
+ struct coresight_device *csdev;
+ struct list_head link;
+};
+
+/*
+ * When operating Coresight drivers from the sysFS interface, only a single
+ * path can exist from a tracer (associated to a CPU) to a sink.
+ */
+static DEFINE_PER_CPU(struct list_head *, sysfs_path);
+
static int coresight_id_match(struct device *dev, void *data)
{
int trace_id, i_trace_id;
@@ -68,15 +84,12 @@ static int coresight_source_is_unique(struct coresight_device *csdev)
csdev, coresight_id_match);
}
-static int coresight_find_link_inport(struct coresight_device *csdev)
+static int coresight_find_link_inport(struct coresight_device *csdev,
+ struct coresight_device *parent)
{
int i;
- struct coresight_device *parent;
struct coresight_connection *conn;
- parent = container_of(csdev->path_link.next,
- struct coresight_device, path_link);
-
for (i = 0; i < parent->nr_outport; i++) {
conn = &parent->conns[i];
if (conn->child_dev == csdev)
@@ -89,15 +102,12 @@ static int coresight_find_link_inport(struct coresight_device *csdev)
return 0;
}
-static int coresight_find_link_outport(struct coresight_device *csdev)
+static int coresight_find_link_outport(struct coresight_device *csdev,
+ struct coresight_device *child)
{
int i;
- struct coresight_device *child;
struct coresight_connection *conn;
- child = container_of(csdev->path_link.prev,
- struct coresight_device, path_link);
-
for (i = 0; i < csdev->nr_outport; i++) {
conn = &csdev->conns[i];
if (conn->child_dev == child)
@@ -110,13 +120,13 @@ static int coresight_find_link_outport(struct coresight_device *csdev)
return 0;
}
-static int coresight_enable_sink(struct coresight_device *csdev)
+static int coresight_enable_sink(struct coresight_device *csdev, u32 mode)
{
int ret;
if (!csdev->enable) {
if (sink_ops(csdev)->enable) {
- ret = sink_ops(csdev)->enable(csdev);
+ ret = sink_ops(csdev)->enable(csdev, mode);
if (ret)
return ret;
}
@@ -138,14 +148,19 @@ static void coresight_disable_sink(struct coresight_device *csdev)
}
}
-static int coresight_enable_link(struct coresight_device *csdev)
+static int coresight_enable_link(struct coresight_device *csdev,
+ struct coresight_device *parent,
+ struct coresight_device *child)
{
int ret;
int link_subtype;
int refport, inport, outport;
- inport = coresight_find_link_inport(csdev);
- outport = coresight_find_link_outport(csdev);
+ if (!parent || !child)
+ return -EINVAL;
+
+ inport = coresight_find_link_inport(csdev, parent);
+ outport = coresight_find_link_outport(csdev, child);
link_subtype = csdev->subtype.link_subtype;
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
@@ -168,14 +183,19 @@ static int coresight_enable_link(struct coresight_device *csdev)
return 0;
}
-static void coresight_disable_link(struct coresight_device *csdev)
+static void coresight_disable_link(struct coresight_device *csdev,
+ struct coresight_device *parent,
+ struct coresight_device *child)
{
int i, nr_conns;
int link_subtype;
int refport, inport, outport;
- inport = coresight_find_link_inport(csdev);
- outport = coresight_find_link_outport(csdev);
+ if (!parent || !child)
+ return;
+
+ inport = coresight_find_link_inport(csdev, parent);
+ outport = coresight_find_link_outport(csdev, child);
link_subtype = csdev->subtype.link_subtype;
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
@@ -201,7 +221,7 @@ static void coresight_disable_link(struct coresight_device *csdev)
csdev->enable = false;
}
-static int coresight_enable_source(struct coresight_device *csdev)
+static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
{
int ret;
@@ -213,7 +233,7 @@ static int coresight_enable_source(struct coresight_device *csdev)
if (!csdev->enable) {
if (source_ops(csdev)->enable) {
- ret = source_ops(csdev)->enable(csdev);
+ ret = source_ops(csdev)->enable(csdev, NULL, mode);
if (ret)
return ret;
}
@@ -235,109 +255,188 @@ static void coresight_disable_source(struct coresight_device *csdev)
}
}
-static int coresight_enable_path(struct list_head *path)
+void coresight_disable_path(struct list_head *path)
{
- int ret = 0;
- struct coresight_device *cd;
-
- /*
- * At this point we have a full @path, from source to sink. The
- * sink is the first entry and the source the last one. Go through
- * all the components and enable them one by one.
- */
- list_for_each_entry(cd, path, path_link) {
- if (cd == list_first_entry(path, struct coresight_device,
- path_link)) {
- ret = coresight_enable_sink(cd);
- } else if (list_is_last(&cd->path_link, path)) {
- /*
- * Don't enable the source just yet - this needs to
- * happen at the very end when all links and sink
- * along the path have been configured properly.
- */
- ;
- } else {
- ret = coresight_enable_link(cd);
+ struct coresight_node *nd;
+ struct coresight_device *csdev, *parent, *child;
+
+ list_for_each_entry(nd, path, link) {
+ csdev = nd->csdev;
+
+ switch (csdev->type) {
+ case CORESIGHT_DEV_TYPE_SINK:
+ case CORESIGHT_DEV_TYPE_LINKSINK:
+ coresight_disable_sink(csdev);
+ break;
+ case CORESIGHT_DEV_TYPE_SOURCE:
+ /* sources are disabled from either sysFS or Perf */
+ break;
+ case CORESIGHT_DEV_TYPE_LINK:
+ parent = list_prev_entry(nd, link)->csdev;
+ child = list_next_entry(nd, link)->csdev;
+ coresight_disable_link(csdev, parent, child);
+ break;
+ default:
+ break;
}
- if (ret)
- goto err;
}
+}
- return 0;
-err:
- list_for_each_entry_continue_reverse(cd, path, path_link) {
- if (cd == list_first_entry(path, struct coresight_device,
- path_link)) {
- coresight_disable_sink(cd);
- } else if (list_is_last(&cd->path_link, path)) {
- ;
- } else {
- coresight_disable_link(cd);
+int coresight_enable_path(struct list_head *path, u32 mode)
+{
+
+ int ret = 0;
+ struct coresight_node *nd;
+ struct coresight_device *csdev, *parent, *child;
+
+ list_for_each_entry_reverse(nd, path, link) {
+ csdev = nd->csdev;
+
+ switch (csdev->type) {
+ case CORESIGHT_DEV_TYPE_SINK:
+ case CORESIGHT_DEV_TYPE_LINKSINK:
+ ret = coresight_enable_sink(csdev, mode);
+ if (ret)
+ goto err;
+ break;
+ case CORESIGHT_DEV_TYPE_SOURCE:
+ /* sources are enabled from either sysFS or Perf */
+ break;
+ case CORESIGHT_DEV_TYPE_LINK:
+ parent = list_prev_entry(nd, link)->csdev;
+ child = list_next_entry(nd, link)->csdev;
+ ret = coresight_enable_link(csdev, parent, child);
+ if (ret)
+ goto err;
+ break;
+ default:
+ goto err;
}
}
+out:
return ret;
+err:
+ coresight_disable_path(path);
+ goto out;
}
-static int coresight_disable_path(struct list_head *path)
+struct coresight_device *coresight_get_sink(struct list_head *path)
{
- struct coresight_device *cd;
+ struct coresight_device *csdev;
- list_for_each_entry_reverse(cd, path, path_link) {
- if (cd == list_first_entry(path, struct coresight_device,
- path_link)) {
- coresight_disable_sink(cd);
- } else if (list_is_last(&cd->path_link, path)) {
- /*
- * The source has already been stopped, no need
- * to do it again here.
- */
- ;
- } else {
- coresight_disable_link(cd);
+ if (!path)
+ return NULL;
+
+ csdev = list_last_entry(path, struct coresight_node, link)->csdev;
+ if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
+ csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
+ return NULL;
+
+ return csdev;
+}
+
+/**
+ * _coresight_build_path - recursively build a path from a @csdev to a sink.
+ * @csdev: The device to start from.
+ * @path: The list to add devices to.
+ *
+ * The tree of Coresight device is traversed until an activated sink is
+ * found. From there the sink is added to the list along with all the
+ * devices that led to that point - the end result is a list from source
+ * to sink. In that list the source is the first device and the sink the
+ * last one.
+ */
+static int _coresight_build_path(struct coresight_device *csdev,
+ struct list_head *path)
+{
+ int i;
+ bool found = false;
+ struct coresight_node *node;
+ struct coresight_connection *conn;
+
+ /* An activated sink has been found. Enqueue the element */
+ if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
+ csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && csdev->activated)
+ goto out;
+
+ /* Not a sink - recursively explore each port found on this element */
+ for (i = 0; i < csdev->nr_outport; i++) {
+ conn = &csdev->conns[i];
+ if (_coresight_build_path(conn->child_dev, path) == 0) {
+ found = true;
+ break;
}
}
+ if (!found)
+ return -ENODEV;
+
+out:
+ /*
+ * A path from this element to a sink has been found. The elements
+ * leading to the sink are already enqueued, all that is left to do
+ * is tell the PM runtime core we need this element and add a node
+ * for it.
+ */
+ node = kzalloc(sizeof(struct coresight_node), GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+
+ node->csdev = csdev;
+ list_add(&node->link, path);
+ pm_runtime_get_sync(csdev->dev.parent);
+
return 0;
}
-static int coresight_build_paths(struct coresight_device *csdev,
- struct list_head *path,
- bool enable)
+struct list_head *coresight_build_path(struct coresight_device *csdev)
{
- int i, ret = -EINVAL;
- struct coresight_connection *conn;
+ struct list_head *path;
- list_add(&csdev->path_link, path);
+ path = kzalloc(sizeof(struct list_head), GFP_KERNEL);
+ if (!path)
+ return NULL;
- if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
- csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
- csdev->activated) {
- if (enable)
- ret = coresight_enable_path(path);
- else
- ret = coresight_disable_path(path);
- } else {
- for (i = 0; i < csdev->nr_outport; i++) {
- conn = &csdev->conns[i];
- if (coresight_build_paths(conn->child_dev,
- path, enable) == 0)
- ret = 0;
- }
+ INIT_LIST_HEAD(path);
+
+ if (_coresight_build_path(csdev, path)) {
+ kfree(path);
+ path = NULL;
}
- if (list_first_entry(path, struct coresight_device, path_link) != csdev)
- dev_err(&csdev->dev, "wrong device in %s\n", __func__);
+ return path;
+}
- list_del(&csdev->path_link);
+/**
+ * coresight_release_path - release a previously built path.
+ * @path: the path to release.
+ *
+ * Go through all the elements of a path and 1) removed it from the list and
+ * 2) free the memory allocated for each node.
+ */
+void coresight_release_path(struct list_head *path)
+{
+ struct coresight_device *csdev;
+ struct coresight_node *nd, *next;
- return ret;
+ list_for_each_entry_safe(nd, next, path, link) {
+ csdev = nd->csdev;
+
+ pm_runtime_put_sync(csdev->dev.parent);
+ list_del(&nd->link);
+ kfree(nd);
+ }
+
+ kfree(path);
+ path = NULL;
}
int coresight_enable(struct coresight_device *csdev)
{
int ret = 0;
- LIST_HEAD(path);
+ int cpu;
+ struct list_head *path;
mutex_lock(&coresight_mutex);
if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
@@ -348,22 +447,47 @@ int coresight_enable(struct coresight_device *csdev)
if (csdev->enable)
goto out;
- if (coresight_build_paths(csdev, &path, true)) {
- dev_err(&csdev->dev, "building path(s) failed\n");
+ path = coresight_build_path(csdev);
+ if (!path) {
+ pr_err("building path(s) failed\n");
goto out;
}
- if (coresight_enable_source(csdev))
- dev_err(&csdev->dev, "source enable failed\n");
+ ret = coresight_enable_path(path, CS_MODE_SYSFS);
+ if (ret)
+ goto err_path;
+
+ ret = coresight_enable_source(csdev, CS_MODE_SYSFS);
+ if (ret)
+ goto err_source;
+
+ /*
+ * When working from sysFS it is important to keep track
+ * of the paths that were created so that they can be
+ * undone in 'coresight_disable()'. Since there can only
+ * be a single session per tracer (when working from sysFS)
+ * a per-cpu variable will do just fine.
+ */
+ cpu = source_ops(csdev)->cpu_id(csdev);
+ per_cpu(sysfs_path, cpu) = path;
+
out:
mutex_unlock(&coresight_mutex);
return ret;
+
+err_source:
+ coresight_disable_path(path);
+
+err_path:
+ coresight_release_path(path);
+ goto out;
}
EXPORT_SYMBOL_GPL(coresight_enable);
void coresight_disable(struct coresight_device *csdev)
{
- LIST_HEAD(path);
+ int cpu;
+ struct list_head *path;
mutex_lock(&coresight_mutex);
if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
@@ -373,9 +497,12 @@ void coresight_disable(struct coresight_device *csdev)
if (!csdev->enable)
goto out;
+ cpu = source_ops(csdev)->cpu_id(csdev);
+ path = per_cpu(sysfs_path, cpu);
coresight_disable_source(csdev);
- if (coresight_build_paths(csdev, &path, false))
- dev_err(&csdev->dev, "releasing path(s) failed\n");
+ coresight_disable_path(path);
+ coresight_release_path(path);
+ per_cpu(sysfs_path, cpu) = NULL;
out:
mutex_unlock(&coresight_mutex);
@@ -481,6 +608,8 @@ static void coresight_device_release(struct device *dev)
{
struct coresight_device *csdev = to_coresight_device(dev);
+ kfree(csdev->conns);
+ kfree(csdev->refcnt);
kfree(csdev);
}
@@ -536,7 +665,7 @@ static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
* are hooked-up with each newly added component.
*/
bus_for_each_dev(&coresight_bustype, NULL,
- csdev, coresight_orphan_match);
+ csdev, coresight_orphan_match);
}
@@ -568,6 +697,8 @@ static void coresight_fixup_device_conns(struct coresight_device *csdev)
if (dev) {
conn->child_dev = to_coresight_device(dev);
+ /* and put reference from 'bus_find_device()' */
+ put_device(dev);
} else {
csdev->orphan = true;
conn->child_dev = NULL;
@@ -575,6 +706,50 @@ static void coresight_fixup_device_conns(struct coresight_device *csdev)
}
}
+static int coresight_remove_match(struct device *dev, void *data)
+{
+ int i;
+ struct coresight_device *csdev, *iterator;
+ struct coresight_connection *conn;
+
+ csdev = data;
+ iterator = to_coresight_device(dev);
+
+ /* No need to check oneself */
+ if (csdev == iterator)
+ return 0;
+
+ /*
+ * Circle throuch all the connection of that component. If we find
+ * a connection whose name matches @csdev, remove it.
+ */
+ for (i = 0; i < iterator->nr_outport; i++) {
+ conn = &iterator->conns[i];
+
+ if (conn->child_dev == NULL)
+ continue;
+
+ if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
+ iterator->orphan = true;
+ conn->child_dev = NULL;
+ /* No need to continue */
+ break;
+ }
+ }
+
+ /*
+ * Returning '0' ensures that all known component on the
+ * bus will be checked.
+ */
+ return 0;
+}
+
+static void coresight_remove_conns(struct coresight_device *csdev)
+{
+ bus_for_each_dev(&coresight_bustype, NULL,
+ csdev, coresight_remove_match);
+}
+
/**
* coresight_timeout - loop until a bit has changed to a specific state.
* @addr: base address of the area of interest.
@@ -713,13 +888,8 @@ EXPORT_SYMBOL_GPL(coresight_register);
void coresight_unregister(struct coresight_device *csdev)
{
- mutex_lock(&coresight_mutex);
-
- kfree(csdev->conns);
+ /* Remove references of that device in the topology */
+ coresight_remove_conns(csdev);
device_unregister(&csdev->dev);
-
- mutex_unlock(&coresight_mutex);
}
EXPORT_SYMBOL_GPL(coresight_unregister);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
index b0973617826f..b68da1888fd5 100644
--- a/drivers/hwtracing/coresight/of_coresight.c
+++ b/drivers/hwtracing/coresight/of_coresight.c
@@ -10,7 +10,6 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/slab.h>
@@ -86,7 +85,7 @@ static int of_coresight_alloc_memory(struct device *dev,
return -ENOMEM;
/* Children connected to this component via @outports */
- pdata->child_names = devm_kzalloc(dev, pdata->nr_outport *
+ pdata->child_names = devm_kzalloc(dev, pdata->nr_outport *
sizeof(*pdata->child_names),
GFP_KERNEL);
if (!pdata->child_names)
diff --git a/drivers/hwtracing/intel_th/Kconfig b/drivers/hwtracing/intel_th/Kconfig
index b7a9073d968b..1b412f8a56b5 100644
--- a/drivers/hwtracing/intel_th/Kconfig
+++ b/drivers/hwtracing/intel_th/Kconfig
@@ -1,5 +1,6 @@
config INTEL_TH
tristate "Intel(R) Trace Hub controller"
+ depends on HAS_DMA && HAS_IOMEM
help
Intel(R) Trace Hub (TH) is a set of hardware blocks (subdevices) that
produce, switch and output trace data from multiple hardware and
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 165d3001c301..4272f2ce5f6e 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -124,17 +124,34 @@ static struct device_type intel_th_source_device_type = {
.release = intel_th_device_release,
};
+static struct intel_th *to_intel_th(struct intel_th_device *thdev)
+{
+ /*
+ * subdevice tree is flat: if this one is not a switch, its
+ * parent must be
+ */
+ if (thdev->type != INTEL_TH_SWITCH)
+ thdev = to_intel_th_hub(thdev);
+
+ if (WARN_ON_ONCE(!thdev || thdev->type != INTEL_TH_SWITCH))
+ return NULL;
+
+ return dev_get_drvdata(thdev->dev.parent);
+}
+
static char *intel_th_output_devnode(struct device *dev, umode_t *mode,
kuid_t *uid, kgid_t *gid)
{
struct intel_th_device *thdev = to_intel_th_device(dev);
+ struct intel_th *th = to_intel_th(thdev);
char *node;
if (thdev->id >= 0)
- node = kasprintf(GFP_KERNEL, "intel_th%d/%s%d", 0, thdev->name,
- thdev->id);
+ node = kasprintf(GFP_KERNEL, "intel_th%d/%s%d", th->id,
+ thdev->name, thdev->id);
else
- node = kasprintf(GFP_KERNEL, "intel_th%d/%s", 0, thdev->name);
+ node = kasprintf(GFP_KERNEL, "intel_th%d/%s", th->id,
+ thdev->name);
return node;
}
@@ -319,6 +336,7 @@ static struct intel_th_subdevice {
unsigned nres;
unsigned type;
unsigned otype;
+ unsigned scrpd;
int id;
} intel_th_subdevices[TH_SUBDEVICE_MAX] = {
{
@@ -352,6 +370,7 @@ static struct intel_th_subdevice {
.id = 0,
.type = INTEL_TH_OUTPUT,
.otype = GTH_MSU,
+ .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC0_IS_ENABLED,
},
{
.nres = 2,
@@ -371,6 +390,7 @@ static struct intel_th_subdevice {
.id = 1,
.type = INTEL_TH_OUTPUT,
.otype = GTH_MSU,
+ .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC1_IS_ENABLED,
},
{
.nres = 2,
@@ -403,6 +423,7 @@ static struct intel_th_subdevice {
.name = "pti",
.type = INTEL_TH_OUTPUT,
.otype = GTH_PTI,
+ .scrpd = SCRPD_PTI_IS_PRIM_DEST,
},
{
.nres = 1,
@@ -477,6 +498,7 @@ static int intel_th_populate(struct intel_th *th, struct resource *devres,
thdev->dev.devt = MKDEV(th->major, i);
thdev->output.type = subdev->otype;
thdev->output.port = -1;
+ thdev->output.scratchpad = subdev->scrpd;
}
err = device_add(&thdev->dev);
@@ -579,6 +601,8 @@ intel_th_alloc(struct device *dev, struct resource *devres,
}
th->dev = dev;
+ dev_set_drvdata(dev, th);
+
err = intel_th_populate(th, devres, ndevres, irq);
if (err)
goto err_chrdev;
diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c
index 2dc5378ccd3a..9beea0b54231 100644
--- a/drivers/hwtracing/intel_th/gth.c
+++ b/drivers/hwtracing/intel_th/gth.c
@@ -146,24 +146,6 @@ gth_master_set(struct gth_device *gth, unsigned int master, int port)
iowrite32(val, gth->base + reg);
}
-/*static int gth_master_get(struct gth_device *gth, unsigned int master)
-{
- unsigned int reg = REG_GTH_SWDEST0 + ((master >> 1) & ~3u);
- unsigned int shift = (master & 0x7) * 4;
- u32 val;
-
- if (master >= 256) {
- reg = REG_GTH_GSWTDEST;
- shift = 0;
- }
-
- val = ioread32(gth->base + reg);
- val &= (0xf << shift);
- val >>= shift;
-
- return val ? val & 0x7 : -1;
- }*/
-
static ssize_t master_attr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -304,6 +286,10 @@ static int intel_th_gth_reset(struct gth_device *gth)
if (scratchpad & SCRPD_DEBUGGER_IN_USE)
return -EBUSY;
+ /* Always save/restore STH and TU registers in S0ix entry/exit */
+ scratchpad |= SCRPD_STH_IS_ENABLED | SCRPD_TRIGGER_IS_ENABLED;
+ iowrite32(scratchpad, gth->base + REG_GTH_SCRPD0);
+
/* output ports */
for (port = 0; port < 8; port++) {
if (gth_output_parm_get(gth, port, TH_OUTPUT_PARM(port)) ==
@@ -506,6 +492,10 @@ static void intel_th_gth_disable(struct intel_th_device *thdev,
if (!count)
dev_dbg(&thdev->dev, "timeout waiting for GTH[%d] PLE\n",
output->port);
+
+ reg = ioread32(gth->base + REG_GTH_SCRPD0);
+ reg &= ~output->scratchpad;
+ iowrite32(reg, gth->base + REG_GTH_SCRPD0);
}
/**
@@ -520,7 +510,7 @@ static void intel_th_gth_enable(struct intel_th_device *thdev,
struct intel_th_output *output)
{
struct gth_device *gth = dev_get_drvdata(&thdev->dev);
- u32 scr = 0xfc0000;
+ u32 scr = 0xfc0000, scrpd;
int master;
spin_lock(&gth->gth_lock);
@@ -535,6 +525,10 @@ static void intel_th_gth_enable(struct intel_th_device *thdev,
output->active = true;
spin_unlock(&gth->gth_lock);
+ scrpd = ioread32(gth->base + REG_GTH_SCRPD0);
+ scrpd |= output->scratchpad;
+ iowrite32(scrpd, gth->base + REG_GTH_SCRPD0);
+
iowrite32(scr, gth->base + REG_GTH_SCR);
iowrite32(0, gth->base + REG_GTH_SCR2);
}
diff --git a/drivers/hwtracing/intel_th/gth.h b/drivers/hwtracing/intel_th/gth.h
index 3b714b7a61db..56f0d2620577 100644
--- a/drivers/hwtracing/intel_th/gth.h
+++ b/drivers/hwtracing/intel_th/gth.h
@@ -57,9 +57,6 @@ enum {
REG_GTH_SCRPD3 = 0xec, /* ScratchPad[3] */
};
-/* Externall debugger is using Intel TH */
-#define SCRPD_DEBUGGER_IN_USE BIT(24)
-
/* waiting for Pipeline Empty bit(s) to assert for GTH */
#define GTH_PLE_WAITLOOP_DEPTH 10000
diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h
index 57fd72b20fae..eedd09332db6 100644
--- a/drivers/hwtracing/intel_th/intel_th.h
+++ b/drivers/hwtracing/intel_th/intel_th.h
@@ -30,6 +30,7 @@ enum {
* struct intel_th_output - descriptor INTEL_TH_OUTPUT type devices
* @port: output port number, assigned by the switch
* @type: GTH_{MSU,CTP,PTI}
+ * @scratchpad: scratchpad bits to flag when this output is enabled
* @multiblock: true for multiblock output configuration
* @active: true when this output is enabled
*
@@ -41,6 +42,7 @@ enum {
struct intel_th_output {
int port;
unsigned int type;
+ unsigned int scratchpad;
bool multiblock;
bool active;
};
@@ -241,4 +243,43 @@ enum {
GTH_PTI = 4, /* MIPI-PTI */
};
+/*
+ * Scratchpad bits: tell firmware and external debuggers
+ * what we are up to.
+ */
+enum {
+ /* Memory is the primary destination */
+ SCRPD_MEM_IS_PRIM_DEST = BIT(0),
+ /* XHCI DbC is the primary destination */
+ SCRPD_DBC_IS_PRIM_DEST = BIT(1),
+ /* PTI is the primary destination */
+ SCRPD_PTI_IS_PRIM_DEST = BIT(2),
+ /* BSSB is the primary destination */
+ SCRPD_BSSB_IS_PRIM_DEST = BIT(3),
+ /* PTI is the alternate destination */
+ SCRPD_PTI_IS_ALT_DEST = BIT(4),
+ /* BSSB is the alternate destination */
+ SCRPD_BSSB_IS_ALT_DEST = BIT(5),
+ /* DeepSx exit occurred */
+ SCRPD_DEEPSX_EXIT = BIT(6),
+ /* S4 exit occurred */
+ SCRPD_S4_EXIT = BIT(7),
+ /* S5 exit occurred */
+ SCRPD_S5_EXIT = BIT(8),
+ /* MSU controller 0/1 is enabled */
+ SCRPD_MSC0_IS_ENABLED = BIT(9),
+ SCRPD_MSC1_IS_ENABLED = BIT(10),
+ /* Sx exit occurred */
+ SCRPD_SX_EXIT = BIT(11),
+ /* Trigger Unit is enabled */
+ SCRPD_TRIGGER_IS_ENABLED = BIT(12),
+ SCRPD_ODLA_IS_ENABLED = BIT(13),
+ SCRPD_SOCHAP_IS_ENABLED = BIT(14),
+ SCRPD_STH_IS_ENABLED = BIT(15),
+ SCRPD_DCIH_IS_ENABLED = BIT(16),
+ SCRPD_VER_IS_ENABLED = BIT(17),
+ /* External debugger is using Intel TH */
+ SCRPD_DEBUGGER_IN_USE = BIT(24),
+};
+
#endif
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
index 70ca27e45602..d9d6022c5aca 100644
--- a/drivers/hwtracing/intel_th/msu.c
+++ b/drivers/hwtracing/intel_th/msu.c
@@ -408,7 +408,7 @@ msc_buffer_iterate(struct msc_iter *iter, size_t size, void *data,
* Second time (wrap_count==1), it's just like any other block,
* containing data in the range of [MSC_BDESC..data_bytes].
*/
- if (iter->block == iter->start_block && iter->wrap_count) {
+ if (iter->block == iter->start_block && iter->wrap_count == 2) {
tocopy = DATA_IN_PAGE - data_bytes;
src += data_bytes;
}
@@ -1112,12 +1112,11 @@ static ssize_t intel_th_msc_read(struct file *file, char __user *buf,
size = msc->nr_pages << PAGE_SHIFT;
if (!size)
- return 0;
+ goto put_count;
- if (off >= size) {
- len = 0;
+ if (off >= size)
goto put_count;
- }
+
if (off + len >= size)
len = size - off;
diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c
index 641e87936064..bca7a2ac00d6 100644
--- a/drivers/hwtracing/intel_th/pci.c
+++ b/drivers/hwtracing/intel_th/pci.c
@@ -46,8 +46,6 @@ static int intel_th_pci_probe(struct pci_dev *pdev,
if (IS_ERR(th))
return PTR_ERR(th);
- pci_set_drvdata(pdev, th);
-
return 0;
}
@@ -67,6 +65,16 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa126),
.driver_data = (kernel_ulong_t)0,
},
+ {
+ /* Apollo Lake */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a8e),
+ .driver_data = (kernel_ulong_t)0,
+ },
+ {
+ /* Broxton */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0a80),
+ .driver_data = (kernel_ulong_t)0,
+ },
{ 0 },
};
diff --git a/drivers/hwtracing/intel_th/sth.c b/drivers/hwtracing/intel_th/sth.c
index 56101c33e10f..e1aee61dd7b3 100644
--- a/drivers/hwtracing/intel_th/sth.c
+++ b/drivers/hwtracing/intel_th/sth.c
@@ -94,10 +94,13 @@ static ssize_t sth_stm_packet(struct stm_data *stm_data, unsigned int master,
case STP_PACKET_TRIG:
if (flags & STP_PACKET_TIMESTAMPED)
reg += 4;
- iowrite8(*payload, sth->base + reg);
+ writeb_relaxed(*payload, sth->base + reg);
break;
case STP_PACKET_MERR:
+ if (size > 4)
+ size = 4;
+
sth_iowrite(&out->MERR, payload, size);
break;
@@ -107,8 +110,8 @@ static ssize_t sth_stm_packet(struct stm_data *stm_data, unsigned int master,
else
outp = (u64 __iomem *)&out->FLAG;
- size = 1;
- sth_iowrite(outp, payload, size);
+ size = 0;
+ writeb_relaxed(0, outp);
break;
case STP_PACKET_USER:
@@ -129,6 +132,8 @@ static ssize_t sth_stm_packet(struct stm_data *stm_data, unsigned int master,
sth_iowrite(outp, payload, size);
break;
+ default:
+ return -ENOTSUPP;
}
return size;
diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig
index 83e9f591a54b..847a39b35307 100644
--- a/drivers/hwtracing/stm/Kconfig
+++ b/drivers/hwtracing/stm/Kconfig
@@ -1,6 +1,7 @@
config STM
tristate "System Trace Module devices"
select CONFIGFS_FS
+ select SRCU
help
A System Trace Module (STM) is a device exporting data in System
Trace Protocol (STP) format as defined by MIPI STP standards.
@@ -8,6 +9,8 @@ config STM
Say Y here to enable System Trace Module device support.
+if STM
+
config STM_DUMMY
tristate "Dummy STM driver"
help
@@ -24,3 +27,16 @@ config STM_SOURCE_CONSOLE
If you want to send kernel console messages over STM devices,
say Y.
+
+config STM_SOURCE_HEARTBEAT
+ tristate "Heartbeat over STM devices"
+ help
+ This is a kernel space trace source that sends periodic
+ heartbeat messages to trace hosts over STM devices. It is
+ also useful for testing stm class drivers and the stm class
+ framework itself.
+
+ If you want to send heartbeat messages over STM devices,
+ say Y.
+
+endif
diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile
index f9312c38dd7a..a9ce3d487e57 100644
--- a/drivers/hwtracing/stm/Makefile
+++ b/drivers/hwtracing/stm/Makefile
@@ -5,5 +5,7 @@ stm_core-y := core.o policy.o
obj-$(CONFIG_STM_DUMMY) += dummy_stm.o
obj-$(CONFIG_STM_SOURCE_CONSOLE) += stm_console.o
+obj-$(CONFIG_STM_SOURCE_HEARTBEAT) += stm_heartbeat.o
stm_console-y := console.o
+stm_heartbeat-y := heartbeat.o
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index b6445d9e5453..de80d45d8df9 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -113,6 +113,7 @@ struct stm_device *stm_find_device(const char *buf)
stm = to_stm_device(dev);
if (!try_module_get(stm->owner)) {
+ /* matches class_find_device() above */
put_device(dev);
return NULL;
}
@@ -125,7 +126,7 @@ struct stm_device *stm_find_device(const char *buf)
* @stm: stm device, previously acquired by stm_find_device()
*
* This drops the module reference and device reference taken by
- * stm_find_device().
+ * stm_find_device() or stm_char_open().
*/
void stm_put_device(struct stm_device *stm)
{
@@ -185,6 +186,9 @@ static void stm_output_claim(struct stm_device *stm, struct stm_output *output)
{
struct stp_master *master = stm_master(stm, output->master);
+ lockdep_assert_held(&stm->mc_lock);
+ lockdep_assert_held(&output->lock);
+
if (WARN_ON_ONCE(master->nr_free < output->nr_chans))
return;
@@ -199,6 +203,9 @@ stm_output_disclaim(struct stm_device *stm, struct stm_output *output)
{
struct stp_master *master = stm_master(stm, output->master);
+ lockdep_assert_held(&stm->mc_lock);
+ lockdep_assert_held(&output->lock);
+
bitmap_release_region(&master->chan_map[0], output->channel,
ilog2(output->nr_chans));
@@ -233,7 +240,7 @@ static int find_free_channels(unsigned long *bitmap, unsigned int start,
return -1;
}
-static unsigned int
+static int
stm_find_master_chan(struct stm_device *stm, unsigned int width,
unsigned int *mstart, unsigned int mend,
unsigned int *cstart, unsigned int cend)
@@ -288,12 +295,13 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width,
}
spin_lock(&stm->mc_lock);
+ spin_lock(&output->lock);
/* output is already assigned -- shouldn't happen */
if (WARN_ON_ONCE(output->nr_chans))
goto unlock;
ret = stm_find_master_chan(stm, width, &midx, mend, &cidx, cend);
- if (ret)
+ if (ret < 0)
goto unlock;
output->master = midx;
@@ -304,6 +312,7 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width,
ret = 0;
unlock:
+ spin_unlock(&output->lock);
spin_unlock(&stm->mc_lock);
return ret;
@@ -312,11 +321,18 @@ unlock:
static void stm_output_free(struct stm_device *stm, struct stm_output *output)
{
spin_lock(&stm->mc_lock);
+ spin_lock(&output->lock);
if (output->nr_chans)
stm_output_disclaim(stm, output);
+ spin_unlock(&output->lock);
spin_unlock(&stm->mc_lock);
}
+static void stm_output_init(struct stm_output *output)
+{
+ spin_lock_init(&output->lock);
+}
+
static int major_match(struct device *dev, const void *data)
{
unsigned int major = *(unsigned int *)data;
@@ -339,6 +355,7 @@ static int stm_char_open(struct inode *inode, struct file *file)
if (!stmf)
return -ENOMEM;
+ stm_output_init(&stmf->output);
stmf->stm = to_stm_device(dev);
if (!try_module_get(stmf->stm->owner))
@@ -349,6 +366,8 @@ static int stm_char_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
err_free:
+ /* matches class_find_device() above */
+ put_device(dev);
kfree(stmf);
return err;
@@ -357,9 +376,19 @@ err_free:
static int stm_char_release(struct inode *inode, struct file *file)
{
struct stm_file *stmf = file->private_data;
+ struct stm_device *stm = stmf->stm;
+
+ if (stm->data->unlink)
+ stm->data->unlink(stm->data, stmf->output.master,
+ stmf->output.channel);
- stm_output_free(stmf->stm, &stmf->output);
- stm_put_device(stmf->stm);
+ stm_output_free(stm, &stmf->output);
+
+ /*
+ * matches the stm_char_open()'s
+ * class_find_device() + try_module_get()
+ */
+ stm_put_device(stm);
kfree(stmf);
return 0;
@@ -380,8 +409,8 @@ static int stm_file_assign(struct stm_file *stmf, char *id, unsigned int width)
return ret;
}
-static void stm_write(struct stm_data *data, unsigned int master,
- unsigned int channel, const char *buf, size_t count)
+static ssize_t stm_write(struct stm_data *data, unsigned int master,
+ unsigned int channel, const char *buf, size_t count)
{
unsigned int flags = STP_PACKET_TIMESTAMPED;
const unsigned char *p = buf, nil = 0;
@@ -393,9 +422,14 @@ static void stm_write(struct stm_data *data, unsigned int master,
sz = data->packet(data, master, channel, STP_PACKET_DATA, flags,
sz, p);
flags = 0;
+
+ if (sz < 0)
+ break;
}
data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, &nil);
+
+ return pos;
}
static ssize_t stm_char_write(struct file *file, const char __user *buf,
@@ -406,6 +440,9 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf,
char *kbuf;
int err;
+ if (count + 1 > PAGE_SIZE)
+ count = PAGE_SIZE - 1;
+
/*
* if no m/c have been assigned to this writer up to this
* point, use "default" policy entry
@@ -430,8 +467,8 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf,
return -EFAULT;
}
- stm_write(stm->data, stmf->output.master, stmf->output.channel, kbuf,
- count);
+ count = stm_write(stm->data, stmf->output.master, stmf->output.channel,
+ kbuf, count);
kfree(kbuf);
@@ -515,10 +552,8 @@ static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg)
ret = stm->data->link(stm->data, stmf->output.master,
stmf->output.channel);
- if (ret) {
+ if (ret)
stm_output_free(stmf->stm, &stmf->output);
- stm_put_device(stmf->stm);
- }
err_free:
kfree(id);
@@ -618,7 +653,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data,
if (!stm_data->packet || !stm_data->sw_nchannels)
return -EINVAL;
- nmasters = stm_data->sw_end - stm_data->sw_start;
+ nmasters = stm_data->sw_end - stm_data->sw_start + 1;
stm = kzalloc(sizeof(*stm) + nmasters * sizeof(void *), GFP_KERNEL);
if (!stm)
return -ENOMEM;
@@ -641,6 +676,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data,
if (err)
goto err_device;
+ mutex_init(&stm->link_mutex);
spin_lock_init(&stm->link_lock);
INIT_LIST_HEAD(&stm->link_list);
@@ -654,6 +690,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data,
return 0;
err_device:
+ /* matches device_initialize() above */
put_device(&stm->dev);
err_free:
kfree(stm);
@@ -662,20 +699,28 @@ err_free:
}
EXPORT_SYMBOL_GPL(stm_register_device);
-static void __stm_source_link_drop(struct stm_source_device *src,
- struct stm_device *stm);
+static int __stm_source_link_drop(struct stm_source_device *src,
+ struct stm_device *stm);
void stm_unregister_device(struct stm_data *stm_data)
{
struct stm_device *stm = stm_data->stm;
struct stm_source_device *src, *iter;
- int i;
+ int i, ret;
- spin_lock(&stm->link_lock);
+ mutex_lock(&stm->link_mutex);
list_for_each_entry_safe(src, iter, &stm->link_list, link_entry) {
- __stm_source_link_drop(src, stm);
+ ret = __stm_source_link_drop(src, stm);
+ /*
+ * src <-> stm link must not change under the same
+ * stm::link_mutex, so complain loudly if it has;
+ * also in this situation ret!=0 means this src is
+ * not connected to this stm and it should be otherwise
+ * safe to proceed with the tear-down of stm.
+ */
+ WARN_ON_ONCE(ret);
}
- spin_unlock(&stm->link_lock);
+ mutex_unlock(&stm->link_mutex);
synchronize_srcu(&stm_source_srcu);
@@ -686,7 +731,7 @@ void stm_unregister_device(struct stm_data *stm_data)
stp_policy_unbind(stm->policy);
mutex_unlock(&stm->policy_mutex);
- for (i = 0; i < stm->sw_nmasters; i++)
+ for (i = stm->data->sw_start; i <= stm->data->sw_end; i++)
stp_master_free(stm, i);
device_unregister(&stm->dev);
@@ -694,6 +739,17 @@ void stm_unregister_device(struct stm_data *stm_data)
}
EXPORT_SYMBOL_GPL(stm_unregister_device);
+/*
+ * stm::link_list access serialization uses a spinlock and a mutex; holding
+ * either of them guarantees that the list is stable; modification requires
+ * holding both of them.
+ *
+ * Lock ordering is as follows:
+ * stm::link_mutex
+ * stm::link_lock
+ * src::link_lock
+ */
+
/**
* stm_source_link_add() - connect an stm_source device to an stm device
* @src: stm_source device
@@ -710,6 +766,7 @@ static int stm_source_link_add(struct stm_source_device *src,
char *id;
int err;
+ mutex_lock(&stm->link_mutex);
spin_lock(&stm->link_lock);
spin_lock(&src->link_lock);
@@ -719,6 +776,7 @@ static int stm_source_link_add(struct stm_source_device *src,
spin_unlock(&src->link_lock);
spin_unlock(&stm->link_lock);
+ mutex_unlock(&stm->link_mutex);
id = kstrdup(src->data->name, GFP_KERNEL);
if (id) {
@@ -753,9 +811,9 @@ static int stm_source_link_add(struct stm_source_device *src,
fail_free_output:
stm_output_free(stm, &src->output);
- stm_put_device(stm);
fail_detach:
+ mutex_lock(&stm->link_mutex);
spin_lock(&stm->link_lock);
spin_lock(&src->link_lock);
@@ -764,6 +822,7 @@ fail_detach:
spin_unlock(&src->link_lock);
spin_unlock(&stm->link_lock);
+ mutex_unlock(&stm->link_mutex);
return err;
}
@@ -776,28 +835,55 @@ fail_detach:
* If @stm is @src::link, disconnect them from one another and put the
* reference on the @stm device.
*
- * Caller must hold stm::link_lock.
+ * Caller must hold stm::link_mutex.
*/
-static void __stm_source_link_drop(struct stm_source_device *src,
- struct stm_device *stm)
+static int __stm_source_link_drop(struct stm_source_device *src,
+ struct stm_device *stm)
{
struct stm_device *link;
+ int ret = 0;
+
+ lockdep_assert_held(&stm->link_mutex);
+ /* for stm::link_list modification, we hold both mutex and spinlock */
+ spin_lock(&stm->link_lock);
spin_lock(&src->link_lock);
link = srcu_dereference_check(src->link, &stm_source_srcu, 1);
- if (WARN_ON_ONCE(link != stm)) {
- spin_unlock(&src->link_lock);
- return;
+
+ /*
+ * The linked device may have changed since we last looked, because
+ * we weren't holding the src::link_lock back then; if this is the
+ * case, tell the caller to retry.
+ */
+ if (link != stm) {
+ ret = -EAGAIN;
+ goto unlock;
}
stm_output_free(link, &src->output);
- /* caller must hold stm::link_lock */
list_del_init(&src->link_entry);
/* matches stm_find_device() from stm_source_link_store() */
stm_put_device(link);
rcu_assign_pointer(src->link, NULL);
+unlock:
spin_unlock(&src->link_lock);
+ spin_unlock(&stm->link_lock);
+
+ /*
+ * Call the unlink callbacks for both source and stm, when we know
+ * that we have actually performed the unlinking.
+ */
+ if (!ret) {
+ if (src->data->unlink)
+ src->data->unlink(src->data);
+
+ if (stm->data->unlink)
+ stm->data->unlink(stm->data, src->output.master,
+ src->output.channel);
+ }
+
+ return ret;
}
/**
@@ -813,21 +899,29 @@ static void __stm_source_link_drop(struct stm_source_device *src,
static void stm_source_link_drop(struct stm_source_device *src)
{
struct stm_device *stm;
- int idx;
+ int idx, ret;
+retry:
idx = srcu_read_lock(&stm_source_srcu);
+ /*
+ * The stm device will be valid for the duration of this
+ * read section, but the link may change before we grab
+ * the src::link_lock in __stm_source_link_drop().
+ */
stm = srcu_dereference(src->link, &stm_source_srcu);
+ ret = 0;
if (stm) {
- if (src->data->unlink)
- src->data->unlink(src->data);
-
- spin_lock(&stm->link_lock);
- __stm_source_link_drop(src, stm);
- spin_unlock(&stm->link_lock);
+ mutex_lock(&stm->link_mutex);
+ ret = __stm_source_link_drop(src, stm);
+ mutex_unlock(&stm->link_mutex);
}
srcu_read_unlock(&stm_source_srcu, idx);
+
+ /* if it did change, retry */
+ if (ret == -EAGAIN)
+ goto retry;
}
static ssize_t stm_source_link_show(struct device *dev,
@@ -862,8 +956,10 @@ static ssize_t stm_source_link_store(struct device *dev,
return -EINVAL;
err = stm_source_link_add(src, link);
- if (err)
+ if (err) {
+ /* matches the stm_find_device() above */
stm_put_device(link);
+ }
return err ? : count;
}
@@ -925,6 +1021,7 @@ int stm_source_register_device(struct device *parent,
if (err)
goto err;
+ stm_output_init(&src->output);
spin_lock_init(&src->link_lock);
INIT_LIST_HEAD(&src->link_entry);
src->data = data;
@@ -973,9 +1070,9 @@ int stm_source_write(struct stm_source_data *data, unsigned int chan,
stm = srcu_dereference(src->link, &stm_source_srcu);
if (stm)
- stm_write(stm->data, src->output.master,
- src->output.channel + chan,
- buf, count);
+ count = stm_write(stm->data, src->output.master,
+ src->output.channel + chan,
+ buf, count);
else
count = -ENODEV;
diff --git a/drivers/hwtracing/stm/dummy_stm.c b/drivers/hwtracing/stm/dummy_stm.c
index 3709bef0b21f..310adf57e7a1 100644
--- a/drivers/hwtracing/stm/dummy_stm.c
+++ b/drivers/hwtracing/stm/dummy_stm.c
@@ -40,22 +40,75 @@ dummy_stm_packet(struct stm_data *stm_data, unsigned int master,
return size;
}
-static struct stm_data dummy_stm = {
- .name = "dummy_stm",
- .sw_start = 0x0000,
- .sw_end = 0xffff,
- .sw_nchannels = 0xffff,
- .packet = dummy_stm_packet,
-};
+#define DUMMY_STM_MAX 32
+
+static struct stm_data dummy_stm[DUMMY_STM_MAX];
+
+static int nr_dummies = 4;
+
+module_param(nr_dummies, int, 0600);
+
+static unsigned int dummy_stm_nr;
+
+static unsigned int fail_mode;
+
+module_param(fail_mode, int, 0600);
+
+static int dummy_stm_link(struct stm_data *data, unsigned int master,
+ unsigned int channel)
+{
+ if (fail_mode && (channel & fail_mode))
+ return -EINVAL;
+
+ return 0;
+}
static int dummy_stm_init(void)
{
- return stm_register_device(NULL, &dummy_stm, THIS_MODULE);
+ int i, ret = -ENOMEM, __nr_dummies = ACCESS_ONCE(nr_dummies);
+
+ if (__nr_dummies < 0 || __nr_dummies > DUMMY_STM_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < __nr_dummies; i++) {
+ dummy_stm[i].name = kasprintf(GFP_KERNEL, "dummy_stm.%d", i);
+ if (!dummy_stm[i].name)
+ goto fail_unregister;
+
+ dummy_stm[i].sw_start = 0x0000;
+ dummy_stm[i].sw_end = 0xffff;
+ dummy_stm[i].sw_nchannels = 0xffff;
+ dummy_stm[i].packet = dummy_stm_packet;
+ dummy_stm[i].link = dummy_stm_link;
+
+ ret = stm_register_device(NULL, &dummy_stm[i], THIS_MODULE);
+ if (ret)
+ goto fail_free;
+ }
+
+ dummy_stm_nr = __nr_dummies;
+
+ return 0;
+
+fail_unregister:
+ for (i--; i >= 0; i--) {
+ stm_unregister_device(&dummy_stm[i]);
+fail_free:
+ kfree(dummy_stm[i].name);
+ }
+
+ return ret;
+
}
static void dummy_stm_exit(void)
{
- stm_unregister_device(&dummy_stm);
+ int i;
+
+ for (i = 0; i < dummy_stm_nr; i++) {
+ stm_unregister_device(&dummy_stm[i]);
+ kfree(dummy_stm[i].name);
+ }
}
module_init(dummy_stm_init);
diff --git a/drivers/hwtracing/stm/heartbeat.c b/drivers/hwtracing/stm/heartbeat.c
new file mode 100644
index 000000000000..0133571b506f
--- /dev/null
+++ b/drivers/hwtracing/stm/heartbeat.c
@@ -0,0 +1,130 @@
+/*
+ * Simple heartbeat STM source driver
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Heartbeat STM source will send repetitive messages over STM devices to a
+ * trace host.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hrtimer.h>
+#include <linux/slab.h>
+#include <linux/stm.h>
+
+#define STM_HEARTBEAT_MAX 32
+
+static int nr_devs = 4;
+static int interval_ms = 10;
+
+module_param(nr_devs, int, 0600);
+module_param(interval_ms, int, 0600);
+
+static struct stm_heartbeat {
+ struct stm_source_data data;
+ struct hrtimer hrtimer;
+ unsigned int active;
+} stm_heartbeat[STM_HEARTBEAT_MAX];
+
+static unsigned int nr_instances;
+
+static const char str[] = "heartbeat stm source driver is here to serve you";
+
+static enum hrtimer_restart stm_heartbeat_hrtimer_handler(struct hrtimer *hr)
+{
+ struct stm_heartbeat *heartbeat = container_of(hr, struct stm_heartbeat,
+ hrtimer);
+
+ stm_source_write(&heartbeat->data, 0, str, sizeof str);
+ if (heartbeat->active)
+ hrtimer_forward_now(hr, ms_to_ktime(interval_ms));
+
+ return heartbeat->active ? HRTIMER_RESTART : HRTIMER_NORESTART;
+}
+
+static int stm_heartbeat_link(struct stm_source_data *data)
+{
+ struct stm_heartbeat *heartbeat =
+ container_of(data, struct stm_heartbeat, data);
+
+ heartbeat->active = 1;
+ hrtimer_start(&heartbeat->hrtimer, ms_to_ktime(interval_ms),
+ HRTIMER_MODE_ABS);
+
+ return 0;
+}
+
+static void stm_heartbeat_unlink(struct stm_source_data *data)
+{
+ struct stm_heartbeat *heartbeat =
+ container_of(data, struct stm_heartbeat, data);
+
+ heartbeat->active = 0;
+ hrtimer_cancel(&heartbeat->hrtimer);
+}
+
+static int stm_heartbeat_init(void)
+{
+ int i, ret = -ENOMEM, __nr_instances = ACCESS_ONCE(nr_devs);
+
+ if (__nr_instances < 0 || __nr_instances > STM_HEARTBEAT_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < __nr_instances; i++) {
+ stm_heartbeat[i].data.name =
+ kasprintf(GFP_KERNEL, "heartbeat.%d", i);
+ if (!stm_heartbeat[i].data.name)
+ goto fail_unregister;
+
+ stm_heartbeat[i].data.nr_chans = 1;
+ stm_heartbeat[i].data.link = stm_heartbeat_link;
+ stm_heartbeat[i].data.unlink = stm_heartbeat_unlink;
+ hrtimer_init(&stm_heartbeat[i].hrtimer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_ABS);
+ stm_heartbeat[i].hrtimer.function =
+ stm_heartbeat_hrtimer_handler;
+
+ ret = stm_source_register_device(NULL, &stm_heartbeat[i].data);
+ if (ret)
+ goto fail_free;
+ }
+
+ nr_instances = __nr_instances;
+
+ return 0;
+
+fail_unregister:
+ for (i--; i >= 0; i--) {
+ stm_source_unregister_device(&stm_heartbeat[i].data);
+fail_free:
+ kfree(stm_heartbeat[i].data.name);
+ }
+
+ return ret;
+}
+
+static void stm_heartbeat_exit(void)
+{
+ int i;
+
+ for (i = 0; i < nr_instances; i++) {
+ stm_source_unregister_device(&stm_heartbeat[i].data);
+ kfree(stm_heartbeat[i].data.name);
+ }
+}
+
+module_init(stm_heartbeat_init);
+module_exit(stm_heartbeat_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("stm_heartbeat driver");
+MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c
index 11ab6d01adf6..1db189657b2b 100644
--- a/drivers/hwtracing/stm/policy.c
+++ b/drivers/hwtracing/stm/policy.c
@@ -272,13 +272,17 @@ void stp_policy_unbind(struct stp_policy *policy)
{
struct stm_device *stm = policy->stm;
+ /*
+ * stp_policy_release() will not call here if the policy is already
+ * unbound; other users should not either, as no link exists between
+ * this policy and anything else in that case
+ */
if (WARN_ON_ONCE(!policy->stm))
return;
- mutex_lock(&stm->policy_mutex);
- stm->policy = NULL;
- mutex_unlock(&stm->policy_mutex);
+ lockdep_assert_held(&stm->policy_mutex);
+ stm->policy = NULL;
policy->stm = NULL;
stm_put_device(stm);
@@ -287,8 +291,16 @@ void stp_policy_unbind(struct stp_policy *policy)
static void stp_policy_release(struct config_item *item)
{
struct stp_policy *policy = to_stp_policy(item);
+ struct stm_device *stm = policy->stm;
+ /* a policy *can* be unbound and still exist in configfs tree */
+ if (!stm)
+ return;
+
+ mutex_lock(&stm->policy_mutex);
stp_policy_unbind(policy);
+ mutex_unlock(&stm->policy_mutex);
+
kfree(policy);
}
@@ -320,10 +332,11 @@ stp_policies_make(struct config_group *group, const char *name)
/*
* node must look like <device_name>.<policy_name>, where
- * <device_name> is the name of an existing stm device and
- * <policy_name> is an arbitrary string
+ * <device_name> is the name of an existing stm device; may
+ * contain dots;
+ * <policy_name> is an arbitrary string; may not contain dots
*/
- p = strchr(devname, '.');
+ p = strrchr(devname, '.');
if (!p) {
kfree(devname);
return ERR_PTR(-EINVAL);
diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h
index 95ece0292c99..4e8c6926260f 100644
--- a/drivers/hwtracing/stm/stm.h
+++ b/drivers/hwtracing/stm/stm.h
@@ -45,6 +45,7 @@ struct stm_device {
int major;
unsigned int sw_nmasters;
struct stm_data *data;
+ struct mutex link_mutex;
spinlock_t link_lock;
struct list_head link_list;
/* master allocation */
@@ -56,6 +57,7 @@ struct stm_device {
container_of((_d), struct stm_device, dev)
struct stm_output {
+ spinlock_t lock;
unsigned int master;
unsigned int channel;
unsigned int nr_chans;
diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c
index 3711df1d4526..4a45408dd820 100644
--- a/drivers/i2c/busses/i2c-brcmstb.c
+++ b/drivers/i2c/busses/i2c-brcmstb.c
@@ -586,8 +586,7 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
if (!dev)
return -ENOMEM;
- dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(struct bsc_regs *),
- GFP_KERNEL);
+ dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(*dev->bsc_regmap), GFP_KERNEL);
if (!dev->bsc_regmap)
return -ENOMEM;
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 438f1b4964c0..d656657b805c 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -123,6 +123,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "80860F41", 0 },
{ "808622C1", 0 },
{ "AMD0010", ACCESS_INTR_MASK },
+ { "AMDI0010", ACCESS_INTR_MASK },
{ "AMDI0510", 0 },
{ "APMC0D0F", 0 },
{ }
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index f62d69799a9c..27fa0cb09538 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -1271,6 +1271,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
switch (dev->device) {
case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS:
case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS:
+ case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS:
+ case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 08d26ba61ed3..13c45296ce5b 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1450,7 +1450,8 @@ omap_i2c_probe(struct platform_device *pdev)
err_unuse_clocks:
omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
- pm_runtime_put(omap->dev);
+ pm_runtime_dont_use_autosuspend(omap->dev);
+ pm_runtime_put_sync(omap->dev);
pm_runtime_disable(&pdev->dev);
err_free_mem:
@@ -1468,6 +1469,7 @@ static int omap_i2c_remove(struct platform_device *pdev)
return ret;
omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index f3e5ff8522f0..213ba55e17c3 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -467,7 +467,7 @@ static int uniphier_fi2c_clk_init(struct device *dev,
bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
if (!bus_speed) {
- dev_err(dev, "clock-freqyency should not be zero\n");
+ dev_err(dev, "clock-frequency should not be zero\n");
return -EINVAL;
}
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
index 1f4f3f53819c..89eaa8a7e1e0 100644
--- a/drivers/i2c/busses/i2c-uniphier.c
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -328,7 +328,7 @@ static int uniphier_i2c_clk_init(struct device *dev,
bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
if (!bus_speed) {
- dev_err(dev, "clock-freqyency should not be zero\n");
+ dev_err(dev, "clock-frequency should not be zero\n");
return -EINVAL;
}
diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c
index 9ad014a7afc7..b33646be699c 100644
--- a/drivers/ide/pdc202xx_new.c
+++ b/drivers/ide/pdc202xx_new.c
@@ -28,7 +28,6 @@
#ifdef CONFIG_PPC_PMAC
#include <asm/prom.h>
-#include <asm/pci-bridge.h>
#endif
#define DRV_NAME "pdc202xx_new"
diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
index 96a345248224..7f0434f7e486 100644
--- a/drivers/ide/pmac.c
+++ b/drivers/ide/pmac.c
@@ -40,7 +40,6 @@
#include <asm/io.h>
#include <asm/dbdma.h>
#include <asm/ide.h>
-#include <asm/pci-bridge.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/sections.h>
diff --git a/drivers/infiniband/core/cma_configfs.c b/drivers/infiniband/core/cma_configfs.c
index 18b112aa577e..41573df1d9fc 100644
--- a/drivers/infiniband/core/cma_configfs.c
+++ b/drivers/infiniband/core/cma_configfs.c
@@ -49,8 +49,6 @@ struct cma_dev_group {
char name[IB_DEVICE_NAME_MAX];
struct config_group device_group;
struct config_group ports_group;
- struct config_group *default_dev_group[2];
- struct config_group **default_ports_group;
struct cma_dev_port_group *ports;
};
@@ -158,7 +156,6 @@ static int make_cma_ports(struct cma_dev_group *cma_dev_group,
unsigned int i;
unsigned int ports_num;
struct cma_dev_port_group *ports;
- struct config_group **ports_group;
int err;
ibdev = cma_get_ib_dev(cma_dev);
@@ -169,9 +166,8 @@ static int make_cma_ports(struct cma_dev_group *cma_dev_group,
ports_num = ibdev->phys_port_cnt;
ports = kcalloc(ports_num, sizeof(*cma_dev_group->ports),
GFP_KERNEL);
- ports_group = kcalloc(ports_num + 1, sizeof(*ports_group), GFP_KERNEL);
- if (!ports || !ports_group) {
+ if (!ports) {
err = -ENOMEM;
goto free;
}
@@ -185,18 +181,16 @@ static int make_cma_ports(struct cma_dev_group *cma_dev_group,
config_group_init_type_name(&ports[i].group,
port_str,
&cma_port_group_type);
- ports_group[i] = &ports[i].group;
+ configfs_add_default_group(&ports[i].group,
+ &cma_dev_group->ports_group);
+
}
- ports_group[i] = NULL;
- cma_dev_group->default_ports_group = ports_group;
cma_dev_group->ports = ports;
return 0;
free:
kfree(ports);
- kfree(ports_group);
cma_dev_group->ports = NULL;
- cma_dev_group->default_ports_group = NULL;
return err;
}
@@ -220,9 +214,7 @@ static void release_cma_ports_group(struct config_item *item)
ports_group);
kfree(cma_dev_group->ports);
- kfree(cma_dev_group->default_ports_group);
cma_dev_group->ports = NULL;
- cma_dev_group->default_ports_group = NULL;
};
static struct configfs_item_operations cma_ports_item_ops = {
@@ -263,22 +255,17 @@ static struct config_group *make_cma_dev(struct config_group *group,
strncpy(cma_dev_group->name, name, sizeof(cma_dev_group->name));
- err = make_cma_ports(cma_dev_group, cma_dev);
- if (err)
- goto fail;
-
- cma_dev_group->ports_group.default_groups =
- cma_dev_group->default_ports_group;
config_group_init_type_name(&cma_dev_group->ports_group, "ports",
&cma_ports_group_type);
- cma_dev_group->device_group.default_groups
- = cma_dev_group->default_dev_group;
- cma_dev_group->default_dev_group[0] = &cma_dev_group->ports_group;
- cma_dev_group->default_dev_group[1] = NULL;
+ err = make_cma_ports(cma_dev_group, cma_dev);
+ if (err)
+ goto fail;
config_group_init_type_name(&cma_dev_group->device_group, name,
&cma_device_group_type);
+ configfs_add_default_group(&cma_dev_group->ports_group,
+ &cma_dev_group->device_group);
cma_deref_dev(cma_dev);
return &cma_dev_group->device_group;
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 00da80e02154..94b80a51ab68 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -358,6 +358,7 @@ int ib_register_device(struct ib_device *device,
ret = device->query_device(device, &device->attrs, &uhw);
if (ret) {
printk(KERN_WARNING "Couldn't query the device attributes\n");
+ ib_cache_cleanup_one(device);
goto out;
}
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index f334090bb612..1e37f3515d98 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -1071,7 +1071,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
}
}
- if (rec->hop_limit > 1 || use_roce) {
+ if (rec->hop_limit > 0 || use_roce) {
ah_attr->ah_flags = IB_AH_GRH;
ah_attr->grh.dgid = rec->dgid;
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 6ffc9c4e93af..6c6fbff19752 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -1970,7 +1970,8 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
resp_size);
INIT_UDATA(&uhw, buf + sizeof(cmd),
(unsigned long)cmd.response + resp_size,
- in_len - sizeof(cmd), out_len - resp_size);
+ in_len - sizeof(cmd) - sizeof(struct ib_uverbs_cmd_hdr),
+ out_len - resp_size);
memset(&cmd_ex, 0, sizeof(cmd_ex));
cmd_ex.user_handle = cmd.user_handle;
@@ -3413,7 +3414,8 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
INIT_UDATA(&udata, buf + sizeof cmd,
(unsigned long) cmd.response + sizeof resp,
- in_len - sizeof cmd, out_len - sizeof resp);
+ in_len - sizeof cmd - sizeof(struct ib_uverbs_cmd_hdr),
+ out_len - sizeof resp);
ret = __uverbs_create_xsrq(file, ib_dev, &xcmd, &udata);
if (ret)
@@ -3439,7 +3441,8 @@ ssize_t ib_uverbs_create_xsrq(struct ib_uverbs_file *file,
INIT_UDATA(&udata, buf + sizeof cmd,
(unsigned long) cmd.response + sizeof resp,
- in_len - sizeof cmd, out_len - sizeof resp);
+ in_len - sizeof cmd - sizeof(struct ib_uverbs_cmd_hdr),
+ out_len - sizeof resp);
ret = __uverbs_create_xsrq(file, ib_dev, &cmd, &udata);
if (ret)
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 26833bfa639b..d68f506c1922 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -817,17 +817,48 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
}
-static void edit_counter(struct mlx4_counter *cnt,
- struct ib_pma_portcounters *pma_cnt)
+static void edit_counter(struct mlx4_counter *cnt, void *counters,
+ __be16 attr_id)
{
- ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
- (be64_to_cpu(cnt->tx_bytes) >> 2));
- ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
- (be64_to_cpu(cnt->rx_bytes) >> 2));
- ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
- be64_to_cpu(cnt->tx_frames));
- ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
- be64_to_cpu(cnt->rx_frames));
+ switch (attr_id) {
+ case IB_PMA_PORT_COUNTERS:
+ {
+ struct ib_pma_portcounters *pma_cnt =
+ (struct ib_pma_portcounters *)counters;
+
+ ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
+ (be64_to_cpu(cnt->tx_bytes) >> 2));
+ ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
+ (be64_to_cpu(cnt->rx_bytes) >> 2));
+ ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
+ be64_to_cpu(cnt->tx_frames));
+ ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
+ be64_to_cpu(cnt->rx_frames));
+ break;
+ }
+ case IB_PMA_PORT_COUNTERS_EXT:
+ {
+ struct ib_pma_portcounters_ext *pma_cnt_ext =
+ (struct ib_pma_portcounters_ext *)counters;
+
+ pma_cnt_ext->port_xmit_data =
+ cpu_to_be64(be64_to_cpu(cnt->tx_bytes) >> 2);
+ pma_cnt_ext->port_rcv_data =
+ cpu_to_be64(be64_to_cpu(cnt->rx_bytes) >> 2);
+ pma_cnt_ext->port_xmit_packets = cnt->tx_frames;
+ pma_cnt_ext->port_rcv_packets = cnt->rx_frames;
+ break;
+ }
+ }
+}
+
+static int iboe_process_mad_port_info(void *out_mad)
+{
+ struct ib_class_port_info cpi = {};
+
+ cpi.capability_mask = IB_PMA_CLASS_CAP_EXT_WIDTH;
+ memcpy(out_mad, &cpi, sizeof(cpi));
+ return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
}
static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
@@ -842,6 +873,9 @@ static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT)
return -EINVAL;
+ if (in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO)
+ return iboe_process_mad_port_info((void *)(out_mad->data + 40));
+
memset(&counter_stats, 0, sizeof(counter_stats));
mutex_lock(&dev->counters_table[port_num - 1].mutex);
list_for_each_entry(tmp_counter,
@@ -863,7 +897,8 @@ static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
switch (counter_stats.counter_mode & 0xf) {
case 0:
edit_counter(&counter_stats,
- (void *)(out_mad->data + 40));
+ (void *)(out_mad->data + 40),
+ in_mad->mad_hdr.attr_id);
err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
break;
default:
@@ -894,8 +929,10 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
*/
if (link == IB_LINK_LAYER_INFINIBAND) {
if (mlx4_is_slave(dev->dev) &&
- in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT &&
- in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS)
+ (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT &&
+ (in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS ||
+ in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS_EXT ||
+ in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO)))
return iboe_process_mad(ibdev, mad_flags, port_num, in_wc,
in_grh, in_mad, out_mad);
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index bc5536f00b6c..fd97534762b8 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1681,9 +1681,12 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
}
if (qp->ibqp.uobject)
- context->usr_page = cpu_to_be32(to_mucontext(ibqp->uobject->context)->uar.index);
+ context->usr_page = cpu_to_be32(
+ mlx4_to_hw_uar_index(dev->dev,
+ to_mucontext(ibqp->uobject->context)->uar.index));
else
- context->usr_page = cpu_to_be32(dev->priv_uar.index);
+ context->usr_page = cpu_to_be32(
+ mlx4_to_hw_uar_index(dev->dev, dev->priv_uar.index));
if (attr_mask & IB_QP_DEST_QPN)
context->remote_qpn = cpu_to_be32(attr->dest_qp_num);
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c
index 4659256cd95e..3b2ddd64a371 100644
--- a/drivers/infiniband/hw/mlx5/srq.c
+++ b/drivers/infiniband/hw/mlx5/srq.c
@@ -75,7 +75,8 @@ static void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type)
static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
struct mlx5_create_srq_mbox_in **in,
- struct ib_udata *udata, int buf_size, int *inlen)
+ struct ib_udata *udata, int buf_size, int *inlen,
+ int is_xrc)
{
struct mlx5_ib_dev *dev = to_mdev(pd->device);
struct mlx5_ib_create_srq ucmd = {};
@@ -87,13 +88,8 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
int ncont;
u32 offset;
u32 uidx = MLX5_IB_DEFAULT_UIDX;
- int drv_data = udata->inlen - sizeof(struct ib_uverbs_cmd_hdr);
- if (drv_data < 0)
- return -EINVAL;
-
- ucmdlen = (drv_data < sizeof(ucmd)) ?
- drv_data : sizeof(ucmd);
+ ucmdlen = min(udata->inlen, sizeof(ucmd));
if (ib_copy_from_udata(&ucmd, udata, ucmdlen)) {
mlx5_ib_dbg(dev, "failed copy udata\n");
@@ -103,15 +99,17 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
if (ucmd.reserved0 || ucmd.reserved1)
return -EINVAL;
- if (drv_data > sizeof(ucmd) &&
+ if (udata->inlen > sizeof(ucmd) &&
!ib_is_udata_cleared(udata, sizeof(ucmd),
- drv_data - sizeof(ucmd)))
+ udata->inlen - sizeof(ucmd)))
return -EINVAL;
- err = get_srq_user_index(to_mucontext(pd->uobject->context),
- &ucmd, udata->inlen, &uidx);
- if (err)
- return err;
+ if (is_xrc) {
+ err = get_srq_user_index(to_mucontext(pd->uobject->context),
+ &ucmd, udata->inlen, &uidx);
+ if (err)
+ return err;
+ }
srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE);
@@ -151,7 +149,8 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
(*in)->ctx.log_pg_sz = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
(*in)->ctx.pgoff_cqn = cpu_to_be32(offset << 26);
- if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) {
+ if ((MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) &&
+ is_xrc){
xsrqc = MLX5_ADDR_OF(create_xrc_srq_in, *in,
xrc_srq_context_entry);
MLX5_SET(xrc_srqc, xsrqc, user_index, uidx);
@@ -170,7 +169,7 @@ err_umem:
static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
struct mlx5_create_srq_mbox_in **in, int buf_size,
- int *inlen)
+ int *inlen, int is_xrc)
{
int err;
int i;
@@ -224,7 +223,8 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
(*in)->ctx.log_pg_sz = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
- if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) {
+ if ((MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) &&
+ is_xrc){
xsrqc = MLX5_ADDR_OF(create_xrc_srq_in, *in,
xrc_srq_context_entry);
/* 0xffffff means we ask to work with cqe version 0 */
@@ -302,10 +302,14 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs,
srq->msrq.max_avail_gather);
+ is_xrc = (init_attr->srq_type == IB_SRQT_XRC);
+
if (pd->uobject)
- err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen);
+ err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen,
+ is_xrc);
else
- err = create_srq_kernel(dev, srq, &in, buf_size, &inlen);
+ err = create_srq_kernel(dev, srq, &in, buf_size, &inlen,
+ is_xrc);
if (err) {
mlx5_ib_warn(dev, "create srq %s failed, err %d\n",
@@ -313,7 +317,6 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
goto err_srq;
}
- is_xrc = (init_attr->srq_type == IB_SRQT_XRC);
in->ctx.state_log_sz = ilog2(srq->msrq.max);
flgs = ((srq->msrq.wqe_shift - 4) | (is_xrc << 5) | (srq->wq_sig << 7)) << 24;
xrcdn = 0;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
index 040bb8b5cb15..12503f15fbd6 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -323,9 +323,6 @@ struct ocrdma_cq {
*/
u32 max_hw_cqe;
bool phase_change;
- bool deferred_arm, deferred_sol;
- bool first_arm;
-
spinlock_t cq_lock ____cacheline_aligned; /* provide synchronization
* to cq polling
*/
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index 37620b4baafb..12420e4ecf3d 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -1094,7 +1094,6 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev,
spin_lock_init(&cq->comp_handler_lock);
INIT_LIST_HEAD(&cq->sq_head);
INIT_LIST_HEAD(&cq->rq_head);
- cq->first_arm = true;
if (ib_ctx) {
uctx = get_ocrdma_ucontext(ib_ctx);
@@ -2910,12 +2909,9 @@ expand_cqe:
}
stop_cqe:
cq->getp = cur_getp;
- if (cq->deferred_arm || polled_hw_cqes) {
- ocrdma_ring_cq_db(dev, cq->id, cq->deferred_arm,
- cq->deferred_sol, polled_hw_cqes);
- cq->deferred_arm = false;
- cq->deferred_sol = false;
- }
+
+ if (polled_hw_cqes)
+ ocrdma_ring_cq_db(dev, cq->id, false, false, polled_hw_cqes);
return i;
}
@@ -2999,13 +2995,7 @@ int ocrdma_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags cq_flags)
if (cq_flags & IB_CQ_SOLICITED)
sol_needed = true;
- if (cq->first_arm) {
- ocrdma_ring_cq_db(dev, cq_id, arm_needed, sol_needed, 0);
- cq->first_arm = false;
- }
-
- cq->deferred_arm = true;
- cq->deferred_sol = sol_needed;
+ ocrdma_ring_cq_db(dev, cq_id, arm_needed, sol_needed, 0);
spin_unlock_irqrestore(&cq->cq_lock, flags);
return 0;
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index e5e223938eec..374c129219ef 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -114,6 +114,7 @@ struct kmem_cache *amd_iommu_irq_cache;
static void update_domain(struct protection_domain *domain);
static int protection_domain_init(struct protection_domain *domain);
+static void detach_device(struct device *dev);
/*
* For dynamic growth the aperture size is split into ranges of 128MB of
@@ -384,6 +385,9 @@ static void iommu_uninit_device(struct device *dev)
if (!dev_data)
return;
+ if (dev_data->domain)
+ detach_device(dev);
+
iommu_device_unlink(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
dev);
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 013bdfff2d4d..bf4959f4225b 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -228,6 +228,10 @@ static int amd_iommu_enable_interrupts(void);
static int __init iommu_go_to_state(enum iommu_init_state state);
static void init_device_table_dma(void);
+static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
+ u8 bank, u8 cntr, u8 fxn,
+ u64 *value, bool is_write);
+
static inline void update_last_devid(u16 devid)
{
if (devid > amd_iommu_last_bdf)
@@ -1016,6 +1020,34 @@ static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
}
/*
+ * Family15h Model 30h-3fh (IOMMU Mishandles ATS Write Permission)
+ * Workaround:
+ * BIOS should enable ATS write permission check by setting
+ * L2_DEBUG_3[AtsIgnoreIWDis](D0F2xF4_x47[0]) = 1b
+ */
+static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu)
+{
+ u32 value;
+
+ if ((boot_cpu_data.x86 != 0x15) ||
+ (boot_cpu_data.x86_model < 0x30) ||
+ (boot_cpu_data.x86_model > 0x3f))
+ return;
+
+ /* Test L2_DEBUG_3[AtsIgnoreIWDis] == 1 */
+ value = iommu_read_l2(iommu, 0x47);
+
+ if (value & BIT(0))
+ return;
+
+ /* Set L2_DEBUG_3[AtsIgnoreIWDis] = 1 */
+ iommu_write_l2(iommu, 0x47, value | BIT(0));
+
+ pr_info("AMD-Vi: Applying ATS write check workaround for IOMMU at %s\n",
+ dev_name(&iommu->dev->dev));
+}
+
+/*
* This function clues the initialization function for one IOMMU
* together and also allocates the command buffer and programs the
* hardware. It does NOT enable the IOMMU. This is done afterwards.
@@ -1142,8 +1174,8 @@ static void init_iommu_perf_ctr(struct amd_iommu *iommu)
amd_iommu_pc_present = true;
/* Check if the performance counters can be written to */
- if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) ||
- (0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) ||
+ if ((0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) ||
+ (0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) ||
(val != val2)) {
pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n");
amd_iommu_pc_present = false;
@@ -1284,6 +1316,7 @@ static int iommu_init_pci(struct amd_iommu *iommu)
}
amd_iommu_erratum_746_workaround(iommu);
+ amd_iommu_ats_write_check_workaround(iommu);
iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
amd_iommu_groups, "ivhd%d",
@@ -2283,22 +2316,15 @@ u8 amd_iommu_pc_get_max_counters(u16 devid)
}
EXPORT_SYMBOL(amd_iommu_pc_get_max_counters);
-int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
+static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
+ u8 bank, u8 cntr, u8 fxn,
u64 *value, bool is_write)
{
- struct amd_iommu *iommu;
u32 offset;
u32 max_offset_lim;
- /* Make sure the IOMMU PC resource is available */
- if (!amd_iommu_pc_present)
- return -ENODEV;
-
- /* Locate the iommu associated with the device ID */
- iommu = amd_iommu_rlookup_table[devid];
-
/* Check for valid iommu and pc register indexing */
- if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7)))
+ if (WARN_ON((fxn > 0x28) || (fxn & 7)))
return -ENODEV;
offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn);
@@ -2322,3 +2348,16 @@ int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
return 0;
}
EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val);
+
+int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
+ u64 *value, bool is_write)
+{
+ struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
+
+ /* Make sure the IOMMU PC resource is available */
+ if (!amd_iommu_pc_present || iommu == NULL)
+ return -ENODEV;
+
+ return iommu_pc_get_set_reg_val(iommu, bank, cntr, fxn,
+ value, is_write);
+}
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 62a400c5ba06..8ffd7568fc91 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -329,7 +329,8 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
/* Only care about add/remove events for physical functions */
if (pdev->is_virtfn)
return NOTIFY_DONE;
- if (action != BUS_NOTIFY_ADD_DEVICE && action != BUS_NOTIFY_DEL_DEVICE)
+ if (action != BUS_NOTIFY_ADD_DEVICE &&
+ action != BUS_NOTIFY_REMOVED_DEVICE)
return NOTIFY_DONE;
info = dmar_alloc_pci_notify_info(pdev, action);
@@ -339,7 +340,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
down_write(&dmar_global_lock);
if (action == BUS_NOTIFY_ADD_DEVICE)
dmar_pci_bus_add_dev(info);
- else if (action == BUS_NOTIFY_DEL_DEVICE)
+ else if (action == BUS_NOTIFY_REMOVED_DEVICE)
dmar_pci_bus_del_dev(info);
up_write(&dmar_global_lock);
@@ -1353,7 +1354,7 @@ void dmar_disable_qi(struct intel_iommu *iommu)
raw_spin_lock_irqsave(&iommu->register_lock, flags);
- sts = dmar_readq(iommu->reg + DMAR_GSTS_REG);
+ sts = readl(iommu->reg + DMAR_GSTS_REG);
if (!(sts & DMA_GSTS_QIES))
goto end;
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 986a53e3eb96..a2e1b7f14df2 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4367,7 +4367,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
rmrru->devices_cnt);
if(ret < 0)
return ret;
- } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
+ } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
dmar_remove_dev_scope(info, rmrr->segment,
rmrru->devices, rmrru->devices_cnt);
}
@@ -4387,7 +4387,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
break;
else if(ret < 0)
return ret;
- } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
+ } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
if (dmar_remove_dev_scope(info, atsr->segment,
atsru->devices, atsru->devices_cnt))
break;
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index 50464833d0b8..d9939fa9b588 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -249,12 +249,30 @@ static void intel_flush_pasid_dev(struct intel_svm *svm, struct intel_svm_dev *s
static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
{
struct intel_svm *svm = container_of(mn, struct intel_svm, notifier);
+ struct intel_svm_dev *sdev;
+ /* This might end up being called from exit_mmap(), *before* the page
+ * tables are cleared. And __mmu_notifier_release() will delete us from
+ * the list of notifiers so that our invalidate_range() callback doesn't
+ * get called when the page tables are cleared. So we need to protect
+ * against hardware accessing those page tables.
+ *
+ * We do it by clearing the entry in the PASID table and then flushing
+ * the IOTLB and the PASID table caches. This might upset hardware;
+ * perhaps we'll want to point the PASID to a dummy PGD (like the zero
+ * page) so that we end up taking a fault that the hardware really
+ * *has* to handle gracefully without affecting other processes.
+ */
svm->iommu->pasid_table[svm->pasid].val = 0;
+ wmb();
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdev, &svm->devs, list) {
+ intel_flush_pasid_dev(svm, sdev, svm->pasid);
+ intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm);
+ }
+ rcu_read_unlock();
- /* There's no need to do any flush because we can't get here if there
- * are any devices left anyway. */
- WARN_ON(!list_empty(&svm->devs));
}
static const struct mmu_notifier_ops intel_mmuops = {
@@ -379,7 +397,6 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
goto out;
}
iommu->pasid_table[svm->pasid].val = (u64)__pa(mm->pgd) | 1;
- mm = NULL;
} else
iommu->pasid_table[svm->pasid].val = (u64)__pa(init_mm.pgd) | 1 | (1ULL << 11);
wmb();
@@ -442,11 +459,11 @@ int intel_svm_unbind_mm(struct device *dev, int pasid)
kfree_rcu(sdev, rcu);
if (list_empty(&svm->devs)) {
- mmu_notifier_unregister(&svm->notifier, svm->mm);
idr_remove(&svm->iommu->pasid_idr, svm->pasid);
if (svm->mm)
- mmput(svm->mm);
+ mmu_notifier_unregister(&svm->notifier, svm->mm);
+
/* We mandate that no page faults may be outstanding
* for the PASID when intel_svm_unbind_mm() is called.
* If that is not obeyed, subtle errors will happen.
@@ -507,6 +524,10 @@ static irqreturn_t prq_event_thread(int irq, void *d)
struct intel_svm *svm = NULL;
int head, tail, handled = 0;
+ /* Clear PPR bit before reading head/tail registers, to
+ * ensure that we get a new interrupt if needed. */
+ writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG);
+
tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
while (head != tail) {
@@ -551,6 +572,9 @@ static irqreturn_t prq_event_thread(int irq, void *d)
* any faults on kernel addresses. */
if (!svm->mm)
goto bad_req;
+ /* If the mm is already defunct, don't handle faults. */
+ if (!atomic_inc_not_zero(&svm->mm->mm_users))
+ goto bad_req;
down_read(&svm->mm->mmap_sem);
vma = find_extend_vma(svm->mm, address);
if (!vma || address < vma->vm_start)
@@ -567,6 +591,7 @@ static irqreturn_t prq_event_thread(int irq, void *d)
result = QI_RESP_SUCCESS;
invalid:
up_read(&svm->mm->mmap_sem);
+ mmput(svm->mm);
bad_req:
/* Accounting for major/minor faults? */
rcu_read_lock();
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index c12ba4516df2..ac596928f6b4 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -629,7 +629,7 @@ static void iommu_disable_irq_remapping(struct intel_iommu *iommu)
raw_spin_lock_irqsave(&iommu->register_lock, flags);
- sts = dmar_readq(iommu->reg + DMAR_GSTS_REG);
+ sts = readl(iommu->reg + DMAR_GSTS_REG);
if (!(sts & DMA_GSTS_IRES))
goto end;
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index fb50911b3940..7e8c441ff2de 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -60,6 +60,17 @@ config ARM_VIC_NR
The maximum number of VICs available in the system, for
power management.
+config ARMADA_370_XP_IRQ
+ bool
+ select GENERIC_IRQ_CHIP
+ select PCI_MSI_IRQ_DOMAIN if PCI_MSI
+
+config ALPINE_MSI
+ bool
+ depends on PCI && PCI_MSI
+ select GENERIC_IRQ_CHIP
+ select PCI_MSI_IRQ_DOMAIN
+
config ATMEL_AIC_IRQ
bool
select GENERIC_IRQ_CHIP
@@ -78,6 +89,11 @@ config I8259
bool
select IRQ_DOMAIN
+config BCM6345_L1_IRQ
+ bool
+ select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+
config BCM7038_L1_IRQ
bool
select GENERIC_IRQ_CHIP
@@ -151,6 +167,11 @@ config ST_IRQCHIP
help
Enables SysCfg Controlled IRQs on STi based platforms.
+config TANGO_IRQ
+ bool
+ select IRQ_DOMAIN
+ select GENERIC_IRQ_CHIP
+
config TB10X_IRQC
bool
select IRQ_DOMAIN
@@ -160,6 +181,7 @@ config TS4800_IRQ
tristate "TS-4800 IRQ controller"
select IRQ_DOMAIN
depends on HAS_IOMEM
+ depends on SOC_IMX51 || COMPILE_TEST
help
Support for the TS-4800 FPGA IRQ controller
@@ -193,6 +215,8 @@ config KEYSTONE_IRQ
config MIPS_GIC
bool
+ select GENERIC_IRQ_IPI
+ select IRQ_DOMAIN_HIERARCHY
select MIPS_CM
config INGENIC_IRQ
@@ -218,3 +242,7 @@ config IRQ_MXS
def_bool y if MACH_ASM9260 || ARCH_MXS
select IRQ_DOMAIN
select STMP_DEVICE
+
+config MVEBU_ODMI
+ bool
+ select GENERIC_MSI_IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 18caacb60d58..b03cfcbbac6b 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -1,11 +1,13 @@
obj-$(CONFIG_IRQCHIP) += irqchip.o
+obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o
+obj-$(CONFIG_ATH79) += irq-ath79-cpu.o
+obj-$(CONFIG_ATH79) += irq-ath79-misc.o
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o
obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o
obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o
obj-$(CONFIG_ARCH_MMP) += irq-mmp.o
-obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o
obj-$(CONFIG_IRQ_MXS) += irq-mxs.o
obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o
obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
@@ -28,6 +30,7 @@ obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-g
obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
+obj-$(CONFIG_ARMADA_370_XP_IRQ) += irq-armada-370-xp.o
obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o
obj-$(CONFIG_ATMEL_AIC5_IRQ) += irq-atmel-aic-common.o irq-atmel-aic5.o
obj-$(CONFIG_I8259) += irq-i8259.o
@@ -40,12 +43,14 @@ obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o
obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
obj-$(CONFIG_ST_IRQCHIP) += irq-st.o
+obj-$(CONFIG_TANGO_IRQ) += irq-tango.o
obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o
obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o
+obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o
obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o
obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o
obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
@@ -59,3 +64,4 @@ obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o
obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o
obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o
obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o
+obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c
new file mode 100644
index 000000000000..25384255b30f
--- /dev/null
+++ b/drivers/irqchip/irq-alpine-msi.c
@@ -0,0 +1,293 @@
+/*
+ * Annapurna Labs MSIX support services
+ *
+ * Copyright (C) 2016, Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Antoine Tenart <antoine.tenart@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/irq.h>
+#include <asm-generic/msi.h>
+
+/* MSIX message address format: local GIC target */
+#define ALPINE_MSIX_SPI_TARGET_CLUSTER0 BIT(16)
+
+struct alpine_msix_data {
+ spinlock_t msi_map_lock;
+ phys_addr_t addr;
+ u32 spi_first; /* The SGI number that MSIs start */
+ u32 num_spis; /* The number of SGIs for MSIs */
+ unsigned long *msi_map;
+};
+
+static void alpine_msix_mask_msi_irq(struct irq_data *d)
+{
+ pci_msi_mask_irq(d);
+ irq_chip_mask_parent(d);
+}
+
+static void alpine_msix_unmask_msi_irq(struct irq_data *d)
+{
+ pci_msi_unmask_irq(d);
+ irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip alpine_msix_irq_chip = {
+ .name = "MSIx",
+ .irq_mask = alpine_msix_mask_msi_irq,
+ .irq_unmask = alpine_msix_unmask_msi_irq,
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+};
+
+static int alpine_msix_allocate_sgi(struct alpine_msix_data *priv, int num_req)
+{
+ int first;
+
+ spin_lock(&priv->msi_map_lock);
+
+ first = bitmap_find_next_zero_area(priv->msi_map, priv->num_spis, 0,
+ num_req, 0);
+ if (first >= priv->num_spis) {
+ spin_unlock(&priv->msi_map_lock);
+ return -ENOSPC;
+ }
+
+ bitmap_set(priv->msi_map, first, num_req);
+
+ spin_unlock(&priv->msi_map_lock);
+
+ return priv->spi_first + first;
+}
+
+static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned sgi,
+ int num_req)
+{
+ int first = sgi - priv->spi_first;
+
+ spin_lock(&priv->msi_map_lock);
+
+ bitmap_clear(priv->msi_map, first, num_req);
+
+ spin_unlock(&priv->msi_map_lock);
+}
+
+static void alpine_msix_compose_msi_msg(struct irq_data *data,
+ struct msi_msg *msg)
+{
+ struct alpine_msix_data *priv = irq_data_get_irq_chip_data(data);
+ phys_addr_t msg_addr = priv->addr;
+
+ msg_addr |= (data->hwirq << 3);
+
+ msg->address_hi = upper_32_bits(msg_addr);
+ msg->address_lo = lower_32_bits(msg_addr);
+ msg->data = 0;
+}
+
+static struct msi_domain_info alpine_msix_domain_info = {
+ .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_PCI_MSIX,
+ .chip = &alpine_msix_irq_chip,
+};
+
+static struct irq_chip middle_irq_chip = {
+ .name = "alpine_msix_middle",
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+ .irq_compose_msi_msg = alpine_msix_compose_msi_msg,
+};
+
+static int alpine_msix_gic_domain_alloc(struct irq_domain *domain,
+ unsigned int virq, int sgi)
+{
+ struct irq_fwspec fwspec;
+ struct irq_data *d;
+ int ret;
+
+ if (!is_of_node(domain->parent->fwnode))
+ return -EINVAL;
+
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 3;
+ fwspec.param[0] = 0;
+ fwspec.param[1] = sgi;
+ fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
+ if (ret)
+ return ret;
+
+ d = irq_domain_get_irq_data(domain->parent, virq);
+ d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING);
+
+ return 0;
+}
+
+static int alpine_msix_middle_domain_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs, void *args)
+{
+ struct alpine_msix_data *priv = domain->host_data;
+ int sgi, err, i;
+
+ sgi = alpine_msix_allocate_sgi(priv, nr_irqs);
+ if (sgi < 0)
+ return sgi;
+
+ for (i = 0; i < nr_irqs; i++) {
+ err = alpine_msix_gic_domain_alloc(domain, virq + i, sgi + i);
+ if (err)
+ goto err_sgi;
+
+ irq_domain_set_hwirq_and_chip(domain, virq + i, sgi + i,
+ &middle_irq_chip, priv);
+ }
+
+ return 0;
+
+err_sgi:
+ while (--i >= 0)
+ irq_domain_free_irqs_parent(domain, virq, i);
+ alpine_msix_free_sgi(priv, sgi, nr_irqs);
+ return err;
+}
+
+static void alpine_msix_middle_domain_free(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+ struct alpine_msix_data *priv = irq_data_get_irq_chip_data(d);
+
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+ alpine_msix_free_sgi(priv, d->hwirq, nr_irqs);
+}
+
+static const struct irq_domain_ops alpine_msix_middle_domain_ops = {
+ .alloc = alpine_msix_middle_domain_alloc,
+ .free = alpine_msix_middle_domain_free,
+};
+
+static int alpine_msix_init_domains(struct alpine_msix_data *priv,
+ struct device_node *node)
+{
+ struct irq_domain *middle_domain, *msi_domain, *gic_domain;
+ struct device_node *gic_node;
+
+ gic_node = of_irq_find_parent(node);
+ if (!gic_node) {
+ pr_err("Failed to find the GIC node\n");
+ return -ENODEV;
+ }
+
+ gic_domain = irq_find_host(gic_node);
+ if (!gic_domain) {
+ pr_err("Failed to find the GIC domain\n");
+ return -ENXIO;
+ }
+
+ middle_domain = irq_domain_add_tree(NULL,
+ &alpine_msix_middle_domain_ops,
+ priv);
+ if (!middle_domain) {
+ pr_err("Failed to create the MSIX middle domain\n");
+ return -ENOMEM;
+ }
+
+ middle_domain->parent = gic_domain;
+
+ msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node),
+ &alpine_msix_domain_info,
+ middle_domain);
+ if (!msi_domain) {
+ pr_err("Failed to create MSI domain\n");
+ irq_domain_remove(middle_domain);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int alpine_msix_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct alpine_msix_data *priv;
+ struct resource res;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ spin_lock_init(&priv->msi_map_lock);
+
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret) {
+ pr_err("Failed to allocate resource\n");
+ goto err_priv;
+ }
+
+ /*
+ * The 20 least significant bits of addr provide direct information
+ * regarding the interrupt destination.
+ *
+ * To select the primary GIC as the target GIC, bits [18:17] must be set
+ * to 0x0. In this case, bit 16 (SPI_TARGET_CLUSTER0) must be set.
+ */
+ priv->addr = res.start & GENMASK_ULL(63,20);
+ priv->addr |= ALPINE_MSIX_SPI_TARGET_CLUSTER0;
+
+ if (of_property_read_u32(node, "al,msi-base-spi", &priv->spi_first)) {
+ pr_err("Unable to parse MSI base\n");
+ ret = -EINVAL;
+ goto err_priv;
+ }
+
+ if (of_property_read_u32(node, "al,msi-num-spis", &priv->num_spis)) {
+ pr_err("Unable to parse MSI numbers\n");
+ ret = -EINVAL;
+ goto err_priv;
+ }
+
+ priv->msi_map = kzalloc(sizeof(*priv->msi_map) * BITS_TO_LONGS(priv->num_spis),
+ GFP_KERNEL);
+ if (!priv->msi_map) {
+ ret = -ENOMEM;
+ goto err_priv;
+ }
+
+ pr_debug("Registering %d msixs, starting at %d\n",
+ priv->num_spis, priv->spi_first);
+
+ ret = alpine_msix_init_domains(priv, node);
+ if (ret)
+ goto err_map;
+
+ return 0;
+
+err_map:
+ kfree(priv->msi_map);
+err_priv:
+ kfree(priv);
+ return ret;
+}
+IRQCHIP_DECLARE(alpine_msix, "al,alpine-msix", alpine_msix_init);
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 3f3a8c3d2175..e7dc6cbda2a1 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -71,6 +71,7 @@ static u32 doorbell_mask_reg;
static int parent_irq;
#ifdef CONFIG_PCI_MSI
static struct irq_domain *armada_370_xp_msi_domain;
+static struct irq_domain *armada_370_xp_msi_inner_domain;
static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
static DEFINE_MUTEX(msi_used_lock);
static phys_addr_t msi_doorbell_addr;
@@ -115,127 +116,102 @@ static void armada_370_xp_irq_unmask(struct irq_data *d)
#ifdef CONFIG_PCI_MSI
-static int armada_370_xp_alloc_msi(void)
-{
- int hwirq;
+static struct irq_chip armada_370_xp_msi_irq_chip = {
+ .name = "MPIC MSI",
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
+};
- mutex_lock(&msi_used_lock);
- hwirq = find_first_zero_bit(&msi_used, PCI_MSI_DOORBELL_NR);
- if (hwirq >= PCI_MSI_DOORBELL_NR)
- hwirq = -ENOSPC;
- else
- set_bit(hwirq, msi_used);
- mutex_unlock(&msi_used_lock);
+static struct msi_domain_info armada_370_xp_msi_domain_info = {
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_MULTI_PCI_MSI),
+ .chip = &armada_370_xp_msi_irq_chip,
+};
- return hwirq;
+static void armada_370_xp_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ msg->address_lo = lower_32_bits(msi_doorbell_addr);
+ msg->address_hi = upper_32_bits(msi_doorbell_addr);
+ msg->data = 0xf00 | (data->hwirq + PCI_MSI_DOORBELL_START);
}
-static void armada_370_xp_free_msi(int hwirq)
+static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
{
- mutex_lock(&msi_used_lock);
- if (!test_bit(hwirq, msi_used))
- pr_err("trying to free unused MSI#%d\n", hwirq);
- else
- clear_bit(hwirq, msi_used);
- mutex_unlock(&msi_used_lock);
+ return -EINVAL;
}
-static int armada_370_xp_setup_msi_irq(struct msi_controller *chip,
- struct pci_dev *pdev,
- struct msi_desc *desc)
-{
- struct msi_msg msg;
- int virq, hwirq;
+static struct irq_chip armada_370_xp_msi_bottom_irq_chip = {
+ .name = "MPIC MSI",
+ .irq_compose_msi_msg = armada_370_xp_compose_msi_msg,
+ .irq_set_affinity = armada_370_xp_msi_set_affinity,
+};
- /* We support MSI, but not MSI-X */
- if (desc->msi_attrib.is_msix)
- return -EINVAL;
+static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *args)
+{
+ int hwirq, i;
- hwirq = armada_370_xp_alloc_msi();
- if (hwirq < 0)
- return hwirq;
+ mutex_lock(&msi_used_lock);
- virq = irq_create_mapping(armada_370_xp_msi_domain, hwirq);
- if (!virq) {
- armada_370_xp_free_msi(hwirq);
- return -EINVAL;
+ hwirq = bitmap_find_next_zero_area(msi_used, PCI_MSI_DOORBELL_NR,
+ 0, nr_irqs, 0);
+ if (hwirq >= PCI_MSI_DOORBELL_NR) {
+ mutex_unlock(&msi_used_lock);
+ return -ENOSPC;
}
- irq_set_msi_desc(virq, desc);
-
- msg.address_lo = msi_doorbell_addr;
- msg.address_hi = 0;
- msg.data = 0xf00 | (hwirq + 16);
-
- pci_write_msi_msg(virq, &msg);
- return 0;
-}
+ bitmap_set(msi_used, hwirq, nr_irqs);
+ mutex_unlock(&msi_used_lock);
-static void armada_370_xp_teardown_msi_irq(struct msi_controller *chip,
- unsigned int irq)
-{
- struct irq_data *d = irq_get_irq_data(irq);
- unsigned long hwirq = d->hwirq;
+ for (i = 0; i < nr_irqs; i++) {
+ irq_domain_set_info(domain, virq + i, hwirq + i,
+ &armada_370_xp_msi_bottom_irq_chip,
+ domain->host_data, handle_simple_irq,
+ NULL, NULL);
+ }
- irq_dispose_mapping(irq);
- armada_370_xp_free_msi(hwirq);
+ return hwirq;
}
-static struct irq_chip armada_370_xp_msi_irq_chip = {
- .name = "armada_370_xp_msi_irq",
- .irq_enable = pci_msi_unmask_irq,
- .irq_disable = pci_msi_mask_irq,
- .irq_mask = pci_msi_mask_irq,
- .irq_unmask = pci_msi_unmask_irq,
-};
-
-static int armada_370_xp_msi_map(struct irq_domain *domain, unsigned int virq,
- irq_hw_number_t hw)
+static void armada_370_xp_msi_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
{
- irq_set_chip_and_handler(virq, &armada_370_xp_msi_irq_chip,
- handle_simple_irq);
+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
- return 0;
+ mutex_lock(&msi_used_lock);
+ bitmap_clear(msi_used, d->hwirq, nr_irqs);
+ mutex_unlock(&msi_used_lock);
}
-static const struct irq_domain_ops armada_370_xp_msi_irq_ops = {
- .map = armada_370_xp_msi_map,
+static const struct irq_domain_ops armada_370_xp_msi_domain_ops = {
+ .alloc = armada_370_xp_msi_alloc,
+ .free = armada_370_xp_msi_free,
};
static int armada_370_xp_msi_init(struct device_node *node,
phys_addr_t main_int_phys_base)
{
- struct msi_controller *msi_chip;
u32 reg;
- int ret;
msi_doorbell_addr = main_int_phys_base +
ARMADA_370_XP_SW_TRIG_INT_OFFS;
- msi_chip = kzalloc(sizeof(*msi_chip), GFP_KERNEL);
- if (!msi_chip)
+ armada_370_xp_msi_inner_domain =
+ irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR,
+ &armada_370_xp_msi_domain_ops, NULL);
+ if (!armada_370_xp_msi_inner_domain)
return -ENOMEM;
- msi_chip->setup_irq = armada_370_xp_setup_msi_irq;
- msi_chip->teardown_irq = armada_370_xp_teardown_msi_irq;
- msi_chip->of_node = node;
-
armada_370_xp_msi_domain =
- irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR,
- &armada_370_xp_msi_irq_ops,
- NULL);
+ pci_msi_create_irq_domain(of_node_to_fwnode(node),
+ &armada_370_xp_msi_domain_info,
+ armada_370_xp_msi_inner_domain);
if (!armada_370_xp_msi_domain) {
- kfree(msi_chip);
+ irq_domain_remove(armada_370_xp_msi_inner_domain);
return -ENOMEM;
}
- ret = of_pci_msi_chip_add(msi_chip);
- if (ret < 0) {
- irq_domain_remove(armada_370_xp_msi_domain);
- kfree(msi_chip);
- return ret;
- }
-
reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS)
| PCI_MSI_DOORBELL_MASK;
@@ -280,7 +256,7 @@ static int armada_xp_set_affinity(struct irq_data *d,
#endif
static struct irq_chip armada_370_xp_irq_chip = {
- .name = "armada_370_xp_irq",
+ .name = "MPIC",
.irq_mask = armada_370_xp_irq_mask,
.irq_mask_ack = armada_370_xp_irq_mask,
.irq_unmask = armada_370_xp_irq_unmask,
@@ -427,12 +403,12 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
continue;
if (is_chained) {
- irq = irq_find_mapping(armada_370_xp_msi_domain,
- msinr - 16);
+ irq = irq_find_mapping(armada_370_xp_msi_inner_domain,
+ msinr - PCI_MSI_DOORBELL_START);
generic_handle_irq(irq);
} else {
- irq = msinr - 16;
- handle_domain_irq(armada_370_xp_msi_domain,
+ irq = msinr - PCI_MSI_DOORBELL_START;
+ handle_domain_irq(armada_370_xp_msi_inner_domain,
irq, regs);
}
}
@@ -604,8 +580,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
armada_370_xp_mpic_domain =
irq_domain_add_linear(node, nr_irqs,
&armada_370_xp_mpic_irq_ops, NULL);
-
BUG_ON(!armada_370_xp_mpic_domain);
+ armada_370_xp_mpic_domain->bus_token = DOMAIN_BUS_WIRED;
/* Setup for the boot CPU */
armada_xp_mpic_perf_init();
diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c
new file mode 100644
index 000000000000..befe93c5a51a
--- /dev/null
+++ b/drivers/irqchip/irq-ath79-cpu.c
@@ -0,0 +1,97 @@
+/*
+ * Atheros AR71xx/AR724x/AR913x specific interrupt handling
+ *
+ * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
+ *
+ * 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 published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqchip.h>
+#include <linux/of.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mach-ath79/ath79.h>
+
+/*
+ * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for
+ * these devices typically allocate coherent DMA memory, however the
+ * DMA controller may still have some unsynchronized data in the FIFO.
+ * Issue a flush in the handlers to ensure that the driver sees
+ * the update.
+ *
+ * This array map the interrupt lines to the DDR write buffer channels.
+ */
+
+static unsigned irq_wb_chan[8] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned long pending;
+ int irq;
+
+ pending = read_c0_status() & read_c0_cause() & ST0_IM;
+
+ if (!pending) {
+ spurious_interrupt();
+ return;
+ }
+
+ pending >>= CAUSEB_IP;
+ while (pending) {
+ irq = fls(pending) - 1;
+ if (irq < ARRAY_SIZE(irq_wb_chan) && irq_wb_chan[irq] != -1)
+ ath79_ddr_wb_flush(irq_wb_chan[irq]);
+ do_IRQ(MIPS_CPU_IRQ_BASE + irq);
+ pending &= ~BIT(irq);
+ }
+}
+
+static int __init ar79_cpu_intc_of_init(
+ struct device_node *node, struct device_node *parent)
+{
+ int err, i, count;
+
+ /* Fill the irq_wb_chan table */
+ count = of_count_phandle_with_args(
+ node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells");
+
+ for (i = 0; i < count; i++) {
+ struct of_phandle_args args;
+ u32 irq = i;
+
+ of_property_read_u32_index(
+ node, "qca,ddr-wb-channel-interrupts", i, &irq);
+ if (irq >= ARRAY_SIZE(irq_wb_chan))
+ continue;
+
+ err = of_parse_phandle_with_args(
+ node, "qca,ddr-wb-channels",
+ "#qca,ddr-wb-channel-cells",
+ i, &args);
+ if (err)
+ return err;
+
+ irq_wb_chan[irq] = args.args[0];
+ }
+
+ return mips_cpu_irq_of_init(node, parent);
+}
+IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",
+ ar79_cpu_intc_of_init);
+
+void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3)
+{
+ irq_wb_chan[2] = irq_wb_chan2;
+ irq_wb_chan[3] = irq_wb_chan3;
+ mips_cpu_irq_init();
+}
diff --git a/drivers/irqchip/irq-ath79-misc.c b/drivers/irqchip/irq-ath79-misc.c
new file mode 100644
index 000000000000..aa7290784636
--- /dev/null
+++ b/drivers/irqchip/irq-ath79-misc.c
@@ -0,0 +1,189 @@
+/*
+ * Atheros AR71xx/AR724x/AR913x MISC interrupt controller
+ *
+ * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
+ *
+ * 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 published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define AR71XX_RESET_REG_MISC_INT_STATUS 0
+#define AR71XX_RESET_REG_MISC_INT_ENABLE 4
+
+#define ATH79_MISC_IRQ_COUNT 32
+
+static void ath79_misc_irq_handler(struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ void __iomem *base = domain->host_data;
+ u32 pending;
+
+ chained_irq_enter(chip, desc);
+
+ pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+ if (!pending) {
+ spurious_interrupt();
+ chained_irq_exit(chip, desc);
+ return;
+ }
+
+ while (pending) {
+ int bit = __ffs(pending);
+
+ generic_handle_irq(irq_linear_revmap(domain, bit));
+ pending &= ~BIT(bit);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void ar71xx_misc_irq_unmask(struct irq_data *d)
+{
+ void __iomem *base = irq_data_get_irq_chip_data(d);
+ unsigned int irq = d->hwirq;
+ u32 t;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+ __raw_writel(t | BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+}
+
+static void ar71xx_misc_irq_mask(struct irq_data *d)
+{
+ void __iomem *base = irq_data_get_irq_chip_data(d);
+ unsigned int irq = d->hwirq;
+ u32 t;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+ __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+}
+
+static void ar724x_misc_irq_ack(struct irq_data *d)
+{
+ void __iomem *base = irq_data_get_irq_chip_data(d);
+ unsigned int irq = d->hwirq;
+ u32 t;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
+ __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
+}
+
+static struct irq_chip ath79_misc_irq_chip = {
+ .name = "MISC",
+ .irq_unmask = ar71xx_misc_irq_unmask,
+ .irq_mask = ar71xx_misc_irq_mask,
+};
+
+static int misc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &ath79_misc_irq_chip, handle_level_irq);
+ irq_set_chip_data(irq, d->host_data);
+ return 0;
+}
+
+static const struct irq_domain_ops misc_irq_domain_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = misc_map,
+};
+
+static void __init ath79_misc_intc_domain_init(
+ struct irq_domain *domain, int irq)
+{
+ void __iomem *base = domain->host_data;
+
+ /* Disable and clear all interrupts */
+ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
+
+ irq_set_chained_handler_and_data(irq, ath79_misc_irq_handler, domain);
+}
+
+static int __init ath79_misc_intc_of_init(
+ struct device_node *node, struct device_node *parent)
+{
+ struct irq_domain *domain;
+ void __iomem *base;
+ int irq;
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (!irq) {
+ pr_err("Failed to get MISC IRQ\n");
+ return -EINVAL;
+ }
+
+ base = of_iomap(node, 0);
+ if (!base) {
+ pr_err("Failed to get MISC IRQ registers\n");
+ return -ENOMEM;
+ }
+
+ domain = irq_domain_add_linear(node, ATH79_MISC_IRQ_COUNT,
+ &misc_irq_domain_ops, base);
+ if (!domain) {
+ pr_err("Failed to add MISC irqdomain\n");
+ return -EINVAL;
+ }
+
+ ath79_misc_intc_domain_init(domain, irq);
+ return 0;
+}
+
+static int __init ar7100_misc_intc_of_init(
+ struct device_node *node, struct device_node *parent)
+{
+ ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
+ return ath79_misc_intc_of_init(node, parent);
+}
+
+IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc",
+ ar7100_misc_intc_of_init);
+
+static int __init ar7240_misc_intc_of_init(
+ struct device_node *node, struct device_node *parent)
+{
+ ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
+ return ath79_misc_intc_of_init(node, parent);
+}
+
+IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc",
+ ar7240_misc_intc_of_init);
+
+void __init ath79_misc_irq_init(void __iomem *regs, int irq,
+ int irq_base, bool is_ar71xx)
+{
+ struct irq_domain *domain;
+
+ if (is_ar71xx)
+ ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
+ else
+ ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
+
+ domain = irq_domain_add_legacy(NULL, ATH79_MISC_IRQ_COUNT,
+ irq_base, 0, &misc_irq_domain_ops, regs);
+ if (!domain)
+ panic("Failed to create MISC irqdomain");
+
+ ath79_misc_intc_domain_init(domain, irq);
+}
diff --git a/drivers/irqchip/irq-atmel-aic-common.c b/drivers/irqchip/irq-atmel-aic-common.c
index 37199b9b2cfa..28b26c80f4cf 100644
--- a/drivers/irqchip/irq-atmel-aic-common.c
+++ b/drivers/irqchip/irq-atmel-aic-common.c
@@ -80,16 +80,10 @@ int aic_common_set_type(struct irq_data *d, unsigned type, unsigned *val)
return 0;
}
-int aic_common_set_priority(int priority, unsigned *val)
+void aic_common_set_priority(int priority, unsigned *val)
{
- if (priority < AT91_AIC_IRQ_MIN_PRIORITY ||
- priority > AT91_AIC_IRQ_MAX_PRIORITY)
- return -EINVAL;
-
*val &= ~AT91_AIC_PRIOR;
*val |= priority;
-
- return 0;
}
int aic_common_irq_domain_xlate(struct irq_domain *d,
@@ -193,7 +187,7 @@ void __init aic_common_rtt_irq_fixup(struct device_node *root)
}
}
-void __init aic_common_irq_fixup(const struct of_device_id *matches)
+static void __init aic_common_irq_fixup(const struct of_device_id *matches)
{
struct device_node *root = of_find_node_by_path("/");
const struct of_device_id *match;
@@ -214,7 +208,8 @@ void __init aic_common_irq_fixup(const struct of_device_id *matches)
struct irq_domain *__init aic_common_of_init(struct device_node *node,
const struct irq_domain_ops *ops,
- const char *name, int nirqs)
+ const char *name, int nirqs,
+ const struct of_device_id *matches)
{
struct irq_chip_generic *gc;
struct irq_domain *domain;
@@ -264,6 +259,7 @@ struct irq_domain *__init aic_common_of_init(struct device_node *node,
}
aic_common_ext_irq_of_init(domain);
+ aic_common_irq_fixup(matches);
return domain;
diff --git a/drivers/irqchip/irq-atmel-aic-common.h b/drivers/irqchip/irq-atmel-aic-common.h
index 603f0a9d5411..af60376d50de 100644
--- a/drivers/irqchip/irq-atmel-aic-common.h
+++ b/drivers/irqchip/irq-atmel-aic-common.h
@@ -19,7 +19,7 @@
int aic_common_set_type(struct irq_data *d, unsigned type, unsigned *val);
-int aic_common_set_priority(int priority, unsigned *val);
+void aic_common_set_priority(int priority, unsigned *val);
int aic_common_irq_domain_xlate(struct irq_domain *d,
struct device_node *ctrlr,
@@ -30,12 +30,11 @@ int aic_common_irq_domain_xlate(struct irq_domain *d,
struct irq_domain *__init aic_common_of_init(struct device_node *node,
const struct irq_domain_ops *ops,
- const char *name, int nirqs);
+ const char *name, int nirqs,
+ const struct of_device_id *matches);
void __init aic_common_rtc_irq_fixup(struct device_node *root);
void __init aic_common_rtt_irq_fixup(struct device_node *root);
-void __init aic_common_irq_fixup(const struct of_device_id *matches);
-
#endif /* __IRQ_ATMEL_AIC_COMMON_H */
diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c
index 8a0c7f288198..112e17c2768b 100644
--- a/drivers/irqchip/irq-atmel-aic.c
+++ b/drivers/irqchip/irq-atmel-aic.c
@@ -196,9 +196,8 @@ static int aic_irq_domain_xlate(struct irq_domain *d,
irq_gc_lock(gc);
smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq));
- ret = aic_common_set_priority(intspec[2], &smr);
- if (!ret)
- irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq));
+ aic_common_set_priority(intspec[2], &smr);
+ irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq));
irq_gc_unlock(gc);
return ret;
@@ -248,12 +247,10 @@ static int __init aic_of_init(struct device_node *node,
return -EEXIST;
domain = aic_common_of_init(node, &aic_irq_ops, "atmel-aic",
- NR_AIC_IRQS);
+ NR_AIC_IRQS, aic_irq_fixups);
if (IS_ERR(domain))
return PTR_ERR(domain);
- aic_common_irq_fixup(aic_irq_fixups);
-
aic_domain = domain;
gc = irq_get_domain_generic_chip(domain, 0);
diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c
index 62bb840c613f..4f0d068e1abe 100644
--- a/drivers/irqchip/irq-atmel-aic5.c
+++ b/drivers/irqchip/irq-atmel-aic5.c
@@ -272,9 +272,8 @@ static int aic5_irq_domain_xlate(struct irq_domain *d,
irq_gc_lock(bgc);
irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR);
smr = irq_reg_readl(bgc, AT91_AIC5_SMR);
- ret = aic_common_set_priority(intspec[2], &smr);
- if (!ret)
- irq_reg_writel(bgc, intspec[2] | smr, AT91_AIC5_SMR);
+ aic_common_set_priority(intspec[2], &smr);
+ irq_reg_writel(bgc, smr, AT91_AIC5_SMR);
irq_gc_unlock(bgc);
return ret;
@@ -312,12 +311,10 @@ static int __init aic5_of_init(struct device_node *node,
return -EEXIST;
domain = aic_common_of_init(node, &aic5_irq_ops, "atmel-aic5",
- nirqs);
+ nirqs, aic5_irq_fixups);
if (IS_ERR(domain))
return PTR_ERR(domain);
- aic_common_irq_fixup(aic5_irq_fixups);
-
aic5_domain = domain;
nchips = aic5_domain->revmap_size / 32;
for (i = 0; i < nchips; i++) {
diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
index 963065a0d774..b6e950d4782a 100644
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -229,7 +229,6 @@ int __init bcm2836_smp_boot_secondary(unsigned int cpu,
unsigned long secondary_startup_phys =
(unsigned long)virt_to_phys((void *)secondary_startup);
- dsb();
writel(secondary_startup_phys,
intc.base + LOCAL_MAILBOX3_SET0 + 16 * cpu);
diff --git a/drivers/irqchip/irq-bcm6345-l1.c b/drivers/irqchip/irq-bcm6345-l1.c
new file mode 100644
index 000000000000..b844c89a9506
--- /dev/null
+++ b/drivers/irqchip/irq-bcm6345-l1.c
@@ -0,0 +1,364 @@
+/*
+ * Broadcom BCM6345 style Level 1 interrupt controller driver
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ * Copyright 2015 Simon Arlott
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This is based on the BCM7038 (which supports SMP) but with a single
+ * enable register instead of separate mask/set/clear registers.
+ *
+ * The BCM3380 has a similar mask/status register layout, but each pair
+ * of words is at separate locations (and SMP is not supported).
+ *
+ * ENABLE/STATUS words are packed next to each other for each CPU:
+ *
+ * BCM6368:
+ * 0x1000_0020: CPU0_W0_ENABLE
+ * 0x1000_0024: CPU0_W1_ENABLE
+ * 0x1000_0028: CPU0_W0_STATUS IRQs 31-63
+ * 0x1000_002c: CPU0_W1_STATUS IRQs 0-31
+ * 0x1000_0030: CPU1_W0_ENABLE
+ * 0x1000_0034: CPU1_W1_ENABLE
+ * 0x1000_0038: CPU1_W0_STATUS IRQs 31-63
+ * 0x1000_003c: CPU1_W1_STATUS IRQs 0-31
+ *
+ * BCM63168:
+ * 0x1000_0020: CPU0_W0_ENABLE
+ * 0x1000_0024: CPU0_W1_ENABLE
+ * 0x1000_0028: CPU0_W2_ENABLE
+ * 0x1000_002c: CPU0_W3_ENABLE
+ * 0x1000_0030: CPU0_W0_STATUS IRQs 96-127
+ * 0x1000_0034: CPU0_W1_STATUS IRQs 64-95
+ * 0x1000_0038: CPU0_W2_STATUS IRQs 32-63
+ * 0x1000_003c: CPU0_W3_STATUS IRQs 0-31
+ * 0x1000_0040: CPU1_W0_ENABLE
+ * 0x1000_0044: CPU1_W1_ENABLE
+ * 0x1000_0048: CPU1_W2_ENABLE
+ * 0x1000_004c: CPU1_W3_ENABLE
+ * 0x1000_0050: CPU1_W0_STATUS IRQs 96-127
+ * 0x1000_0054: CPU1_W1_STATUS IRQs 64-95
+ * 0x1000_0058: CPU1_W2_STATUS IRQs 32-63
+ * 0x1000_005c: CPU1_W3_STATUS IRQs 0-31
+ *
+ * IRQs are numbered in CPU native endian order
+ * (which is big-endian in these examples)
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/cpumask.h>
+#include <linux/kconfig.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+
+#define IRQS_PER_WORD 32
+#define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 2)
+
+struct bcm6345_l1_cpu;
+
+struct bcm6345_l1_chip {
+ raw_spinlock_t lock;
+ unsigned int n_words;
+ struct irq_domain *domain;
+ struct cpumask cpumask;
+ struct bcm6345_l1_cpu *cpus[NR_CPUS];
+};
+
+struct bcm6345_l1_cpu {
+ void __iomem *map_base;
+ unsigned int parent_irq;
+ u32 enable_cache[];
+};
+
+static inline unsigned int reg_enable(struct bcm6345_l1_chip *intc,
+ unsigned int word)
+{
+#ifdef __BIG_ENDIAN
+ return (1 * intc->n_words - word - 1) * sizeof(u32);
+#else
+ return (0 * intc->n_words + word) * sizeof(u32);
+#endif
+}
+
+static inline unsigned int reg_status(struct bcm6345_l1_chip *intc,
+ unsigned int word)
+{
+#ifdef __BIG_ENDIAN
+ return (2 * intc->n_words - word - 1) * sizeof(u32);
+#else
+ return (1 * intc->n_words + word) * sizeof(u32);
+#endif
+}
+
+static inline unsigned int cpu_for_irq(struct bcm6345_l1_chip *intc,
+ struct irq_data *d)
+{
+ return cpumask_first_and(&intc->cpumask, irq_data_get_affinity_mask(d));
+}
+
+static void bcm6345_l1_irq_handle(struct irq_desc *desc)
+{
+ struct bcm6345_l1_chip *intc = irq_desc_get_handler_data(desc);
+ struct bcm6345_l1_cpu *cpu;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned int idx;
+
+#ifdef CONFIG_SMP
+ cpu = intc->cpus[cpu_logical_map(smp_processor_id())];
+#else
+ cpu = intc->cpus[0];
+#endif
+
+ chained_irq_enter(chip, desc);
+
+ for (idx = 0; idx < intc->n_words; idx++) {
+ int base = idx * IRQS_PER_WORD;
+ unsigned long pending;
+ irq_hw_number_t hwirq;
+ unsigned int irq;
+
+ pending = __raw_readl(cpu->map_base + reg_status(intc, idx));
+ pending &= __raw_readl(cpu->map_base + reg_enable(intc, idx));
+
+ for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
+ irq = irq_linear_revmap(intc->domain, base + hwirq);
+ if (irq)
+ do_IRQ(irq);
+ else
+ spurious_interrupt();
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static inline void __bcm6345_l1_unmask(struct irq_data *d)
+{
+ struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ u32 word = d->hwirq / IRQS_PER_WORD;
+ u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
+ unsigned int cpu_idx = cpu_for_irq(intc, d);
+
+ intc->cpus[cpu_idx]->enable_cache[word] |= mask;
+ __raw_writel(intc->cpus[cpu_idx]->enable_cache[word],
+ intc->cpus[cpu_idx]->map_base + reg_enable(intc, word));
+}
+
+static inline void __bcm6345_l1_mask(struct irq_data *d)
+{
+ struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ u32 word = d->hwirq / IRQS_PER_WORD;
+ u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
+ unsigned int cpu_idx = cpu_for_irq(intc, d);
+
+ intc->cpus[cpu_idx]->enable_cache[word] &= ~mask;
+ __raw_writel(intc->cpus[cpu_idx]->enable_cache[word],
+ intc->cpus[cpu_idx]->map_base + reg_enable(intc, word));
+}
+
+static void bcm6345_l1_unmask(struct irq_data *d)
+{
+ struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&intc->lock, flags);
+ __bcm6345_l1_unmask(d);
+ raw_spin_unlock_irqrestore(&intc->lock, flags);
+}
+
+static void bcm6345_l1_mask(struct irq_data *d)
+{
+ struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&intc->lock, flags);
+ __bcm6345_l1_mask(d);
+ raw_spin_unlock_irqrestore(&intc->lock, flags);
+}
+
+static int bcm6345_l1_set_affinity(struct irq_data *d,
+ const struct cpumask *dest,
+ bool force)
+{
+ struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ u32 word = d->hwirq / IRQS_PER_WORD;
+ u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
+ unsigned int old_cpu = cpu_for_irq(intc, d);
+ unsigned int new_cpu;
+ struct cpumask valid;
+ unsigned long flags;
+ bool enabled;
+
+ if (!cpumask_and(&valid, &intc->cpumask, dest))
+ return -EINVAL;
+
+ new_cpu = cpumask_any_and(&valid, cpu_online_mask);
+ if (new_cpu >= nr_cpu_ids)
+ return -EINVAL;
+
+ dest = cpumask_of(new_cpu);
+
+ raw_spin_lock_irqsave(&intc->lock, flags);
+ if (old_cpu != new_cpu) {
+ enabled = intc->cpus[old_cpu]->enable_cache[word] & mask;
+ if (enabled)
+ __bcm6345_l1_mask(d);
+ cpumask_copy(irq_data_get_affinity_mask(d), dest);
+ if (enabled)
+ __bcm6345_l1_unmask(d);
+ } else {
+ cpumask_copy(irq_data_get_affinity_mask(d), dest);
+ }
+ raw_spin_unlock_irqrestore(&intc->lock, flags);
+
+ return IRQ_SET_MASK_OK_NOCOPY;
+}
+
+static int __init bcm6345_l1_init_one(struct device_node *dn,
+ unsigned int idx,
+ struct bcm6345_l1_chip *intc)
+{
+ struct resource res;
+ resource_size_t sz;
+ struct bcm6345_l1_cpu *cpu;
+ unsigned int i, n_words;
+
+ if (of_address_to_resource(dn, idx, &res))
+ return -EINVAL;
+ sz = resource_size(&res);
+ n_words = sz / REG_BYTES_PER_IRQ_WORD;
+
+ if (!intc->n_words)
+ intc->n_words = n_words;
+ else if (intc->n_words != n_words)
+ return -EINVAL;
+
+ cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32),
+ GFP_KERNEL);
+ if (!cpu)
+ return -ENOMEM;
+
+ cpu->map_base = ioremap(res.start, sz);
+ if (!cpu->map_base)
+ return -ENOMEM;
+
+ for (i = 0; i < n_words; i++) {
+ cpu->enable_cache[i] = 0;
+ __raw_writel(0, cpu->map_base + reg_enable(intc, i));
+ }
+
+ cpu->parent_irq = irq_of_parse_and_map(dn, idx);
+ if (!cpu->parent_irq) {
+ pr_err("failed to map parent interrupt %d\n", cpu->parent_irq);
+ return -EINVAL;
+ }
+ irq_set_chained_handler_and_data(cpu->parent_irq,
+ bcm6345_l1_irq_handle, intc);
+
+ return 0;
+}
+
+static struct irq_chip bcm6345_l1_irq_chip = {
+ .name = "bcm6345-l1",
+ .irq_mask = bcm6345_l1_mask,
+ .irq_unmask = bcm6345_l1_unmask,
+ .irq_set_affinity = bcm6345_l1_set_affinity,
+};
+
+static int bcm6345_l1_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw_irq)
+{
+ irq_set_chip_and_handler(virq,
+ &bcm6345_l1_irq_chip, handle_percpu_irq);
+ irq_set_chip_data(virq, d->host_data);
+ return 0;
+}
+
+static const struct irq_domain_ops bcm6345_l1_domain_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = bcm6345_l1_map,
+};
+
+static int __init bcm6345_l1_of_init(struct device_node *dn,
+ struct device_node *parent)
+{
+ struct bcm6345_l1_chip *intc;
+ unsigned int idx;
+ int ret;
+
+ intc = kzalloc(sizeof(*intc), GFP_KERNEL);
+ if (!intc)
+ return -ENOMEM;
+
+ for_each_possible_cpu(idx) {
+ ret = bcm6345_l1_init_one(dn, idx, intc);
+ if (ret)
+ pr_err("failed to init intc L1 for cpu %d: %d\n",
+ idx, ret);
+ else
+ cpumask_set_cpu(idx, &intc->cpumask);
+ }
+
+ if (!cpumask_weight(&intc->cpumask)) {
+ ret = -ENODEV;
+ goto out_free;
+ }
+
+ raw_spin_lock_init(&intc->lock);
+
+ intc->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * intc->n_words,
+ &bcm6345_l1_domain_ops,
+ intc);
+ if (!intc->domain) {
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+
+ pr_info("registered BCM6345 L1 intc (IRQs: %d)\n",
+ IRQS_PER_WORD * intc->n_words);
+ for_each_cpu(idx, &intc->cpumask) {
+ struct bcm6345_l1_cpu *cpu = intc->cpus[idx];
+
+ pr_info(" CPU%u at MMIO 0x%p (irq = %d)\n", idx,
+ cpu->map_base, cpu->parent_irq);
+ }
+
+ return 0;
+
+out_unmap:
+ for_each_possible_cpu(idx) {
+ struct bcm6345_l1_cpu *cpu = intc->cpus[idx];
+
+ if (cpu) {
+ if (cpu->map_base)
+ iounmap(cpu->map_base);
+ kfree(cpu);
+ }
+ }
+out_free:
+ kfree(intc);
+ return ret;
+}
+
+IRQCHIP_DECLARE(bcm6345_l1, "brcm,bcm6345-l1-intc", bcm6345_l1_of_init);
diff --git a/drivers/irqchip/irq-gic-realview.c b/drivers/irqchip/irq-gic-realview.c
index aa46eb280a7f..54c296401525 100644
--- a/drivers/irqchip/irq-gic-realview.c
+++ b/drivers/irqchip/irq-gic-realview.c
@@ -10,7 +10,8 @@
#include <linux/irqchip/arm-gic.h>
#define REALVIEW_SYS_LOCK_OFFSET 0x20
-#define REALVIEW_PB11MP_SYS_PLD_CTRL1 0x74
+#define REALVIEW_SYS_PLD_CTRL1 0x74
+#define REALVIEW_EB_REVB_SYS_PLD_CTRL1 0xD8
#define VERSATILE_LOCK_VAL 0xA05F
#define PLD_INTMODE_MASK BIT(22)|BIT(23)|BIT(24)
#define PLD_INTMODE_LEGACY 0x0
@@ -18,26 +19,57 @@
#define PLD_INTMODE_NEW_NO_DCC BIT(23)
#define PLD_INTMODE_FIQ_ENABLE BIT(24)
+/* For some reason RealView EB Rev B moved this register */
+static const struct of_device_id syscon_pldset_of_match[] = {
+ {
+ .compatible = "arm,realview-eb11mp-revb-syscon",
+ .data = (void *)REALVIEW_EB_REVB_SYS_PLD_CTRL1,
+ },
+ {
+ .compatible = "arm,realview-eb11mp-revc-syscon",
+ .data = (void *)REALVIEW_SYS_PLD_CTRL1,
+ },
+ {
+ .compatible = "arm,realview-eb-syscon",
+ .data = (void *)REALVIEW_SYS_PLD_CTRL1,
+ },
+ {
+ .compatible = "arm,realview-pb11mp-syscon",
+ .data = (void *)REALVIEW_SYS_PLD_CTRL1,
+ },
+ {},
+};
+
static int __init
realview_gic_of_init(struct device_node *node, struct device_node *parent)
{
static struct regmap *map;
+ struct device_node *np;
+ const struct of_device_id *gic_id;
+ u32 pld1_ctrl;
+
+ np = of_find_matching_node_and_match(NULL, syscon_pldset_of_match,
+ &gic_id);
+ if (!np)
+ return -ENODEV;
+ pld1_ctrl = (u32)gic_id->data;
/* The PB11MPCore GIC needs to be configured in the syscon */
- map = syscon_regmap_lookup_by_compatible("arm,realview-pb11mp-syscon");
+ map = syscon_node_to_regmap(np);
if (!IS_ERR(map)) {
/* new irq mode with no DCC */
regmap_write(map, REALVIEW_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
- regmap_update_bits(map, REALVIEW_PB11MP_SYS_PLD_CTRL1,
+ regmap_update_bits(map, pld1_ctrl,
PLD_INTMODE_NEW_NO_DCC,
PLD_INTMODE_MASK);
regmap_write(map, REALVIEW_SYS_LOCK_OFFSET, 0x0000);
- pr_info("TC11MP GIC: set up interrupt controller to NEW mode, no DCC\n");
+ pr_info("RealView GIC: set up interrupt controller to NEW mode, no DCC\n");
} else {
- pr_err("TC11MP GIC setup: could not find syscon\n");
- return -ENXIO;
+ pr_err("RealView GIC setup: could not find syscon\n");
+ return -ENODEV;
}
return gic_of_init(node, parent);
}
IRQCHIP_DECLARE(armtc11mp_gic, "arm,tc11mp-gic", realview_gic_of_init);
+IRQCHIP_DECLARE(armeb11mp_gic, "arm,eb11mp-gic", realview_gic_of_init);
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index c779f83e511d..28f047c61baa 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -92,18 +92,6 @@ static struct msi_domain_info gicv2m_msi_domain_info = {
.chip = &gicv2m_msi_irq_chip,
};
-static int gicv2m_set_affinity(struct irq_data *irq_data,
- const struct cpumask *mask, bool force)
-{
- int ret;
-
- ret = irq_chip_set_affinity_parent(irq_data, mask, force);
- if (ret == IRQ_SET_MASK_OK)
- ret = IRQ_SET_MASK_OK_DONE;
-
- return ret;
-}
-
static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
struct v2m_data *v2m = irq_data_get_irq_chip_data(data);
@@ -122,7 +110,7 @@ static struct irq_chip gicv2m_irq_chip = {
.irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent,
.irq_eoi = irq_chip_eoi_parent,
- .irq_set_affinity = gicv2m_set_affinity,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
.irq_compose_msi_msg = gicv2m_compose_msi_msg,
};
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 0a73632b28d5..39261798c59f 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -78,6 +78,9 @@ struct its_node {
#define ITS_ITT_ALIGN SZ_256
+/* Convert page order to size in bytes */
+#define PAGE_ORDER_TO_SIZE(o) (PAGE_SIZE << (o))
+
struct event_lpi_map {
unsigned long *lpi_map;
u16 *col_map;
@@ -100,7 +103,6 @@ struct its_device {
static LIST_HEAD(its_nodes);
static DEFINE_SPINLOCK(its_lock);
-static struct device_node *gic_root_node;
static struct rdists *gic_rdists;
#define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist))
@@ -600,11 +602,6 @@ static void its_unmask_irq(struct irq_data *d)
lpi_set_config(d, true);
}
-static void its_eoi_irq(struct irq_data *d)
-{
- gic_write_eoir(d->hwirq);
-}
-
static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
bool force)
{
@@ -641,7 +638,7 @@ static struct irq_chip its_irq_chip = {
.name = "ITS",
.irq_mask = its_mask_irq,
.irq_unmask = its_unmask_irq,
- .irq_eoi = its_eoi_irq,
+ .irq_eoi = irq_chip_eoi_parent,
.irq_set_affinity = its_set_affinity,
.irq_compose_msi_msg = its_irq_compose_msi_msg,
};
@@ -673,7 +670,7 @@ static int its_chunk_to_lpi(int chunk)
return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
}
-static int its_lpi_init(u32 id_bits)
+static int __init its_lpi_init(u32 id_bits)
{
lpi_chunks = its_lpi_to_chunk(1UL << id_bits);
@@ -846,7 +843,6 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
u64 type = GITS_BASER_TYPE(val);
u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
int order = get_order(psz);
- int alloc_size;
int alloc_pages;
u64 tmp;
void *base;
@@ -878,9 +874,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
}
}
- alloc_size = (1 << order) * PAGE_SIZE;
retry_alloc_baser:
- alloc_pages = (alloc_size / psz);
+ alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz);
if (alloc_pages > GITS_BASER_PAGES_MAX) {
alloc_pages = GITS_BASER_PAGES_MAX;
order = get_order(GITS_BASER_PAGES_MAX * psz);
@@ -933,7 +928,7 @@ retry_baser:
shr = tmp & GITS_BASER_SHAREABILITY_MASK;
if (!shr) {
cache = GITS_BASER_nC;
- __flush_dcache_area(base, alloc_size);
+ __flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order));
}
goto retry_baser;
}
@@ -966,7 +961,7 @@ retry_baser:
}
pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
- (int)(alloc_size / entry_size),
+ (int)(PAGE_ORDER_TO_SIZE(order) / entry_size),
its_base_type_string[type],
(unsigned long)virt_to_phys(base),
psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
@@ -1434,7 +1429,8 @@ static void its_enable_quirks(struct its_node *its)
gic_enable_quirks(iidr, its_quirks, its);
}
-static int its_probe(struct device_node *node, struct irq_domain *parent)
+static int __init its_probe(struct device_node *node,
+ struct irq_domain *parent)
{
struct resource res;
struct its_node *its;
@@ -1595,7 +1591,7 @@ static struct of_device_id its_device_id[] = {
{},
};
-int its_init(struct device_node *node, struct rdists *rdists,
+int __init its_init(struct device_node *node, struct rdists *rdists,
struct irq_domain *parent_domain)
{
struct device_node *np;
@@ -1611,8 +1607,6 @@ int its_init(struct device_node *node, struct rdists *rdists,
}
gic_rdists = rdists;
- gic_root_node = node;
-
its_alloc_lpi_tables();
its_lpi_init(rdists->id_bits);
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index d7be6ddc34f6..5b7d3c2129d8 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -15,10 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/cpu_pm.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -38,6 +40,7 @@
struct redist_region {
void __iomem *redist_base;
phys_addr_t phys_base;
+ bool single_redist;
};
struct gic_chip_data {
@@ -434,6 +437,9 @@ static int gic_populate_rdist(void)
return 0;
}
+ if (gic_data.redist_regions[i].single_redist)
+ break;
+
if (gic_data.redist_stride) {
ptr += gic_data.redist_stride;
} else {
@@ -634,7 +640,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
else
gic_dist_wait_for_rwp();
- return IRQ_SET_MASK_OK;
+ return IRQ_SET_MASK_OK_DONE;
}
#else
#define gic_set_affinity NULL
@@ -764,6 +770,15 @@ static int gic_irq_domain_translate(struct irq_domain *d,
return 0;
}
+ if (is_fwnode_irqchip(fwspec->fwnode)) {
+ if(fwspec->param_count != 2)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[1];
+ return 0;
+ }
+
return -EINVAL;
}
@@ -811,17 +826,88 @@ static void gicv3_enable_quirks(void)
#endif
}
+static int __init gic_init_bases(void __iomem *dist_base,
+ struct redist_region *rdist_regs,
+ u32 nr_redist_regions,
+ u64 redist_stride,
+ struct fwnode_handle *handle)
+{
+ struct device_node *node;
+ u32 typer;
+ int gic_irqs;
+ int err;
+
+ if (!is_hyp_mode_available())
+ static_key_slow_dec(&supports_deactivate);
+
+ if (static_key_true(&supports_deactivate))
+ pr_info("GIC: Using split EOI/Deactivate mode\n");
+
+ gic_data.dist_base = dist_base;
+ gic_data.redist_regions = rdist_regs;
+ gic_data.nr_redist_regions = nr_redist_regions;
+ gic_data.redist_stride = redist_stride;
+
+ gicv3_enable_quirks();
+
+ /*
+ * Find out how many interrupts are supported.
+ * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
+ */
+ typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
+ gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
+ gic_irqs = GICD_TYPER_IRQS(typer);
+ if (gic_irqs > 1020)
+ gic_irqs = 1020;
+ gic_data.irq_nr = gic_irqs;
+
+ gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
+ &gic_data);
+ gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
+
+ if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ set_handle_irq(gic_handle_irq);
+
+ node = to_of_node(handle);
+ if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
+ node) /* Temp hack to prevent ITS init for ACPI */
+ its_init(node, &gic_data.rdists, gic_data.domain);
+
+ gic_smp_init();
+ gic_dist_init();
+ gic_cpu_init();
+ gic_cpu_pm_init();
+
+ return 0;
+
+out_free:
+ if (gic_data.domain)
+ irq_domain_remove(gic_data.domain);
+ free_percpu(gic_data.rdists.rdist);
+ return err;
+}
+
+static int __init gic_validate_dist_version(void __iomem *dist_base)
+{
+ u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
+
+ if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4)
+ return -ENODEV;
+
+ return 0;
+}
+
static int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
void __iomem *dist_base;
struct redist_region *rdist_regs;
u64 redist_stride;
u32 nr_redist_regions;
- u32 typer;
- u32 reg;
- int gic_irqs;
- int err;
- int i;
+ int err, i;
dist_base = of_iomap(node, 0);
if (!dist_base) {
@@ -830,11 +916,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
return -ENXIO;
}
- reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
- if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
+ err = gic_validate_dist_version(dist_base);
+ if (err) {
pr_err("%s: no distributor detected, giving up\n",
node->full_name);
- err = -ENODEV;
goto out_unmap_dist;
}
@@ -865,63 +950,229 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
redist_stride = 0;
- if (!is_hyp_mode_available())
- static_key_slow_dec(&supports_deactivate);
+ err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
+ redist_stride, &node->fwnode);
+ if (!err)
+ return 0;
- if (static_key_true(&supports_deactivate))
- pr_info("GIC: Using split EOI/Deactivate mode\n");
+out_unmap_rdist:
+ for (i = 0; i < nr_redist_regions; i++)
+ if (rdist_regs[i].redist_base)
+ iounmap(rdist_regs[i].redist_base);
+ kfree(rdist_regs);
+out_unmap_dist:
+ iounmap(dist_base);
+ return err;
+}
- gic_data.dist_base = dist_base;
- gic_data.redist_regions = rdist_regs;
- gic_data.nr_redist_regions = nr_redist_regions;
- gic_data.redist_stride = redist_stride;
+IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
- gicv3_enable_quirks();
+#ifdef CONFIG_ACPI
+static void __iomem *dist_base;
+static struct redist_region *redist_regs __initdata;
+static u32 nr_redist_regions __initdata;
+static bool single_redist;
+
+static void __init
+gic_acpi_register_redist(phys_addr_t phys_base, void __iomem *redist_base)
+{
+ static int count = 0;
+
+ redist_regs[count].phys_base = phys_base;
+ redist_regs[count].redist_base = redist_base;
+ redist_regs[count].single_redist = single_redist;
+ count++;
+}
+
+static int __init
+gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_redistributor *redist =
+ (struct acpi_madt_generic_redistributor *)header;
+ void __iomem *redist_base;
+
+ redist_base = ioremap(redist->base_address, redist->length);
+ if (!redist_base) {
+ pr_err("Couldn't map GICR region @%llx\n", redist->base_address);
+ return -ENOMEM;
+ }
+
+ gic_acpi_register_redist(redist->base_address, redist_base);
+ return 0;
+}
+
+static int __init
+gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_interrupt *gicc =
+ (struct acpi_madt_generic_interrupt *)header;
+ u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
+ u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
+ void __iomem *redist_base;
+
+ redist_base = ioremap(gicc->gicr_base_address, size);
+ if (!redist_base)
+ return -ENOMEM;
+
+ gic_acpi_register_redist(gicc->gicr_base_address, redist_base);
+ return 0;
+}
+
+static int __init gic_acpi_collect_gicr_base(void)
+{
+ acpi_tbl_entry_handler redist_parser;
+ enum acpi_madt_type type;
+
+ if (single_redist) {
+ type = ACPI_MADT_TYPE_GENERIC_INTERRUPT;
+ redist_parser = gic_acpi_parse_madt_gicc;
+ } else {
+ type = ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR;
+ redist_parser = gic_acpi_parse_madt_redist;
+ }
+
+ /* Collect redistributor base addresses in GICR entries */
+ if (acpi_table_parse_madt(type, redist_parser, 0) > 0)
+ return 0;
+
+ pr_info("No valid GICR entries exist\n");
+ return -ENODEV;
+}
+
+static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ /* Subtable presence means that redist exists, that's it */
+ return 0;
+}
+
+static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_interrupt *gicc =
+ (struct acpi_madt_generic_interrupt *)header;
/*
- * Find out how many interrupts are supported.
- * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
+ * If GICC is enabled and has valid gicr base address, then it means
+ * GICR base is presented via GICC
*/
- typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
- gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
- gic_irqs = GICD_TYPER_IRQS(typer);
- if (gic_irqs > 1020)
- gic_irqs = 1020;
- gic_data.irq_nr = gic_irqs;
+ if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
+ return 0;
- gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
- &gic_data);
- gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
+ return -ENODEV;
+}
- if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
+static int __init gic_acpi_count_gicr_regions(void)
+{
+ int count;
+
+ /*
+ * Count how many redistributor regions we have. It is not allowed
+ * to mix redistributor description, GICR and GICC subtables have to be
+ * mutually exclusive.
+ */
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
+ gic_acpi_match_gicr, 0);
+ if (count > 0) {
+ single_redist = false;
+ return count;
+ }
+
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
+ gic_acpi_match_gicc, 0);
+ if (count > 0)
+ single_redist = true;
+
+ return count;
+}
+
+static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header,
+ struct acpi_probe_entry *ape)
+{
+ struct acpi_madt_generic_distributor *dist;
+ int count;
+
+ dist = (struct acpi_madt_generic_distributor *)header;
+ if (dist->version != ape->driver_data)
+ return false;
+
+ /* We need to do that exercise anyway, the sooner the better */
+ count = gic_acpi_count_gicr_regions();
+ if (count <= 0)
+ return false;
+
+ nr_redist_regions = count;
+ return true;
+}
+
+#define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K)
+
+static int __init
+gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
+{
+ struct acpi_madt_generic_distributor *dist;
+ struct fwnode_handle *domain_handle;
+ int i, err;
+
+ /* Get distributor base address */
+ dist = (struct acpi_madt_generic_distributor *)header;
+ dist_base = ioremap(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE);
+ if (!dist_base) {
+ pr_err("Unable to map GICD registers\n");
+ return -ENOMEM;
+ }
+
+ err = gic_validate_dist_version(dist_base);
+ if (err) {
+ pr_err("No distributor detected at @%p, giving up", dist_base);
+ goto out_dist_unmap;
+ }
+
+ redist_regs = kzalloc(sizeof(*redist_regs) * nr_redist_regions,
+ GFP_KERNEL);
+ if (!redist_regs) {
err = -ENOMEM;
- goto out_free;
+ goto out_dist_unmap;
}
- set_handle_irq(gic_handle_irq);
+ err = gic_acpi_collect_gicr_base();
+ if (err)
+ goto out_redist_unmap;
- if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
- its_init(node, &gic_data.rdists, gic_data.domain);
+ domain_handle = irq_domain_alloc_fwnode(dist_base);
+ if (!domain_handle) {
+ err = -ENOMEM;
+ goto out_redist_unmap;
+ }
- gic_smp_init();
- gic_dist_init();
- gic_cpu_init();
- gic_cpu_pm_init();
+ err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
+ domain_handle);
+ if (err)
+ goto out_fwhandle_free;
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
return 0;
-out_free:
- if (gic_data.domain)
- irq_domain_remove(gic_data.domain);
- free_percpu(gic_data.rdists.rdist);
-out_unmap_rdist:
+out_fwhandle_free:
+ irq_domain_free_fwnode(domain_handle);
+out_redist_unmap:
for (i = 0; i < nr_redist_regions; i++)
- if (rdist_regs[i].redist_base)
- iounmap(rdist_regs[i].redist_base);
- kfree(rdist_regs);
-out_unmap_dist:
+ if (redist_regs[i].redist_base)
+ iounmap(redist_regs[i].redist_base);
+ kfree(redist_regs);
+out_dist_unmap:
iounmap(dist_base);
return err;
}
-
-IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
+IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+ acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V3,
+ gic_acpi_init);
+IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+ acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V4,
+ gic_acpi_init);
+IRQCHIP_ACPI_DECLARE(gic_v3_or_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+ acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_NONE,
+ gic_acpi_init);
+#endif
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 8f9ebf714e2b..282344b95ec2 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -319,7 +319,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
writel_relaxed(val | bit, reg);
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
- return IRQ_SET_MASK_OK;
+ return IRQ_SET_MASK_OK_DONE;
}
#endif
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 9e17ef27a183..94a30da0cfac 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -29,16 +29,32 @@ struct gic_pcpu_mask {
DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
};
+struct gic_irq_spec {
+ enum {
+ GIC_DEVICE,
+ GIC_IPI
+ } type;
+
+ union {
+ struct cpumask *ipimask;
+ unsigned int hwirq;
+ };
+};
+
static unsigned long __gic_base_addr;
+
static void __iomem *gic_base;
static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
static DEFINE_SPINLOCK(gic_lock);
static struct irq_domain *gic_irq_domain;
+static struct irq_domain *gic_dev_domain;
+static struct irq_domain *gic_ipi_domain;
static int gic_shared_intrs;
static int gic_vpes;
static unsigned int gic_cpu_pin;
static unsigned int timer_cpu_pin;
static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
+DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
static void __gic_irq_dispatch(void);
@@ -264,9 +280,11 @@ static void gic_bind_eic_interrupt(int irq, int set)
GIC_VPE_EIC_SS(irq), set);
}
-void gic_send_ipi(unsigned int intr)
+static void gic_send_ipi(struct irq_data *d, unsigned int cpu)
{
- gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_SET(intr));
+ irq_hw_number_t hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(d));
+
+ gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_SET(hwirq));
}
int gic_get_c0_compare_int(void)
@@ -449,7 +467,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
gic_map_to_vpe(irq, mips_cm_vp_id(cpumask_first(&tmp)));
/* Update the pcpu_masks */
- for (i = 0; i < NR_CPUS; i++)
+ for (i = 0; i < gic_vpes; i++)
clear_bit(irq, pcpu_masks[i].pcpu_mask);
set_bit(irq, pcpu_masks[cpumask_first(&tmp)].pcpu_mask);
@@ -479,6 +497,7 @@ static struct irq_chip gic_edge_irq_controller = {
#ifdef CONFIG_SMP
.irq_set_affinity = gic_set_affinity,
#endif
+ .ipi_send_single = gic_send_ipi,
};
static void gic_handle_local_int(bool chained)
@@ -572,83 +591,6 @@ static void gic_irq_dispatch(struct irq_desc *desc)
gic_handle_shared_int(true);
}
-#ifdef CONFIG_MIPS_GIC_IPI
-static int gic_resched_int_base;
-static int gic_call_int_base;
-
-unsigned int plat_ipi_resched_int_xlate(unsigned int cpu)
-{
- return gic_resched_int_base + cpu;
-}
-
-unsigned int plat_ipi_call_int_xlate(unsigned int cpu)
-{
- return gic_call_int_base + cpu;
-}
-
-static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
-{
- scheduler_ipi();
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
-{
- generic_smp_call_function_interrupt();
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction irq_resched = {
- .handler = ipi_resched_interrupt,
- .flags = IRQF_PERCPU,
- .name = "IPI resched"
-};
-
-static struct irqaction irq_call = {
- .handler = ipi_call_interrupt,
- .flags = IRQF_PERCPU,
- .name = "IPI call"
-};
-
-static __init void gic_ipi_init_one(unsigned int intr, int cpu,
- struct irqaction *action)
-{
- int virq = irq_create_mapping(gic_irq_domain,
- GIC_SHARED_TO_HWIRQ(intr));
- int i;
-
- gic_map_to_vpe(intr, mips_cm_vp_id(cpu));
- for (i = 0; i < NR_CPUS; i++)
- clear_bit(intr, pcpu_masks[i].pcpu_mask);
- set_bit(intr, pcpu_masks[cpu].pcpu_mask);
-
- irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
-
- irq_set_handler(virq, handle_percpu_irq);
- setup_irq(virq, action);
-}
-
-static __init void gic_ipi_init(void)
-{
- int i;
-
- /* Use last 2 * NR_CPUS interrupts as IPIs */
- gic_resched_int_base = gic_shared_intrs - nr_cpu_ids;
- gic_call_int_base = gic_resched_int_base - nr_cpu_ids;
-
- for (i = 0; i < nr_cpu_ids; i++) {
- gic_ipi_init_one(gic_call_int_base + i, i, &irq_call);
- gic_ipi_init_one(gic_resched_int_base + i, i, &irq_resched);
- }
-}
-#else
-static inline void gic_ipi_init(void)
-{
-}
-#endif
-
static void __init gic_basic_init(void)
{
unsigned int i;
@@ -753,19 +695,21 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
}
static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
- irq_hw_number_t hw)
+ irq_hw_number_t hw, unsigned int vpe)
{
int intr = GIC_HWIRQ_TO_SHARED(hw);
unsigned long flags;
+ int i;
irq_set_chip_and_handler(virq, &gic_level_irq_controller,
handle_level_irq);
spin_lock_irqsave(&gic_lock, flags);
gic_map_to_pin(intr, gic_cpu_pin);
- /* Map to VPE 0 by default */
- gic_map_to_vpe(intr, 0);
- set_bit(intr, pcpu_masks[0].pcpu_mask);
+ gic_map_to_vpe(intr, vpe);
+ for (i = 0; i < gic_vpes; i++)
+ clear_bit(intr, pcpu_masks[i].pcpu_mask);
+ set_bit(intr, pcpu_masks[vpe].pcpu_mask);
spin_unlock_irqrestore(&gic_lock, flags);
return 0;
@@ -776,10 +720,93 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
{
if (GIC_HWIRQ_TO_LOCAL(hw) < GIC_NUM_LOCAL_INTRS)
return gic_local_irq_domain_map(d, virq, hw);
- return gic_shared_irq_domain_map(d, virq, hw);
+ return gic_shared_irq_domain_map(d, virq, hw, 0);
}
-static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct gic_irq_spec *spec = arg;
+ irq_hw_number_t hwirq, base_hwirq;
+ int cpu, ret, i;
+
+ if (spec->type == GIC_DEVICE) {
+ /* verify that it doesn't conflict with an IPI irq */
+ if (test_bit(spec->hwirq, ipi_resrv))
+ return -EBUSY;
+ } else {
+ base_hwirq = find_first_bit(ipi_resrv, gic_shared_intrs);
+ if (base_hwirq == gic_shared_intrs) {
+ return -ENOMEM;
+ }
+
+ /* check that we have enough space */
+ for (i = base_hwirq; i < nr_irqs; i++) {
+ if (!test_bit(i, ipi_resrv))
+ return -EBUSY;
+ }
+ bitmap_clear(ipi_resrv, base_hwirq, nr_irqs);
+
+ /* map the hwirq for each cpu consecutively */
+ i = 0;
+ for_each_cpu(cpu, spec->ipimask) {
+ hwirq = GIC_SHARED_TO_HWIRQ(base_hwirq + i);
+
+ ret = irq_domain_set_hwirq_and_chip(d, virq + i, hwirq,
+ &gic_edge_irq_controller,
+ NULL);
+ if (ret)
+ goto error;
+
+ ret = gic_shared_irq_domain_map(d, virq + i, hwirq, cpu);
+ if (ret)
+ goto error;
+
+ i++;
+ }
+
+ /*
+ * tell the parent about the base hwirq we allocated so it can
+ * set its own domain data
+ */
+ spec->hwirq = base_hwirq;
+ }
+
+ return 0;
+error:
+ bitmap_set(ipi_resrv, base_hwirq, nr_irqs);
+ return ret;
+}
+
+void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ irq_hw_number_t base_hwirq;
+ struct irq_data *data;
+
+ data = irq_get_irq_data(virq);
+ if (!data)
+ return;
+
+ base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data));
+ bitmap_set(ipi_resrv, base_hwirq, nr_irqs);
+}
+
+int gic_irq_domain_match(struct irq_domain *d, struct device_node *node,
+ enum irq_domain_bus_token bus_token)
+{
+ /* this domain should'nt be accessed directly */
+ return 0;
+}
+
+static const struct irq_domain_ops gic_irq_domain_ops = {
+ .map = gic_irq_domain_map,
+ .alloc = gic_irq_domain_alloc,
+ .free = gic_irq_domain_free,
+ .match = gic_irq_domain_match,
+};
+
+static int gic_dev_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq,
unsigned int *out_type)
@@ -798,9 +825,130 @@ static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
return 0;
}
-static const struct irq_domain_ops gic_irq_domain_ops = {
- .map = gic_irq_domain_map,
- .xlate = gic_irq_domain_xlate,
+static int gic_dev_domain_alloc(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct irq_fwspec *fwspec = arg;
+ struct gic_irq_spec spec = {
+ .type = GIC_DEVICE,
+ .hwirq = fwspec->param[1],
+ };
+ int i, ret;
+ bool is_shared = fwspec->param[0] == GIC_SHARED;
+
+ if (is_shared) {
+ ret = irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &spec);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_hw_number_t hwirq;
+
+ if (is_shared)
+ hwirq = GIC_SHARED_TO_HWIRQ(spec.hwirq + i);
+ else
+ hwirq = GIC_LOCAL_TO_HWIRQ(spec.hwirq + i);
+
+ ret = irq_domain_set_hwirq_and_chip(d, virq + i,
+ hwirq,
+ &gic_level_irq_controller,
+ NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void gic_dev_domain_free(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ /* no real allocation is done for dev irqs, so no need to free anything */
+ return;
+}
+
+static struct irq_domain_ops gic_dev_domain_ops = {
+ .xlate = gic_dev_domain_xlate,
+ .alloc = gic_dev_domain_alloc,
+ .free = gic_dev_domain_free,
+};
+
+static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq,
+ unsigned int *out_type)
+{
+ /*
+ * There's nothing to translate here. hwirq is dynamically allocated and
+ * the irq type is always edge triggered.
+ * */
+ *out_hwirq = 0;
+ *out_type = IRQ_TYPE_EDGE_RISING;
+
+ return 0;
+}
+
+static int gic_ipi_domain_alloc(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct cpumask *ipimask = arg;
+ struct gic_irq_spec spec = {
+ .type = GIC_IPI,
+ .ipimask = ipimask
+ };
+ int ret, i;
+
+ ret = irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &spec);
+ if (ret)
+ return ret;
+
+ /* the parent should have set spec.hwirq to the base_hwirq it allocated */
+ for (i = 0; i < nr_irqs; i++) {
+ ret = irq_domain_set_hwirq_and_chip(d, virq + i,
+ GIC_SHARED_TO_HWIRQ(spec.hwirq + i),
+ &gic_edge_irq_controller,
+ NULL);
+ if (ret)
+ goto error;
+
+ ret = irq_set_irq_type(virq + i, IRQ_TYPE_EDGE_RISING);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+error:
+ irq_domain_free_irqs_parent(d, virq, nr_irqs);
+ return ret;
+}
+
+void gic_ipi_domain_free(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ irq_domain_free_irqs_parent(d, virq, nr_irqs);
+}
+
+int gic_ipi_domain_match(struct irq_domain *d, struct device_node *node,
+ enum irq_domain_bus_token bus_token)
+{
+ bool is_ipi;
+
+ switch (bus_token) {
+ case DOMAIN_BUS_IPI:
+ is_ipi = d->bus_token == bus_token;
+ return to_of_node(d->fwnode) == node && is_ipi;
+ break;
+ default:
+ return 0;
+ }
+}
+
+static struct irq_domain_ops gic_ipi_domain_ops = {
+ .xlate = gic_ipi_domain_xlate,
+ .alloc = gic_ipi_domain_alloc,
+ .free = gic_ipi_domain_free,
+ .match = gic_ipi_domain_match,
};
static void __init __gic_init(unsigned long gic_base_addr,
@@ -809,6 +957,7 @@ static void __init __gic_init(unsigned long gic_base_addr,
struct device_node *node)
{
unsigned int gicconfig;
+ unsigned int v[2];
__gic_base_addr = gic_base_addr;
@@ -864,9 +1013,32 @@ static void __init __gic_init(unsigned long gic_base_addr,
if (!gic_irq_domain)
panic("Failed to add GIC IRQ domain");
- gic_basic_init();
+ gic_dev_domain = irq_domain_add_hierarchy(gic_irq_domain, 0,
+ GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
+ node, &gic_dev_domain_ops, NULL);
+ if (!gic_dev_domain)
+ panic("Failed to add GIC DEV domain");
+
+ gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain,
+ IRQ_DOMAIN_FLAG_IPI_PER_CPU,
+ GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
+ node, &gic_ipi_domain_ops, NULL);
+ if (!gic_ipi_domain)
+ panic("Failed to add GIC IPI domain");
- gic_ipi_init();
+ gic_ipi_domain->bus_token = DOMAIN_BUS_IPI;
+
+ if (node &&
+ !of_property_read_u32_array(node, "mti,reserved-ipi-vectors", v, 2)) {
+ bitmap_set(ipi_resrv, v[0], v[1]);
+ } else {
+ /* Make the last 2 * gic_vpes available for IPIs */
+ bitmap_set(ipi_resrv,
+ gic_shared_intrs - 2 * gic_vpes,
+ 2 * gic_vpes);
+ }
+
+ gic_basic_init();
}
void __init gic_init(unsigned long gic_base_addr,
diff --git a/drivers/irqchip/irq-mvebu-odmi.c b/drivers/irqchip/irq-mvebu-odmi.c
new file mode 100644
index 000000000000..b4d367868dbb
--- /dev/null
+++ b/drivers/irqchip/irq-mvebu-odmi.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2016 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) "GIC-ODMI: " fmt
+
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#define GICP_ODMIN_SET 0x40
+#define GICP_ODMI_INT_NUM_SHIFT 12
+#define GICP_ODMIN_GM_EP_R0 0x110
+#define GICP_ODMIN_GM_EP_R1 0x114
+#define GICP_ODMIN_GM_EA_R0 0x108
+#define GICP_ODMIN_GM_EA_R1 0x118
+
+/*
+ * We don't support the group events, so we simply have 8 interrupts
+ * per frame.
+ */
+#define NODMIS_SHIFT 3
+#define NODMIS_PER_FRAME (1 << NODMIS_SHIFT)
+#define NODMIS_MASK (NODMIS_PER_FRAME - 1)
+
+struct odmi_data {
+ struct resource res;
+ void __iomem *base;
+ unsigned int spi_base;
+};
+
+static struct odmi_data *odmis;
+static unsigned long *odmis_bm;
+static unsigned int odmis_count;
+
+/* Protects odmis_bm */
+static DEFINE_SPINLOCK(odmis_bm_lock);
+
+static void odmi_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+ struct odmi_data *odmi;
+ phys_addr_t addr;
+ unsigned int odmin;
+
+ if (WARN_ON(d->hwirq >= odmis_count * NODMIS_PER_FRAME))
+ return;
+
+ odmi = &odmis[d->hwirq >> NODMIS_SHIFT];
+ odmin = d->hwirq & NODMIS_MASK;
+
+ addr = odmi->res.start + GICP_ODMIN_SET;
+
+ msg->address_hi = upper_32_bits(addr);
+ msg->address_lo = lower_32_bits(addr);
+ msg->data = odmin << GICP_ODMI_INT_NUM_SHIFT;
+}
+
+static struct irq_chip odmi_irq_chip = {
+ .name = "ODMI",
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+ .irq_compose_msi_msg = odmi_compose_msi_msg,
+};
+
+static int odmi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *args)
+{
+ struct odmi_data *odmi = NULL;
+ struct irq_fwspec fwspec;
+ struct irq_data *d;
+ unsigned int hwirq, odmin;
+ int ret;
+
+ spin_lock(&odmis_bm_lock);
+ hwirq = find_first_zero_bit(odmis_bm, NODMIS_PER_FRAME * odmis_count);
+ if (hwirq >= NODMIS_PER_FRAME * odmis_count) {
+ spin_unlock(&odmis_bm_lock);
+ return -ENOSPC;
+ }
+
+ __set_bit(hwirq, odmis_bm);
+ spin_unlock(&odmis_bm_lock);
+
+ odmi = &odmis[hwirq >> NODMIS_SHIFT];
+ odmin = hwirq & NODMIS_MASK;
+
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 3;
+ fwspec.param[0] = GIC_SPI;
+ fwspec.param[1] = odmi->spi_base - 32 + odmin;
+ fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
+ if (ret) {
+ pr_err("Cannot allocate parent IRQ\n");
+ spin_lock(&odmis_bm_lock);
+ __clear_bit(odmin, odmis_bm);
+ spin_unlock(&odmis_bm_lock);
+ return ret;
+ }
+
+ /* Configure the interrupt line to be edge */
+ d = irq_domain_get_irq_data(domain->parent, virq);
+ d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING);
+
+ irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+ &odmi_irq_chip, NULL);
+
+ return 0;
+}
+
+static void odmi_irq_domain_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+
+ if (d->hwirq >= odmis_count * NODMIS_PER_FRAME) {
+ pr_err("Failed to teardown msi. Invalid hwirq %lu\n", d->hwirq);
+ return;
+ }
+
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+
+ /* Actually free the MSI */
+ spin_lock(&odmis_bm_lock);
+ __clear_bit(d->hwirq, odmis_bm);
+ spin_unlock(&odmis_bm_lock);
+}
+
+static const struct irq_domain_ops odmi_domain_ops = {
+ .alloc = odmi_irq_domain_alloc,
+ .free = odmi_irq_domain_free,
+};
+
+static struct irq_chip odmi_msi_irq_chip = {
+ .name = "ODMI",
+};
+
+static struct msi_domain_ops odmi_msi_ops = {
+};
+
+static struct msi_domain_info odmi_msi_domain_info = {
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
+ .ops = &odmi_msi_ops,
+ .chip = &odmi_msi_irq_chip,
+};
+
+static int __init mvebu_odmi_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct irq_domain *inner_domain, *plat_domain;
+ int ret, i;
+
+ if (of_property_read_u32(node, "marvell,odmi-frames", &odmis_count))
+ return -EINVAL;
+
+ odmis = kcalloc(odmis_count, sizeof(struct odmi_data), GFP_KERNEL);
+ if (!odmis)
+ return -ENOMEM;
+
+ odmis_bm = kcalloc(BITS_TO_LONGS(odmis_count * NODMIS_PER_FRAME),
+ sizeof(long), GFP_KERNEL);
+ if (!odmis_bm) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ for (i = 0; i < odmis_count; i++) {
+ struct odmi_data *odmi = &odmis[i];
+
+ ret = of_address_to_resource(node, i, &odmi->res);
+ if (ret)
+ goto err_unmap;
+
+ odmi->base = of_io_request_and_map(node, i, "odmi");
+ if (IS_ERR(odmi->base)) {
+ ret = PTR_ERR(odmi->base);
+ goto err_unmap;
+ }
+
+ if (of_property_read_u32_index(node, "marvell,spi-base",
+ i, &odmi->spi_base)) {
+ ret = -EINVAL;
+ goto err_unmap;
+ }
+ }
+
+ inner_domain = irq_domain_create_linear(of_node_to_fwnode(node),
+ odmis_count * NODMIS_PER_FRAME,
+ &odmi_domain_ops, NULL);
+ if (!inner_domain) {
+ ret = -ENOMEM;
+ goto err_unmap;
+ }
+
+ inner_domain->parent = irq_find_host(parent);
+
+ plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(node),
+ &odmi_msi_domain_info,
+ inner_domain);
+ if (!plat_domain) {
+ ret = -ENOMEM;
+ goto err_remove_inner;
+ }
+
+ return 0;
+
+err_remove_inner:
+ irq_domain_remove(inner_domain);
+err_unmap:
+ for (i = 0; i < odmis_count; i++) {
+ struct odmi_data *odmi = &odmis[i];
+
+ if (odmi->base && !IS_ERR(odmi->base))
+ iounmap(odmis[i].base);
+ }
+ kfree(odmis_bm);
+err_alloc:
+ kfree(odmis);
+ return ret;
+}
+
+IRQCHIP_DECLARE(mvebu_odmi, "marvell,odmi-controller", mvebu_odmi_init);
diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
index efe50845939d..17304705f2cf 100644
--- a/drivers/irqchip/irq-mxs.c
+++ b/drivers/irqchip/irq-mxs.c
@@ -183,7 +183,7 @@ static void __iomem * __init icoll_init_iobase(struct device_node *np)
void __iomem *icoll_base;
icoll_base = of_io_request_and_map(np, 0, np->name);
- if (!icoll_base)
+ if (IS_ERR(icoll_base))
panic("%s: unable to map resource", np->full_name);
return icoll_base;
}
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
index 0820f67cc9a7..668730c5cb66 100644
--- a/drivers/irqchip/irq-sunxi-nmi.c
+++ b/drivers/irqchip/irq-sunxi-nmi.c
@@ -160,9 +160,9 @@ static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
gc = irq_get_domain_generic_chip(domain, 0);
gc->reg_base = of_io_request_and_map(node, 0, of_node_full_name(node));
- if (!gc->reg_base) {
+ if (IS_ERR(gc->reg_base)) {
pr_err("unable to map resource\n");
- ret = -ENOMEM;
+ ret = PTR_ERR(gc->reg_base);
goto fail_irqd_remove;
}
diff --git a/drivers/irqchip/irq-tango.c b/drivers/irqchip/irq-tango.c
new file mode 100644
index 000000000000..bdbb5c0ff7fe
--- /dev/null
+++ b/drivers/irqchip/irq-tango.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2014 Mans Rullgard <mans@mansr.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.
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+
+#define IRQ0_CTL_BASE 0x0000
+#define IRQ1_CTL_BASE 0x0100
+#define EDGE_CTL_BASE 0x0200
+#define IRQ2_CTL_BASE 0x0300
+
+#define IRQ_CTL_HI 0x18
+#define EDGE_CTL_HI 0x20
+
+#define IRQ_STATUS 0x00
+#define IRQ_RAWSTAT 0x04
+#define IRQ_EN_SET 0x08
+#define IRQ_EN_CLR 0x0c
+#define IRQ_SOFT_SET 0x10
+#define IRQ_SOFT_CLR 0x14
+
+#define EDGE_STATUS 0x00
+#define EDGE_RAWSTAT 0x04
+#define EDGE_CFG_RISE 0x08
+#define EDGE_CFG_FALL 0x0c
+#define EDGE_CFG_RISE_SET 0x10
+#define EDGE_CFG_RISE_CLR 0x14
+#define EDGE_CFG_FALL_SET 0x18
+#define EDGE_CFG_FALL_CLR 0x1c
+
+struct tangox_irq_chip {
+ void __iomem *base;
+ unsigned long ctl;
+};
+
+static inline u32 intc_readl(struct tangox_irq_chip *chip, int reg)
+{
+ return readl_relaxed(chip->base + reg);
+}
+
+static inline void intc_writel(struct tangox_irq_chip *chip, int reg, u32 val)
+{
+ writel_relaxed(val, chip->base + reg);
+}
+
+static void tangox_dispatch_irqs(struct irq_domain *dom, unsigned int status,
+ int base)
+{
+ unsigned int hwirq;
+ unsigned int virq;
+
+ while (status) {
+ hwirq = __ffs(status);
+ virq = irq_find_mapping(dom, base + hwirq);
+ if (virq)
+ generic_handle_irq(virq);
+ status &= ~BIT(hwirq);
+ }
+}
+
+static void tangox_irq_handler(struct irq_desc *desc)
+{
+ struct irq_domain *dom = irq_desc_get_handler_data(desc);
+ struct irq_chip *host_chip = irq_desc_get_chip(desc);
+ struct tangox_irq_chip *chip = dom->host_data;
+ unsigned int status_lo, status_hi;
+
+ chained_irq_enter(host_chip, desc);
+
+ status_lo = intc_readl(chip, chip->ctl + IRQ_STATUS);
+ status_hi = intc_readl(chip, chip->ctl + IRQ_CTL_HI + IRQ_STATUS);
+
+ tangox_dispatch_irqs(dom, status_lo, 0);
+ tangox_dispatch_irqs(dom, status_hi, 32);
+
+ chained_irq_exit(host_chip, desc);
+}
+
+static int tangox_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct tangox_irq_chip *chip = gc->domain->host_data;
+ struct irq_chip_regs *regs = &gc->chip_types[0].regs;
+
+ switch (flow_type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_RISING:
+ intc_writel(chip, regs->type + EDGE_CFG_RISE_SET, d->mask);
+ intc_writel(chip, regs->type + EDGE_CFG_FALL_CLR, d->mask);
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ intc_writel(chip, regs->type + EDGE_CFG_RISE_CLR, d->mask);
+ intc_writel(chip, regs->type + EDGE_CFG_FALL_SET, d->mask);
+ break;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ intc_writel(chip, regs->type + EDGE_CFG_RISE_CLR, d->mask);
+ intc_writel(chip, regs->type + EDGE_CFG_FALL_CLR, d->mask);
+ break;
+
+ case IRQ_TYPE_LEVEL_LOW:
+ intc_writel(chip, regs->type + EDGE_CFG_RISE_SET, d->mask);
+ intc_writel(chip, regs->type + EDGE_CFG_FALL_SET, d->mask);
+ break;
+
+ default:
+ pr_err("Invalid trigger mode %x for IRQ %d\n",
+ flow_type, d->irq);
+ return -EINVAL;
+ }
+
+ return irq_setup_alt_chip(d, flow_type);
+}
+
+static void __init tangox_irq_init_chip(struct irq_chip_generic *gc,
+ unsigned long ctl_offs,
+ unsigned long edge_offs)
+{
+ struct tangox_irq_chip *chip = gc->domain->host_data;
+ struct irq_chip_type *ct = gc->chip_types;
+ unsigned long ctl_base = chip->ctl + ctl_offs;
+ unsigned long edge_base = EDGE_CTL_BASE + edge_offs;
+ int i;
+
+ gc->reg_base = chip->base;
+ gc->unused = 0;
+
+ for (i = 0; i < 2; i++) {
+ ct[i].chip.irq_ack = irq_gc_ack_set_bit;
+ ct[i].chip.irq_mask = irq_gc_mask_disable_reg;
+ ct[i].chip.irq_mask_ack = irq_gc_mask_disable_reg_and_ack;
+ ct[i].chip.irq_unmask = irq_gc_unmask_enable_reg;
+ ct[i].chip.irq_set_type = tangox_irq_set_type;
+ ct[i].chip.name = gc->domain->name;
+
+ ct[i].regs.enable = ctl_base + IRQ_EN_SET;
+ ct[i].regs.disable = ctl_base + IRQ_EN_CLR;
+ ct[i].regs.ack = edge_base + EDGE_RAWSTAT;
+ ct[i].regs.type = edge_base;
+ }
+
+ ct[0].type = IRQ_TYPE_LEVEL_MASK;
+ ct[0].handler = handle_level_irq;
+
+ ct[1].type = IRQ_TYPE_EDGE_BOTH;
+ ct[1].handler = handle_edge_irq;
+
+ intc_writel(chip, ct->regs.disable, 0xffffffff);
+ intc_writel(chip, ct->regs.ack, 0xffffffff);
+}
+
+static void __init tangox_irq_domain_init(struct irq_domain *dom)
+{
+ struct irq_chip_generic *gc;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ gc = irq_get_domain_generic_chip(dom, i * 32);
+ tangox_irq_init_chip(gc, i * IRQ_CTL_HI, i * EDGE_CTL_HI);
+ }
+}
+
+static int __init tangox_irq_init(void __iomem *base, struct resource *baseres,
+ struct device_node *node)
+{
+ struct tangox_irq_chip *chip;
+ struct irq_domain *dom;
+ struct resource res;
+ int irq;
+ int err;
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (!irq)
+ panic("%s: failed to get IRQ", node->name);
+
+ err = of_address_to_resource(node, 0, &res);
+ if (err)
+ panic("%s: failed to get address", node->name);
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip->ctl = res.start - baseres->start;
+ chip->base = base;
+
+ dom = irq_domain_add_linear(node, 64, &irq_generic_chip_ops, chip);
+ if (!dom)
+ panic("%s: failed to create irqdomain", node->name);
+
+ err = irq_alloc_domain_generic_chips(dom, 32, 2, node->name,
+ handle_level_irq, 0, 0, 0);
+ if (err)
+ panic("%s: failed to allocate irqchip", node->name);
+
+ tangox_irq_domain_init(dom);
+
+ irq_set_chained_handler(irq, tangox_irq_handler);
+ irq_set_handler_data(irq, dom);
+
+ return 0;
+}
+
+static int __init tangox_of_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct device_node *c;
+ struct resource res;
+ void __iomem *base;
+
+ base = of_iomap(node, 0);
+ if (!base)
+ panic("%s: of_iomap failed", node->name);
+
+ of_address_to_resource(node, 0, &res);
+
+ for_each_child_of_node(node, c)
+ tangox_irq_init(base, &res, c);
+
+ return 0;
+}
+IRQCHIP_DECLARE(tangox_intc, "sigma,smp8642-intc", tangox_of_irq_init);
diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c
index 4192bdcd2734..2325fb3c482b 100644
--- a/drivers/irqchip/irq-ts4800.c
+++ b/drivers/irqchip/irq-ts4800.c
@@ -59,7 +59,7 @@ static int ts4800_irqdomain_map(struct irq_domain *d, unsigned int irq,
return 0;
}
-struct irq_domain_ops ts4800_ic_ops = {
+static const struct irq_domain_ops ts4800_ic_ops = {
.map = ts4800_irqdomain_map,
.xlate = irq_domain_xlate_onecell,
};
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index 2a506fe0c8a4..d1f8ab915b15 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -373,13 +373,7 @@ static void gigaset_freecshw(struct cardstate *cs)
static void gigaset_device_release(struct device *dev)
{
- struct cardstate *cs = dev_get_drvdata(dev);
-
- if (!cs)
- return;
- dev_set_drvdata(dev, NULL);
- kfree(cs->hw.ser);
- cs->hw.ser = NULL;
+ kfree(container_of(dev, struct ser_cardstate, dev.dev));
}
/*
@@ -408,7 +402,6 @@ static int gigaset_initcshw(struct cardstate *cs)
cs->hw.ser = NULL;
return rc;
}
- dev_set_drvdata(&cs->hw.ser->dev.dev, cs);
tasklet_init(&cs->write_tasklet,
gigaset_modem_fill, (unsigned long) cs);
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index 8e2944784e00..afde4edef9ae 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -392,7 +392,7 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt)
}
stat = bchannel_get_rxbuf(&bc->bch, cnt);
/* only transparent use the count here, HDLC overun is detected later */
- if (stat == ENOMEM) {
+ if (stat == -ENOMEM) {
pr_warning("%s.B%d: No memory for %d bytes\n",
card->name, bc->bch.nr, cnt);
return;
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 2175225af742..947d5c978b8f 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1572,7 +1572,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
#endif
return;
}
- port->flags |= ASYNC_CLOSING;
+ info->closing = 1;
tty->closing = 1;
/*
@@ -1603,6 +1603,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
info->ncarrier = 0;
tty_port_close_end(port, tty);
+ info->closing = 0;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_close normal exit\n");
#endif
@@ -2236,7 +2237,7 @@ isdn_tty_at_cout(char *msg, modem_info *info)
l = strlen(msg);
spin_lock_irqsave(&info->readlock, flags);
- if (port->flags & ASYNC_CLOSING) {
+ if (info->closing) {
spin_unlock_irqrestore(&info->readlock, flags);
return;
}
@@ -2386,13 +2387,12 @@ isdn_tty_modem_result(int code, modem_info *info)
case RESULT_NO_CARRIER:
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
- (info->port.flags & ASYNC_CLOSING),
- (!info->port.tty));
+ info->closing, !info->port.tty);
#endif
m->mdmreg[REG_RINGCNT] = 0;
del_timer(&info->nc_timer);
info->ncarrier = 0;
- if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
+ if (info->closing || !info->port.tty)
return;
#ifdef CONFIG_ISDN_AUDIO
@@ -2525,7 +2525,7 @@ isdn_tty_modem_result(int code, modem_info *info)
}
}
if (code == RESULT_NO_CARRIER) {
- if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
+ if (info->closing || (!info->port.tty))
return;
if (info->port.flags & ASYNC_CHECK_CD)
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 7f940c24a16b..1f6415168998 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -568,6 +568,14 @@ config LEDS_SEAD3
This driver can also be built as a module. If so the module
will be called leds-sead3.
+config LEDS_IS31FL32XX
+ tristate "LED support for ISSI IS31FL32XX I2C LED controller family"
+ depends on LEDS_CLASS && I2C && OF
+ help
+ Say Y here to include support for ISSI IS31FL32XX and Si-En SN32xx
+ LED controllers. They are I2C devices with multiple constant-current
+ channels, each with independent 256-level PWM control.
+
comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
config LEDS_BLINKM
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index e9d53092765d..cb2013df52d9 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o
obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
obj-$(CONFIG_LEDS_SEAD3) += leds-sead3.o
+obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 14139c337312..aa84e5b37593 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -245,6 +245,8 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
up_write(&led_cdev->trigger_lock);
#endif
+ led_cdev->flags |= LED_UNREGISTERING;
+
/* Stop blinking */
led_stop_software_blink(led_cdev);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 19e1e60dfaa3..3495d5d6547f 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -25,6 +25,26 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list);
+static int __led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (!led_cdev->brightness_set)
+ return -ENOTSUPP;
+
+ led_cdev->brightness_set(led_cdev, value);
+
+ return 0;
+}
+
+static int __led_set_brightness_blocking(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (!led_cdev->brightness_set_blocking)
+ return -ENOTSUPP;
+
+ return led_cdev->brightness_set_blocking(led_cdev, value);
+}
+
static void led_timer_function(unsigned long data)
{
struct led_classdev *led_cdev = (void *)data;
@@ -91,14 +111,14 @@ static void set_brightness_delayed(struct work_struct *ws)
led_cdev->flags &= ~LED_BLINK_DISABLE;
}
- if (led_cdev->brightness_set)
- led_cdev->brightness_set(led_cdev, led_cdev->delayed_set_value);
- else if (led_cdev->brightness_set_blocking)
- ret = led_cdev->brightness_set_blocking(led_cdev,
- led_cdev->delayed_set_value);
- else
- ret = -ENOTSUPP;
- if (ret < 0)
+ ret = __led_set_brightness(led_cdev, led_cdev->delayed_set_value);
+ if (ret == -ENOTSUPP)
+ ret = __led_set_brightness_blocking(led_cdev,
+ led_cdev->delayed_set_value);
+ if (ret < 0 &&
+ /* LED HW might have been unplugged, therefore don't warn */
+ !(ret == -ENODEV && (led_cdev->flags & LED_UNREGISTERING) &&
+ (led_cdev->flags & LED_HW_PLUGGABLE)))
dev_err(led_cdev->dev,
"Setting an LED's brightness failed (%d)\n", ret);
}
@@ -233,10 +253,8 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,
enum led_brightness value)
{
/* Use brightness_set op if available, it is guaranteed not to sleep */
- if (led_cdev->brightness_set) {
- led_cdev->brightness_set(led_cdev, value);
+ if (!__led_set_brightness(led_cdev, value))
return;
- }
/* If brightness setting can sleep, delegate it to a work queue task */
led_cdev->delayed_set_value = value;
@@ -267,10 +285,7 @@ int led_set_brightness_sync(struct led_classdev *led_cdev,
if (led_cdev->flags & LED_SUSPENDED)
return 0;
- if (led_cdev->brightness_set_blocking)
- return led_cdev->brightness_set_blocking(led_cdev,
- led_cdev->brightness);
- return -ENOTSUPP;
+ return __led_set_brightness_blocking(led_cdev, led_cdev->brightness);
}
EXPORT_SYMBOL_GPL(led_set_brightness_sync);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index e1e933424ac9..2181581795d3 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -34,9 +34,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
- char trigger_name[TRIG_NAME_MAX];
struct led_trigger *trig;
- size_t len;
int ret = count;
mutex_lock(&led_cdev->led_access);
@@ -46,21 +44,14 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
goto unlock;
}
- trigger_name[sizeof(trigger_name) - 1] = '\0';
- strncpy(trigger_name, buf, sizeof(trigger_name) - 1);
- len = strlen(trigger_name);
-
- if (len && trigger_name[len - 1] == '\n')
- trigger_name[len - 1] = '\0';
-
- if (!strcmp(trigger_name, "none")) {
+ if (sysfs_streq(buf, "none")) {
led_trigger_remove(led_cdev);
goto unlock;
}
down_read(&triggers_list_lock);
list_for_each_entry(trig, &trigger_list, next_trig) {
- if (!strcmp(trigger_name, trig->name)) {
+ if (sysfs_streq(buf, trig->name)) {
down_write(&led_cdev->trigger_lock);
led_trigger_set(led_cdev, trig);
up_write(&led_cdev->trigger_lock);
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index 1ad4d03a0a3c..77a104d2b124 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -195,7 +195,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
sprintf(data->name, "led1-blue");
break;
}
- platform_set_drvdata(pdev, data);
data->chip = chip;
data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
data->port = pdev->id;
@@ -208,7 +207,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
data->cdev.brightness_set_blocking = pm860x_led_set;
mutex_init(&data->lock);
- ret = led_classdev_register(chip->dev, &data->cdev);
+ ret = devm_led_classdev_register(chip->dev, &data->cdev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
return ret;
@@ -217,21 +216,12 @@ static int pm860x_led_probe(struct platform_device *pdev)
return 0;
}
-static int pm860x_led_remove(struct platform_device *pdev)
-{
- struct pm860x_led *data = platform_get_drvdata(pdev);
-
- led_classdev_unregister(&data->cdev);
-
- return 0;
-}
static struct platform_driver pm860x_led_driver = {
.driver = {
.name = "88pm860x-led",
},
.probe = pm860x_led_probe,
- .remove = pm860x_led_remove,
};
module_platform_driver(pm860x_led_driver);
diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c
index 4752a2b6ba2b..5ff7d72f73aa 100644
--- a/drivers/leds/leds-da903x.c
+++ b/drivers/leds/leds-da903x.c
@@ -113,21 +113,12 @@ static int da903x_led_probe(struct platform_device *pdev)
led->flags = pdata->flags;
led->master = pdev->dev.parent;
- ret = led_classdev_register(led->master, &led->cdev);
+ ret = devm_led_classdev_register(led->master, &led->cdev);
if (ret) {
dev_err(&pdev->dev, "failed to register LED %d\n", id);
return ret;
}
- platform_set_drvdata(pdev, led);
- return 0;
-}
-
-static int da903x_led_remove(struct platform_device *pdev)
-{
- struct da903x_led *led = platform_get_drvdata(pdev);
-
- led_classdev_unregister(&led->cdev);
return 0;
}
@@ -136,7 +127,6 @@ static struct platform_driver da903x_led_driver = {
.name = "da903x-led",
},
.probe = da903x_led_probe,
- .remove = da903x_led_remove,
};
module_platform_driver(da903x_led_driver);
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 7bc53280dbfd..61143f55597e 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -86,7 +86,7 @@ static int create_gpio_led(const struct gpio_led *template,
* still uses GPIO numbers. Ultimately we would like to get
* rid of this block completely.
*/
- unsigned long flags = 0;
+ unsigned long flags = GPIOF_OUT_INIT_LOW;
/* skip leds that aren't available */
if (!gpio_is_valid(template->gpio)) {
@@ -104,8 +104,8 @@ static int create_gpio_led(const struct gpio_led *template,
return ret;
led_dat->gpiod = gpio_to_desc(template->gpio);
- if (IS_ERR(led_dat->gpiod))
- return PTR_ERR(led_dat->gpiod);
+ if (!led_dat->gpiod)
+ return -EINVAL;
}
led_dat->cdev.name = template->name;
diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c
new file mode 100644
index 000000000000..c901d132d80c
--- /dev/null
+++ b/drivers/leds/leds-is31fl32xx.c
@@ -0,0 +1,508 @@
+/*
+ * Driver for ISSI IS31FL32xx family of I2C LED controllers
+ *
+ * Copyright 2015 Allworx Corp.
+ *
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * Datasheets:
+ * http://www.issi.com/US/product-analog-fxled-driver.shtml
+ * http://www.si-en.com/product.asp?parentid=890
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+/* Used to indicate a device has no such register */
+#define IS31FL32XX_REG_NONE 0xFF
+
+/* Software Shutdown bit in Shutdown Register */
+#define IS31FL32XX_SHUTDOWN_SSD_ENABLE 0
+#define IS31FL32XX_SHUTDOWN_SSD_DISABLE BIT(0)
+
+/* IS31FL3216 has a number of unique registers */
+#define IS31FL3216_CONFIG_REG 0x00
+#define IS31FL3216_LIGHTING_EFFECT_REG 0x03
+#define IS31FL3216_CHANNEL_CONFIG_REG 0x04
+
+/* Software Shutdown bit in 3216 Config Register */
+#define IS31FL3216_CONFIG_SSD_ENABLE BIT(7)
+#define IS31FL3216_CONFIG_SSD_DISABLE 0
+
+struct is31fl32xx_priv;
+struct is31fl32xx_led_data {
+ struct led_classdev cdev;
+ u8 channel; /* 1-based, max priv->cdef->channels */
+ struct is31fl32xx_priv *priv;
+};
+
+struct is31fl32xx_priv {
+ const struct is31fl32xx_chipdef *cdef;
+ struct i2c_client *client;
+ unsigned int num_leds;
+ struct is31fl32xx_led_data leds[0];
+};
+
+/**
+ * struct is31fl32xx_chipdef - chip-specific attributes
+ * @channels : Number of LED channels
+ * @shutdown_reg : address of Shutdown register (optional)
+ * @pwm_update_reg : address of PWM Update register
+ * @global_control_reg : address of Global Control register (optional)
+ * @reset_reg : address of Reset register (optional)
+ * @pwm_register_base : address of first PWM register
+ * @pwm_registers_reversed: : true if PWM registers count down instead of up
+ * @led_control_register_base : address of first LED control register (optional)
+ * @enable_bits_per_led_control_register: number of LEDs enable bits in each
+ * @reset_func: : pointer to reset function
+ *
+ * For all optional register addresses, the sentinel value %IS31FL32XX_REG_NONE
+ * indicates that this chip has no such register.
+ *
+ * If non-NULL, @reset_func will be called during probing to set all
+ * necessary registers to a known initialization state. This is needed
+ * for chips that do not have a @reset_reg.
+ *
+ * @enable_bits_per_led_control_register must be >=1 if
+ * @led_control_register_base != %IS31FL32XX_REG_NONE.
+ */
+struct is31fl32xx_chipdef {
+ u8 channels;
+ u8 shutdown_reg;
+ u8 pwm_update_reg;
+ u8 global_control_reg;
+ u8 reset_reg;
+ u8 pwm_register_base;
+ bool pwm_registers_reversed;
+ u8 led_control_register_base;
+ u8 enable_bits_per_led_control_register;
+ int (*reset_func)(struct is31fl32xx_priv *priv);
+ int (*sw_shutdown_func)(struct is31fl32xx_priv *priv, bool enable);
+};
+
+static const struct is31fl32xx_chipdef is31fl3236_cdef = {
+ .channels = 36,
+ .shutdown_reg = 0x00,
+ .pwm_update_reg = 0x25,
+ .global_control_reg = 0x4a,
+ .reset_reg = 0x4f,
+ .pwm_register_base = 0x01,
+ .led_control_register_base = 0x26,
+ .enable_bits_per_led_control_register = 1,
+};
+
+static const struct is31fl32xx_chipdef is31fl3235_cdef = {
+ .channels = 28,
+ .shutdown_reg = 0x00,
+ .pwm_update_reg = 0x25,
+ .global_control_reg = 0x4a,
+ .reset_reg = 0x4f,
+ .pwm_register_base = 0x05,
+ .led_control_register_base = 0x2a,
+ .enable_bits_per_led_control_register = 1,
+};
+
+static const struct is31fl32xx_chipdef is31fl3218_cdef = {
+ .channels = 18,
+ .shutdown_reg = 0x00,
+ .pwm_update_reg = 0x16,
+ .global_control_reg = IS31FL32XX_REG_NONE,
+ .reset_reg = 0x17,
+ .pwm_register_base = 0x01,
+ .led_control_register_base = 0x13,
+ .enable_bits_per_led_control_register = 6,
+};
+
+static int is31fl3216_reset(struct is31fl32xx_priv *priv);
+static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
+ bool enable);
+static const struct is31fl32xx_chipdef is31fl3216_cdef = {
+ .channels = 16,
+ .shutdown_reg = IS31FL32XX_REG_NONE,
+ .pwm_update_reg = 0xB0,
+ .global_control_reg = IS31FL32XX_REG_NONE,
+ .reset_reg = IS31FL32XX_REG_NONE,
+ .pwm_register_base = 0x10,
+ .pwm_registers_reversed = true,
+ .led_control_register_base = 0x01,
+ .enable_bits_per_led_control_register = 8,
+ .reset_func = is31fl3216_reset,
+ .sw_shutdown_func = is31fl3216_software_shutdown,
+};
+
+static int is31fl32xx_write(struct is31fl32xx_priv *priv, u8 reg, u8 val)
+{
+ int ret;
+
+ dev_dbg(&priv->client->dev, "writing register 0x%02X=0x%02X", reg, val);
+
+ ret = i2c_smbus_write_byte_data(priv->client, reg, val);
+ if (ret) {
+ dev_err(&priv->client->dev,
+ "register write to 0x%02X failed (error %d)",
+ reg, ret);
+ }
+ return ret;
+}
+
+/*
+ * Custom reset function for IS31FL3216 because it does not have a RESET
+ * register the way that the other IS31FL32xx chips do. We don't bother
+ * writing the GPIO and animation registers, because the registers we
+ * do write ensure those will have no effect.
+ */
+static int is31fl3216_reset(struct is31fl32xx_priv *priv)
+{
+ unsigned int i;
+ int ret;
+
+ ret = is31fl32xx_write(priv, IS31FL3216_CONFIG_REG,
+ IS31FL3216_CONFIG_SSD_ENABLE);
+ if (ret)
+ return ret;
+ for (i = 0; i < priv->cdef->channels; i++) {
+ ret = is31fl32xx_write(priv, priv->cdef->pwm_register_base+i,
+ 0x00);
+ if (ret)
+ return ret;
+ }
+ ret = is31fl32xx_write(priv, priv->cdef->pwm_update_reg, 0);
+ if (ret)
+ return ret;
+ ret = is31fl32xx_write(priv, IS31FL3216_LIGHTING_EFFECT_REG, 0x00);
+ if (ret)
+ return ret;
+ ret = is31fl32xx_write(priv, IS31FL3216_CHANNEL_CONFIG_REG, 0x00);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * Custom Software-Shutdown function for IS31FL3216 because it does not have
+ * a SHUTDOWN register the way that the other IS31FL32xx chips do.
+ * We don't bother doing a read/modify/write on the CONFIG register because
+ * we only ever use a value of '0' for the other fields in that register.
+ */
+static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
+ bool enable)
+{
+ u8 value = enable ? IS31FL3216_CONFIG_SSD_ENABLE :
+ IS31FL3216_CONFIG_SSD_DISABLE;
+
+ return is31fl32xx_write(priv, IS31FL3216_CONFIG_REG, value);
+}
+
+/*
+ * NOTE: A mutex is not needed in this function because:
+ * - All referenced data is read-only after probe()
+ * - The I2C core has a mutex on to protect the bus
+ * - There are no read/modify/write operations
+ * - Intervening operations between the write of the PWM register
+ * and the Update register are harmless.
+ *
+ * Example:
+ * PWM_REG_1 write 16
+ * UPDATE_REG write 0
+ * PWM_REG_2 write 128
+ * UPDATE_REG write 0
+ * vs:
+ * PWM_REG_1 write 16
+ * PWM_REG_2 write 128
+ * UPDATE_REG write 0
+ * UPDATE_REG write 0
+ * are equivalent. Poking the Update register merely applies all PWM
+ * register writes up to that point.
+ */
+static int is31fl32xx_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ const struct is31fl32xx_led_data *led_data =
+ container_of(led_cdev, struct is31fl32xx_led_data, cdev);
+ const struct is31fl32xx_chipdef *cdef = led_data->priv->cdef;
+ u8 pwm_register_offset;
+ int ret;
+
+ dev_dbg(led_cdev->dev, "%s: %d\n", __func__, brightness);
+
+ /* NOTE: led_data->channel is 1-based */
+ if (cdef->pwm_registers_reversed)
+ pwm_register_offset = cdef->channels - led_data->channel;
+ else
+ pwm_register_offset = led_data->channel - 1;
+
+ ret = is31fl32xx_write(led_data->priv,
+ cdef->pwm_register_base + pwm_register_offset,
+ brightness);
+ if (ret)
+ return ret;
+
+ return is31fl32xx_write(led_data->priv, cdef->pwm_update_reg, 0);
+}
+
+static int is31fl32xx_reset_regs(struct is31fl32xx_priv *priv)
+{
+ const struct is31fl32xx_chipdef *cdef = priv->cdef;
+ int ret;
+
+ if (cdef->reset_reg != IS31FL32XX_REG_NONE) {
+ ret = is31fl32xx_write(priv, cdef->reset_reg, 0);
+ if (ret)
+ return ret;
+ }
+
+ if (cdef->reset_func)
+ return cdef->reset_func(priv);
+
+ return 0;
+}
+
+static int is31fl32xx_software_shutdown(struct is31fl32xx_priv *priv,
+ bool enable)
+{
+ const struct is31fl32xx_chipdef *cdef = priv->cdef;
+ int ret;
+
+ if (cdef->shutdown_reg != IS31FL32XX_REG_NONE) {
+ u8 value = enable ? IS31FL32XX_SHUTDOWN_SSD_ENABLE :
+ IS31FL32XX_SHUTDOWN_SSD_DISABLE;
+ ret = is31fl32xx_write(priv, cdef->shutdown_reg, value);
+ if (ret)
+ return ret;
+ }
+
+ if (cdef->sw_shutdown_func)
+ return cdef->sw_shutdown_func(priv, enable);
+
+ return 0;
+}
+
+static int is31fl32xx_init_regs(struct is31fl32xx_priv *priv)
+{
+ const struct is31fl32xx_chipdef *cdef = priv->cdef;
+ int ret;
+
+ ret = is31fl32xx_reset_regs(priv);
+ if (ret)
+ return ret;
+
+ /*
+ * Set enable bit for all channels.
+ * We will control state with PWM registers alone.
+ */
+ if (cdef->led_control_register_base != IS31FL32XX_REG_NONE) {
+ u8 value =
+ GENMASK(cdef->enable_bits_per_led_control_register-1, 0);
+ u8 num_regs = cdef->channels /
+ cdef->enable_bits_per_led_control_register;
+ int i;
+
+ for (i = 0; i < num_regs; i++) {
+ ret = is31fl32xx_write(priv,
+ cdef->led_control_register_base+i,
+ value);
+ if (ret)
+ return ret;
+ }
+ }
+
+ ret = is31fl32xx_software_shutdown(priv, false);
+ if (ret)
+ return ret;
+
+ if (cdef->global_control_reg != IS31FL32XX_REG_NONE) {
+ ret = is31fl32xx_write(priv, cdef->global_control_reg, 0x00);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline size_t sizeof_is31fl32xx_priv(int num_leds)
+{
+ return sizeof(struct is31fl32xx_priv) +
+ (sizeof(struct is31fl32xx_led_data) * num_leds);
+}
+
+static int is31fl32xx_parse_child_dt(const struct device *dev,
+ const struct device_node *child,
+ struct is31fl32xx_led_data *led_data)
+{
+ struct led_classdev *cdev = &led_data->cdev;
+ int ret = 0;
+ u32 reg;
+
+ if (of_property_read_string(child, "label", &cdev->name))
+ cdev->name = child->name;
+
+ ret = of_property_read_u32(child, "reg", &reg);
+ if (ret || reg < 1 || reg > led_data->priv->cdef->channels) {
+ dev_err(dev,
+ "Child node %s does not have a valid reg property\n",
+ child->full_name);
+ return -EINVAL;
+ }
+ led_data->channel = reg;
+
+ of_property_read_string(child, "linux,default-trigger",
+ &cdev->default_trigger);
+
+ cdev->brightness_set_blocking = is31fl32xx_brightness_set;
+
+ return 0;
+}
+
+static struct is31fl32xx_led_data *is31fl32xx_find_led_data(
+ struct is31fl32xx_priv *priv,
+ u8 channel)
+{
+ size_t i;
+
+ for (i = 0; i < priv->num_leds; i++) {
+ if (priv->leds[i].channel == channel)
+ return &priv->leds[i];
+ }
+
+ return NULL;
+}
+
+static int is31fl32xx_parse_dt(struct device *dev,
+ struct is31fl32xx_priv *priv)
+{
+ struct device_node *child;
+ int ret = 0;
+
+ for_each_child_of_node(dev->of_node, child) {
+ struct is31fl32xx_led_data *led_data =
+ &priv->leds[priv->num_leds];
+ const struct is31fl32xx_led_data *other_led_data;
+
+ led_data->priv = priv;
+
+ ret = is31fl32xx_parse_child_dt(dev, child, led_data);
+ if (ret)
+ goto err;
+
+ /* Detect if channel is already in use by another child */
+ other_led_data = is31fl32xx_find_led_data(priv,
+ led_data->channel);
+ if (other_led_data) {
+ dev_err(dev,
+ "%s and %s both attempting to use channel %d\n",
+ led_data->cdev.name,
+ other_led_data->cdev.name,
+ led_data->channel);
+ goto err;
+ }
+
+ ret = devm_led_classdev_register(dev, &led_data->cdev);
+ if (ret) {
+ dev_err(dev, "failed to register PWM led for %s: %d\n",
+ led_data->cdev.name, ret);
+ goto err;
+ }
+
+ priv->num_leds++;
+ }
+
+ return 0;
+
+err:
+ of_node_put(child);
+ return ret;
+}
+
+static const struct of_device_id of_is31fl31xx_match[] = {
+ { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, },
+ { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, },
+ { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, },
+ { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, },
+ { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, },
+ { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, of_is31fl31xx_match);
+
+static int is31fl32xx_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct is31fl32xx_chipdef *cdef;
+ const struct of_device_id *of_dev_id;
+ struct device *dev = &client->dev;
+ struct is31fl32xx_priv *priv;
+ int count;
+ int ret = 0;
+
+ of_dev_id = of_match_device(of_is31fl31xx_match, dev);
+ if (!of_dev_id)
+ return -EINVAL;
+
+ cdef = of_dev_id->data;
+
+ count = of_get_child_count(dev->of_node);
+ if (!count)
+ return -EINVAL;
+
+ priv = devm_kzalloc(dev, sizeof_is31fl32xx_priv(count),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+ priv->cdef = cdef;
+ i2c_set_clientdata(client, priv);
+
+ ret = is31fl32xx_init_regs(priv);
+ if (ret)
+ return ret;
+
+ ret = is31fl32xx_parse_dt(dev, priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int is31fl32xx_remove(struct i2c_client *client)
+{
+ struct is31fl32xx_priv *priv = i2c_get_clientdata(client);
+
+ return is31fl32xx_reset_regs(priv);
+}
+
+/*
+ * i2c-core requires that id_table be non-NULL, even though
+ * it is not used for DeviceTree based instantiation.
+ */
+static const struct i2c_device_id is31fl31xx_id[] = {
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, is31fl31xx_id);
+
+static struct i2c_driver is31fl32xx_driver = {
+ .driver = {
+ .name = "is31fl32xx",
+ .of_match_table = of_is31fl31xx_match,
+ },
+ .probe = is31fl32xx_probe,
+ .remove = is31fl32xx_remove,
+ .id_table = is31fl31xx_id,
+};
+
+module_i2c_driver(is31fl32xx_driver);
+
+MODULE_AUTHOR("David Rivshin <drivshin@allworx.com>");
+MODULE_DESCRIPTION("ISSI IS31FL32xx LED driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c
index 196dcb5e6004..5b529dc013d2 100644
--- a/drivers/leds/leds-lm3533.c
+++ b/drivers/leds/leds-lm3533.c
@@ -698,7 +698,7 @@ static int lm3533_led_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, led);
- ret = led_classdev_register(pdev->dev.parent, &led->cdev);
+ ret = devm_led_classdev_register(pdev->dev.parent, &led->cdev);
if (ret) {
dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id);
return ret;
@@ -708,18 +708,13 @@ static int lm3533_led_probe(struct platform_device *pdev)
ret = lm3533_led_setup(led, pdata);
if (ret)
- goto err_unregister;
+ return ret;
ret = lm3533_ctrlbank_enable(&led->cb);
if (ret)
- goto err_unregister;
+ return ret;
return 0;
-
-err_unregister:
- led_classdev_unregister(&led->cdev);
-
- return ret;
}
static int lm3533_led_remove(struct platform_device *pdev)
@@ -729,7 +724,6 @@ static int lm3533_led_remove(struct platform_device *pdev)
dev_dbg(&pdev->dev, "%s\n", __func__);
lm3533_ctrlbank_disable(&led->cb);
- led_classdev_unregister(&led->cdev);
return 0;
}
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index 6c758aea1bbd..be60c181222a 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -199,8 +199,11 @@ static int lp3944_led_set(struct lp3944_led_data *led, u8 status)
if (status > LP3944_LED_STATUS_DIM1)
return -EINVAL;
- /* invert only 0 and 1, leave unchanged the other values,
- * remember we are abusing status to set blink patterns
+ /*
+ * Invert status only when it's < 2 (i.e. 0 or 1) which means it's
+ * controlling the on/off state directly.
+ * When, instead, status is >= 2 don't invert it because it would mean
+ * to mess with the hardware blinking mode.
*/
if (led->type == LP3944_LED_TYPE_LED_INVERTED && status < 2)
status = 1 - status;
diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c
index 0eee38fc0565..38c253a43700 100644
--- a/drivers/leds/leds-lp8788.c
+++ b/drivers/leds/leds-lp8788.c
@@ -146,15 +146,13 @@ static int lp8788_led_probe(struct platform_device *pdev)
mutex_init(&led->lock);
- platform_set_drvdata(pdev, led);
-
ret = lp8788_led_init_device(led, led_pdata);
if (ret) {
dev_err(dev, "led init device err: %d\n", ret);
return ret;
}
- ret = led_classdev_register(dev, &led->led_dev);
+ ret = devm_led_classdev_register(dev, &led->led_dev);
if (ret) {
dev_err(dev, "led register err: %d\n", ret);
return ret;
@@ -163,18 +161,8 @@ static int lp8788_led_probe(struct platform_device *pdev)
return 0;
}
-static int lp8788_led_remove(struct platform_device *pdev)
-{
- struct lp8788_led *led = platform_get_drvdata(pdev);
-
- led_classdev_unregister(&led->led_dev);
-
- return 0;
-}
-
static struct platform_driver lp8788_led_driver = {
.probe = lp8788_led_probe,
- .remove = lp8788_led_remove,
.driver = {
.name = LP8788_DEV_KEYLED,
},
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
index 01b459069358..4edf74f1d6d4 100644
--- a/drivers/leds/leds-max8997.c
+++ b/drivers/leds/leds-max8997.c
@@ -281,30 +281,18 @@ static int max8997_led_probe(struct platform_device *pdev)
mutex_init(&led->mutex);
- platform_set_drvdata(pdev, led);
-
- ret = led_classdev_register(&pdev->dev, &led->cdev);
+ ret = devm_led_classdev_register(&pdev->dev, &led->cdev);
if (ret < 0)
return ret;
return 0;
}
-static int max8997_led_remove(struct platform_device *pdev)
-{
- struct max8997_led *led = platform_get_drvdata(pdev);
-
- led_classdev_unregister(&led->cdev);
-
- return 0;
-}
-
static struct platform_driver max8997_led_driver = {
.driver = {
.name = "max8997-led",
},
.probe = max8997_led_probe,
- .remove = max8997_led_remove,
};
module_platform_driver(max8997_led_driver);
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index 83641a7b299a..404da451cb88 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -29,11 +29,6 @@ struct s3c24xx_gpio_led {
struct s3c24xx_led_platdata *pdata;
};
-static inline struct s3c24xx_gpio_led *pdev_to_gpio(struct platform_device *dev)
-{
- return platform_get_drvdata(dev);
-}
-
static inline struct s3c24xx_gpio_led *to_gpio(struct led_classdev *led_cdev)
{
return container_of(led_cdev, struct s3c24xx_gpio_led, cdev);
@@ -59,15 +54,6 @@ static void s3c24xx_led_set(struct led_classdev *led_cdev,
}
}
-static int s3c24xx_led_remove(struct platform_device *dev)
-{
- struct s3c24xx_gpio_led *led = pdev_to_gpio(dev);
-
- led_classdev_unregister(&led->cdev);
-
- return 0;
-}
-
static int s3c24xx_led_probe(struct platform_device *dev)
{
struct s3c24xx_led_platdata *pdata = dev_get_platdata(&dev->dev);
@@ -79,8 +65,6 @@ static int s3c24xx_led_probe(struct platform_device *dev)
if (!led)
return -ENOMEM;
- platform_set_drvdata(dev, led);
-
led->cdev.brightness_set = s3c24xx_led_set;
led->cdev.default_trigger = pdata->def_trigger;
led->cdev.name = pdata->name;
@@ -104,7 +88,7 @@ static int s3c24xx_led_probe(struct platform_device *dev)
/* register our new led device */
- ret = led_classdev_register(&dev->dev, &led->cdev);
+ ret = devm_led_classdev_register(&dev->dev, &led->cdev);
if (ret < 0)
dev_err(&dev->dev, "led_classdev_register failed\n");
@@ -113,7 +97,6 @@ static int s3c24xx_led_probe(struct platform_device *dev)
static struct platform_driver s3c24xx_led_driver = {
.probe = s3c24xx_led_probe,
- .remove = s3c24xx_led_remove,
.driver = {
.name = "s3c24xx_led",
},
diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c
index 64a22263e7fc..be93b20e792a 100644
--- a/drivers/leds/leds-wm831x-status.c
+++ b/drivers/leds/leds-wm831x-status.c
@@ -239,7 +239,6 @@ static int wm831x_status_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- platform_set_drvdata(pdev, drvdata);
drvdata->wm831x = wm831x;
drvdata->reg = res->start;
@@ -284,7 +283,7 @@ static int wm831x_status_probe(struct platform_device *pdev)
drvdata->cdev.blink_set = wm831x_status_blink_set;
drvdata->cdev.groups = wm831x_status_groups;
- ret = led_classdev_register(wm831x->dev, &drvdata->cdev);
+ ret = devm_led_classdev_register(wm831x->dev, &drvdata->cdev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
return ret;
@@ -293,21 +292,11 @@ static int wm831x_status_probe(struct platform_device *pdev)
return 0;
}
-static int wm831x_status_remove(struct platform_device *pdev)
-{
- struct wm831x_status *drvdata = platform_get_drvdata(pdev);
-
- led_classdev_unregister(&drvdata->cdev);
-
- return 0;
-}
-
static struct platform_driver wm831x_status_driver = {
.driver = {
.name = "wm831x-status",
},
.probe = wm831x_status_probe,
- .remove = wm831x_status_remove,
};
module_platform_driver(wm831x_status_driver);
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 33224cb91c5b..9f6acd5d1d2e 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -572,11 +572,13 @@ int nvm_register(struct request_queue *q, char *disk_name,
}
}
- ret = nvm_get_sysblock(dev, &dev->sb);
- if (!ret)
- pr_err("nvm: device not initialized.\n");
- else if (ret < 0)
- pr_err("nvm: err (%d) on device initialization\n", ret);
+ if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) {
+ ret = nvm_get_sysblock(dev, &dev->sb);
+ if (!ret)
+ pr_err("nvm: device not initialized.\n");
+ else if (ret < 0)
+ pr_err("nvm: err (%d) on device initialization\n", ret);
+ }
/* register device with a supported media manager */
down_write(&nvm_lock);
@@ -1055,9 +1057,11 @@ static long __nvm_ioctl_dev_init(struct nvm_ioctl_dev_init *init)
strncpy(info.mmtype, init->mmtype, NVM_MMTYPE_LEN);
info.fs_ppa.ppa = -1;
- ret = nvm_init_sysblock(dev, &info);
- if (ret)
- return ret;
+ if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) {
+ ret = nvm_init_sysblock(dev, &info);
+ if (ret)
+ return ret;
+ }
memcpy(&dev->sb, &info, sizeof(struct nvm_sb_info));
@@ -1117,7 +1121,10 @@ static long nvm_ioctl_dev_factory(struct file *file, void __user *arg)
dev->mt = NULL;
}
- return nvm_dev_factory(dev, fact.flags);
+ if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT)
+ return nvm_dev_factory(dev, fact.flags);
+
+ return 0;
}
static long nvm_ctl_ioctl(struct file *file, uint cmd, unsigned long arg)
diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c
index d8c75958ced3..307db1ea22de 100644
--- a/drivers/lightnvm/rrpc.c
+++ b/drivers/lightnvm/rrpc.c
@@ -300,8 +300,10 @@ static int rrpc_move_valid_pages(struct rrpc *rrpc, struct rrpc_block *rblk)
}
page = mempool_alloc(rrpc->page_pool, GFP_NOIO);
- if (!page)
+ if (!page) {
+ bio_put(bio);
return -ENOMEM;
+ }
while ((slot = find_first_zero_bit(rblk->invalid_pages,
nr_pgs_per_blk)) < nr_pgs_per_blk) {
diff --git a/drivers/lightnvm/rrpc.h b/drivers/lightnvm/rrpc.h
index ef13ac7700c8..f7b37336353f 100644
--- a/drivers/lightnvm/rrpc.h
+++ b/drivers/lightnvm/rrpc.h
@@ -174,8 +174,7 @@ static inline sector_t rrpc_get_sector(sector_t laddr)
static inline int request_intersects(struct rrpc_inflight_rq *r,
sector_t laddr_start, sector_t laddr_end)
{
- return (laddr_end >= r->l_start && laddr_end <= r->l_end) &&
- (laddr_start >= r->l_start && laddr_start <= r->l_end);
+ return (laddr_end >= r->l_start) && (laddr_start <= r->l_end);
}
static int __rrpc_lock_laddr(struct rrpc *rrpc, sector_t laddr,
@@ -184,6 +183,8 @@ static int __rrpc_lock_laddr(struct rrpc *rrpc, sector_t laddr,
sector_t laddr_end = laddr + pages - 1;
struct rrpc_inflight_rq *rtmp;
+ WARN_ON(irqs_disabled());
+
spin_lock_irq(&rrpc->inflights.lock);
list_for_each_entry(rtmp, &rrpc->inflights.reqs, list) {
if (unlikely(request_intersects(rtmp, laddr, laddr_end))) {
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 4f12c6f01fe7..b6819f0fc608 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -31,7 +31,6 @@
#include <asm/macio.h>
#include <asm/pmac_feature.h>
#include <asm/prom.h>
-#include <asm/pci-bridge.h>
#undef DEBUG
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index 8f779a1ec99c..0ddf638d60f3 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -63,6 +63,7 @@
#include <linux/platform_device.h>
#include <linux/mailbox_controller.h>
#include <linux/mailbox_client.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
#include "mailbox.h"
@@ -70,6 +71,9 @@
static struct mbox_chan *pcc_mbox_channels;
+/* Array of cached virtual address for doorbell registers */
+static void __iomem **pcc_doorbell_vaddr;
+
static struct mbox_controller pcc_mbox_ctrl = {};
/**
* get_pcc_channel - Given a PCC subspace idx, get
@@ -160,6 +164,66 @@ void pcc_mbox_free_channel(struct mbox_chan *chan)
}
EXPORT_SYMBOL_GPL(pcc_mbox_free_channel);
+/*
+ * PCC can be used with perf critical drivers such as CPPC
+ * So it makes sense to locally cache the virtual address and
+ * use it to read/write to PCC registers such as doorbell register
+ *
+ * The below read_register and write_registers are used to read and
+ * write from perf critical registers such as PCC doorbell register
+ */
+static int read_register(void __iomem *vaddr, u64 *val, unsigned int bit_width)
+{
+ int ret_val = 0;
+
+ switch (bit_width) {
+ case 8:
+ *val = readb(vaddr);
+ break;
+ case 16:
+ *val = readw(vaddr);
+ break;
+ case 32:
+ *val = readl(vaddr);
+ break;
+ case 64:
+ *val = readq(vaddr);
+ break;
+ default:
+ pr_debug("Error: Cannot read register of %u bit width",
+ bit_width);
+ ret_val = -EFAULT;
+ break;
+ }
+ return ret_val;
+}
+
+static int write_register(void __iomem *vaddr, u64 val, unsigned int bit_width)
+{
+ int ret_val = 0;
+
+ switch (bit_width) {
+ case 8:
+ writeb(val, vaddr);
+ break;
+ case 16:
+ writew(val, vaddr);
+ break;
+ case 32:
+ writel(val, vaddr);
+ break;
+ case 64:
+ writeq(val, vaddr);
+ break;
+ default:
+ pr_debug("Error: Cannot write register of %u bit width",
+ bit_width);
+ ret_val = -EFAULT;
+ break;
+ }
+ return ret_val;
+}
+
/**
* pcc_send_data - Called from Mailbox Controller code. Used
* here only to ring the channel doorbell. The PCC client
@@ -175,21 +239,39 @@ EXPORT_SYMBOL_GPL(pcc_mbox_free_channel);
static int pcc_send_data(struct mbox_chan *chan, void *data)
{
struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv;
- struct acpi_generic_address doorbell;
+ struct acpi_generic_address *doorbell;
u64 doorbell_preserve;
u64 doorbell_val;
u64 doorbell_write;
+ u32 id = chan - pcc_mbox_channels;
+ int ret = 0;
+
+ if (id >= pcc_mbox_ctrl.num_chans) {
+ pr_debug("pcc_send_data: Invalid mbox_chan passed\n");
+ return -ENOENT;
+ }
- doorbell = pcct_ss->doorbell_register;
+ doorbell = &pcct_ss->doorbell_register;
doorbell_preserve = pcct_ss->preserve_mask;
doorbell_write = pcct_ss->write_mask;
/* Sync notification from OS to Platform. */
- acpi_read(&doorbell_val, &doorbell);
- acpi_write((doorbell_val & doorbell_preserve) | doorbell_write,
- &doorbell);
-
- return 0;
+ if (pcc_doorbell_vaddr[id]) {
+ ret = read_register(pcc_doorbell_vaddr[id], &doorbell_val,
+ doorbell->bit_width);
+ if (ret)
+ return ret;
+ ret = write_register(pcc_doorbell_vaddr[id],
+ (doorbell_val & doorbell_preserve) | doorbell_write,
+ doorbell->bit_width);
+ } else {
+ ret = acpi_read(&doorbell_val, doorbell);
+ if (ret)
+ return ret;
+ ret = acpi_write((doorbell_val & doorbell_preserve) | doorbell_write,
+ doorbell);
+ }
+ return ret;
}
static const struct mbox_chan_ops pcc_chan_ops = {
@@ -265,14 +347,29 @@ static int __init acpi_pcc_probe(void)
return -ENOMEM;
}
+ pcc_doorbell_vaddr = kcalloc(count, sizeof(void *), GFP_KERNEL);
+ if (!pcc_doorbell_vaddr) {
+ kfree(pcc_mbox_channels);
+ return -ENOMEM;
+ }
+
/* Point to the first PCC subspace entry */
pcct_entry = (struct acpi_subtable_header *) (
(unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct));
for (i = 0; i < count; i++) {
+ struct acpi_generic_address *db_reg;
+ struct acpi_pcct_hw_reduced *pcct_ss;
pcc_mbox_channels[i].con_priv = pcct_entry;
pcct_entry = (struct acpi_subtable_header *)
((unsigned long) pcct_entry + pcct_entry->length);
+
+ /* If doorbell is in system memory cache the virt address */
+ pcct_ss = (struct acpi_pcct_hw_reduced *)pcct_entry;
+ db_reg = &pcct_ss->doorbell_register;
+ if (db_reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ pcc_doorbell_vaddr[i] = acpi_os_ioremap(db_reg->address,
+ db_reg->bit_width/8);
}
pcc_mbox_ctrl.num_chans = count;
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 0a2e7273db9e..02a5345a44a6 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -249,6 +249,7 @@ config DM_DEBUG_BLOCK_STACK_TRACING
block manager locking used by thin provisioning and caching.
If unsure, say N.
+
config DM_BIO_PRISON
tristate
depends on BLK_DEV_DM
@@ -304,16 +305,6 @@ config DM_CACHE
algorithms used to select which blocks are promoted, demoted,
cleaned etc. It supports writeback and writethrough modes.
-config DM_CACHE_MQ
- tristate "MQ Cache Policy (EXPERIMENTAL)"
- depends on DM_CACHE
- default y
- ---help---
- A cache policy that uses a multiqueue ordered by recent hit
- count to select which blocks should be promoted and demoted.
- This is meant to be a general purpose policy. It prioritises
- reads over writes.
-
config DM_CACHE_SMQ
tristate "Stochastic MQ Cache Policy (EXPERIMENTAL)"
depends on DM_CACHE
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 62a65764e8e0..52ba8dd82821 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -12,7 +12,6 @@ dm-log-userspace-y \
+= dm-log-userspace-base.o dm-log-userspace-transfer.o
dm-thin-pool-y += dm-thin.o dm-thin-metadata.o
dm-cache-y += dm-cache-target.o dm-cache-metadata.o dm-cache-policy.o
-dm-cache-mq-y += dm-cache-policy-mq.o
dm-cache-smq-y += dm-cache-policy-smq.o
dm-cache-cleaner-y += dm-cache-policy-cleaner.o
dm-era-y += dm-era-target.o
@@ -55,7 +54,6 @@ obj-$(CONFIG_DM_RAID) += dm-raid.o
obj-$(CONFIG_DM_THIN_PROVISIONING) += dm-thin-pool.o
obj-$(CONFIG_DM_VERITY) += dm-verity.o
obj-$(CONFIG_DM_CACHE) += dm-cache.o
-obj-$(CONFIG_DM_CACHE_MQ) += dm-cache-mq.o
obj-$(CONFIG_DM_CACHE_SMQ) += dm-cache-smq.o
obj-$(CONFIG_DM_CACHE_CLEANER) += dm-cache-cleaner.o
obj-$(CONFIG_DM_ERA) += dm-era.o
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index f6543f3a970f..27f2ef300f8b 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -867,19 +867,40 @@ static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd,
return 0;
}
-#define WRITE_LOCK(cmd) \
- if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
+#define WRITE_LOCK(cmd) \
+ down_write(&cmd->root_lock); \
+ if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
+ up_write(&cmd->root_lock); \
return -EINVAL; \
- down_write(&cmd->root_lock)
+ }
#define WRITE_LOCK_VOID(cmd) \
- if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
+ down_write(&cmd->root_lock); \
+ if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
+ up_write(&cmd->root_lock); \
return; \
- down_write(&cmd->root_lock)
+ }
#define WRITE_UNLOCK(cmd) \
up_write(&cmd->root_lock)
+#define READ_LOCK(cmd) \
+ down_read(&cmd->root_lock); \
+ if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
+ up_read(&cmd->root_lock); \
+ return -EINVAL; \
+ }
+
+#define READ_LOCK_VOID(cmd) \
+ down_read(&cmd->root_lock); \
+ if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
+ up_read(&cmd->root_lock); \
+ return; \
+ }
+
+#define READ_UNLOCK(cmd) \
+ up_read(&cmd->root_lock)
+
int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size)
{
int r;
@@ -1015,22 +1036,20 @@ int dm_cache_load_discards(struct dm_cache_metadata *cmd,
{
int r;
- down_read(&cmd->root_lock);
+ READ_LOCK(cmd);
r = __load_discards(cmd, fn, context);
- up_read(&cmd->root_lock);
+ READ_UNLOCK(cmd);
return r;
}
-dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd)
+int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result)
{
- dm_cblock_t r;
+ READ_LOCK(cmd);
+ *result = cmd->cache_blocks;
+ READ_UNLOCK(cmd);
- down_read(&cmd->root_lock);
- r = cmd->cache_blocks;
- up_read(&cmd->root_lock);
-
- return r;
+ return 0;
}
static int __remove(struct dm_cache_metadata *cmd, dm_cblock_t cblock)
@@ -1188,9 +1207,9 @@ int dm_cache_load_mappings(struct dm_cache_metadata *cmd,
{
int r;
- down_read(&cmd->root_lock);
+ READ_LOCK(cmd);
r = __load_mappings(cmd, policy, fn, context);
- up_read(&cmd->root_lock);
+ READ_UNLOCK(cmd);
return r;
}
@@ -1215,18 +1234,18 @@ static int __dump_mappings(struct dm_cache_metadata *cmd)
void dm_cache_dump(struct dm_cache_metadata *cmd)
{
- down_read(&cmd->root_lock);
+ READ_LOCK_VOID(cmd);
__dump_mappings(cmd);
- up_read(&cmd->root_lock);
+ READ_UNLOCK(cmd);
}
int dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd)
{
int r;
- down_read(&cmd->root_lock);
+ READ_LOCK(cmd);
r = cmd->changed;
- up_read(&cmd->root_lock);
+ READ_UNLOCK(cmd);
return r;
}
@@ -1276,9 +1295,9 @@ int dm_cache_set_dirty(struct dm_cache_metadata *cmd,
void dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd,
struct dm_cache_statistics *stats)
{
- down_read(&cmd->root_lock);
+ READ_LOCK_VOID(cmd);
*stats = cmd->stats;
- up_read(&cmd->root_lock);
+ READ_UNLOCK(cmd);
}
void dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd,
@@ -1312,9 +1331,9 @@ int dm_cache_get_free_metadata_block_count(struct dm_cache_metadata *cmd,
{
int r = -EINVAL;
- down_read(&cmd->root_lock);
+ READ_LOCK(cmd);
r = dm_sm_get_nr_free(cmd->metadata_sm, result);
- up_read(&cmd->root_lock);
+ READ_UNLOCK(cmd);
return r;
}
@@ -1324,9 +1343,9 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd,
{
int r = -EINVAL;
- down_read(&cmd->root_lock);
+ READ_LOCK(cmd);
r = dm_sm_get_nr_blocks(cmd->metadata_sm, result);
- up_read(&cmd->root_lock);
+ READ_UNLOCK(cmd);
return r;
}
@@ -1417,7 +1436,13 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *
int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result)
{
- return blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
+ int r;
+
+ READ_LOCK(cmd);
+ r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
+ READ_UNLOCK(cmd);
+
+ return r;
}
void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd)
@@ -1440,10 +1465,7 @@ int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd)
struct dm_block *sblock;
struct cache_disk_superblock *disk_super;
- /*
- * We ignore fail_io for this function.
- */
- down_write(&cmd->root_lock);
+ WRITE_LOCK(cmd);
set_bit(NEEDS_CHECK, &cmd->flags);
r = superblock_lock(cmd, &sblock);
@@ -1458,19 +1480,17 @@ int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd)
dm_bm_unlock(sblock);
out:
- up_write(&cmd->root_lock);
+ WRITE_UNLOCK(cmd);
return r;
}
-bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd)
+int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result)
{
- bool needs_check;
+ READ_LOCK(cmd);
+ *result = !!test_bit(NEEDS_CHECK, &cmd->flags);
+ READ_UNLOCK(cmd);
- down_read(&cmd->root_lock);
- needs_check = !!test_bit(NEEDS_CHECK, &cmd->flags);
- up_read(&cmd->root_lock);
-
- return needs_check;
+ return 0;
}
int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h
index 2ffee21f318d..8528744195e5 100644
--- a/drivers/md/dm-cache-metadata.h
+++ b/drivers/md/dm-cache-metadata.h
@@ -66,7 +66,7 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd);
* origin blocks to map to.
*/
int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size);
-dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd);
+int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result);
int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd,
sector_t discard_block_size,
@@ -137,7 +137,7 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *
*/
int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result);
-bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd);
+int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result);
int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd);
void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd);
void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd);
diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c
deleted file mode 100644
index ddb26980cd66..000000000000
--- a/drivers/md/dm-cache-policy-mq.c
+++ /dev/null
@@ -1,1473 +0,0 @@
-/*
- * Copyright (C) 2012 Red Hat. All rights reserved.
- *
- * This file is released under the GPL.
- */
-
-#include "dm-cache-policy.h"
-#include "dm.h"
-
-#include <linux/hash.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#define DM_MSG_PREFIX "cache-policy-mq"
-
-static struct kmem_cache *mq_entry_cache;
-
-/*----------------------------------------------------------------*/
-
-static unsigned next_power(unsigned n, unsigned min)
-{
- return roundup_pow_of_two(max(n, min));
-}
-
-/*----------------------------------------------------------------*/
-
-/*
- * Large, sequential ios are probably better left on the origin device since
- * spindles tend to have good bandwidth.
- *
- * The io_tracker tries to spot when the io is in one of these sequential
- * modes.
- *
- * Two thresholds to switch between random and sequential io mode are defaulting
- * as follows and can be adjusted via the constructor and message interfaces.
- */
-#define RANDOM_THRESHOLD_DEFAULT 4
-#define SEQUENTIAL_THRESHOLD_DEFAULT 512
-
-enum io_pattern {
- PATTERN_SEQUENTIAL,
- PATTERN_RANDOM
-};
-
-struct io_tracker {
- enum io_pattern pattern;
-
- unsigned nr_seq_samples;
- unsigned nr_rand_samples;
- unsigned thresholds[2];
-
- dm_oblock_t last_end_oblock;
-};
-
-static void iot_init(struct io_tracker *t,
- int sequential_threshold, int random_threshold)
-{
- t->pattern = PATTERN_RANDOM;
- t->nr_seq_samples = 0;
- t->nr_rand_samples = 0;
- t->last_end_oblock = 0;
- t->thresholds[PATTERN_RANDOM] = random_threshold;
- t->thresholds[PATTERN_SEQUENTIAL] = sequential_threshold;
-}
-
-static enum io_pattern iot_pattern(struct io_tracker *t)
-{
- return t->pattern;
-}
-
-static void iot_update_stats(struct io_tracker *t, struct bio *bio)
-{
- if (bio->bi_iter.bi_sector == from_oblock(t->last_end_oblock) + 1)
- t->nr_seq_samples++;
- else {
- /*
- * Just one non-sequential IO is enough to reset the
- * counters.
- */
- if (t->nr_seq_samples) {
- t->nr_seq_samples = 0;
- t->nr_rand_samples = 0;
- }
-
- t->nr_rand_samples++;
- }
-
- t->last_end_oblock = to_oblock(bio_end_sector(bio) - 1);
-}
-
-static void iot_check_for_pattern_switch(struct io_tracker *t)
-{
- switch (t->pattern) {
- case PATTERN_SEQUENTIAL:
- if (t->nr_rand_samples >= t->thresholds[PATTERN_RANDOM]) {
- t->pattern = PATTERN_RANDOM;
- t->nr_seq_samples = t->nr_rand_samples = 0;
- }
- break;
-
- case PATTERN_RANDOM:
- if (t->nr_seq_samples >= t->thresholds[PATTERN_SEQUENTIAL]) {
- t->pattern = PATTERN_SEQUENTIAL;
- t->nr_seq_samples = t->nr_rand_samples = 0;
- }
- break;
- }
-}
-
-static void iot_examine_bio(struct io_tracker *t, struct bio *bio)
-{
- iot_update_stats(t, bio);
- iot_check_for_pattern_switch(t);
-}
-
-/*----------------------------------------------------------------*/
-
-
-/*
- * This queue is divided up into different levels. Allowing us to push
- * entries to the back of any of the levels. Think of it as a partially
- * sorted queue.
- */
-#define NR_QUEUE_LEVELS 16u
-#define NR_SENTINELS NR_QUEUE_LEVELS * 3
-
-#define WRITEBACK_PERIOD HZ
-
-struct queue {
- unsigned nr_elts;
- bool current_writeback_sentinels;
- unsigned long next_writeback;
- struct list_head qs[NR_QUEUE_LEVELS];
- struct list_head sentinels[NR_SENTINELS];
-};
-
-static void queue_init(struct queue *q)
-{
- unsigned i;
-
- q->nr_elts = 0;
- q->current_writeback_sentinels = false;
- q->next_writeback = 0;
- for (i = 0; i < NR_QUEUE_LEVELS; i++) {
- INIT_LIST_HEAD(q->qs + i);
- INIT_LIST_HEAD(q->sentinels + i);
- INIT_LIST_HEAD(q->sentinels + NR_QUEUE_LEVELS + i);
- INIT_LIST_HEAD(q->sentinels + (2 * NR_QUEUE_LEVELS) + i);
- }
-}
-
-static unsigned queue_size(struct queue *q)
-{
- return q->nr_elts;
-}
-
-static bool queue_empty(struct queue *q)
-{
- return q->nr_elts == 0;
-}
-
-/*
- * Insert an entry to the back of the given level.
- */
-static void queue_push(struct queue *q, unsigned level, struct list_head *elt)
-{
- q->nr_elts++;
- list_add_tail(elt, q->qs + level);
-}
-
-static void queue_remove(struct queue *q, struct list_head *elt)
-{
- q->nr_elts--;
- list_del(elt);
-}
-
-static bool is_sentinel(struct queue *q, struct list_head *h)
-{
- return (h >= q->sentinels) && (h < (q->sentinels + NR_SENTINELS));
-}
-
-/*
- * Gives us the oldest entry of the lowest popoulated level. If the first
- * level is emptied then we shift down one level.
- */
-static struct list_head *queue_peek(struct queue *q)
-{
- unsigned level;
- struct list_head *h;
-
- for (level = 0; level < NR_QUEUE_LEVELS; level++)
- list_for_each(h, q->qs + level)
- if (!is_sentinel(q, h))
- return h;
-
- return NULL;
-}
-
-static struct list_head *queue_pop(struct queue *q)
-{
- struct list_head *r = queue_peek(q);
-
- if (r) {
- q->nr_elts--;
- list_del(r);
- }
-
- return r;
-}
-
-/*
- * Pops an entry from a level that is not past a sentinel.
- */
-static struct list_head *queue_pop_old(struct queue *q)
-{
- unsigned level;
- struct list_head *h;
-
- for (level = 0; level < NR_QUEUE_LEVELS; level++)
- list_for_each(h, q->qs + level) {
- if (is_sentinel(q, h))
- break;
-
- q->nr_elts--;
- list_del(h);
- return h;
- }
-
- return NULL;
-}
-
-static struct list_head *list_pop(struct list_head *lh)
-{
- struct list_head *r = lh->next;
-
- BUG_ON(!r);
- list_del_init(r);
-
- return r;
-}
-
-static struct list_head *writeback_sentinel(struct queue *q, unsigned level)
-{
- if (q->current_writeback_sentinels)
- return q->sentinels + NR_QUEUE_LEVELS + level;
- else
- return q->sentinels + 2 * NR_QUEUE_LEVELS + level;
-}
-
-static void queue_update_writeback_sentinels(struct queue *q)
-{
- unsigned i;
- struct list_head *h;
-
- if (time_after(jiffies, q->next_writeback)) {
- for (i = 0; i < NR_QUEUE_LEVELS; i++) {
- h = writeback_sentinel(q, i);
- list_del(h);
- list_add_tail(h, q->qs + i);
- }
-
- q->next_writeback = jiffies + WRITEBACK_PERIOD;
- q->current_writeback_sentinels = !q->current_writeback_sentinels;
- }
-}
-
-/*
- * Sometimes we want to iterate through entries that have been pushed since
- * a certain event. We use sentinel entries on the queues to delimit these
- * 'tick' events.
- */
-static void queue_tick(struct queue *q)
-{
- unsigned i;
-
- for (i = 0; i < NR_QUEUE_LEVELS; i++) {
- list_del(q->sentinels + i);
- list_add_tail(q->sentinels + i, q->qs + i);
- }
-}
-
-typedef void (*iter_fn)(struct list_head *, void *);
-static void queue_iterate_tick(struct queue *q, iter_fn fn, void *context)
-{
- unsigned i;
- struct list_head *h;
-
- for (i = 0; i < NR_QUEUE_LEVELS; i++) {
- list_for_each_prev(h, q->qs + i) {
- if (is_sentinel(q, h))
- break;
-
- fn(h, context);
- }
- }
-}
-
-/*----------------------------------------------------------------*/
-
-/*
- * Describes a cache entry. Used in both the cache and the pre_cache.
- */
-struct entry {
- struct hlist_node hlist;
- struct list_head list;
- dm_oblock_t oblock;
-
- /*
- * FIXME: pack these better
- */
- bool dirty:1;
- unsigned hit_count;
-};
-
-/*
- * Rather than storing the cblock in an entry, we allocate all entries in
- * an array, and infer the cblock from the entry position.
- *
- * Free entries are linked together into a list.
- */
-struct entry_pool {
- struct entry *entries, *entries_end;
- struct list_head free;
- unsigned nr_allocated;
-};
-
-static int epool_init(struct entry_pool *ep, unsigned nr_entries)
-{
- unsigned i;
-
- ep->entries = vzalloc(sizeof(struct entry) * nr_entries);
- if (!ep->entries)
- return -ENOMEM;
-
- ep->entries_end = ep->entries + nr_entries;
-
- INIT_LIST_HEAD(&ep->free);
- for (i = 0; i < nr_entries; i++)
- list_add(&ep->entries[i].list, &ep->free);
-
- ep->nr_allocated = 0;
-
- return 0;
-}
-
-static void epool_exit(struct entry_pool *ep)
-{
- vfree(ep->entries);
-}
-
-static struct entry *alloc_entry(struct entry_pool *ep)
-{
- struct entry *e;
-
- if (list_empty(&ep->free))
- return NULL;
-
- e = list_entry(list_pop(&ep->free), struct entry, list);
- INIT_LIST_HEAD(&e->list);
- INIT_HLIST_NODE(&e->hlist);
- ep->nr_allocated++;
-
- return e;
-}
-
-/*
- * This assumes the cblock hasn't already been allocated.
- */
-static struct entry *alloc_particular_entry(struct entry_pool *ep, dm_cblock_t cblock)
-{
- struct entry *e = ep->entries + from_cblock(cblock);
-
- list_del_init(&e->list);
- INIT_HLIST_NODE(&e->hlist);
- ep->nr_allocated++;
-
- return e;
-}
-
-static void free_entry(struct entry_pool *ep, struct entry *e)
-{
- BUG_ON(!ep->nr_allocated);
- ep->nr_allocated--;
- INIT_HLIST_NODE(&e->hlist);
- list_add(&e->list, &ep->free);
-}
-
-/*
- * Returns NULL if the entry is free.
- */
-static struct entry *epool_find(struct entry_pool *ep, dm_cblock_t cblock)
-{
- struct entry *e = ep->entries + from_cblock(cblock);
- return !hlist_unhashed(&e->hlist) ? e : NULL;
-}
-
-static bool epool_empty(struct entry_pool *ep)
-{
- return list_empty(&ep->free);
-}
-
-static bool in_pool(struct entry_pool *ep, struct entry *e)
-{
- return e >= ep->entries && e < ep->entries_end;
-}
-
-static dm_cblock_t infer_cblock(struct entry_pool *ep, struct entry *e)
-{
- return to_cblock(e - ep->entries);
-}
-
-/*----------------------------------------------------------------*/
-
-struct mq_policy {
- struct dm_cache_policy policy;
-
- /* protects everything */
- struct mutex lock;
- dm_cblock_t cache_size;
- struct io_tracker tracker;
-
- /*
- * Entries come from two pools, one of pre-cache entries, and one
- * for the cache proper.
- */
- struct entry_pool pre_cache_pool;
- struct entry_pool cache_pool;
-
- /*
- * We maintain three queues of entries. The cache proper,
- * consisting of a clean and dirty queue, contains the currently
- * active mappings. Whereas the pre_cache tracks blocks that
- * are being hit frequently and potential candidates for promotion
- * to the cache.
- */
- struct queue pre_cache;
- struct queue cache_clean;
- struct queue cache_dirty;
-
- /*
- * Keeps track of time, incremented by the core. We use this to
- * avoid attributing multiple hits within the same tick.
- *
- * Access to tick_protected should be done with the spin lock held.
- * It's copied to tick at the start of the map function (within the
- * mutex).
- */
- spinlock_t tick_lock;
- unsigned tick_protected;
- unsigned tick;
-
- /*
- * A count of the number of times the map function has been called
- * and found an entry in the pre_cache or cache. Currently used to
- * calculate the generation.
- */
- unsigned hit_count;
-
- /*
- * A generation is a longish period that is used to trigger some
- * book keeping effects. eg, decrementing hit counts on entries.
- * This is needed to allow the cache to evolve as io patterns
- * change.
- */
- unsigned generation;
- unsigned generation_period; /* in lookups (will probably change) */
-
- unsigned discard_promote_adjustment;
- unsigned read_promote_adjustment;
- unsigned write_promote_adjustment;
-
- /*
- * The hash table allows us to quickly find an entry by origin
- * block. Both pre_cache and cache entries are in here.
- */
- unsigned nr_buckets;
- dm_block_t hash_bits;
- struct hlist_head *table;
-};
-
-#define DEFAULT_DISCARD_PROMOTE_ADJUSTMENT 1
-#define DEFAULT_READ_PROMOTE_ADJUSTMENT 4
-#define DEFAULT_WRITE_PROMOTE_ADJUSTMENT 8
-#define DISCOURAGE_DEMOTING_DIRTY_THRESHOLD 128
-
-/*----------------------------------------------------------------*/
-
-/*
- * Simple hash table implementation. Should replace with the standard hash
- * table that's making its way upstream.
- */
-static void hash_insert(struct mq_policy *mq, struct entry *e)
-{
- unsigned h = hash_64(from_oblock(e->oblock), mq->hash_bits);
-
- hlist_add_head(&e->hlist, mq->table + h);
-}
-
-static struct entry *hash_lookup(struct mq_policy *mq, dm_oblock_t oblock)
-{
- unsigned h = hash_64(from_oblock(oblock), mq->hash_bits);
- struct hlist_head *bucket = mq->table + h;
- struct entry *e;
-
- hlist_for_each_entry(e, bucket, hlist)
- if (e->oblock == oblock) {
- hlist_del(&e->hlist);
- hlist_add_head(&e->hlist, bucket);
- return e;
- }
-
- return NULL;
-}
-
-static void hash_remove(struct entry *e)
-{
- hlist_del(&e->hlist);
-}
-
-/*----------------------------------------------------------------*/
-
-static bool any_free_cblocks(struct mq_policy *mq)
-{
- return !epool_empty(&mq->cache_pool);
-}
-
-static bool any_clean_cblocks(struct mq_policy *mq)
-{
- return !queue_empty(&mq->cache_clean);
-}
-
-/*----------------------------------------------------------------*/
-
-/*
- * Now we get to the meat of the policy. This section deals with deciding
- * when to to add entries to the pre_cache and cache, and move between
- * them.
- */
-
-/*
- * The queue level is based on the log2 of the hit count.
- */
-static unsigned queue_level(struct entry *e)
-{
- return min((unsigned) ilog2(e->hit_count), NR_QUEUE_LEVELS - 1u);
-}
-
-static bool in_cache(struct mq_policy *mq, struct entry *e)
-{
- return in_pool(&mq->cache_pool, e);
-}
-
-/*
- * Inserts the entry into the pre_cache or the cache. Ensures the cache
- * block is marked as allocated if necc. Inserts into the hash table.
- * Sets the tick which records when the entry was last moved about.
- */
-static void push(struct mq_policy *mq, struct entry *e)
-{
- hash_insert(mq, e);
-
- if (in_cache(mq, e))
- queue_push(e->dirty ? &mq->cache_dirty : &mq->cache_clean,
- queue_level(e), &e->list);
- else
- queue_push(&mq->pre_cache, queue_level(e), &e->list);
-}
-
-/*
- * Removes an entry from pre_cache or cache. Removes from the hash table.
- */
-static void del(struct mq_policy *mq, struct entry *e)
-{
- if (in_cache(mq, e))
- queue_remove(e->dirty ? &mq->cache_dirty : &mq->cache_clean, &e->list);
- else
- queue_remove(&mq->pre_cache, &e->list);
-
- hash_remove(e);
-}
-
-/*
- * Like del, except it removes the first entry in the queue (ie. the least
- * recently used).
- */
-static struct entry *pop(struct mq_policy *mq, struct queue *q)
-{
- struct entry *e;
- struct list_head *h = queue_pop(q);
-
- if (!h)
- return NULL;
-
- e = container_of(h, struct entry, list);
- hash_remove(e);
-
- return e;
-}
-
-static struct entry *pop_old(struct mq_policy *mq, struct queue *q)
-{
- struct entry *e;
- struct list_head *h = queue_pop_old(q);
-
- if (!h)
- return NULL;
-
- e = container_of(h, struct entry, list);
- hash_remove(e);
-
- return e;
-}
-
-static struct entry *peek(struct queue *q)
-{
- struct list_head *h = queue_peek(q);
- return h ? container_of(h, struct entry, list) : NULL;
-}
-
-/*
- * The promotion threshold is adjusted every generation. As are the counts
- * of the entries.
- *
- * At the moment the threshold is taken by averaging the hit counts of some
- * of the entries in the cache (the first 20 entries across all levels in
- * ascending order, giving preference to the clean entries at each level).
- *
- * We can be much cleverer than this though. For example, each promotion
- * could bump up the threshold helping to prevent churn. Much more to do
- * here.
- */
-
-#define MAX_TO_AVERAGE 20
-
-static void check_generation(struct mq_policy *mq)
-{
- unsigned total = 0, nr = 0, count = 0, level;
- struct list_head *head;
- struct entry *e;
-
- if ((mq->hit_count >= mq->generation_period) && (epool_empty(&mq->cache_pool))) {
- mq->hit_count = 0;
- mq->generation++;
-
- for (level = 0; level < NR_QUEUE_LEVELS && count < MAX_TO_AVERAGE; level++) {
- head = mq->cache_clean.qs + level;
- list_for_each_entry(e, head, list) {
- nr++;
- total += e->hit_count;
-
- if (++count >= MAX_TO_AVERAGE)
- break;
- }
-
- head = mq->cache_dirty.qs + level;
- list_for_each_entry(e, head, list) {
- nr++;
- total += e->hit_count;
-
- if (++count >= MAX_TO_AVERAGE)
- break;
- }
- }
- }
-}
-
-/*
- * Whenever we use an entry we bump up it's hit counter, and push it to the
- * back to it's current level.
- */
-static void requeue(struct mq_policy *mq, struct entry *e)
-{
- check_generation(mq);
- del(mq, e);
- push(mq, e);
-}
-
-/*
- * Demote the least recently used entry from the cache to the pre_cache.
- * Returns the new cache entry to use, and the old origin block it was
- * mapped to.
- *
- * We drop the hit count on the demoted entry back to 1 to stop it bouncing
- * straight back into the cache if it's subsequently hit. There are
- * various options here, and more experimentation would be good:
- *
- * - just forget about the demoted entry completely (ie. don't insert it
- into the pre_cache).
- * - divide the hit count rather that setting to some hard coded value.
- * - set the hit count to a hard coded value other than 1, eg, is it better
- * if it goes in at level 2?
- */
-static int demote_cblock(struct mq_policy *mq,
- struct policy_locker *locker, dm_oblock_t *oblock)
-{
- struct entry *demoted = peek(&mq->cache_clean);
-
- if (!demoted)
- /*
- * We could get a block from mq->cache_dirty, but that
- * would add extra latency to the triggering bio as it
- * waits for the writeback. Better to not promote this
- * time and hope there's a clean block next time this block
- * is hit.
- */
- return -ENOSPC;
-
- if (locker->fn(locker, demoted->oblock))
- /*
- * We couldn't lock the demoted block.
- */
- return -EBUSY;
-
- del(mq, demoted);
- *oblock = demoted->oblock;
- free_entry(&mq->cache_pool, demoted);
-
- /*
- * We used to put the demoted block into the pre-cache, but I think
- * it's simpler to just let it work it's way up from zero again.
- * Stops blocks flickering in and out of the cache.
- */
-
- return 0;
-}
-
-/*
- * Entries in the pre_cache whose hit count passes the promotion
- * threshold move to the cache proper. Working out the correct
- * value for the promotion_threshold is crucial to this policy.
- */
-static unsigned promote_threshold(struct mq_policy *mq)
-{
- struct entry *e;
-
- if (any_free_cblocks(mq))
- return 0;
-
- e = peek(&mq->cache_clean);
- if (e)
- return e->hit_count;
-
- e = peek(&mq->cache_dirty);
- if (e)
- return e->hit_count + DISCOURAGE_DEMOTING_DIRTY_THRESHOLD;
-
- /* This should never happen */
- return 0;
-}
-
-/*
- * We modify the basic promotion_threshold depending on the specific io.
- *
- * If the origin block has been discarded then there's no cost to copy it
- * to the cache.
- *
- * We bias towards reads, since they can be demoted at no cost if they
- * haven't been dirtied.
- */
-static unsigned adjusted_promote_threshold(struct mq_policy *mq,
- bool discarded_oblock, int data_dir)
-{
- if (data_dir == READ)
- return promote_threshold(mq) + mq->read_promote_adjustment;
-
- if (discarded_oblock && (any_free_cblocks(mq) || any_clean_cblocks(mq))) {
- /*
- * We don't need to do any copying at all, so give this a
- * very low threshold.
- */
- return mq->discard_promote_adjustment;
- }
-
- return promote_threshold(mq) + mq->write_promote_adjustment;
-}
-
-static bool should_promote(struct mq_policy *mq, struct entry *e,
- bool discarded_oblock, int data_dir)
-{
- return e->hit_count >=
- adjusted_promote_threshold(mq, discarded_oblock, data_dir);
-}
-
-static int cache_entry_found(struct mq_policy *mq,
- struct entry *e,
- struct policy_result *result)
-{
- requeue(mq, e);
-
- if (in_cache(mq, e)) {
- result->op = POLICY_HIT;
- result->cblock = infer_cblock(&mq->cache_pool, e);
- }
-
- return 0;
-}
-
-/*
- * Moves an entry from the pre_cache to the cache. The main work is
- * finding which cache block to use.
- */
-static int pre_cache_to_cache(struct mq_policy *mq, struct entry *e,
- struct policy_locker *locker,
- struct policy_result *result)
-{
- int r;
- struct entry *new_e;
-
- /* Ensure there's a free cblock in the cache */
- if (epool_empty(&mq->cache_pool)) {
- result->op = POLICY_REPLACE;
- r = demote_cblock(mq, locker, &result->old_oblock);
- if (r) {
- result->op = POLICY_MISS;
- return 0;
- }
-
- } else
- result->op = POLICY_NEW;
-
- new_e = alloc_entry(&mq->cache_pool);
- BUG_ON(!new_e);
-
- new_e->oblock = e->oblock;
- new_e->dirty = false;
- new_e->hit_count = e->hit_count;
-
- del(mq, e);
- free_entry(&mq->pre_cache_pool, e);
- push(mq, new_e);
-
- result->cblock = infer_cblock(&mq->cache_pool, new_e);
-
- return 0;
-}
-
-static int pre_cache_entry_found(struct mq_policy *mq, struct entry *e,
- bool can_migrate, bool discarded_oblock,
- int data_dir, struct policy_locker *locker,
- struct policy_result *result)
-{
- int r = 0;
-
- if (!should_promote(mq, e, discarded_oblock, data_dir)) {
- requeue(mq, e);
- result->op = POLICY_MISS;
-
- } else if (!can_migrate)
- r = -EWOULDBLOCK;
-
- else {
- requeue(mq, e);
- r = pre_cache_to_cache(mq, e, locker, result);
- }
-
- return r;
-}
-
-static void insert_in_pre_cache(struct mq_policy *mq,
- dm_oblock_t oblock)
-{
- struct entry *e = alloc_entry(&mq->pre_cache_pool);
-
- if (!e)
- /*
- * There's no spare entry structure, so we grab the least
- * used one from the pre_cache.
- */
- e = pop(mq, &mq->pre_cache);
-
- if (unlikely(!e)) {
- DMWARN("couldn't pop from pre cache");
- return;
- }
-
- e->dirty = false;
- e->oblock = oblock;
- e->hit_count = 1;
- push(mq, e);
-}
-
-static void insert_in_cache(struct mq_policy *mq, dm_oblock_t oblock,
- struct policy_locker *locker,
- struct policy_result *result)
-{
- int r;
- struct entry *e;
-
- if (epool_empty(&mq->cache_pool)) {
- result->op = POLICY_REPLACE;
- r = demote_cblock(mq, locker, &result->old_oblock);
- if (unlikely(r)) {
- result->op = POLICY_MISS;
- insert_in_pre_cache(mq, oblock);
- return;
- }
-
- /*
- * This will always succeed, since we've just demoted.
- */
- e = alloc_entry(&mq->cache_pool);
- BUG_ON(!e);
-
- } else {
- e = alloc_entry(&mq->cache_pool);
- result->op = POLICY_NEW;
- }
-
- e->oblock = oblock;
- e->dirty = false;
- e->hit_count = 1;
- push(mq, e);
-
- result->cblock = infer_cblock(&mq->cache_pool, e);
-}
-
-static int no_entry_found(struct mq_policy *mq, dm_oblock_t oblock,
- bool can_migrate, bool discarded_oblock,
- int data_dir, struct policy_locker *locker,
- struct policy_result *result)
-{
- if (adjusted_promote_threshold(mq, discarded_oblock, data_dir) <= 1) {
- if (can_migrate)
- insert_in_cache(mq, oblock, locker, result);
- else
- return -EWOULDBLOCK;
- } else {
- insert_in_pre_cache(mq, oblock);
- result->op = POLICY_MISS;
- }
-
- return 0;
-}
-
-/*
- * Looks the oblock up in the hash table, then decides whether to put in
- * pre_cache, or cache etc.
- */
-static int map(struct mq_policy *mq, dm_oblock_t oblock,
- bool can_migrate, bool discarded_oblock,
- int data_dir, struct policy_locker *locker,
- struct policy_result *result)
-{
- int r = 0;
- struct entry *e = hash_lookup(mq, oblock);
-
- if (e && in_cache(mq, e))
- r = cache_entry_found(mq, e, result);
-
- else if (mq->tracker.thresholds[PATTERN_SEQUENTIAL] &&
- iot_pattern(&mq->tracker) == PATTERN_SEQUENTIAL)
- result->op = POLICY_MISS;
-
- else if (e)
- r = pre_cache_entry_found(mq, e, can_migrate, discarded_oblock,
- data_dir, locker, result);
-
- else
- r = no_entry_found(mq, oblock, can_migrate, discarded_oblock,
- data_dir, locker, result);
-
- if (r == -EWOULDBLOCK)
- result->op = POLICY_MISS;
-
- return r;
-}
-
-/*----------------------------------------------------------------*/
-
-/*
- * Public interface, via the policy struct. See dm-cache-policy.h for a
- * description of these.
- */
-
-static struct mq_policy *to_mq_policy(struct dm_cache_policy *p)
-{
- return container_of(p, struct mq_policy, policy);
-}
-
-static void mq_destroy(struct dm_cache_policy *p)
-{
- struct mq_policy *mq = to_mq_policy(p);
-
- vfree(mq->table);
- epool_exit(&mq->cache_pool);
- epool_exit(&mq->pre_cache_pool);
- kfree(mq);
-}
-
-static void update_pre_cache_hits(struct list_head *h, void *context)
-{
- struct entry *e = container_of(h, struct entry, list);
- e->hit_count++;
-}
-
-static void update_cache_hits(struct list_head *h, void *context)
-{
- struct mq_policy *mq = context;
- struct entry *e = container_of(h, struct entry, list);
- e->hit_count++;
- mq->hit_count++;
-}
-
-static void copy_tick(struct mq_policy *mq)
-{
- unsigned long flags, tick;
-
- spin_lock_irqsave(&mq->tick_lock, flags);
- tick = mq->tick_protected;
- if (tick != mq->tick) {
- queue_iterate_tick(&mq->pre_cache, update_pre_cache_hits, mq);
- queue_iterate_tick(&mq->cache_dirty, update_cache_hits, mq);
- queue_iterate_tick(&mq->cache_clean, update_cache_hits, mq);
- mq->tick = tick;
- }
-
- queue_tick(&mq->pre_cache);
- queue_tick(&mq->cache_dirty);
- queue_tick(&mq->cache_clean);
- queue_update_writeback_sentinels(&mq->cache_dirty);
- spin_unlock_irqrestore(&mq->tick_lock, flags);
-}
-
-static int mq_map(struct dm_cache_policy *p, dm_oblock_t oblock,
- bool can_block, bool can_migrate, bool discarded_oblock,
- struct bio *bio, struct policy_locker *locker,
- struct policy_result *result)
-{
- int r;
- struct mq_policy *mq = to_mq_policy(p);
-
- result->op = POLICY_MISS;
-
- if (can_block)
- mutex_lock(&mq->lock);
- else if (!mutex_trylock(&mq->lock))
- return -EWOULDBLOCK;
-
- copy_tick(mq);
-
- iot_examine_bio(&mq->tracker, bio);
- r = map(mq, oblock, can_migrate, discarded_oblock,
- bio_data_dir(bio), locker, result);
-
- mutex_unlock(&mq->lock);
-
- return r;
-}
-
-static int mq_lookup(struct dm_cache_policy *p, dm_oblock_t oblock, dm_cblock_t *cblock)
-{
- int r;
- struct mq_policy *mq = to_mq_policy(p);
- struct entry *e;
-
- if (!mutex_trylock(&mq->lock))
- return -EWOULDBLOCK;
-
- e = hash_lookup(mq, oblock);
- if (e && in_cache(mq, e)) {
- *cblock = infer_cblock(&mq->cache_pool, e);
- r = 0;
- } else
- r = -ENOENT;
-
- mutex_unlock(&mq->lock);
-
- return r;
-}
-
-static void __mq_set_clear_dirty(struct mq_policy *mq, dm_oblock_t oblock, bool set)
-{
- struct entry *e;
-
- e = hash_lookup(mq, oblock);
- BUG_ON(!e || !in_cache(mq, e));
-
- del(mq, e);
- e->dirty = set;
- push(mq, e);
-}
-
-static void mq_set_dirty(struct dm_cache_policy *p, dm_oblock_t oblock)
-{
- struct mq_policy *mq = to_mq_policy(p);
-
- mutex_lock(&mq->lock);
- __mq_set_clear_dirty(mq, oblock, true);
- mutex_unlock(&mq->lock);
-}
-
-static void mq_clear_dirty(struct dm_cache_policy *p, dm_oblock_t oblock)
-{
- struct mq_policy *mq = to_mq_policy(p);
-
- mutex_lock(&mq->lock);
- __mq_set_clear_dirty(mq, oblock, false);
- mutex_unlock(&mq->lock);
-}
-
-static int mq_load_mapping(struct dm_cache_policy *p,
- dm_oblock_t oblock, dm_cblock_t cblock,
- uint32_t hint, bool hint_valid)
-{
- struct mq_policy *mq = to_mq_policy(p);
- struct entry *e;
-
- e = alloc_particular_entry(&mq->cache_pool, cblock);
- e->oblock = oblock;
- e->dirty = false; /* this gets corrected in a minute */
- e->hit_count = hint_valid ? hint : 1;
- push(mq, e);
-
- return 0;
-}
-
-static int mq_save_hints(struct mq_policy *mq, struct queue *q,
- policy_walk_fn fn, void *context)
-{
- int r;
- unsigned level;
- struct list_head *h;
- struct entry *e;
-
- for (level = 0; level < NR_QUEUE_LEVELS; level++)
- list_for_each(h, q->qs + level) {
- if (is_sentinel(q, h))
- continue;
-
- e = container_of(h, struct entry, list);
- r = fn(context, infer_cblock(&mq->cache_pool, e),
- e->oblock, e->hit_count);
- if (r)
- return r;
- }
-
- return 0;
-}
-
-static int mq_walk_mappings(struct dm_cache_policy *p, policy_walk_fn fn,
- void *context)
-{
- struct mq_policy *mq = to_mq_policy(p);
- int r = 0;
-
- mutex_lock(&mq->lock);
-
- r = mq_save_hints(mq, &mq->cache_clean, fn, context);
- if (!r)
- r = mq_save_hints(mq, &mq->cache_dirty, fn, context);
-
- mutex_unlock(&mq->lock);
-
- return r;
-}
-
-static void __remove_mapping(struct mq_policy *mq, dm_oblock_t oblock)
-{
- struct entry *e;
-
- e = hash_lookup(mq, oblock);
- BUG_ON(!e || !in_cache(mq, e));
-
- del(mq, e);
- free_entry(&mq->cache_pool, e);
-}
-
-static void mq_remove_mapping(struct dm_cache_policy *p, dm_oblock_t oblock)
-{
- struct mq_policy *mq = to_mq_policy(p);
-
- mutex_lock(&mq->lock);
- __remove_mapping(mq, oblock);
- mutex_unlock(&mq->lock);
-}
-
-static int __remove_cblock(struct mq_policy *mq, dm_cblock_t cblock)
-{
- struct entry *e = epool_find(&mq->cache_pool, cblock);
-
- if (!e)
- return -ENODATA;
-
- del(mq, e);
- free_entry(&mq->cache_pool, e);
-
- return 0;
-}
-
-static int mq_remove_cblock(struct dm_cache_policy *p, dm_cblock_t cblock)
-{
- int r;
- struct mq_policy *mq = to_mq_policy(p);
-
- mutex_lock(&mq->lock);
- r = __remove_cblock(mq, cblock);
- mutex_unlock(&mq->lock);
-
- return r;
-}
-
-#define CLEAN_TARGET_PERCENTAGE 25
-
-static bool clean_target_met(struct mq_policy *mq)
-{
- /*
- * Cache entries may not be populated. So we're cannot rely on the
- * size of the clean queue.
- */
- unsigned nr_clean = from_cblock(mq->cache_size) - queue_size(&mq->cache_dirty);
- unsigned target = from_cblock(mq->cache_size) * CLEAN_TARGET_PERCENTAGE / 100;
-
- return nr_clean >= target;
-}
-
-static int __mq_writeback_work(struct mq_policy *mq, dm_oblock_t *oblock,
- dm_cblock_t *cblock)
-{
- struct entry *e = pop_old(mq, &mq->cache_dirty);
-
- if (!e && !clean_target_met(mq))
- e = pop(mq, &mq->cache_dirty);
-
- if (!e)
- return -ENODATA;
-
- *oblock = e->oblock;
- *cblock = infer_cblock(&mq->cache_pool, e);
- e->dirty = false;
- push(mq, e);
-
- return 0;
-}
-
-static int mq_writeback_work(struct dm_cache_policy *p, dm_oblock_t *oblock,
- dm_cblock_t *cblock, bool critical_only)
-{
- int r;
- struct mq_policy *mq = to_mq_policy(p);
-
- mutex_lock(&mq->lock);
- r = __mq_writeback_work(mq, oblock, cblock);
- mutex_unlock(&mq->lock);
-
- return r;
-}
-
-static void __force_mapping(struct mq_policy *mq,
- dm_oblock_t current_oblock, dm_oblock_t new_oblock)
-{
- struct entry *e = hash_lookup(mq, current_oblock);
-
- if (e && in_cache(mq, e)) {
- del(mq, e);
- e->oblock = new_oblock;
- e->dirty = true;
- push(mq, e);
- }
-}
-
-static void mq_force_mapping(struct dm_cache_policy *p,
- dm_oblock_t current_oblock, dm_oblock_t new_oblock)
-{
- struct mq_policy *mq = to_mq_policy(p);
-
- mutex_lock(&mq->lock);
- __force_mapping(mq, current_oblock, new_oblock);
- mutex_unlock(&mq->lock);
-}
-
-static dm_cblock_t mq_residency(struct dm_cache_policy *p)
-{
- dm_cblock_t r;
- struct mq_policy *mq = to_mq_policy(p);
-
- mutex_lock(&mq->lock);
- r = to_cblock(mq->cache_pool.nr_allocated);
- mutex_unlock(&mq->lock);
-
- return r;
-}
-
-static void mq_tick(struct dm_cache_policy *p, bool can_block)
-{
- struct mq_policy *mq = to_mq_policy(p);
- unsigned long flags;
-
- spin_lock_irqsave(&mq->tick_lock, flags);
- mq->tick_protected++;
- spin_unlock_irqrestore(&mq->tick_lock, flags);
-
- if (can_block) {
- mutex_lock(&mq->lock);
- copy_tick(mq);
- mutex_unlock(&mq->lock);
- }
-}
-
-static int mq_set_config_value(struct dm_cache_policy *p,
- const char *key, const char *value)
-{
- struct mq_policy *mq = to_mq_policy(p);
- unsigned long tmp;
-
- if (kstrtoul(value, 10, &tmp))
- return -EINVAL;
-
- if (!strcasecmp(key, "random_threshold")) {
- mq->tracker.thresholds[PATTERN_RANDOM] = tmp;
-
- } else if (!strcasecmp(key, "sequential_threshold")) {
- mq->tracker.thresholds[PATTERN_SEQUENTIAL] = tmp;
-
- } else if (!strcasecmp(key, "discard_promote_adjustment"))
- mq->discard_promote_adjustment = tmp;
-
- else if (!strcasecmp(key, "read_promote_adjustment"))
- mq->read_promote_adjustment = tmp;
-
- else if (!strcasecmp(key, "write_promote_adjustment"))
- mq->write_promote_adjustment = tmp;
-
- else
- return -EINVAL;
-
- return 0;
-}
-
-static int mq_emit_config_values(struct dm_cache_policy *p, char *result,
- unsigned maxlen, ssize_t *sz_ptr)
-{
- ssize_t sz = *sz_ptr;
- struct mq_policy *mq = to_mq_policy(p);
-
- DMEMIT("10 random_threshold %u "
- "sequential_threshold %u "
- "discard_promote_adjustment %u "
- "read_promote_adjustment %u "
- "write_promote_adjustment %u ",
- mq->tracker.thresholds[PATTERN_RANDOM],
- mq->tracker.thresholds[PATTERN_SEQUENTIAL],
- mq->discard_promote_adjustment,
- mq->read_promote_adjustment,
- mq->write_promote_adjustment);
-
- *sz_ptr = sz;
- return 0;
-}
-
-/* Init the policy plugin interface function pointers. */
-static void init_policy_functions(struct mq_policy *mq)
-{
- mq->policy.destroy = mq_destroy;
- mq->policy.map = mq_map;
- mq->policy.lookup = mq_lookup;
- mq->policy.set_dirty = mq_set_dirty;
- mq->policy.clear_dirty = mq_clear_dirty;
- mq->policy.load_mapping = mq_load_mapping;
- mq->policy.walk_mappings = mq_walk_mappings;
- mq->policy.remove_mapping = mq_remove_mapping;
- mq->policy.remove_cblock = mq_remove_cblock;
- mq->policy.writeback_work = mq_writeback_work;
- mq->policy.force_mapping = mq_force_mapping;
- mq->policy.residency = mq_residency;
- mq->policy.tick = mq_tick;
- mq->policy.emit_config_values = mq_emit_config_values;
- mq->policy.set_config_value = mq_set_config_value;
-}
-
-static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
- sector_t origin_size,
- sector_t cache_block_size)
-{
- struct mq_policy *mq = kzalloc(sizeof(*mq), GFP_KERNEL);
-
- if (!mq)
- return NULL;
-
- init_policy_functions(mq);
- iot_init(&mq->tracker, SEQUENTIAL_THRESHOLD_DEFAULT, RANDOM_THRESHOLD_DEFAULT);
- mq->cache_size = cache_size;
-
- if (epool_init(&mq->pre_cache_pool, from_cblock(cache_size))) {
- DMERR("couldn't initialize pool of pre-cache entries");
- goto bad_pre_cache_init;
- }
-
- if (epool_init(&mq->cache_pool, from_cblock(cache_size))) {
- DMERR("couldn't initialize pool of cache entries");
- goto bad_cache_init;
- }
-
- mq->tick_protected = 0;
- mq->tick = 0;
- mq->hit_count = 0;
- mq->generation = 0;
- mq->discard_promote_adjustment = DEFAULT_DISCARD_PROMOTE_ADJUSTMENT;
- mq->read_promote_adjustment = DEFAULT_READ_PROMOTE_ADJUSTMENT;
- mq->write_promote_adjustment = DEFAULT_WRITE_PROMOTE_ADJUSTMENT;
- mutex_init(&mq->lock);
- spin_lock_init(&mq->tick_lock);
-
- queue_init(&mq->pre_cache);
- queue_init(&mq->cache_clean);
- queue_init(&mq->cache_dirty);
-
- mq->generation_period = max((unsigned) from_cblock(cache_size), 1024U);
-
- mq->nr_buckets = next_power(from_cblock(cache_size) / 2, 16);
- mq->hash_bits = __ffs(mq->nr_buckets);
- mq->table = vzalloc(sizeof(*mq->table) * mq->nr_buckets);
- if (!mq->table)
- goto bad_alloc_table;
-
- return &mq->policy;
-
-bad_alloc_table:
- epool_exit(&mq->cache_pool);
-bad_cache_init:
- epool_exit(&mq->pre_cache_pool);
-bad_pre_cache_init:
- kfree(mq);
-
- return NULL;
-}
-
-/*----------------------------------------------------------------*/
-
-static struct dm_cache_policy_type mq_policy_type = {
- .name = "mq",
- .version = {1, 4, 0},
- .hint_size = 4,
- .owner = THIS_MODULE,
- .create = mq_create
-};
-
-static int __init mq_init(void)
-{
- int r;
-
- mq_entry_cache = kmem_cache_create("dm_mq_policy_cache_entry",
- sizeof(struct entry),
- __alignof__(struct entry),
- 0, NULL);
- if (!mq_entry_cache)
- return -ENOMEM;
-
- r = dm_cache_policy_register(&mq_policy_type);
- if (r) {
- DMERR("register failed %d", r);
- kmem_cache_destroy(mq_entry_cache);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void __exit mq_exit(void)
-{
- dm_cache_policy_unregister(&mq_policy_type);
-
- kmem_cache_destroy(mq_entry_cache);
-}
-
-module_init(mq_init);
-module_exit(mq_exit);
-
-MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("mq cache policy");
diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c
index 28d4586748d0..cf48a617a3a4 100644
--- a/drivers/md/dm-cache-policy-smq.c
+++ b/drivers/md/dm-cache-policy-smq.c
@@ -1567,8 +1567,48 @@ static void smq_tick(struct dm_cache_policy *p, bool can_block)
spin_unlock_irqrestore(&mq->lock, flags);
}
+/*
+ * smq has no config values, but the old mq policy did. To avoid breaking
+ * software we continue to accept these configurables for the mq policy,
+ * but they have no effect.
+ */
+static int mq_set_config_value(struct dm_cache_policy *p,
+ const char *key, const char *value)
+{
+ unsigned long tmp;
+
+ if (kstrtoul(value, 10, &tmp))
+ return -EINVAL;
+
+ if (!strcasecmp(key, "random_threshold") ||
+ !strcasecmp(key, "sequential_threshold") ||
+ !strcasecmp(key, "discard_promote_adjustment") ||
+ !strcasecmp(key, "read_promote_adjustment") ||
+ !strcasecmp(key, "write_promote_adjustment")) {
+ DMWARN("tunable '%s' no longer has any effect, mq policy is now an alias for smq", key);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int mq_emit_config_values(struct dm_cache_policy *p, char *result,
+ unsigned maxlen, ssize_t *sz_ptr)
+{
+ ssize_t sz = *sz_ptr;
+
+ DMEMIT("10 random_threshold 0 "
+ "sequential_threshold 0 "
+ "discard_promote_adjustment 0 "
+ "read_promote_adjustment 0 "
+ "write_promote_adjustment 0 ");
+
+ *sz_ptr = sz;
+ return 0;
+}
+
/* Init the policy plugin interface function pointers. */
-static void init_policy_functions(struct smq_policy *mq)
+static void init_policy_functions(struct smq_policy *mq, bool mimic_mq)
{
mq->policy.destroy = smq_destroy;
mq->policy.map = smq_map;
@@ -1583,6 +1623,11 @@ static void init_policy_functions(struct smq_policy *mq)
mq->policy.force_mapping = smq_force_mapping;
mq->policy.residency = smq_residency;
mq->policy.tick = smq_tick;
+
+ if (mimic_mq) {
+ mq->policy.set_config_value = mq_set_config_value;
+ mq->policy.emit_config_values = mq_emit_config_values;
+ }
}
static bool too_many_hotspot_blocks(sector_t origin_size,
@@ -1606,9 +1651,10 @@ static void calc_hotspot_params(sector_t origin_size,
*hotspot_block_size /= 2u;
}
-static struct dm_cache_policy *smq_create(dm_cblock_t cache_size,
- sector_t origin_size,
- sector_t cache_block_size)
+static struct dm_cache_policy *__smq_create(dm_cblock_t cache_size,
+ sector_t origin_size,
+ sector_t cache_block_size,
+ bool mimic_mq)
{
unsigned i;
unsigned nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS;
@@ -1618,7 +1664,7 @@ static struct dm_cache_policy *smq_create(dm_cblock_t cache_size,
if (!mq)
return NULL;
- init_policy_functions(mq);
+ init_policy_functions(mq, mimic_mq);
mq->cache_size = cache_size;
mq->cache_block_size = cache_block_size;
@@ -1706,19 +1752,41 @@ bad_pool_init:
return NULL;
}
+static struct dm_cache_policy *smq_create(dm_cblock_t cache_size,
+ sector_t origin_size,
+ sector_t cache_block_size)
+{
+ return __smq_create(cache_size, origin_size, cache_block_size, false);
+}
+
+static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
+ sector_t origin_size,
+ sector_t cache_block_size)
+{
+ return __smq_create(cache_size, origin_size, cache_block_size, true);
+}
+
/*----------------------------------------------------------------*/
static struct dm_cache_policy_type smq_policy_type = {
.name = "smq",
- .version = {1, 0, 0},
+ .version = {1, 5, 0},
.hint_size = 4,
.owner = THIS_MODULE,
.create = smq_create
};
+static struct dm_cache_policy_type mq_policy_type = {
+ .name = "mq",
+ .version = {1, 5, 0},
+ .hint_size = 4,
+ .owner = THIS_MODULE,
+ .create = mq_create,
+};
+
static struct dm_cache_policy_type default_policy_type = {
.name = "default",
- .version = {1, 4, 0},
+ .version = {1, 5, 0},
.hint_size = 4,
.owner = THIS_MODULE,
.create = smq_create,
@@ -1735,9 +1803,17 @@ static int __init smq_init(void)
return -ENOMEM;
}
+ r = dm_cache_policy_register(&mq_policy_type);
+ if (r) {
+ DMERR("register failed (as mq) %d", r);
+ dm_cache_policy_unregister(&smq_policy_type);
+ return -ENOMEM;
+ }
+
r = dm_cache_policy_register(&default_policy_type);
if (r) {
DMERR("register failed (as default) %d", r);
+ dm_cache_policy_unregister(&mq_policy_type);
dm_cache_policy_unregister(&smq_policy_type);
return -ENOMEM;
}
@@ -1748,6 +1824,7 @@ static int __init smq_init(void)
static void __exit smq_exit(void)
{
dm_cache_policy_unregister(&smq_policy_type);
+ dm_cache_policy_unregister(&mq_policy_type);
dm_cache_policy_unregister(&default_policy_type);
}
@@ -1759,3 +1836,4 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("smq cache policy");
MODULE_ALIAS("dm-cache-default");
+MODULE_ALIAS("dm-cache-mq");
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 5780accffa30..ee0510f9a85e 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -984,9 +984,14 @@ static void notify_mode_switch(struct cache *cache, enum cache_metadata_mode mod
static void set_cache_mode(struct cache *cache, enum cache_metadata_mode new_mode)
{
- bool needs_check = dm_cache_metadata_needs_check(cache->cmd);
+ bool needs_check;
enum cache_metadata_mode old_mode = get_cache_mode(cache);
+ if (dm_cache_metadata_needs_check(cache->cmd, &needs_check)) {
+ DMERR("unable to read needs_check flag, setting failure mode");
+ new_mode = CM_FAIL;
+ }
+
if (new_mode == CM_WRITE && needs_check) {
DMERR("%s: unable to switch cache to write mode until repaired.",
cache_device_name(cache));
@@ -2771,7 +2776,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
ti->split_discard_bios = false;
cache->features = ca->features;
- ti->per_bio_data_size = get_per_bio_data_size(cache);
+ ti->per_io_data_size = get_per_bio_data_size(cache);
cache->callbacks.congested_fn = cache_is_congested;
dm_table_add_target_callbacks(ti->table, &cache->callbacks);
@@ -3510,6 +3515,7 @@ static void cache_status(struct dm_target *ti, status_type_t type,
char buf[BDEVNAME_SIZE];
struct cache *cache = ti->private;
dm_cblock_t residency;
+ bool needs_check;
switch (type) {
case STATUSTYPE_INFO:
@@ -3583,7 +3589,9 @@ static void cache_status(struct dm_target *ti, status_type_t type,
else
DMEMIT("rw ");
- if (dm_cache_metadata_needs_check(cache->cmd))
+ r = dm_cache_metadata_needs_check(cache->cmd, &needs_check);
+
+ if (r || needs_check)
DMEMIT("needs_check ");
else
DMEMIT("- ");
@@ -3806,7 +3814,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits)
static struct target_type cache_target = {
.name = "cache",
- .version = {1, 8, 0},
+ .version = {1, 9, 0},
.module = THIS_MODULE,
.ctr = cache_ctr,
.dtr = cache_dtr,
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 3147c8d09ea8..4f3cb3554944 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -28,6 +28,7 @@
#include <crypto/hash.h>
#include <crypto/md5.h>
#include <crypto/algapi.h>
+#include <crypto/skcipher.h>
#include <linux/device-mapper.h>
@@ -44,7 +45,7 @@ struct convert_context {
struct bvec_iter iter_out;
sector_t cc_sector;
atomic_t cc_pending;
- struct ablkcipher_request *req;
+ struct skcipher_request *req;
};
/*
@@ -86,7 +87,7 @@ struct crypt_iv_operations {
};
struct iv_essiv_private {
- struct crypto_hash *hash_tfm;
+ struct crypto_ahash *hash_tfm;
u8 *salt;
};
@@ -153,13 +154,13 @@ struct crypt_config {
/* ESSIV: struct crypto_cipher *essiv_tfm */
void *iv_private;
- struct crypto_ablkcipher **tfms;
+ struct crypto_skcipher **tfms;
unsigned tfms_count;
/*
* Layout of each crypto request:
*
- * struct ablkcipher_request
+ * struct skcipher_request
* context
* padding
* struct dm_crypt_request
@@ -189,7 +190,7 @@ static u8 *iv_of_dmreq(struct crypt_config *cc, struct dm_crypt_request *dmreq);
/*
* Use this to access cipher attributes that are the same for each CPU.
*/
-static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc)
+static struct crypto_skcipher *any_tfm(struct crypt_config *cc)
{
return cc->tfms[0];
}
@@ -263,23 +264,25 @@ static int crypt_iv_plain64_gen(struct crypt_config *cc, u8 *iv,
static int crypt_iv_essiv_init(struct crypt_config *cc)
{
struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
- struct hash_desc desc;
+ AHASH_REQUEST_ON_STACK(req, essiv->hash_tfm);
struct scatterlist sg;
struct crypto_cipher *essiv_tfm;
int err;
sg_init_one(&sg, cc->key, cc->key_size);
- desc.tfm = essiv->hash_tfm;
- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ ahash_request_set_tfm(req, essiv->hash_tfm);
+ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
+ ahash_request_set_crypt(req, &sg, essiv->salt, cc->key_size);
- err = crypto_hash_digest(&desc, &sg, cc->key_size, essiv->salt);
+ err = crypto_ahash_digest(req);
+ ahash_request_zero(req);
if (err)
return err;
essiv_tfm = cc->iv_private;
err = crypto_cipher_setkey(essiv_tfm, essiv->salt,
- crypto_hash_digestsize(essiv->hash_tfm));
+ crypto_ahash_digestsize(essiv->hash_tfm));
if (err)
return err;
@@ -290,7 +293,7 @@ static int crypt_iv_essiv_init(struct crypt_config *cc)
static int crypt_iv_essiv_wipe(struct crypt_config *cc)
{
struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
- unsigned salt_size = crypto_hash_digestsize(essiv->hash_tfm);
+ unsigned salt_size = crypto_ahash_digestsize(essiv->hash_tfm);
struct crypto_cipher *essiv_tfm;
int r, err = 0;
@@ -320,7 +323,7 @@ static struct crypto_cipher *setup_essiv_cpu(struct crypt_config *cc,
}
if (crypto_cipher_blocksize(essiv_tfm) !=
- crypto_ablkcipher_ivsize(any_tfm(cc))) {
+ crypto_skcipher_ivsize(any_tfm(cc))) {
ti->error = "Block size of ESSIV cipher does "
"not match IV size of block cipher";
crypto_free_cipher(essiv_tfm);
@@ -342,7 +345,7 @@ static void crypt_iv_essiv_dtr(struct crypt_config *cc)
struct crypto_cipher *essiv_tfm;
struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
- crypto_free_hash(essiv->hash_tfm);
+ crypto_free_ahash(essiv->hash_tfm);
essiv->hash_tfm = NULL;
kzfree(essiv->salt);
@@ -360,7 +363,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
const char *opts)
{
struct crypto_cipher *essiv_tfm = NULL;
- struct crypto_hash *hash_tfm = NULL;
+ struct crypto_ahash *hash_tfm = NULL;
u8 *salt = NULL;
int err;
@@ -370,14 +373,14 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
}
/* Allocate hash algorithm */
- hash_tfm = crypto_alloc_hash(opts, 0, CRYPTO_ALG_ASYNC);
+ hash_tfm = crypto_alloc_ahash(opts, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(hash_tfm)) {
ti->error = "Error initializing ESSIV hash";
err = PTR_ERR(hash_tfm);
goto bad;
}
- salt = kzalloc(crypto_hash_digestsize(hash_tfm), GFP_KERNEL);
+ salt = kzalloc(crypto_ahash_digestsize(hash_tfm), GFP_KERNEL);
if (!salt) {
ti->error = "Error kmallocing salt storage in ESSIV";
err = -ENOMEM;
@@ -388,7 +391,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
cc->iv_gen_private.essiv.hash_tfm = hash_tfm;
essiv_tfm = setup_essiv_cpu(cc, ti, salt,
- crypto_hash_digestsize(hash_tfm));
+ crypto_ahash_digestsize(hash_tfm));
if (IS_ERR(essiv_tfm)) {
crypt_iv_essiv_dtr(cc);
return PTR_ERR(essiv_tfm);
@@ -399,7 +402,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
bad:
if (hash_tfm && !IS_ERR(hash_tfm))
- crypto_free_hash(hash_tfm);
+ crypto_free_ahash(hash_tfm);
kfree(salt);
return err;
}
@@ -419,7 +422,7 @@ static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv,
static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti,
const char *opts)
{
- unsigned bs = crypto_ablkcipher_blocksize(any_tfm(cc));
+ unsigned bs = crypto_skcipher_blocksize(any_tfm(cc));
int log = ilog2(bs);
/* we need to calculate how far we must shift the sector count
@@ -816,27 +819,27 @@ static void crypt_convert_init(struct crypt_config *cc,
}
static struct dm_crypt_request *dmreq_of_req(struct crypt_config *cc,
- struct ablkcipher_request *req)
+ struct skcipher_request *req)
{
return (struct dm_crypt_request *)((char *)req + cc->dmreq_start);
}
-static struct ablkcipher_request *req_of_dmreq(struct crypt_config *cc,
+static struct skcipher_request *req_of_dmreq(struct crypt_config *cc,
struct dm_crypt_request *dmreq)
{
- return (struct ablkcipher_request *)((char *)dmreq - cc->dmreq_start);
+ return (struct skcipher_request *)((char *)dmreq - cc->dmreq_start);
}
static u8 *iv_of_dmreq(struct crypt_config *cc,
struct dm_crypt_request *dmreq)
{
return (u8 *)ALIGN((unsigned long)(dmreq + 1),
- crypto_ablkcipher_alignmask(any_tfm(cc)) + 1);
+ crypto_skcipher_alignmask(any_tfm(cc)) + 1);
}
static int crypt_convert_block(struct crypt_config *cc,
struct convert_context *ctx,
- struct ablkcipher_request *req)
+ struct skcipher_request *req)
{
struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in);
struct bio_vec bv_out = bio_iter_iovec(ctx->bio_out, ctx->iter_out);
@@ -866,13 +869,13 @@ static int crypt_convert_block(struct crypt_config *cc,
return r;
}
- ablkcipher_request_set_crypt(req, &dmreq->sg_in, &dmreq->sg_out,
- 1 << SECTOR_SHIFT, iv);
+ skcipher_request_set_crypt(req, &dmreq->sg_in, &dmreq->sg_out,
+ 1 << SECTOR_SHIFT, iv);
if (bio_data_dir(ctx->bio_in) == WRITE)
- r = crypto_ablkcipher_encrypt(req);
+ r = crypto_skcipher_encrypt(req);
else
- r = crypto_ablkcipher_decrypt(req);
+ r = crypto_skcipher_decrypt(req);
if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
r = cc->iv_gen_ops->post(cc, iv, dmreq);
@@ -891,23 +894,23 @@ static void crypt_alloc_req(struct crypt_config *cc,
if (!ctx->req)
ctx->req = mempool_alloc(cc->req_pool, GFP_NOIO);
- ablkcipher_request_set_tfm(ctx->req, cc->tfms[key_index]);
+ skcipher_request_set_tfm(ctx->req, cc->tfms[key_index]);
/*
* Use REQ_MAY_BACKLOG so a cipher driver internally backlogs
* requests if driver request queue is full.
*/
- ablkcipher_request_set_callback(ctx->req,
+ skcipher_request_set_callback(ctx->req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
kcryptd_async_done, dmreq_of_req(cc, ctx->req));
}
static void crypt_free_req(struct crypt_config *cc,
- struct ablkcipher_request *req, struct bio *base_bio)
+ struct skcipher_request *req, struct bio *base_bio)
{
struct dm_crypt_io *io = dm_per_bio_data(base_bio, cc->per_bio_data_size);
- if ((struct ablkcipher_request *)(io + 1) != req)
+ if ((struct skcipher_request *)(io + 1) != req)
mempool_free(req, cc->req_pool);
}
@@ -1437,7 +1440,7 @@ static void crypt_free_tfms(struct crypt_config *cc)
for (i = 0; i < cc->tfms_count; i++)
if (cc->tfms[i] && !IS_ERR(cc->tfms[i])) {
- crypto_free_ablkcipher(cc->tfms[i]);
+ crypto_free_skcipher(cc->tfms[i]);
cc->tfms[i] = NULL;
}
@@ -1450,13 +1453,13 @@ static int crypt_alloc_tfms(struct crypt_config *cc, char *ciphermode)
unsigned i;
int err;
- cc->tfms = kmalloc(cc->tfms_count * sizeof(struct crypto_ablkcipher *),
+ cc->tfms = kmalloc(cc->tfms_count * sizeof(struct crypto_skcipher *),
GFP_KERNEL);
if (!cc->tfms)
return -ENOMEM;
for (i = 0; i < cc->tfms_count; i++) {
- cc->tfms[i] = crypto_alloc_ablkcipher(ciphermode, 0, 0);
+ cc->tfms[i] = crypto_alloc_skcipher(ciphermode, 0, 0);
if (IS_ERR(cc->tfms[i])) {
err = PTR_ERR(cc->tfms[i]);
crypt_free_tfms(cc);
@@ -1476,9 +1479,9 @@ static int crypt_setkey_allcpus(struct crypt_config *cc)
subkey_size = (cc->key_size - cc->key_extra_size) >> ilog2(cc->tfms_count);
for (i = 0; i < cc->tfms_count; i++) {
- r = crypto_ablkcipher_setkey(cc->tfms[i],
- cc->key + (i * subkey_size),
- subkey_size);
+ r = crypto_skcipher_setkey(cc->tfms[i],
+ cc->key + (i * subkey_size),
+ subkey_size);
if (r)
err = r;
}
@@ -1645,7 +1648,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
}
/* Initialize IV */
- cc->iv_size = crypto_ablkcipher_ivsize(any_tfm(cc));
+ cc->iv_size = crypto_skcipher_ivsize(any_tfm(cc));
if (cc->iv_size)
/* at least a 64 bit sector number should fit in our buffer */
cc->iv_size = max(cc->iv_size,
@@ -1763,21 +1766,21 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (ret < 0)
goto bad;
- cc->dmreq_start = sizeof(struct ablkcipher_request);
- cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc));
+ cc->dmreq_start = sizeof(struct skcipher_request);
+ cc->dmreq_start += crypto_skcipher_reqsize(any_tfm(cc));
cc->dmreq_start = ALIGN(cc->dmreq_start, __alignof__(struct dm_crypt_request));
- if (crypto_ablkcipher_alignmask(any_tfm(cc)) < CRYPTO_MINALIGN) {
+ if (crypto_skcipher_alignmask(any_tfm(cc)) < CRYPTO_MINALIGN) {
/* Allocate the padding exactly */
iv_size_padding = -(cc->dmreq_start + sizeof(struct dm_crypt_request))
- & crypto_ablkcipher_alignmask(any_tfm(cc));
+ & crypto_skcipher_alignmask(any_tfm(cc));
} else {
/*
* If the cipher requires greater alignment than kmalloc
* alignment, we don't know the exact position of the
* initialization vector. We must assume worst case.
*/
- iv_size_padding = crypto_ablkcipher_alignmask(any_tfm(cc));
+ iv_size_padding = crypto_skcipher_alignmask(any_tfm(cc));
}
ret = -ENOMEM;
@@ -1788,7 +1791,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad;
}
- cc->per_bio_data_size = ti->per_bio_data_size =
+ cc->per_bio_data_size = ti->per_io_data_size =
ALIGN(sizeof(struct dm_crypt_io) + cc->dmreq_start +
sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size,
ARCH_KMALLOC_MINALIGN);
@@ -1922,7 +1925,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
io = dm_per_bio_data(bio, cc->per_bio_data_size);
crypt_io_init(io, cc, bio, dm_target_offset(ti, bio->bi_iter.bi_sector));
- io->ctx.req = (struct ablkcipher_request *)(io + 1);
+ io->ctx.req = (struct skcipher_request *)(io + 1);
if (bio_data_dir(io->base_bio) == READ) {
if (kcryptd_io_read(io, GFP_NOWAIT))
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index b4c356a21123..cc70871a6d29 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -204,7 +204,7 @@ out:
ti->num_flush_bios = 1;
ti->num_discard_bios = 1;
- ti->per_bio_data_size = sizeof(struct dm_delay_info);
+ ti->per_io_data_size = sizeof(struct dm_delay_info);
ti->private = dc;
return 0;
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index 09e2afcafd2d..b7341de87015 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -220,7 +220,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->num_flush_bios = 1;
ti->num_discard_bios = 1;
- ti->per_bio_data_size = sizeof(struct per_bio_data);
+ ti->per_io_data_size = sizeof(struct per_bio_data);
ti->private = fc;
return 0;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 80a439543259..2adf81d81fca 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1291,7 +1291,8 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
immutable_target_type = dm_get_immutable_target_type(md);
if (immutable_target_type &&
- (immutable_target_type != dm_table_get_immutable_target_type(t))) {
+ (immutable_target_type != dm_table_get_immutable_target_type(t)) &&
+ !dm_table_get_wildcard_target(t)) {
DMWARN("can't replace immutable target type %s",
immutable_target_type->name);
r = -EINVAL;
@@ -1303,7 +1304,7 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
dm_set_md_type(md, dm_table_get_type(t));
/* setup md->queue to reflect md's type (may block) */
- r = dm_setup_md_queue(md);
+ r = dm_setup_md_queue(md, t);
if (r) {
DMWARN("unable to set up device queue for new table.");
goto err_unlock_md_type;
diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c
index 624589d51c2c..608302e222af 100644
--- a/drivers/md/dm-log-writes.c
+++ b/drivers/md/dm-log-writes.c
@@ -475,7 +475,7 @@ static int log_writes_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->flush_supported = true;
ti->num_discard_bios = 1;
ti->discards_supported = true;
- ti->per_bio_data_size = sizeof(struct per_bio_data);
+ ti->per_io_data_size = sizeof(struct per_bio_data);
ti->private = lc;
return 0;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index cfa29f574c2a..677ba223e2ae 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <scsi/scsi_dh.h>
#include <linux/atomic.h>
+#include <linux/blk-mq.h>
#define DM_MSG_PREFIX "multipath"
#define DM_PG_INIT_DELAY_MSECS 2000
@@ -33,11 +34,12 @@ struct pgpath {
struct list_head list;
struct priority_group *pg; /* Owning PG */
- unsigned is_active; /* Path status */
unsigned fail_count; /* Cumulative failure count */
struct dm_path path;
struct delayed_work activate_path;
+
+ bool is_active:1; /* Path status */
};
#define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path)
@@ -53,10 +55,10 @@ struct priority_group {
struct path_selector ps;
unsigned pg_num; /* Reference number */
- unsigned bypassed; /* Temporarily bypass this PG? */
-
unsigned nr_pgpaths; /* Number of paths in PG */
struct list_head pgpaths;
+
+ bool bypassed:1; /* Temporarily bypass this PG? */
};
/* Multipath context */
@@ -74,21 +76,20 @@ struct multipath {
wait_queue_head_t pg_init_wait; /* Wait for pg_init completion */
- unsigned pg_init_required; /* pg_init needs calling? */
unsigned pg_init_in_progress; /* Only one pg_init allowed at once */
- unsigned pg_init_delay_retry; /* Delay pg_init retry? */
unsigned nr_valid_paths; /* Total number of usable paths */
struct pgpath *current_pgpath;
struct priority_group *current_pg;
struct priority_group *next_pg; /* Switch to this PG if set */
- unsigned repeat_count; /* I/Os left before calling PS again */
- unsigned queue_io:1; /* Must we queue all I/O? */
- unsigned queue_if_no_path:1; /* Queue I/O if last path fails? */
- unsigned saved_queue_if_no_path:1; /* Saved state during suspension */
- unsigned retain_attached_hw_handler:1; /* If there's already a hw_handler present, don't change it. */
- unsigned pg_init_disabled:1; /* pg_init is not currently allowed */
+ bool queue_io:1; /* Must we queue all I/O? */
+ bool queue_if_no_path:1; /* Queue I/O if last path fails? */
+ bool saved_queue_if_no_path:1; /* Saved state during suspension */
+ bool retain_attached_hw_handler:1; /* If there's already a hw_handler present, don't change it. */
+ bool pg_init_disabled:1; /* pg_init is not currently allowed */
+ bool pg_init_required:1; /* pg_init needs calling? */
+ bool pg_init_delay_retry:1; /* Delay pg_init retry? */
unsigned pg_init_retries; /* Number of times to retry pg_init */
unsigned pg_init_count; /* Number of times pg_init called */
@@ -120,7 +121,6 @@ static struct kmem_cache *_mpio_cache;
static struct workqueue_struct *kmultipathd, *kmpath_handlerd;
static void trigger_event(struct work_struct *work);
static void activate_path(struct work_struct *work);
-static int __pgpath_busy(struct pgpath *pgpath);
/*-----------------------------------------------
@@ -132,7 +132,7 @@ static struct pgpath *alloc_pgpath(void)
struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL);
if (pgpath) {
- pgpath->is_active = 1;
+ pgpath->is_active = true;
INIT_DELAYED_WORK(&pgpath->activate_path, activate_path);
}
@@ -181,25 +181,31 @@ static void free_priority_group(struct priority_group *pg,
kfree(pg);
}
-static struct multipath *alloc_multipath(struct dm_target *ti)
+static struct multipath *alloc_multipath(struct dm_target *ti, bool use_blk_mq)
{
struct multipath *m;
- unsigned min_ios = dm_get_reserved_rq_based_ios();
m = kzalloc(sizeof(*m), GFP_KERNEL);
if (m) {
INIT_LIST_HEAD(&m->priority_groups);
spin_lock_init(&m->lock);
- m->queue_io = 1;
+ m->queue_io = true;
m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT;
INIT_WORK(&m->trigger_event, trigger_event);
init_waitqueue_head(&m->pg_init_wait);
mutex_init(&m->work_mutex);
- m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache);
- if (!m->mpio_pool) {
- kfree(m);
- return NULL;
+
+ m->mpio_pool = NULL;
+ if (!use_blk_mq) {
+ unsigned min_ios = dm_get_reserved_rq_based_ios();
+
+ m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache);
+ if (!m->mpio_pool) {
+ kfree(m);
+ return NULL;
+ }
}
+
m->ti = ti;
ti->private = m;
}
@@ -222,26 +228,41 @@ static void free_multipath(struct multipath *m)
kfree(m);
}
-static int set_mapinfo(struct multipath *m, union map_info *info)
+static struct dm_mpath_io *get_mpio(union map_info *info)
+{
+ return info->ptr;
+}
+
+static struct dm_mpath_io *set_mpio(struct multipath *m, union map_info *info)
{
struct dm_mpath_io *mpio;
+ if (!m->mpio_pool) {
+ /* Use blk-mq pdu memory requested via per_io_data_size */
+ mpio = get_mpio(info);
+ memset(mpio, 0, sizeof(*mpio));
+ return mpio;
+ }
+
mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
if (!mpio)
- return -ENOMEM;
+ return NULL;
memset(mpio, 0, sizeof(*mpio));
info->ptr = mpio;
- return 0;
+ return mpio;
}
-static void clear_mapinfo(struct multipath *m, union map_info *info)
+static void clear_request_fn_mpio(struct multipath *m, union map_info *info)
{
- struct dm_mpath_io *mpio = info->ptr;
+ /* Only needed for non blk-mq (.request_fn) multipath */
+ if (m->mpio_pool) {
+ struct dm_mpath_io *mpio = info->ptr;
- info->ptr = NULL;
- mempool_free(mpio, m->mpio_pool);
+ info->ptr = NULL;
+ mempool_free(mpio, m->mpio_pool);
+ }
}
/*-----------------------------------------------
@@ -257,7 +278,7 @@ static int __pg_init_all_paths(struct multipath *m)
return 0;
m->pg_init_count++;
- m->pg_init_required = 0;
+ m->pg_init_required = false;
/* Check here to reset pg_init_required */
if (!m->current_pg)
@@ -283,11 +304,11 @@ static void __switch_pg(struct multipath *m, struct pgpath *pgpath)
/* Must we initialise the PG first, and queue I/O till it's ready? */
if (m->hw_handler_name) {
- m->pg_init_required = 1;
- m->queue_io = 1;
+ m->pg_init_required = true;
+ m->queue_io = true;
} else {
- m->pg_init_required = 0;
- m->queue_io = 0;
+ m->pg_init_required = false;
+ m->queue_io = false;
}
m->pg_init_count = 0;
@@ -298,7 +319,7 @@ static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg,
{
struct dm_path *path;
- path = pg->ps.type->select_path(&pg->ps, &m->repeat_count, nr_bytes);
+ path = pg->ps.type->select_path(&pg->ps, nr_bytes);
if (!path)
return -ENXIO;
@@ -313,10 +334,10 @@ static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg,
static void __choose_pgpath(struct multipath *m, size_t nr_bytes)
{
struct priority_group *pg;
- unsigned bypassed = 1;
+ bool bypassed = true;
if (!m->nr_valid_paths) {
- m->queue_io = 0;
+ m->queue_io = false;
goto failed;
}
@@ -344,7 +365,7 @@ static void __choose_pgpath(struct multipath *m, size_t nr_bytes)
continue;
if (!__choose_path_in_pg(m, pg, nr_bytes)) {
if (!bypassed)
- m->pg_init_delay_retry = 1;
+ m->pg_init_delay_retry = true;
return;
}
}
@@ -380,7 +401,7 @@ static int __multipath_map(struct dm_target *ti, struct request *clone,
union map_info *map_context,
struct request *rq, struct request **__clone)
{
- struct multipath *m = (struct multipath *) ti->private;
+ struct multipath *m = ti->private;
int r = DM_MAPIO_REQUEUE;
size_t nr_bytes = clone ? blk_rq_bytes(clone) : blk_rq_bytes(rq);
struct pgpath *pgpath;
@@ -390,8 +411,7 @@ static int __multipath_map(struct dm_target *ti, struct request *clone,
spin_lock_irq(&m->lock);
/* Do we need to select a new pgpath? */
- if (!m->current_pgpath ||
- (!m->queue_io && (m->repeat_count && --m->repeat_count == 0)))
+ if (!m->current_pgpath || !m->queue_io)
__choose_pgpath(m, nr_bytes);
pgpath = m->current_pgpath;
@@ -405,11 +425,11 @@ static int __multipath_map(struct dm_target *ti, struct request *clone,
goto out_unlock;
}
- if (set_mapinfo(m, map_context) < 0)
+ mpio = set_mpio(m, map_context);
+ if (!mpio)
/* ENOMEM, requeue */
goto out_unlock;
- mpio = map_context->ptr;
mpio->pgpath = pgpath;
mpio->nr_bytes = nr_bytes;
@@ -418,17 +438,24 @@ static int __multipath_map(struct dm_target *ti, struct request *clone,
spin_unlock_irq(&m->lock);
if (clone) {
- /* Old request-based interface: allocated clone is passed in */
+ /*
+ * Old request-based interface: allocated clone is passed in.
+ * Used by: .request_fn stacked on .request_fn path(s).
+ */
clone->q = bdev_get_queue(bdev);
clone->rq_disk = bdev->bd_disk;
clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
} else {
- /* blk-mq request-based interface */
- *__clone = blk_get_request(bdev_get_queue(bdev),
- rq_data_dir(rq), GFP_ATOMIC);
+ /*
+ * blk-mq request-based interface; used by both:
+ * .request_fn stacked on blk-mq path(s) and
+ * blk-mq stacked on blk-mq path(s).
+ */
+ *__clone = blk_mq_alloc_request(bdev_get_queue(bdev),
+ rq_data_dir(rq), BLK_MQ_REQ_NOWAIT);
if (IS_ERR(*__clone)) {
/* ENOMEM, requeue */
- clear_mapinfo(m, map_context);
+ clear_request_fn_mpio(m, map_context);
return r;
}
(*__clone)->bio = (*__clone)->biotail = NULL;
@@ -463,14 +490,14 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
static void multipath_release_clone(struct request *clone)
{
- blk_put_request(clone);
+ blk_mq_free_request(clone);
}
/*
* If we run out of usable paths, should we queue I/O or error it?
*/
-static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path,
- unsigned save_old_value)
+static int queue_if_no_path(struct multipath *m, bool queue_if_no_path,
+ bool save_old_value)
{
unsigned long flags;
@@ -776,12 +803,12 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)
argc--;
if (!strcasecmp(arg_name, "queue_if_no_path")) {
- r = queue_if_no_path(m, 1, 0);
+ r = queue_if_no_path(m, true, false);
continue;
}
if (!strcasecmp(arg_name, "retain_attached_hw_handler")) {
- m->retain_attached_hw_handler = 1;
+ m->retain_attached_hw_handler = true;
continue;
}
@@ -820,11 +847,12 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
struct dm_arg_set as;
unsigned pg_count = 0;
unsigned next_pg_num;
+ bool use_blk_mq = dm_use_blk_mq(dm_table_get_md(ti->table));
as.argc = argc;
as.argv = argv;
- m = alloc_multipath(ti);
+ m = alloc_multipath(ti, use_blk_mq);
if (!m) {
ti->error = "can't allocate multipath";
return -EINVAL;
@@ -880,6 +908,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
ti->num_flush_bios = 1;
ti->num_discard_bios = 1;
ti->num_write_same_bios = 1;
+ if (use_blk_mq)
+ ti->per_io_data_size = sizeof(struct dm_mpath_io);
return 0;
@@ -917,7 +947,7 @@ static void flush_multipath_work(struct multipath *m)
unsigned long flags;
spin_lock_irqsave(&m->lock, flags);
- m->pg_init_disabled = 1;
+ m->pg_init_disabled = true;
spin_unlock_irqrestore(&m->lock, flags);
flush_workqueue(kmpath_handlerd);
@@ -926,7 +956,7 @@ static void flush_multipath_work(struct multipath *m)
flush_work(&m->trigger_event);
spin_lock_irqsave(&m->lock, flags);
- m->pg_init_disabled = 0;
+ m->pg_init_disabled = false;
spin_unlock_irqrestore(&m->lock, flags);
}
@@ -954,7 +984,7 @@ static int fail_path(struct pgpath *pgpath)
DMWARN("Failing path %s.", pgpath->path.dev->name);
pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path);
- pgpath->is_active = 0;
+ pgpath->is_active = false;
pgpath->fail_count++;
m->nr_valid_paths--;
@@ -987,18 +1017,13 @@ static int reinstate_path(struct pgpath *pgpath)
if (pgpath->is_active)
goto out;
- if (!pgpath->pg->ps.type->reinstate_path) {
- DMWARN("Reinstate path not supported by path selector %s",
- pgpath->pg->ps.type->name);
- r = -EINVAL;
- goto out;
- }
+ DMWARN("Reinstating path %s.", pgpath->path.dev->name);
r = pgpath->pg->ps.type->reinstate_path(&pgpath->pg->ps, &pgpath->path);
if (r)
goto out;
- pgpath->is_active = 1;
+ pgpath->is_active = true;
if (!m->nr_valid_paths++) {
m->current_pgpath = NULL;
@@ -1045,7 +1070,7 @@ static int action_dev(struct multipath *m, struct dm_dev *dev,
* Temporarily try to avoid having to use the specified PG
*/
static void bypass_pg(struct multipath *m, struct priority_group *pg,
- int bypassed)
+ bool bypassed)
{
unsigned long flags;
@@ -1078,7 +1103,7 @@ static int switch_pg_num(struct multipath *m, const char *pgstr)
spin_lock_irqsave(&m->lock, flags);
list_for_each_entry(pg, &m->priority_groups, list) {
- pg->bypassed = 0;
+ pg->bypassed = false;
if (--pgnum)
continue;
@@ -1096,7 +1121,7 @@ static int switch_pg_num(struct multipath *m, const char *pgstr)
* Set/clear bypassed status of a PG.
* PGs are numbered upwards from 1 in the order they were declared.
*/
-static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
+static int bypass_pg_num(struct multipath *m, const char *pgstr, bool bypassed)
{
struct priority_group *pg;
unsigned pgnum;
@@ -1120,17 +1145,17 @@ static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
/*
* Should we retry pg_init immediately?
*/
-static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)
+static bool pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)
{
unsigned long flags;
- int limit_reached = 0;
+ bool limit_reached = false;
spin_lock_irqsave(&m->lock, flags);
if (m->pg_init_count <= m->pg_init_retries && !m->pg_init_disabled)
- m->pg_init_required = 1;
+ m->pg_init_required = true;
else
- limit_reached = 1;
+ limit_reached = true;
spin_unlock_irqrestore(&m->lock, flags);
@@ -1143,7 +1168,7 @@ static void pg_init_done(void *data, int errors)
struct priority_group *pg = pgpath->pg;
struct multipath *m = pg->m;
unsigned long flags;
- unsigned delay_retry = 0;
+ bool delay_retry = false;
/* device or driver problems */
switch (errors) {
@@ -1166,7 +1191,7 @@ static void pg_init_done(void *data, int errors)
* Probably doing something like FW upgrade on the
* controller so try the other pg.
*/
- bypass_pg(m, pg, 1);
+ bypass_pg(m, pg, true);
break;
case SCSI_DH_RETRY:
/* Wait before retrying. */
@@ -1177,6 +1202,7 @@ static void pg_init_done(void *data, int errors)
fail_path(pgpath);
errors = 0;
break;
+ case SCSI_DH_DEV_OFFLINED:
default:
/*
* We probably do not want to fail the path for a device
@@ -1194,7 +1220,7 @@ static void pg_init_done(void *data, int errors)
m->current_pg = NULL;
}
} else if (!m->pg_init_required)
- pg->bypassed = 0;
+ pg->bypassed = false;
if (--m->pg_init_in_progress)
/* Activations of other paths are still on going */
@@ -1205,7 +1231,7 @@ static void pg_init_done(void *data, int errors)
if (__pg_init_all_paths(m))
goto out;
}
- m->queue_io = 0;
+ m->queue_io = false;
/*
* Wake up any thread waiting to suspend.
@@ -1291,21 +1317,21 @@ static int multipath_end_io(struct dm_target *ti, struct request *clone,
int error, union map_info *map_context)
{
struct multipath *m = ti->private;
- struct dm_mpath_io *mpio = map_context->ptr;
+ struct dm_mpath_io *mpio = get_mpio(map_context);
struct pgpath *pgpath;
struct path_selector *ps;
int r;
BUG_ON(!mpio);
- r = do_end_io(m, clone, error, mpio);
+ r = do_end_io(m, clone, error, mpio);
pgpath = mpio->pgpath;
if (pgpath) {
ps = &pgpath->pg->ps;
if (ps->type->end_io)
ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes);
}
- clear_mapinfo(m, map_context);
+ clear_request_fn_mpio(m, map_context);
return r;
}
@@ -1318,9 +1344,9 @@ static int multipath_end_io(struct dm_target *ti, struct request *clone,
*/
static void multipath_presuspend(struct dm_target *ti)
{
- struct multipath *m = (struct multipath *) ti->private;
+ struct multipath *m = ti->private;
- queue_if_no_path(m, 0, 1);
+ queue_if_no_path(m, false, true);
}
static void multipath_postsuspend(struct dm_target *ti)
@@ -1337,7 +1363,7 @@ static void multipath_postsuspend(struct dm_target *ti)
*/
static void multipath_resume(struct dm_target *ti)
{
- struct multipath *m = (struct multipath *) ti->private;
+ struct multipath *m = ti->private;
unsigned long flags;
spin_lock_irqsave(&m->lock, flags);
@@ -1366,7 +1392,7 @@ static void multipath_status(struct dm_target *ti, status_type_t type,
{
int sz = 0;
unsigned long flags;
- struct multipath *m = (struct multipath *) ti->private;
+ struct multipath *m = ti->private;
struct priority_group *pg;
struct pgpath *p;
unsigned pg_num;
@@ -1474,7 +1500,7 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
{
int r = -EINVAL;
struct dm_dev *dev;
- struct multipath *m = (struct multipath *) ti->private;
+ struct multipath *m = ti->private;
action_fn action;
mutex_lock(&m->work_mutex);
@@ -1486,10 +1512,10 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
if (argc == 1) {
if (!strcasecmp(argv[0], "queue_if_no_path")) {
- r = queue_if_no_path(m, 1, 0);
+ r = queue_if_no_path(m, true, false);
goto out;
} else if (!strcasecmp(argv[0], "fail_if_no_path")) {
- r = queue_if_no_path(m, 0, 0);
+ r = queue_if_no_path(m, false, false);
goto out;
}
}
@@ -1500,10 +1526,10 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
}
if (!strcasecmp(argv[0], "disable_group")) {
- r = bypass_pg_num(m, argv[1], 1);
+ r = bypass_pg_num(m, argv[1], true);
goto out;
} else if (!strcasecmp(argv[0], "enable_group")) {
- r = bypass_pg_num(m, argv[1], 0);
+ r = bypass_pg_num(m, argv[1], false);
goto out;
} else if (!strcasecmp(argv[0], "switch_group")) {
r = switch_pg_num(m, argv[1]);
@@ -1604,7 +1630,7 @@ out:
return ret;
}
-static int __pgpath_busy(struct pgpath *pgpath)
+static int pgpath_busy(struct pgpath *pgpath)
{
struct request_queue *q = bdev_get_queue(pgpath->path.dev->bdev);
@@ -1621,7 +1647,7 @@ static int __pgpath_busy(struct pgpath *pgpath)
*/
static int multipath_busy(struct dm_target *ti)
{
- int busy = 0, has_active = 0;
+ bool busy = false, has_active = false;
struct multipath *m = ti->private;
struct priority_group *pg;
struct pgpath *pgpath;
@@ -1632,7 +1658,7 @@ static int multipath_busy(struct dm_target *ti)
/* pg_init in progress or no paths available */
if (m->pg_init_in_progress ||
(!m->nr_valid_paths && m->queue_if_no_path)) {
- busy = 1;
+ busy = true;
goto out;
}
/* Guess which priority_group will be used at next mapping time */
@@ -1654,13 +1680,12 @@ static int multipath_busy(struct dm_target *ti)
* If there is one non-busy active path at least, the path selector
* will be able to select it. So we consider such a pg as not busy.
*/
- busy = 1;
+ busy = true;
list_for_each_entry(pgpath, &pg->pgpaths, list)
if (pgpath->is_active) {
- has_active = 1;
-
- if (!__pgpath_busy(pgpath)) {
- busy = 0;
+ has_active = true;
+ if (!pgpath_busy(pgpath)) {
+ busy = false;
break;
}
}
@@ -1671,7 +1696,7 @@ static int multipath_busy(struct dm_target *ti)
* the current_pg will be changed at next mapping time.
* We need to try mapping to determine it.
*/
- busy = 0;
+ busy = false;
out:
spin_unlock_irqrestore(&m->lock, flags);
@@ -1684,7 +1709,8 @@ out:
*---------------------------------------------------------------*/
static struct target_type multipath_target = {
.name = "multipath",
- .version = {1, 10, 0},
+ .version = {1, 11, 0},
+ .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE,
.module = THIS_MODULE,
.ctr = multipath_ctr,
.dtr = multipath_dtr,
diff --git a/drivers/md/dm-path-selector.h b/drivers/md/dm-path-selector.h
index e7d1fa8b0459..b6eb5365b1a4 100644
--- a/drivers/md/dm-path-selector.h
+++ b/drivers/md/dm-path-selector.h
@@ -50,13 +50,8 @@ struct path_selector_type {
/*
* Chooses a path for this io, if no paths are available then
* NULL will be returned.
- *
- * repeat_count is the number of times to use the path before
- * calling the function again. 0 means don't call it again unless
- * the path fails.
*/
struct dm_path *(*select_path) (struct path_selector *ps,
- unsigned *repeat_count,
size_t nr_bytes);
/*
diff --git a/drivers/md/dm-queue-length.c b/drivers/md/dm-queue-length.c
index 3941fae0de9f..23f178641794 100644
--- a/drivers/md/dm-queue-length.c
+++ b/drivers/md/dm-queue-length.c
@@ -23,12 +23,13 @@
#include <linux/atomic.h>
#define DM_MSG_PREFIX "multipath queue-length"
-#define QL_MIN_IO 128
-#define QL_VERSION "0.1.0"
+#define QL_MIN_IO 1
+#define QL_VERSION "0.2.0"
struct selector {
struct list_head valid_paths;
struct list_head failed_paths;
+ spinlock_t lock;
};
struct path_info {
@@ -45,6 +46,7 @@ static struct selector *alloc_selector(void)
if (s) {
INIT_LIST_HEAD(&s->valid_paths);
INIT_LIST_HEAD(&s->failed_paths);
+ spin_lock_init(&s->lock);
}
return s;
@@ -113,6 +115,7 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
struct path_info *pi;
unsigned repeat_count = QL_MIN_IO;
char dummy;
+ unsigned long flags;
/*
* Arguments: [<repeat_count>]
@@ -129,6 +132,11 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
return -EINVAL;
}
+ if (repeat_count > 1) {
+ DMWARN_LIMIT("repeat_count > 1 is deprecated, using 1 instead");
+ repeat_count = 1;
+ }
+
/* Allocate the path information structure */
pi = kmalloc(sizeof(*pi), GFP_KERNEL);
if (!pi) {
@@ -142,7 +150,9 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
path->pscontext = pi;
+ spin_lock_irqsave(&s->lock, flags);
list_add_tail(&pi->list, &s->valid_paths);
+ spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
@@ -151,16 +161,22 @@ static void ql_fail_path(struct path_selector *ps, struct dm_path *path)
{
struct selector *s = ps->context;
struct path_info *pi = path->pscontext;
+ unsigned long flags;
+ spin_lock_irqsave(&s->lock, flags);
list_move(&pi->list, &s->failed_paths);
+ spin_unlock_irqrestore(&s->lock, flags);
}
static int ql_reinstate_path(struct path_selector *ps, struct dm_path *path)
{
struct selector *s = ps->context;
struct path_info *pi = path->pscontext;
+ unsigned long flags;
+ spin_lock_irqsave(&s->lock, flags);
list_move_tail(&pi->list, &s->valid_paths);
+ spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
@@ -168,14 +184,16 @@ static int ql_reinstate_path(struct path_selector *ps, struct dm_path *path)
/*
* Select a path having the minimum number of in-flight I/Os
*/
-static struct dm_path *ql_select_path(struct path_selector *ps,
- unsigned *repeat_count, size_t nr_bytes)
+static struct dm_path *ql_select_path(struct path_selector *ps, size_t nr_bytes)
{
struct selector *s = ps->context;
struct path_info *pi = NULL, *best = NULL;
+ struct dm_path *ret = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&s->lock, flags);
if (list_empty(&s->valid_paths))
- return NULL;
+ goto out;
/* Change preferred (first in list) path to evenly balance. */
list_move_tail(s->valid_paths.next, &s->valid_paths);
@@ -190,11 +208,12 @@ static struct dm_path *ql_select_path(struct path_selector *ps,
}
if (!best)
- return NULL;
-
- *repeat_count = best->repeat_count;
+ goto out;
- return best->path;
+ ret = best->path;
+out:
+ spin_unlock_irqrestore(&s->lock, flags);
+ return ret;
}
static int ql_start_io(struct path_selector *ps, struct dm_path *path,
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index f2a363a89629..b3ccf1e0d4f2 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1121,7 +1121,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->num_flush_bios = 1;
ti->num_discard_bios = 1;
- ti->per_bio_data_size = sizeof(struct dm_raid1_bio_record);
+ ti->per_io_data_size = sizeof(struct dm_raid1_bio_record);
ti->discard_zeroes_data_unsupported = true;
ms->kmirrord_wq = alloc_workqueue("kmirrord", WQ_MEM_RECLAIM, 0);
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c
index 6ab1192cdd5f..4ace1da17db8 100644
--- a/drivers/md/dm-round-robin.c
+++ b/drivers/md/dm-round-robin.c
@@ -17,6 +17,8 @@
#include <linux/module.h>
#define DM_MSG_PREFIX "multipath round-robin"
+#define RR_MIN_IO 1000
+#define RR_VERSION "1.1.0"
/*-----------------------------------------------------------------
* Path-handling code, paths are held in lists
@@ -41,23 +43,48 @@ static void free_paths(struct list_head *paths)
* Round-robin selector
*---------------------------------------------------------------*/
-#define RR_MIN_IO 1000
-
struct selector {
struct list_head valid_paths;
struct list_head invalid_paths;
+ spinlock_t lock;
+ struct dm_path * __percpu *current_path;
+ struct percpu_counter repeat_count;
};
+static void set_percpu_current_path(struct selector *s, struct dm_path *path)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ *per_cpu_ptr(s->current_path, cpu) = path;
+}
+
static struct selector *alloc_selector(void)
{
struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
- if (s) {
- INIT_LIST_HEAD(&s->valid_paths);
- INIT_LIST_HEAD(&s->invalid_paths);
- }
+ if (!s)
+ return NULL;
+
+ INIT_LIST_HEAD(&s->valid_paths);
+ INIT_LIST_HEAD(&s->invalid_paths);
+ spin_lock_init(&s->lock);
+
+ s->current_path = alloc_percpu(struct dm_path *);
+ if (!s->current_path)
+ goto out_current_path;
+ set_percpu_current_path(s, NULL);
+
+ if (percpu_counter_init(&s->repeat_count, 0, GFP_KERNEL))
+ goto out_repeat_count;
return s;
+
+out_repeat_count:
+ free_percpu(s->current_path);
+out_current_path:
+ kfree(s);
+ return NULL;;
}
static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
@@ -74,10 +101,12 @@ static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
static void rr_destroy(struct path_selector *ps)
{
- struct selector *s = (struct selector *) ps->context;
+ struct selector *s = ps->context;
free_paths(&s->valid_paths);
free_paths(&s->invalid_paths);
+ free_percpu(s->current_path);
+ percpu_counter_destroy(&s->repeat_count);
kfree(s);
ps->context = NULL;
}
@@ -111,10 +140,11 @@ static int rr_status(struct path_selector *ps, struct dm_path *path,
static int rr_add_path(struct path_selector *ps, struct dm_path *path,
int argc, char **argv, char **error)
{
- struct selector *s = (struct selector *) ps->context;
+ struct selector *s = ps->context;
struct path_info *pi;
unsigned repeat_count = RR_MIN_IO;
char dummy;
+ unsigned long flags;
if (argc > 1) {
*error = "round-robin ps: incorrect number of arguments";
@@ -139,42 +169,65 @@ static int rr_add_path(struct path_selector *ps, struct dm_path *path,
path->pscontext = pi;
+ spin_lock_irqsave(&s->lock, flags);
list_add_tail(&pi->list, &s->valid_paths);
+ spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
{
- struct selector *s = (struct selector *) ps->context;
+ unsigned long flags;
+ struct selector *s = ps->context;
struct path_info *pi = p->pscontext;
+ spin_lock_irqsave(&s->lock, flags);
+ if (p == *this_cpu_ptr(s->current_path))
+ set_percpu_current_path(s, NULL);
+
list_move(&pi->list, &s->invalid_paths);
+ spin_unlock_irqrestore(&s->lock, flags);
}
static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
{
- struct selector *s = (struct selector *) ps->context;
+ unsigned long flags;
+ struct selector *s = ps->context;
struct path_info *pi = p->pscontext;
+ spin_lock_irqsave(&s->lock, flags);
list_move(&pi->list, &s->valid_paths);
+ spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
-static struct dm_path *rr_select_path(struct path_selector *ps,
- unsigned *repeat_count, size_t nr_bytes)
+static struct dm_path *rr_select_path(struct path_selector *ps, size_t nr_bytes)
{
- struct selector *s = (struct selector *) ps->context;
+ unsigned long flags;
+ struct selector *s = ps->context;
struct path_info *pi = NULL;
+ struct dm_path *current_path = NULL;
+
+ current_path = *this_cpu_ptr(s->current_path);
+ if (current_path) {
+ percpu_counter_dec(&s->repeat_count);
+ if (percpu_counter_read_positive(&s->repeat_count) > 0)
+ return current_path;
+ }
+ spin_lock_irqsave(&s->lock, flags);
if (!list_empty(&s->valid_paths)) {
pi = list_entry(s->valid_paths.next, struct path_info, list);
list_move_tail(&pi->list, &s->valid_paths);
- *repeat_count = pi->repeat_count;
+ percpu_counter_set(&s->repeat_count, pi->repeat_count);
+ set_percpu_current_path(s, pi->path);
+ current_path = pi->path;
}
+ spin_unlock_irqrestore(&s->lock, flags);
- return pi ? pi->path : NULL;
+ return current_path;
}
static struct path_selector_type rr_ps = {
@@ -198,7 +251,7 @@ static int __init dm_rr_init(void)
if (r < 0)
DMERR("register failed %d", r);
- DMINFO("version 1.0.0 loaded");
+ DMINFO("version " RR_VERSION " loaded");
return r;
}
diff --git a/drivers/md/dm-service-time.c b/drivers/md/dm-service-time.c
index 9df8f6bd6418..7b8642045c55 100644
--- a/drivers/md/dm-service-time.c
+++ b/drivers/md/dm-service-time.c
@@ -19,11 +19,12 @@
#define ST_MAX_RELATIVE_THROUGHPUT 100
#define ST_MAX_RELATIVE_THROUGHPUT_SHIFT 7
#define ST_MAX_INFLIGHT_SIZE ((size_t)-1 >> ST_MAX_RELATIVE_THROUGHPUT_SHIFT)
-#define ST_VERSION "0.2.0"
+#define ST_VERSION "0.3.0"
struct selector {
struct list_head valid_paths;
struct list_head failed_paths;
+ spinlock_t lock;
};
struct path_info {
@@ -41,6 +42,7 @@ static struct selector *alloc_selector(void)
if (s) {
INIT_LIST_HEAD(&s->valid_paths);
INIT_LIST_HEAD(&s->failed_paths);
+ spin_lock_init(&s->lock);
}
return s;
@@ -111,6 +113,7 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
unsigned repeat_count = ST_MIN_IO;
unsigned relative_throughput = 1;
char dummy;
+ unsigned long flags;
/*
* Arguments: [<repeat_count> [<relative_throughput>]]
@@ -134,6 +137,11 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
return -EINVAL;
}
+ if (repeat_count > 1) {
+ DMWARN_LIMIT("repeat_count > 1 is deprecated, using 1 instead");
+ repeat_count = 1;
+ }
+
if ((argc == 2) &&
(sscanf(argv[1], "%u%c", &relative_throughput, &dummy) != 1 ||
relative_throughput > ST_MAX_RELATIVE_THROUGHPUT)) {
@@ -155,7 +163,9 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
path->pscontext = pi;
+ spin_lock_irqsave(&s->lock, flags);
list_add_tail(&pi->list, &s->valid_paths);
+ spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
@@ -164,16 +174,22 @@ static void st_fail_path(struct path_selector *ps, struct dm_path *path)
{
struct selector *s = ps->context;
struct path_info *pi = path->pscontext;
+ unsigned long flags;
+ spin_lock_irqsave(&s->lock, flags);
list_move(&pi->list, &s->failed_paths);
+ spin_unlock_irqrestore(&s->lock, flags);
}
static int st_reinstate_path(struct path_selector *ps, struct dm_path *path)
{
struct selector *s = ps->context;
struct path_info *pi = path->pscontext;
+ unsigned long flags;
+ spin_lock_irqsave(&s->lock, flags);
list_move_tail(&pi->list, &s->valid_paths);
+ spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
@@ -255,14 +271,16 @@ static int st_compare_load(struct path_info *pi1, struct path_info *pi2,
return pi2->relative_throughput - pi1->relative_throughput;
}
-static struct dm_path *st_select_path(struct path_selector *ps,
- unsigned *repeat_count, size_t nr_bytes)
+static struct dm_path *st_select_path(struct path_selector *ps, size_t nr_bytes)
{
struct selector *s = ps->context;
struct path_info *pi = NULL, *best = NULL;
+ struct dm_path *ret = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&s->lock, flags);
if (list_empty(&s->valid_paths))
- return NULL;
+ goto out;
/* Change preferred (first in list) path to evenly balance. */
list_move_tail(s->valid_paths.next, &s->valid_paths);
@@ -272,11 +290,12 @@ static struct dm_path *st_select_path(struct path_selector *ps,
best = pi;
if (!best)
- return NULL;
-
- *repeat_count = best->repeat_count;
+ goto out;
- return best->path;
+ ret = best->path;
+out:
+ spin_unlock_irqrestore(&s->lock, flags);
+ return ret;
}
static int st_start_io(struct path_selector *ps, struct dm_path *path,
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 3766386080a4..70bb0e8b62ce 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -1105,6 +1105,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
int i;
int r = -EINVAL;
char *origin_path, *cow_path;
+ dev_t origin_dev, cow_dev;
unsigned args_used, num_flush_bios = 1;
fmode_t origin_mode = FMODE_READ;
@@ -1135,11 +1136,19 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->error = "Cannot get origin device";
goto bad_origin;
}
+ origin_dev = s->origin->bdev->bd_dev;
cow_path = argv[0];
argv++;
argc--;
+ cow_dev = dm_get_dev_t(cow_path);
+ if (cow_dev && cow_dev == origin_dev) {
+ ti->error = "COW device cannot be the same as origin device";
+ r = -EINVAL;
+ goto bad_cow;
+ }
+
r = dm_get_device(ti, cow_path, dm_table_get_mode(ti->table), &s->cow);
if (r) {
ti->error = "Cannot get COW device";
@@ -1201,7 +1210,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->private = s;
ti->num_flush_bios = num_flush_bios;
- ti->per_bio_data_size = sizeof(struct dm_snap_tracked_chunk);
+ ti->per_io_data_size = sizeof(struct dm_snap_tracked_chunk);
/* Add snapshot to the list of snapshots for this origin */
/* Exceptions aren't triggered till snapshot_resume() is called */
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 061152a43730..f9e8f0bef332 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -365,6 +365,26 @@ static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
}
/*
+ * Convert the path to a device
+ */
+dev_t dm_get_dev_t(const char *path)
+{
+ dev_t uninitialized_var(dev);
+ struct block_device *bdev;
+
+ bdev = lookup_bdev(path);
+ if (IS_ERR(bdev))
+ dev = name_to_dev_t(path);
+ else {
+ dev = bdev->bd_dev;
+ bdput(bdev);
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(dm_get_dev_t);
+
+/*
* Add a device to the list, or just increment the usage count if
* it's already present.
*/
@@ -372,23 +392,15 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
struct dm_dev **result)
{
int r;
- dev_t uninitialized_var(dev);
+ dev_t dev;
struct dm_dev_internal *dd;
struct dm_table *t = ti->table;
- struct block_device *bdev;
BUG_ON(!t);
- /* convert the path to a device */
- bdev = lookup_bdev(path);
- if (IS_ERR(bdev)) {
- dev = name_to_dev_t(path);
- if (!dev)
- return -ENODEV;
- } else {
- dev = bdev->bd_dev;
- bdput(bdev);
- }
+ dev = dm_get_dev_t(path);
+ if (!dev)
+ return -ENODEV;
dd = find_device(&t->devices, dev);
if (!dd) {
@@ -920,6 +932,30 @@ struct target_type *dm_table_get_immutable_target_type(struct dm_table *t)
return t->immutable_target_type;
}
+struct dm_target *dm_table_get_immutable_target(struct dm_table *t)
+{
+ /* Immutable target is implicitly a singleton */
+ if (t->num_targets > 1 ||
+ !dm_target_is_immutable(t->targets[0].type))
+ return NULL;
+
+ return t->targets;
+}
+
+struct dm_target *dm_table_get_wildcard_target(struct dm_table *t)
+{
+ struct dm_target *uninitialized_var(ti);
+ unsigned i = 0;
+
+ while (i < dm_table_get_num_targets(t)) {
+ ti = dm_table_get_target(t, i++);
+ if (dm_target_is_wildcard(ti->type))
+ return ti;
+ }
+
+ return NULL;
+}
+
bool dm_table_request_based(struct dm_table *t)
{
return __table_type_request_based(dm_table_get_type(t));
@@ -933,7 +969,7 @@ bool dm_table_mq_request_based(struct dm_table *t)
static int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *md)
{
unsigned type = dm_table_get_type(t);
- unsigned per_bio_data_size = 0;
+ unsigned per_io_data_size = 0;
struct dm_target *tgt;
unsigned i;
@@ -945,10 +981,10 @@ static int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *
if (type == DM_TYPE_BIO_BASED)
for (i = 0; i < t->num_targets; i++) {
tgt = t->targets + i;
- per_bio_data_size = max(per_bio_data_size, tgt->per_bio_data_size);
+ per_io_data_size = max(per_io_data_size, tgt->per_io_data_size);
}
- t->mempools = dm_alloc_md_mempools(md, type, t->integrity_supported, per_bio_data_size);
+ t->mempools = dm_alloc_md_mempools(md, type, t->integrity_supported, per_io_data_size);
if (!t->mempools)
return -ENOMEM;
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
index 925ec1b15e75..a317dd884ba6 100644
--- a/drivers/md/dm-target.c
+++ b/drivers/md/dm-target.c
@@ -150,7 +150,8 @@ static void io_err_release_clone_rq(struct request *clone)
static struct target_type error_target = {
.name = "error",
- .version = {1, 3, 0},
+ .version = {1, 4, 0},
+ .features = DM_TARGET_WILDCARD,
.ctr = io_err_ctr,
.dtr = io_err_dtr,
.map = io_err_map,
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index f962d6453afd..43824d73366d 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -344,7 +344,7 @@ static void subtree_dec(void *context, const void *value)
memcpy(&root_le, value, sizeof(root_le));
root = le64_to_cpu(root_le);
if (dm_btree_del(info, root))
- DMERR("btree delete failed\n");
+ DMERR("btree delete failed");
}
static int subtree_equal(void *context, const void *value1_le, const void *value2_le)
@@ -1981,5 +1981,8 @@ bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd)
void dm_pool_issue_prefetches(struct dm_pool_metadata *pmd)
{
- dm_tm_issue_prefetches(pmd->tm);
+ down_read(&pmd->root_lock);
+ if (!pmd->fail_io)
+ dm_tm_issue_prefetches(pmd->tm);
+ up_read(&pmd->root_lock);
}
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 72d91f477683..92237b6fa8cd 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -235,6 +235,7 @@ struct pool {
struct pool_features pf;
bool low_water_triggered:1; /* A dm event has been sent */
bool suspended:1;
+ bool out_of_data_space:1;
struct dm_bio_prison *prison;
struct dm_kcopyd_client *copier;
@@ -461,9 +462,16 @@ static void cell_error_with_code(struct pool *pool,
dm_bio_prison_free_cell(pool->prison, cell);
}
+static int get_pool_io_error_code(struct pool *pool)
+{
+ return pool->out_of_data_space ? -ENOSPC : -EIO;
+}
+
static void cell_error(struct pool *pool, struct dm_bio_prison_cell *cell)
{
- cell_error_with_code(pool, cell, -EIO);
+ int error = get_pool_io_error_code(pool);
+
+ cell_error_with_code(pool, cell, error);
}
static void cell_success(struct pool *pool, struct dm_bio_prison_cell *cell)
@@ -622,7 +630,9 @@ static void error_retry_list_with_code(struct pool *pool, int error)
static void error_retry_list(struct pool *pool)
{
- return error_retry_list_with_code(pool, -EIO);
+ int error = get_pool_io_error_code(pool);
+
+ return error_retry_list_with_code(pool, error);
}
/*
@@ -2419,6 +2429,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
*/
if (old_mode != new_mode)
notify_of_pool_mode_change_to_oods(pool);
+ pool->out_of_data_space = true;
pool->process_bio = process_bio_read_only;
pool->process_discard = process_discard_bio;
pool->process_cell = process_cell_read_only;
@@ -2432,6 +2443,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
case PM_WRITE:
if (old_mode != new_mode)
notify_of_pool_mode_change(pool, "write");
+ pool->out_of_data_space = false;
pool->pf.error_if_no_space = pt->requested_pf.error_if_no_space;
dm_pool_metadata_read_write(pool->pmd);
pool->process_bio = process_bio;
@@ -2832,6 +2844,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
INIT_LIST_HEAD(&pool->active_thins);
pool->low_water_triggered = false;
pool->suspended = true;
+ pool->out_of_data_space = false;
pool->shared_read_ds = dm_deferred_set_create();
if (!pool->shared_read_ds) {
@@ -3886,7 +3899,7 @@ static struct target_type pool_target = {
.name = "thin-pool",
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
DM_TARGET_IMMUTABLE,
- .version = {1, 17, 0},
+ .version = {1, 18, 0},
.module = THIS_MODULE,
.ctr = pool_ctr,
.dtr = pool_dtr,
@@ -4037,7 +4050,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->num_flush_bios = 1;
ti->flush_supported = true;
- ti->per_bio_data_size = sizeof(struct dm_thin_endio_hook);
+ ti->per_io_data_size = sizeof(struct dm_thin_endio_hook);
/* In case the pool supports discards, pass them on. */
ti->discard_zeroes_data_unsupported = true;
@@ -4260,7 +4273,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
static struct target_type thin_target = {
.name = "thin",
- .version = {1, 17, 0},
+ .version = {1, 18, 0},
.module = THIS_MODULE,
.ctr = thin_ctr,
.dtr = thin_dtr,
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 1cc10c4de701..459a9f8905ed 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -812,7 +812,7 @@ int verity_fec_ctr(struct dm_verity *v)
}
/* Reserve space for our per-bio data */
- ti->per_bio_data_size += sizeof(struct dm_verity_fec_io);
+ ti->per_io_data_size += sizeof(struct dm_verity_fec_io);
return 0;
}
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 5c5d30cb6ec5..0aba34a7b3b3 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -354,7 +354,7 @@ int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
size_t len))
{
unsigned todo = 1 << v->data_dev_block_bits;
- struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
+ struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
do {
int r;
@@ -460,7 +460,7 @@ static int verity_verify_io(struct dm_verity_io *io)
static void verity_finish_io(struct dm_verity_io *io, int error)
{
struct dm_verity *v = io->v;
- struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
+ struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
bio->bi_end_io = io->orig_bi_end_io;
bio->bi_error = error;
@@ -574,7 +574,7 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
if (bio_data_dir(bio) == WRITE)
return -EIO;
- io = dm_per_bio_data(bio, ti->per_bio_data_size);
+ io = dm_per_bio_data(bio, ti->per_io_data_size);
io->v = v;
io->orig_bi_end_io = bio->bi_end_io;
io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
@@ -1036,15 +1036,15 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
}
- ti->per_bio_data_size = sizeof(struct dm_verity_io) +
+ ti->per_io_data_size = sizeof(struct dm_verity_io) +
v->shash_descsize + v->digest_size * 2;
r = verity_fec_ctr(v);
if (r)
goto bad;
- ti->per_bio_data_size = roundup(ti->per_bio_data_size,
- __alignof__(struct dm_verity_io));
+ ti->per_io_data_size = roundup(ti->per_io_data_size,
+ __alignof__(struct dm_verity_io));
return 0;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 5df40480228b..be4905769a45 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -106,14 +106,6 @@ struct dm_rq_clone_bio_info {
struct bio clone;
};
-union map_info *dm_get_rq_mapinfo(struct request *rq)
-{
- if (rq && rq->end_io_data)
- return &((struct dm_rq_target_io *)rq->end_io_data)->info;
- return NULL;
-}
-EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
-
#define MINOR_ALLOCED ((void *)-1)
/*
@@ -129,28 +121,18 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
#define DMF_SUSPENDED_INTERNALLY 7
/*
- * A dummy definition to make RCU happy.
- * struct dm_table should never be dereferenced in this file.
- */
-struct dm_table {
- int undefined__;
-};
-
-/*
* Work processed by per-device workqueue.
*/
struct mapped_device {
struct srcu_struct io_barrier;
struct mutex suspend_lock;
- atomic_t holders;
- atomic_t open_count;
/*
- * The current mapping.
+ * The current mapping (struct dm_table *).
* Use dm_get_live_table{_fast} or take suspend_lock for
* dereference.
*/
- struct dm_table __rcu *map;
+ void __rcu *map;
struct list_head table_devices;
struct mutex table_devices_lock;
@@ -158,10 +140,16 @@ struct mapped_device {
unsigned long flags;
struct request_queue *queue;
+ int numa_node_id;
+
unsigned type;
/* Protect queue and type against concurrent access. */
struct mutex type_lock;
+ atomic_t holders;
+ atomic_t open_count;
+
+ struct dm_target *immutable_target;
struct target_type *immutable_target_type;
struct gendisk *disk;
@@ -175,8 +163,20 @@ struct mapped_device {
atomic_t pending[2];
wait_queue_head_t wait;
struct work_struct work;
- struct bio_list deferred;
spinlock_t deferred_lock;
+ struct bio_list deferred;
+
+ /*
+ * Event handling.
+ */
+ wait_queue_head_t eventq;
+ atomic_t event_nr;
+ atomic_t uevent_seq;
+ struct list_head uevent_list;
+ spinlock_t uevent_lock; /* Protect access to uevent_list */
+
+ /* the number of internal suspends */
+ unsigned internal_suspend_count;
/*
* Processing queue (flush)
@@ -192,32 +192,21 @@ struct mapped_device {
struct bio_set *bs;
/*
- * Event handling.
- */
- atomic_t event_nr;
- wait_queue_head_t eventq;
- atomic_t uevent_seq;
- struct list_head uevent_list;
- spinlock_t uevent_lock; /* Protect access to uevent_list */
-
- /*
* freeze/thaw support require holding onto a super block
*/
struct super_block *frozen_sb;
- struct block_device *bdev;
/* forced geometry settings */
struct hd_geometry geometry;
+ struct block_device *bdev;
+
/* kobject and completion */
struct dm_kobject_holder kobj_holder;
/* zero-length flush that will be cloned and submitted to targets */
struct bio flush_bio;
- /* the number of internal suspends */
- unsigned internal_suspend_count;
-
struct dm_stats stats;
struct kthread_worker kworker;
@@ -230,8 +219,9 @@ struct mapped_device {
ktime_t last_rq_start_time;
/* for blk-mq request-based DM support */
- struct blk_mq_tag_set tag_set;
- bool use_blk_mq;
+ struct blk_mq_tag_set *tag_set;
+ bool use_blk_mq:1;
+ bool init_tio_pdu:1;
};
#ifdef CONFIG_DM_MQ_DEFAULT
@@ -240,10 +230,19 @@ static bool use_blk_mq = true;
static bool use_blk_mq = false;
#endif
+#define DM_MQ_NR_HW_QUEUES 1
+#define DM_MQ_QUEUE_DEPTH 2048
+#define DM_NUMA_NODE NUMA_NO_NODE
+
+static unsigned dm_mq_nr_hw_queues = DM_MQ_NR_HW_QUEUES;
+static unsigned dm_mq_queue_depth = DM_MQ_QUEUE_DEPTH;
+static int dm_numa_node = DM_NUMA_NODE;
+
bool dm_use_blk_mq(struct mapped_device *md)
{
return md->use_blk_mq;
}
+EXPORT_SYMBOL_GPL(dm_use_blk_mq);
/*
* For mempools pre-allocation at the table loading time.
@@ -277,6 +276,27 @@ static unsigned reserved_bio_based_ios = RESERVED_BIO_BASED_IOS;
*/
static unsigned reserved_rq_based_ios = RESERVED_REQUEST_BASED_IOS;
+static int __dm_get_module_param_int(int *module_param, int min, int max)
+{
+ int param = ACCESS_ONCE(*module_param);
+ int modified_param = 0;
+ bool modified = true;
+
+ if (param < min)
+ modified_param = min;
+ else if (param > max)
+ modified_param = max;
+ else
+ modified = false;
+
+ if (modified) {
+ (void)cmpxchg(module_param, param, modified_param);
+ param = modified_param;
+ }
+
+ return param;
+}
+
static unsigned __dm_get_module_param(unsigned *module_param,
unsigned def, unsigned max)
{
@@ -310,6 +330,23 @@ unsigned dm_get_reserved_rq_based_ios(void)
}
EXPORT_SYMBOL_GPL(dm_get_reserved_rq_based_ios);
+static unsigned dm_get_blk_mq_nr_hw_queues(void)
+{
+ return __dm_get_module_param(&dm_mq_nr_hw_queues, 1, 32);
+}
+
+static unsigned dm_get_blk_mq_queue_depth(void)
+{
+ return __dm_get_module_param(&dm_mq_queue_depth,
+ DM_MQ_QUEUE_DEPTH, BLK_MQ_MAX_DEPTH);
+}
+
+static unsigned dm_get_numa_node(void)
+{
+ return __dm_get_module_param_int(&dm_numa_node,
+ DM_NUMA_NODE, num_online_nodes() - 1);
+}
+
static int __init local_init(void)
{
int r = -ENOMEM;
@@ -323,7 +360,7 @@ static int __init local_init(void)
if (!_rq_tio_cache)
goto out_free_io_cache;
- _rq_cache = kmem_cache_create("dm_clone_request", sizeof(struct request),
+ _rq_cache = kmem_cache_create("dm_old_clone_request", sizeof(struct request),
__alignof__(struct request), 0, NULL);
if (!_rq_cache)
goto out_free_rq_tio_cache;
@@ -556,16 +593,17 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return dm_get_geometry(md, geo);
}
-static int dm_get_live_table_for_ioctl(struct mapped_device *md,
- struct dm_target **tgt, struct block_device **bdev,
- fmode_t *mode, int *srcu_idx)
+static int dm_grab_bdev_for_ioctl(struct mapped_device *md,
+ struct block_device **bdev,
+ fmode_t *mode)
{
+ struct dm_target *tgt;
struct dm_table *map;
- int r;
+ int srcu_idx, r;
retry:
r = -ENOTTY;
- map = dm_get_live_table(md, srcu_idx);
+ map = dm_get_live_table(md, &srcu_idx);
if (!map || !dm_table_get_size(map))
goto out;
@@ -573,9 +611,8 @@ retry:
if (dm_table_get_num_targets(map) != 1)
goto out;
- *tgt = dm_table_get_target(map, 0);
-
- if (!(*tgt)->type->prepare_ioctl)
+ tgt = dm_table_get_target(map, 0);
+ if (!tgt->type->prepare_ioctl)
goto out;
if (dm_suspended_md(md)) {
@@ -583,14 +620,16 @@ retry:
goto out;
}
- r = (*tgt)->type->prepare_ioctl(*tgt, bdev, mode);
+ r = tgt->type->prepare_ioctl(tgt, bdev, mode);
if (r < 0)
goto out;
+ bdgrab(*bdev);
+ dm_put_live_table(md, srcu_idx);
return r;
out:
- dm_put_live_table(md, *srcu_idx);
+ dm_put_live_table(md, srcu_idx);
if (r == -ENOTCONN && !fatal_signal_pending(current)) {
msleep(10);
goto retry;
@@ -602,11 +641,9 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
struct mapped_device *md = bdev->bd_disk->private_data;
- struct dm_target *tgt;
- struct block_device *tgt_bdev = NULL;
- int srcu_idx, r;
+ int r;
- r = dm_get_live_table_for_ioctl(md, &tgt, &tgt_bdev, &mode, &srcu_idx);
+ r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
if (r < 0)
return r;
@@ -621,9 +658,9 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
goto out;
}
- r = __blkdev_driver_ioctl(tgt_bdev, mode, cmd, arg);
+ r = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
out:
- dm_put_live_table(md, srcu_idx);
+ bdput(bdev);
return r;
}
@@ -642,24 +679,24 @@ static void free_tio(struct mapped_device *md, struct dm_target_io *tio)
bio_put(&tio->clone);
}
-static struct dm_rq_target_io *alloc_rq_tio(struct mapped_device *md,
- gfp_t gfp_mask)
+static struct dm_rq_target_io *alloc_old_rq_tio(struct mapped_device *md,
+ gfp_t gfp_mask)
{
return mempool_alloc(md->io_pool, gfp_mask);
}
-static void free_rq_tio(struct dm_rq_target_io *tio)
+static void free_old_rq_tio(struct dm_rq_target_io *tio)
{
mempool_free(tio, tio->md->io_pool);
}
-static struct request *alloc_clone_request(struct mapped_device *md,
- gfp_t gfp_mask)
+static struct request *alloc_old_clone_request(struct mapped_device *md,
+ gfp_t gfp_mask)
{
return mempool_alloc(md->rq_pool, gfp_mask);
}
-static void free_clone_request(struct mapped_device *md, struct request *rq)
+static void free_old_clone_request(struct mapped_device *md, struct request *rq)
{
mempool_free(rq, md->rq_pool);
}
@@ -827,7 +864,7 @@ int dm_get_table_device(struct mapped_device *md, dev_t dev, fmode_t mode,
mutex_lock(&md->table_devices_lock);
td = find_table_device(&md->table_devices, dev, mode);
if (!td) {
- td = kmalloc(sizeof(*td), GFP_KERNEL);
+ td = kmalloc_node(sizeof(*td), GFP_KERNEL, md->numa_node_id);
if (!td) {
mutex_unlock(&md->table_devices_lock);
return -ENOMEM;
@@ -1109,12 +1146,8 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
* back into ->request_fn() could deadlock attempting to grab the
* queue lock again.
*/
- if (run_queue) {
- if (md->queue->mq_ops)
- blk_mq_run_hw_queues(md->queue, true);
- else
- blk_run_queue_async(md->queue);
- }
+ if (!md->queue->mq_ops && run_queue)
+ blk_run_queue_async(md->queue);
/*
* dm_put() must be at the end of this function. See the comment above
@@ -1134,15 +1167,10 @@ static void free_rq_clone(struct request *clone)
tio->ti->type->release_clone_rq(clone);
else if (!md->queue->mq_ops)
/* request_fn queue stacked on request_fn queue(s) */
- free_clone_request(md, clone);
- /*
- * NOTE: for the blk-mq queue stacked on request_fn queue(s) case:
- * no need to call free_clone_request() because we leverage blk-mq by
- * allocating the clone at the end of the blk-mq pdu (see: clone_rq)
- */
+ free_old_clone_request(md, clone);
if (!md->queue->mq_ops)
- free_rq_tio(tio);
+ free_old_rq_tio(tio);
}
/*
@@ -1191,12 +1219,14 @@ static void dm_unprep_request(struct request *rq)
if (clone)
free_rq_clone(clone);
+ else if (!tio->md->queue->mq_ops)
+ free_old_rq_tio(tio);
}
/*
* Requeue the original request of a clone.
*/
-static void old_requeue_request(struct request *rq)
+static void dm_old_requeue_request(struct request *rq)
{
struct request_queue *q = rq->q;
unsigned long flags;
@@ -1207,45 +1237,57 @@ static void old_requeue_request(struct request *rq)
spin_unlock_irqrestore(q->queue_lock, flags);
}
+static void dm_mq_requeue_request(struct request *rq)
+{
+ struct request_queue *q = rq->q;
+ unsigned long flags;
+
+ blk_mq_requeue_request(rq);
+ spin_lock_irqsave(q->queue_lock, flags);
+ if (!blk_queue_stopped(q))
+ blk_mq_kick_requeue_list(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
static void dm_requeue_original_request(struct mapped_device *md,
struct request *rq)
{
int rw = rq_data_dir(rq);
+ rq_end_stats(md, rq);
dm_unprep_request(rq);
- rq_end_stats(md, rq);
if (!rq->q->mq_ops)
- old_requeue_request(rq);
- else {
- blk_mq_requeue_request(rq);
- blk_mq_kick_requeue_list(rq->q);
- }
+ dm_old_requeue_request(rq);
+ else
+ dm_mq_requeue_request(rq);
rq_completed(md, rw, false);
}
-static void old_stop_queue(struct request_queue *q)
+static void dm_old_stop_queue(struct request_queue *q)
{
unsigned long flags;
- if (blk_queue_stopped(q))
+ spin_lock_irqsave(q->queue_lock, flags);
+ if (blk_queue_stopped(q)) {
+ spin_unlock_irqrestore(q->queue_lock, flags);
return;
+ }
- spin_lock_irqsave(q->queue_lock, flags);
blk_stop_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
}
-static void stop_queue(struct request_queue *q)
+static void dm_stop_queue(struct request_queue *q)
{
if (!q->mq_ops)
- old_stop_queue(q);
+ dm_old_stop_queue(q);
else
blk_mq_stop_hw_queues(q);
}
-static void old_start_queue(struct request_queue *q)
+static void dm_old_start_queue(struct request_queue *q)
{
unsigned long flags;
@@ -1255,12 +1297,14 @@ static void old_start_queue(struct request_queue *q)
spin_unlock_irqrestore(q->queue_lock, flags);
}
-static void start_queue(struct request_queue *q)
+static void dm_start_queue(struct request_queue *q)
{
if (!q->mq_ops)
- old_start_queue(q);
- else
+ dm_old_start_queue(q);
+ else {
blk_mq_start_stopped_hw_queues(q, true);
+ blk_mq_kick_requeue_list(q);
+ }
}
static void dm_done(struct request *clone, int error, bool mapped)
@@ -1311,7 +1355,7 @@ static void dm_softirq_done(struct request *rq)
if (!rq->q->mq_ops) {
blk_end_request_all(rq, tio->error);
rq_completed(tio->md, rw, false);
- free_rq_tio(tio);
+ free_old_rq_tio(tio);
} else {
blk_mq_end_request(rq, tio->error);
rq_completed(tio->md, rw, false);
@@ -1334,7 +1378,10 @@ static void dm_complete_request(struct request *rq, int error)
struct dm_rq_target_io *tio = tio_from_request(rq);
tio->error = error;
- blk_complete_request(rq);
+ if (!rq->q->mq_ops)
+ blk_complete_request(rq);
+ else
+ blk_mq_complete_request(rq, error);
}
/*
@@ -1350,7 +1397,7 @@ static void dm_kill_unmapped_request(struct request *rq, int error)
}
/*
- * Called with the clone's queue lock held (for non-blk-mq)
+ * Called with the clone's queue lock held (in the case of .request_fn)
*/
static void end_clone_request(struct request *clone, int error)
{
@@ -1520,21 +1567,26 @@ static void bio_setup_sector(struct bio *bio, sector_t sector, unsigned len)
/*
* Creates a bio that consists of range of complete bvecs.
*/
-static void clone_bio(struct dm_target_io *tio, struct bio *bio,
- sector_t sector, unsigned len)
+static int clone_bio(struct dm_target_io *tio, struct bio *bio,
+ sector_t sector, unsigned len)
{
struct bio *clone = &tio->clone;
__bio_clone_fast(clone, bio);
- if (bio_integrity(bio))
- bio_integrity_clone(clone, bio, GFP_NOIO);
+ if (bio_integrity(bio)) {
+ int r = bio_integrity_clone(clone, bio, GFP_NOIO);
+ if (r < 0)
+ return r;
+ }
bio_advance(clone, to_bytes(sector - clone->bi_iter.bi_sector));
clone->bi_iter.bi_size = to_bytes(len);
if (bio_integrity(bio))
bio_integrity_trim(clone, 0, len);
+
+ return 0;
}
static struct dm_target_io *alloc_tio(struct clone_info *ci,
@@ -1591,13 +1643,14 @@ static int __send_empty_flush(struct clone_info *ci)
return 0;
}
-static void __clone_and_map_data_bio(struct clone_info *ci, struct dm_target *ti,
+static int __clone_and_map_data_bio(struct clone_info *ci, struct dm_target *ti,
sector_t sector, unsigned *len)
{
struct bio *bio = ci->bio;
struct dm_target_io *tio;
unsigned target_bio_nr;
unsigned num_target_bios = 1;
+ int r = 0;
/*
* Does the target want to receive duplicate copies of the bio?
@@ -1608,9 +1661,13 @@ static void __clone_and_map_data_bio(struct clone_info *ci, struct dm_target *ti
for (target_bio_nr = 0; target_bio_nr < num_target_bios; target_bio_nr++) {
tio = alloc_tio(ci, ti, target_bio_nr);
tio->len_ptr = len;
- clone_bio(tio, bio, sector, *len);
+ r = clone_bio(tio, bio, sector, *len);
+ if (r < 0)
+ break;
__map_bio(tio);
}
+
+ return r;
}
typedef unsigned (*get_num_bios_fn)(struct dm_target *ti);
@@ -1687,6 +1744,7 @@ static int __split_and_process_non_flush(struct clone_info *ci)
struct bio *bio = ci->bio;
struct dm_target *ti;
unsigned len;
+ int r;
if (unlikely(bio->bi_rw & REQ_DISCARD))
return __send_discard(ci);
@@ -1699,7 +1757,9 @@ static int __split_and_process_non_flush(struct clone_info *ci)
len = min_t(sector_t, max_io_len(ci->sector, ti), ci->sector_count);
- __clone_and_map_data_bio(ci, ti, ci->sector, &len);
+ r = __clone_and_map_data_bio(ci, ti, ci->sector, &len);
+ if (r < 0)
+ return r;
ci->sector += len;
ci->sector_count -= len;
@@ -1837,28 +1897,22 @@ static int setup_clone(struct request *clone, struct request *rq,
return 0;
}
-static struct request *clone_rq(struct request *rq, struct mapped_device *md,
- struct dm_rq_target_io *tio, gfp_t gfp_mask)
+static struct request *clone_old_rq(struct request *rq, struct mapped_device *md,
+ struct dm_rq_target_io *tio, gfp_t gfp_mask)
{
/*
- * Do not allocate a clone if tio->clone was already set
- * (see: dm_mq_queue_rq).
+ * Create clone for use with .request_fn request_queue
*/
- bool alloc_clone = !tio->clone;
struct request *clone;
- if (alloc_clone) {
- clone = alloc_clone_request(md, gfp_mask);
- if (!clone)
- return NULL;
- } else
- clone = tio->clone;
+ clone = alloc_old_clone_request(md, gfp_mask);
+ if (!clone)
+ return NULL;
blk_rq_init(NULL, clone);
if (setup_clone(clone, rq, tio, gfp_mask)) {
/* -ENOMEM */
- if (alloc_clone)
- free_clone_request(md, clone);
+ free_old_clone_request(md, clone);
return NULL;
}
@@ -1875,29 +1929,40 @@ static void init_tio(struct dm_rq_target_io *tio, struct request *rq,
tio->clone = NULL;
tio->orig = rq;
tio->error = 0;
- memset(&tio->info, 0, sizeof(tio->info));
+ /*
+ * Avoid initializing info for blk-mq; it passes
+ * target-specific data through info.ptr
+ * (see: dm_mq_init_request)
+ */
+ if (!md->init_tio_pdu)
+ memset(&tio->info, 0, sizeof(tio->info));
if (md->kworker_task)
init_kthread_work(&tio->work, map_tio_request);
}
-static struct dm_rq_target_io *prep_tio(struct request *rq,
- struct mapped_device *md, gfp_t gfp_mask)
+static struct dm_rq_target_io *dm_old_prep_tio(struct request *rq,
+ struct mapped_device *md,
+ gfp_t gfp_mask)
{
struct dm_rq_target_io *tio;
int srcu_idx;
struct dm_table *table;
- tio = alloc_rq_tio(md, gfp_mask);
+ tio = alloc_old_rq_tio(md, gfp_mask);
if (!tio)
return NULL;
init_tio(tio, rq, md);
table = dm_get_live_table(md, &srcu_idx);
+ /*
+ * Must clone a request if this .request_fn DM device
+ * is stacked on .request_fn device(s).
+ */
if (!dm_table_mq_request_based(table)) {
- if (!clone_rq(rq, md, tio, gfp_mask)) {
+ if (!clone_old_rq(rq, md, tio, gfp_mask)) {
dm_put_live_table(md, srcu_idx);
- free_rq_tio(tio);
+ free_old_rq_tio(tio);
return NULL;
}
}
@@ -1909,7 +1974,7 @@ static struct dm_rq_target_io *prep_tio(struct request *rq,
/*
* Called with the queue lock held.
*/
-static int dm_prep_fn(struct request_queue *q, struct request *rq)
+static int dm_old_prep_fn(struct request_queue *q, struct request *rq)
{
struct mapped_device *md = q->queuedata;
struct dm_rq_target_io *tio;
@@ -1919,7 +1984,7 @@ static int dm_prep_fn(struct request_queue *q, struct request *rq)
return BLKPREP_KILL;
}
- tio = prep_tio(rq, md, GFP_ATOMIC);
+ tio = dm_old_prep_tio(rq, md, GFP_ATOMIC);
if (!tio)
return BLKPREP_DEFER;
@@ -2077,12 +2142,18 @@ static bool dm_request_peeked_before_merge_deadline(struct mapped_device *md)
static void dm_request_fn(struct request_queue *q)
{
struct mapped_device *md = q->queuedata;
- int srcu_idx;
- struct dm_table *map = dm_get_live_table(md, &srcu_idx);
- struct dm_target *ti;
+ struct dm_target *ti = md->immutable_target;
struct request *rq;
struct dm_rq_target_io *tio;
- sector_t pos;
+ sector_t pos = 0;
+
+ if (unlikely(!ti)) {
+ int srcu_idx;
+ struct dm_table *map = dm_get_live_table(md, &srcu_idx);
+
+ ti = dm_table_find_target(map, pos);
+ dm_put_live_table(md, srcu_idx);
+ }
/*
* For suspend, check blk_queue_stopped() and increment
@@ -2093,33 +2164,21 @@ static void dm_request_fn(struct request_queue *q)
while (!blk_queue_stopped(q)) {
rq = blk_peek_request(q);
if (!rq)
- goto out;
+ return;
/* always use block 0 to find the target for flushes for now */
pos = 0;
if (!(rq->cmd_flags & REQ_FLUSH))
pos = blk_rq_pos(rq);
- ti = dm_table_find_target(map, pos);
- if (!dm_target_is_valid(ti)) {
- /*
- * Must perform setup, that rq_completed() requires,
- * before calling dm_kill_unmapped_request
- */
- DMERR_LIMIT("request attempted access beyond the end of device");
- dm_start_request(md, rq);
- dm_kill_unmapped_request(rq, -EIO);
- continue;
+ if ((dm_request_peeked_before_merge_deadline(md) &&
+ md_in_flight(md) && rq->bio && rq->bio->bi_vcnt == 1 &&
+ md->last_rq_pos == pos && md->last_rq_rw == rq_data_dir(rq)) ||
+ (ti->type->busy && ti->type->busy(ti))) {
+ blk_delay_queue(q, HZ / 100);
+ return;
}
- if (dm_request_peeked_before_merge_deadline(md) &&
- md_in_flight(md) && rq->bio && rq->bio->bi_vcnt == 1 &&
- md->last_rq_pos == pos && md->last_rq_rw == rq_data_dir(rq))
- goto delay_and_out;
-
- if (ti->type->busy && ti->type->busy(ti))
- goto delay_and_out;
-
dm_start_request(md, rq);
tio = tio_from_request(rq);
@@ -2128,13 +2187,6 @@ static void dm_request_fn(struct request_queue *q)
queue_kthread_work(&md->kworker, &tio->work);
BUG_ON(!irqs_disabled());
}
-
- goto out;
-
-delay_and_out:
- blk_delay_queue(q, HZ / 100);
-out:
- dm_put_live_table(md, srcu_idx);
}
static int dm_any_congested(void *congested_data, int bdi_bits)
@@ -2144,19 +2196,18 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
struct dm_table *map;
if (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
- map = dm_get_live_table_fast(md);
- if (map) {
+ if (dm_request_based(md)) {
/*
- * Request-based dm cares about only own queue for
- * the query about congestion status of request_queue
+ * With request-based DM we only need to check the
+ * top-level queue for congestion.
*/
- if (dm_request_based(md))
- r = md->queue->backing_dev_info.wb.state &
- bdi_bits;
- else
+ r = md->queue->backing_dev_info.wb.state & bdi_bits;
+ } else {
+ map = dm_get_live_table_fast(md);
+ if (map)
r = dm_table_any_congested(map, bdi_bits);
+ dm_put_live_table_fast(md);
}
- dm_put_live_table_fast(md);
}
return r;
@@ -2236,7 +2287,7 @@ static void dm_init_md_queue(struct mapped_device *md)
md->queue->backing_dev_info.congested_data = md;
}
-static void dm_init_old_md_queue(struct mapped_device *md)
+static void dm_init_normal_md_queue(struct mapped_device *md)
{
md->use_blk_mq = false;
dm_init_md_queue(md);
@@ -2283,10 +2334,11 @@ static void cleanup_mapped_device(struct mapped_device *md)
*/
static struct mapped_device *alloc_dev(int minor)
{
- int r;
- struct mapped_device *md = kzalloc(sizeof(*md), GFP_KERNEL);
+ int r, numa_node_id = dm_get_numa_node();
+ struct mapped_device *md;
void *old_md;
+ md = kzalloc_node(sizeof(*md), GFP_KERNEL, numa_node_id);
if (!md) {
DMWARN("unable to allocate device, out of memory.");
return NULL;
@@ -2307,7 +2359,9 @@ static struct mapped_device *alloc_dev(int minor)
if (r < 0)
goto bad_io_barrier;
+ md->numa_node_id = numa_node_id;
md->use_blk_mq = use_blk_mq;
+ md->init_tio_pdu = false;
md->type = DM_TYPE_NONE;
mutex_init(&md->suspend_lock);
mutex_init(&md->type_lock);
@@ -2321,13 +2375,13 @@ static struct mapped_device *alloc_dev(int minor)
INIT_LIST_HEAD(&md->table_devices);
spin_lock_init(&md->uevent_lock);
- md->queue = blk_alloc_queue(GFP_KERNEL);
+ md->queue = blk_alloc_queue_node(GFP_KERNEL, numa_node_id);
if (!md->queue)
goto bad;
dm_init_md_queue(md);
- md->disk = alloc_disk(1);
+ md->disk = alloc_disk_node(1, numa_node_id);
if (!md->disk)
goto bad;
@@ -2391,8 +2445,10 @@ static void free_dev(struct mapped_device *md)
unlock_fs(md);
cleanup_mapped_device(md);
- if (md->use_blk_mq)
- blk_mq_free_tag_set(&md->tag_set);
+ if (md->tag_set) {
+ blk_mq_free_tag_set(md->tag_set);
+ kfree(md->tag_set);
+ }
free_table_devices(&md->table_devices);
dm_stats_cleanup(&md->stats);
@@ -2500,13 +2556,20 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
* This must be done before setting the queue restrictions,
* because request-based dm may be run just after the setting.
*/
- if (dm_table_request_based(t))
- stop_queue(q);
+ if (dm_table_request_based(t)) {
+ dm_stop_queue(q);
+ /*
+ * Leverage the fact that request-based DM targets are
+ * immutable singletons and establish md->immutable_target
+ * - used to optimize both dm_request_fn and dm_mq_queue_rq
+ */
+ md->immutable_target = dm_table_get_immutable_target(t);
+ }
__bind_mempools(md, t);
old_map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
- rcu_assign_pointer(md->map, t);
+ rcu_assign_pointer(md->map, (void *)t);
md->immutable_target_type = dm_table_get_immutable_target_type(t);
dm_table_set_restrictions(t, q, limits);
@@ -2572,7 +2635,6 @@ void dm_set_md_type(struct mapped_device *md, unsigned type)
unsigned dm_get_md_type(struct mapped_device *md)
{
- BUG_ON(!mutex_is_locked(&md->type_lock));
return md->type;
}
@@ -2592,7 +2654,7 @@ struct queue_limits *dm_get_queue_limits(struct mapped_device *md)
}
EXPORT_SYMBOL_GPL(dm_get_queue_limits);
-static void init_rq_based_worker_thread(struct mapped_device *md)
+static void dm_old_init_rq_based_worker_thread(struct mapped_device *md)
{
/* Initialize the request-based DM worker thread */
init_kthread_worker(&md->kworker);
@@ -2601,26 +2663,22 @@ static void init_rq_based_worker_thread(struct mapped_device *md)
}
/*
- * Fully initialize a request-based queue (->elevator, ->request_fn, etc).
+ * Fully initialize a .request_fn request-based queue.
*/
-static int dm_init_request_based_queue(struct mapped_device *md)
+static int dm_old_init_request_queue(struct mapped_device *md)
{
- struct request_queue *q = NULL;
-
/* Fully initialize the queue */
- q = blk_init_allocated_queue(md->queue, dm_request_fn, NULL);
- if (!q)
+ if (!blk_init_allocated_queue(md->queue, dm_request_fn, NULL))
return -EINVAL;
/* disable dm_request_fn's merge heuristic by default */
md->seq_rq_merge_deadline_usecs = 0;
- md->queue = q;
- dm_init_old_md_queue(md);
+ dm_init_normal_md_queue(md);
blk_queue_softirq_done(md->queue, dm_softirq_done);
- blk_queue_prep_rq(md->queue, dm_prep_fn);
+ blk_queue_prep_rq(md->queue, dm_old_prep_fn);
- init_rq_based_worker_thread(md);
+ dm_old_init_rq_based_worker_thread(md);
elv_register_queue(md->queue);
@@ -2640,6 +2698,11 @@ static int dm_mq_init_request(void *data, struct request *rq,
*/
tio->md = md;
+ if (md->init_tio_pdu) {
+ /* target-specific per-io data is immediately after the tio */
+ tio->info.ptr = tio + 1;
+ }
+
return 0;
}
@@ -2649,28 +2712,15 @@ static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
struct request *rq = bd->rq;
struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq);
struct mapped_device *md = tio->md;
- int srcu_idx;
- struct dm_table *map = dm_get_live_table(md, &srcu_idx);
- struct dm_target *ti;
- sector_t pos;
+ struct dm_target *ti = md->immutable_target;
- /* always use block 0 to find the target for flushes for now */
- pos = 0;
- if (!(rq->cmd_flags & REQ_FLUSH))
- pos = blk_rq_pos(rq);
+ if (unlikely(!ti)) {
+ int srcu_idx;
+ struct dm_table *map = dm_get_live_table(md, &srcu_idx);
- ti = dm_table_find_target(map, pos);
- if (!dm_target_is_valid(ti)) {
+ ti = dm_table_find_target(map, 0);
dm_put_live_table(md, srcu_idx);
- DMERR_LIMIT("request attempted access beyond the end of device");
- /*
- * Must perform setup, that rq_completed() requires,
- * before returning BLK_MQ_RQ_QUEUE_ERROR
- */
- dm_start_request(md, rq);
- return BLK_MQ_RQ_QUEUE_ERROR;
}
- dm_put_live_table(md, srcu_idx);
if (ti->type->busy && ti->type->busy(ti))
return BLK_MQ_RQ_QUEUE_BUSY;
@@ -2686,20 +2736,12 @@ static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
*/
tio->ti = ti;
- /* Clone the request if underlying devices aren't blk-mq */
- if (dm_table_get_type(map) == DM_TYPE_REQUEST_BASED) {
- /* clone request is allocated at the end of the pdu */
- tio->clone = (void *)blk_mq_rq_to_pdu(rq) + sizeof(struct dm_rq_target_io);
- (void) clone_rq(rq, md, tio, GFP_ATOMIC);
- queue_kthread_work(&md->kworker, &tio->work);
- } else {
- /* Direct call is fine since .queue_rq allows allocations */
- if (map_request(tio, rq, md) == DM_MAPIO_REQUEUE) {
- /* Undo dm_start_request() before requeuing */
- rq_end_stats(md, rq);
- rq_completed(md, rq_data_dir(rq), false);
- return BLK_MQ_RQ_QUEUE_BUSY;
- }
+ /* Direct call is fine since .queue_rq allows allocations */
+ if (map_request(tio, rq, md) == DM_MAPIO_REQUEUE) {
+ /* Undo dm_start_request() before requeuing */
+ rq_end_stats(md, rq);
+ rq_completed(md, rq_data_dir(rq), false);
+ return BLK_MQ_RQ_QUEUE_BUSY;
}
return BLK_MQ_RQ_QUEUE_OK;
@@ -2712,47 +2754,56 @@ static struct blk_mq_ops dm_mq_ops = {
.init_request = dm_mq_init_request,
};
-static int dm_init_request_based_blk_mq_queue(struct mapped_device *md)
+static int dm_mq_init_request_queue(struct mapped_device *md,
+ struct dm_target *immutable_tgt)
{
- unsigned md_type = dm_get_md_type(md);
struct request_queue *q;
int err;
- memset(&md->tag_set, 0, sizeof(md->tag_set));
- md->tag_set.ops = &dm_mq_ops;
- md->tag_set.queue_depth = BLKDEV_MAX_RQ;
- md->tag_set.numa_node = NUMA_NO_NODE;
- md->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE;
- md->tag_set.nr_hw_queues = 1;
- if (md_type == DM_TYPE_REQUEST_BASED) {
- /* make the memory for non-blk-mq clone part of the pdu */
- md->tag_set.cmd_size = sizeof(struct dm_rq_target_io) + sizeof(struct request);
- } else
- md->tag_set.cmd_size = sizeof(struct dm_rq_target_io);
- md->tag_set.driver_data = md;
-
- err = blk_mq_alloc_tag_set(&md->tag_set);
+ if (dm_get_md_type(md) == DM_TYPE_REQUEST_BASED) {
+ DMERR("request-based dm-mq may only be stacked on blk-mq device(s)");
+ return -EINVAL;
+ }
+
+ md->tag_set = kzalloc_node(sizeof(struct blk_mq_tag_set), GFP_KERNEL, md->numa_node_id);
+ if (!md->tag_set)
+ return -ENOMEM;
+
+ md->tag_set->ops = &dm_mq_ops;
+ md->tag_set->queue_depth = dm_get_blk_mq_queue_depth();
+ md->tag_set->numa_node = md->numa_node_id;
+ md->tag_set->flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE;
+ md->tag_set->nr_hw_queues = dm_get_blk_mq_nr_hw_queues();
+ md->tag_set->driver_data = md;
+
+ md->tag_set->cmd_size = sizeof(struct dm_rq_target_io);
+ if (immutable_tgt && immutable_tgt->per_io_data_size) {
+ /* any target-specific per-io data is immediately after the tio */
+ md->tag_set->cmd_size += immutable_tgt->per_io_data_size;
+ md->init_tio_pdu = true;
+ }
+
+ err = blk_mq_alloc_tag_set(md->tag_set);
if (err)
- return err;
+ goto out_kfree_tag_set;
- q = blk_mq_init_allocated_queue(&md->tag_set, md->queue);
+ q = blk_mq_init_allocated_queue(md->tag_set, md->queue);
if (IS_ERR(q)) {
err = PTR_ERR(q);
goto out_tag_set;
}
- md->queue = q;
dm_init_md_queue(md);
/* backfill 'mq' sysfs registration normally done in blk_register_queue */
blk_mq_register_disk(md->disk);
- if (md_type == DM_TYPE_REQUEST_BASED)
- init_rq_based_worker_thread(md);
-
return 0;
out_tag_set:
- blk_mq_free_tag_set(&md->tag_set);
+ blk_mq_free_tag_set(md->tag_set);
+out_kfree_tag_set:
+ kfree(md->tag_set);
+
return err;
}
@@ -2767,28 +2818,28 @@ static unsigned filter_md_type(unsigned type, struct mapped_device *md)
/*
* Setup the DM device's queue based on md's type
*/
-int dm_setup_md_queue(struct mapped_device *md)
+int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t)
{
int r;
unsigned md_type = filter_md_type(dm_get_md_type(md), md);
switch (md_type) {
case DM_TYPE_REQUEST_BASED:
- r = dm_init_request_based_queue(md);
+ r = dm_old_init_request_queue(md);
if (r) {
- DMWARN("Cannot initialize queue for request-based mapped device");
+ DMERR("Cannot initialize queue for request-based mapped device");
return r;
}
break;
case DM_TYPE_MQ_REQUEST_BASED:
- r = dm_init_request_based_blk_mq_queue(md);
+ r = dm_mq_init_request_queue(md, dm_table_get_immutable_target(t));
if (r) {
- DMWARN("Cannot initialize queue for request-based blk-mq mapped device");
+ DMERR("Cannot initialize queue for request-based dm-mq mapped device");
return r;
}
break;
case DM_TYPE_BIO_BASED:
- dm_init_old_md_queue(md);
+ dm_init_normal_md_queue(md);
blk_queue_make_request(md->queue, dm_make_request);
/*
* DM handles splitting bios as needed. Free the bio_split bioset
@@ -3131,7 +3182,7 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
* dm defers requests to md->wq from md->queue.
*/
if (dm_request_based(md)) {
- stop_queue(md->queue);
+ dm_stop_queue(md->queue);
if (md->kworker_task)
flush_kthread_worker(&md->kworker);
}
@@ -3155,7 +3206,7 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
dm_queue_flush(md);
if (dm_request_based(md))
- start_queue(md->queue);
+ dm_start_queue(md->queue);
unlock_fs(md);
dm_table_presuspend_undo_targets(map);
@@ -3234,7 +3285,7 @@ static int __dm_resume(struct mapped_device *md, struct dm_table *map)
* Request-based dm is queueing the deferred I/Os in its request_queue.
*/
if (dm_request_based(md))
- start_queue(md->queue);
+ dm_start_queue(md->queue);
unlock_fs(md);
@@ -3480,9 +3531,9 @@ int dm_noflush_suspending(struct dm_target *ti)
EXPORT_SYMBOL_GPL(dm_noflush_suspending);
struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned type,
- unsigned integrity, unsigned per_bio_data_size)
+ unsigned integrity, unsigned per_io_data_size)
{
- struct dm_md_mempools *pools = kzalloc(sizeof(*pools), GFP_KERNEL);
+ struct dm_md_mempools *pools = kzalloc_node(sizeof(*pools), GFP_KERNEL, md->numa_node_id);
struct kmem_cache *cachep = NULL;
unsigned int pool_size = 0;
unsigned int front_pad;
@@ -3496,7 +3547,7 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t
case DM_TYPE_BIO_BASED:
cachep = _io_cache;
pool_size = dm_get_reserved_bio_based_ios();
- front_pad = roundup(per_bio_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone);
+ front_pad = roundup(per_io_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone);
break;
case DM_TYPE_REQUEST_BASED:
cachep = _rq_tio_cache;
@@ -3509,8 +3560,7 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t
if (!pool_size)
pool_size = dm_get_reserved_rq_based_ios();
front_pad = offsetof(struct dm_rq_clone_bio_info, clone);
- /* per_bio_data_size is not used. See __bind_mempools(). */
- WARN_ON(per_bio_data_size != 0);
+ /* per_io_data_size is used for blk-mq pdu at queue allocation */
break;
default:
BUG();
@@ -3552,15 +3602,14 @@ void dm_free_md_mempools(struct dm_md_mempools *pools)
}
static int dm_pr_register(struct block_device *bdev, u64 old_key, u64 new_key,
- u32 flags)
+ u32 flags)
{
struct mapped_device *md = bdev->bd_disk->private_data;
const struct pr_ops *ops;
- struct dm_target *tgt;
fmode_t mode;
- int srcu_idx, r;
+ int r;
- r = dm_get_live_table_for_ioctl(md, &tgt, &bdev, &mode, &srcu_idx);
+ r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
if (r < 0)
return r;
@@ -3570,20 +3619,19 @@ static int dm_pr_register(struct block_device *bdev, u64 old_key, u64 new_key,
else
r = -EOPNOTSUPP;
- dm_put_live_table(md, srcu_idx);
+ bdput(bdev);
return r;
}
static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type,
- u32 flags)
+ u32 flags)
{
struct mapped_device *md = bdev->bd_disk->private_data;
const struct pr_ops *ops;
- struct dm_target *tgt;
fmode_t mode;
- int srcu_idx, r;
+ int r;
- r = dm_get_live_table_for_ioctl(md, &tgt, &bdev, &mode, &srcu_idx);
+ r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
if (r < 0)
return r;
@@ -3593,7 +3641,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type,
else
r = -EOPNOTSUPP;
- dm_put_live_table(md, srcu_idx);
+ bdput(bdev);
return r;
}
@@ -3601,11 +3649,10 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
{
struct mapped_device *md = bdev->bd_disk->private_data;
const struct pr_ops *ops;
- struct dm_target *tgt;
fmode_t mode;
- int srcu_idx, r;
+ int r;
- r = dm_get_live_table_for_ioctl(md, &tgt, &bdev, &mode, &srcu_idx);
+ r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
if (r < 0)
return r;
@@ -3615,20 +3662,19 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
else
r = -EOPNOTSUPP;
- dm_put_live_table(md, srcu_idx);
+ bdput(bdev);
return r;
}
static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key,
- enum pr_type type, bool abort)
+ enum pr_type type, bool abort)
{
struct mapped_device *md = bdev->bd_disk->private_data;
const struct pr_ops *ops;
- struct dm_target *tgt;
fmode_t mode;
- int srcu_idx, r;
+ int r;
- r = dm_get_live_table_for_ioctl(md, &tgt, &bdev, &mode, &srcu_idx);
+ r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
if (r < 0)
return r;
@@ -3638,7 +3684,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key,
else
r = -EOPNOTSUPP;
- dm_put_live_table(md, srcu_idx);
+ bdput(bdev);
return r;
}
@@ -3646,11 +3692,10 @@ static int dm_pr_clear(struct block_device *bdev, u64 key)
{
struct mapped_device *md = bdev->bd_disk->private_data;
const struct pr_ops *ops;
- struct dm_target *tgt;
fmode_t mode;
- int srcu_idx, r;
+ int r;
- r = dm_get_live_table_for_ioctl(md, &tgt, &bdev, &mode, &srcu_idx);
+ r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
if (r < 0)
return r;
@@ -3660,7 +3705,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key)
else
r = -EOPNOTSUPP;
- dm_put_live_table(md, srcu_idx);
+ bdput(bdev);
return r;
}
@@ -3699,6 +3744,15 @@ MODULE_PARM_DESC(reserved_rq_based_ios, "Reserved IOs in request-based mempools"
module_param(use_blk_mq, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(use_blk_mq, "Use block multiqueue for request-based DM devices");
+module_param(dm_mq_nr_hw_queues, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dm_mq_nr_hw_queues, "Number of hardware queues for request-based dm-mq devices");
+
+module_param(dm_mq_queue_depth, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dm_mq_queue_depth, "Queue depth for request-based dm-mq devices");
+
+module_param(dm_numa_node, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dm_numa_node, "NUMA node for DM device memory allocations");
+
MODULE_DESCRIPTION(DM_NAME " driver");
MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 7edcf97dfa5a..13a758ec0f88 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -73,6 +73,8 @@ int dm_table_resume_targets(struct dm_table *t);
int dm_table_any_congested(struct dm_table *t, int bdi_bits);
unsigned dm_table_get_type(struct dm_table *t);
struct target_type *dm_table_get_immutable_target_type(struct dm_table *t);
+struct dm_target *dm_table_get_immutable_target(struct dm_table *t);
+struct dm_target *dm_table_get_wildcard_target(struct dm_table *t);
bool dm_table_request_based(struct dm_table *t);
bool dm_table_mq_request_based(struct dm_table *t);
void dm_table_free_md_mempools(struct dm_table *t);
@@ -84,7 +86,7 @@ void dm_set_md_type(struct mapped_device *md, unsigned type);
unsigned dm_get_md_type(struct mapped_device *md);
struct target_type *dm_get_immutable_target_type(struct mapped_device *md);
-int dm_setup_md_queue(struct mapped_device *md);
+int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t);
/*
* To check the return value from dm_table_find_target().
diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c
index 9c59f4306883..f5956402fc69 100644
--- a/drivers/media/common/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c
@@ -38,7 +38,7 @@ static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
#endif
/* lnb control */
-#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
+#if (FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)) && FE_SUPPORTED(PLL)
static int flexcop_set_voltage(struct dvb_frontend *fe,
enum fe_sec_voltage voltage)
{
@@ -68,7 +68,7 @@ static int flexcop_set_voltage(struct dvb_frontend *fe,
#endif
#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
-static int flexcop_sleep(struct dvb_frontend* fe)
+static int __maybe_unused flexcop_sleep(struct dvb_frontend* fe)
{
struct flexcop_device *fc = fe->dvb->priv;
if (fc->fe_sleep)
diff --git a/drivers/media/common/b2c2/flexcop.c b/drivers/media/common/b2c2/flexcop.c
index 412c5daf2b48..0f5114d406f8 100644
--- a/drivers/media/common/b2c2/flexcop.c
+++ b/drivers/media/common/b2c2/flexcop.c
@@ -1,7 +1,7 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop.c - main module part
- * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@posteo.de>
* based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
*
* Acknowledgements:
@@ -34,7 +34,7 @@
#include "flexcop.h"
#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
-#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@posteo.de"
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
#define DEBSTATUS ""
diff --git a/drivers/media/common/cypress_firmware.c b/drivers/media/common/cypress_firmware.c
index 577e82058fdc..50e3f76d4847 100644
--- a/drivers/media/common/cypress_firmware.c
+++ b/drivers/media/common/cypress_firmware.c
@@ -1,6 +1,6 @@
/* cypress_firmware.c is part of the DVB USB library.
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for downloading the firmware to Cypress FX 1
diff --git a/drivers/media/common/cypress_firmware.h b/drivers/media/common/cypress_firmware.h
index e493cbc7a528..1e4f27356205 100644
--- a/drivers/media/common/cypress_firmware.h
+++ b/drivers/media/common/cypress_firmware.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for downloading the firmware to Cypress FX 1
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index 2a8d9a36d6f0..f3a42834d7d6 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -1167,8 +1167,8 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
return rc;
}
pr_debug("read fw %s, buffer size=0x%zx\n", fw_filename, fw->size);
- fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
- GFP_KERNEL | GFP_DMA);
+ fw_buf = kmalloc(ALIGN(fw->size + sizeof(struct sms_firmware),
+ SMS_ALLOC_ALIGNMENT), GFP_KERNEL | GFP_DMA);
if (!fw_buf) {
pr_err("failed to allocate firmware buffer\n");
rc = -ENOMEM;
diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c
index d31f468830cf..9148e14c9d07 100644
--- a/drivers/media/common/siano/smsdvb-main.c
+++ b/drivers/media/common/siano/smsdvb-main.c
@@ -1015,12 +1015,6 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe)
}
}
-/* Nothing to do here, as stats are automatically updated */
-static int smsdvb_get_frontend(struct dvb_frontend *fe)
-{
- return 0;
-}
-
static int smsdvb_init(struct dvb_frontend *fe)
{
struct smsdvb_client_t *client =
@@ -1069,7 +1063,6 @@ static struct dvb_frontend_ops smsdvb_fe_ops = {
.release = smsdvb_release,
.set_frontend = smsdvb_set_frontend,
- .get_frontend = smsdvb_get_frontend,
.get_tune_settings = smsdvb_get_tune_settings,
.read_status = smsdvb_read_status,
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 1c1c298d2289..0afad395ef97 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -1,6 +1,6 @@
/* dvb-usb-ids.h is part of the DVB USB library.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de) see
* dvb-usb-init.c for copyright information.
*
* a header file containing define's for the USB device supported by the
@@ -118,6 +118,7 @@
#define USB_PID_DIBCOM_STK807XP 0x1f90
#define USB_PID_DIBCOM_STK807XPVR 0x1f98
#define USB_PID_DIBCOM_STK8096GP 0x1fa0
+#define USB_PID_DIBCOM_STK8096PVR 0x1faa
#define USB_PID_DIBCOM_NIM8096MD 0x1fa8
#define USB_PID_DIBCOM_TFE8096P 0x1f9C
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
@@ -241,12 +242,14 @@
#define USB_PID_AVERMEDIA_1867 0x1867
#define USB_PID_AVERMEDIA_A867 0xa867
#define USB_PID_AVERMEDIA_H335 0x0335
+#define USB_PID_AVERMEDIA_TD110 0xa110
#define USB_PID_AVERMEDIA_TWINSTAR 0x0825
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
#define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009
#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d
#define USB_PID_TECHNOTREND_CONNECT_S2_4600 0x3011
#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI 0x3012
+#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI_2 0x3015
#define USB_PID_TECHNOTREND_TVSTICK_CT2_4400 0x3014
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081
@@ -255,6 +258,10 @@
#define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062
#define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078
#define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab
+#define USB_PID_TERRATEC_CINERGY_S2_R1 0x00a8
+#define USB_PID_TERRATEC_CINERGY_S2_R2 0x00b0
+#define USB_PID_TERRATEC_CINERGY_S2_R3 0x0102
+#define USB_PID_TERRATEC_CINERGY_S2_R4 0x0105
#define USB_PID_TERRATEC_H7 0x10b4
#define USB_PID_TERRATEC_H7_2 0x10a3
#define USB_PID_TERRATEC_H7_3 0x10a5
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 40080645341e..c0142614c408 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -134,15 +134,17 @@ struct dvb_frontend_private {
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_pipeline pipe;
- struct media_entity *pipe_start_entity;
#endif
};
static void dvb_frontend_wakeup(struct dvb_frontend *fe);
static int dtv_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p_out);
-static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p);
+static int
+dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+ const struct dtv_frontend_properties *c,
+ struct dvb_frontend_parameters *p);
static bool has_get_frontend(struct dvb_frontend *fe)
{
@@ -202,6 +204,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe,
enum fe_status status)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_fe_events *events = &fepriv->events;
struct dvb_frontend_event *e;
int wp;
@@ -209,7 +212,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe,
dev_dbg(fe->dvb->device, "%s:\n", __func__);
if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
- dtv_get_frontend(fe, &fepriv->parameters_out);
+ dtv_get_frontend(fe, c, &fepriv->parameters_out);
mutex_lock(&events->mtx);
@@ -596,104 +599,13 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
wake_up_interruptible(&fepriv->wait_queue);
}
-/**
- * dvb_enable_media_tuner() - tries to enable the DVB tuner
- *
- * @fe: struct dvb_frontend pointer
- *
- * This function ensures that just one media tuner is enabled for a given
- * frontend. It has two different behaviors:
- * - For trivial devices with just one tuner:
- * it just enables the existing tuner->fe link
- * - For devices with more than one tuner:
- * It is up to the driver to implement the logic that will enable one tuner
- * and disable the other ones. However, if more than one tuner is enabled for
- * the same frontend, it will print an error message and return -EINVAL.
- *
- * At return, it will return the error code returned by media_entity_setup_link,
- * or 0 if everything is OK, if no tuner is linked to the frontend or if the
- * mdev is NULL.
- */
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
-static int dvb_enable_media_tuner(struct dvb_frontend *fe)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct dvb_adapter *adapter = fe->dvb;
- struct media_device *mdev = adapter->mdev;
- struct media_entity *entity, *source;
- struct media_link *link, *found_link = NULL;
- int ret, n_links = 0, active_links = 0;
-
- fepriv->pipe_start_entity = NULL;
-
- if (!mdev)
- return 0;
-
- entity = fepriv->dvbdev->entity;
- fepriv->pipe_start_entity = entity;
-
- list_for_each_entry(link, &entity->links, list) {
- if (link->sink->entity == entity) {
- found_link = link;
- n_links++;
- if (link->flags & MEDIA_LNK_FL_ENABLED)
- active_links++;
- }
- }
-
- if (!n_links || active_links == 1 || !found_link)
- return 0;
-
- /*
- * If a frontend has more than one tuner linked, it is up to the driver
- * to select with one will be the active one, as the frontend core can't
- * guess. If the driver doesn't do that, it is a bug.
- */
- if (n_links > 1 && active_links != 1) {
- dev_err(fe->dvb->device,
- "WARNING: there are %d active links among %d tuners. This is a driver's bug!\n",
- active_links, n_links);
- return -EINVAL;
- }
-
- source = found_link->source->entity;
- fepriv->pipe_start_entity = source;
- list_for_each_entry(link, &source->links, list) {
- struct media_entity *sink;
- int flags = 0;
-
- sink = link->sink->entity;
- if (sink == entity)
- flags = MEDIA_LNK_FL_ENABLED;
-
- ret = media_entity_setup_link(link, flags);
- if (ret) {
- dev_err(fe->dvb->device,
- "Couldn't change link %s->%s to %s. Error %d\n",
- source->name, sink->name,
- flags ? "enabled" : "disabled",
- ret);
- return ret;
- } else
- dev_dbg(fe->dvb->device,
- "link %s->%s was %s\n",
- source->name, sink->name,
- flags ? "ENABLED" : "disabled");
- }
- return 0;
-}
-#endif
-
static int dvb_frontend_thread(void *data)
{
struct dvb_frontend *fe = data;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
enum fe_status s;
enum dvbfe_algo algo;
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
- int ret;
-#endif
-
bool re_tune = false;
bool semheld = false;
@@ -706,20 +618,6 @@ static int dvb_frontend_thread(void *data)
fepriv->wakeup = 0;
fepriv->reinitialise = 0;
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
- ret = dvb_enable_media_tuner(fe);
- if (ret) {
- /* FIXME: return an error if it fails */
- dev_info(fe->dvb->device,
- "proceeding with FE task\n");
- } else if (fepriv->pipe_start_entity) {
- ret = media_entity_pipeline_start(fepriv->pipe_start_entity,
- &fepriv->pipe);
- if (ret)
- return ret;
- }
-#endif
-
dvb_frontend_init(fe);
set_freezable();
@@ -807,7 +705,7 @@ restart:
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
fepriv->delay = HZ / 2;
}
- dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
+ dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s); /* update event list */
@@ -829,12 +727,6 @@ restart:
}
}
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
- if (fepriv->pipe_start_entity)
- media_entity_pipeline_stop(fepriv->pipe_start_entity);
- fepriv->pipe_start_entity = NULL;
-#endif
-
if (dvb_powerdown_on_sleep) {
if (fe->ops.set_voltage)
fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
@@ -899,10 +791,10 @@ void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec)
s32 delta;
*waketime = ktime_add_us(*waketime, add_usec);
- delta = ktime_us_delta(ktime_get_real(), *waketime);
+ delta = ktime_us_delta(ktime_get_boottime(), *waketime);
if (delta > 2500) {
msleep((delta - 1500) / 1000);
- delta = ktime_us_delta(ktime_get_real(), *waketime);
+ delta = ktime_us_delta(ktime_get_boottime(), *waketime);
}
if (delta > 0)
udelay(delta);
@@ -1162,18 +1054,24 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
};
-static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp)
+static void dtv_property_dump(struct dvb_frontend *fe,
+ bool is_set,
+ struct dtv_property *tvp)
{
int i;
if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
- dev_warn(fe->dvb->device, "%s: tvp.cmd = 0x%08x undefined\n",
- __func__, tvp->cmd);
+ dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n",
+ __func__,
+ is_set ? "SET" : "GET",
+ tvp->cmd);
return;
}
- dev_dbg(fe->dvb->device, "%s: tvp.cmd = 0x%08x (%s)\n", __func__,
- tvp->cmd, dtv_cmds[tvp->cmd].name);
+ dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__,
+ is_set ? "SET" : "GET",
+ tvp->cmd,
+ dtv_cmds[tvp->cmd].name);
if (dtv_cmds[tvp->cmd].buffer) {
dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n",
@@ -1268,11 +1166,11 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe,
/* Ensure the cached values are set correctly in the frontend
* legacy tuning structures, for the advanced tuning API.
*/
-static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int
+dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+ const struct dtv_frontend_properties *c,
+ struct dvb_frontend_parameters *p)
{
- const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
p->frequency = c->frequency;
p->inversion = c->inversion;
@@ -1344,16 +1242,17 @@ static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
* If p_out is not null, it will update the DVBv3 params pointed by it.
*/
static int dtv_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p_out)
{
int r;
if (fe->ops.get_frontend) {
- r = fe->ops.get_frontend(fe);
+ r = fe->ops.get_frontend(fe, c);
if (unlikely(r < 0))
return r;
if (p_out)
- dtv_property_legacy_params_sync(fe, p_out);
+ dtv_property_legacy_params_sync(fe, c, p_out);
return 0;
}
@@ -1589,7 +1488,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
return r;
}
- dtv_property_dump(fe, tvp);
+ dtv_property_dump(fe, false, tvp);
return 0;
}
@@ -1830,6 +1729,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
return r;
}
+ dtv_property_dump(fe, true, tvp);
+
switch(tvp->cmd) {
case DTV_CLEAR:
/*
@@ -2073,6 +1974,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
} else if (cmd == FE_GET_PROPERTY) {
+ struct dtv_frontend_properties getp = fe->dtv_property_cache;
+
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
@@ -2094,17 +1997,18 @@ static int dvb_frontend_ioctl_properties(struct file *file,
}
/*
- * Fills the cache out struct with the cache contents, plus
- * the data retrieved from get_frontend, if the frontend
- * is not idle. Otherwise, returns the cached content
+ * Let's use our own copy of property cache, in order to
+ * avoid mangling with DTV zigzag logic, as drivers might
+ * return crap, if they don't check if the data is available
+ * before updating the properties cache.
*/
if (fepriv->state != FESTATE_IDLE) {
- err = dtv_get_frontend(fe, NULL);
+ err = dtv_get_frontend(fe, &getp, NULL);
if (err < 0)
goto out;
}
for (i = 0; i < tvps->num; i++) {
- err = dtv_property_process_get(fe, c, tvp + i, file);
+ err = dtv_property_process_get(fe, &getp, tvp + i, file);
if (err < 0)
goto out;
(tvp + i)->result = err;
@@ -2139,7 +2043,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
* the user. FE_SET_FRONTEND triggers an initial frontend event
* with status = 0, which copies output parameters to userspace.
*/
- dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
+ dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
/*
* Be sure that the bandwidth will be filled for all
@@ -2451,7 +2355,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
u8 last = 1;
if (dvb_frontend_debug)
printk("%s switch command: 0x%04lx\n", __func__, swcmd);
- nexttime = ktime_get_real();
+ nexttime = ktime_get_boottime();
if (dvb_frontend_debug)
tv[0] = nexttime;
/* before sending a command, initialize by sending
@@ -2462,7 +2366,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
for (i = 0; i < 9; i++) {
if (dvb_frontend_debug)
- tv[i+1] = ktime_get_real();
+ tv[i+1] = ktime_get_boottime();
if ((swcmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */
fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
@@ -2509,10 +2413,18 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
err = dvb_frontend_get_event (fe, parg, file->f_flags);
break;
- case FE_GET_FRONTEND:
- err = dtv_get_frontend(fe, parg);
- break;
+ case FE_GET_FRONTEND: {
+ struct dtv_frontend_properties getp = fe->dtv_property_cache;
+ /*
+ * Let's use our own copy of property cache, in order to
+ * avoid mangling with DTV zigzag logic, as drivers might
+ * return crap, if they don't check if the data is available
+ * before updating the properties cache.
+ */
+ err = dtv_get_frontend(fe, &getp, parg);
+ break;
+ }
case FE_SET_FRONTEND_TUNE_MODE:
fepriv->tune_mode_flags = (unsigned long) parg;
err = 0;
@@ -2612,9 +2524,20 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
fepriv->tone = -1;
fepriv->voltage = -1;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (fe->dvb->mdev && fe->dvb->mdev->enable_source) {
+ ret = fe->dvb->mdev->enable_source(dvbdev->entity,
+ &fepriv->pipe);
+ if (ret) {
+ dev_err(fe->dvb->device,
+ "Tuner is busy. Error %d\n", ret);
+ goto err2;
+ }
+ }
+#endif
ret = dvb_frontend_start (fe);
if (ret)
- goto err2;
+ goto err3;
/* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0;
@@ -2624,7 +2547,12 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
mutex_unlock (&adapter->mfe_lock);
return ret;
+err3:
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (fe->dvb->mdev && fe->dvb->mdev->disable_source)
+ fe->dvb->mdev->disable_source(dvbdev->entity);
err2:
+#endif
dvb_generic_release(inode, file);
err1:
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
@@ -2653,6 +2581,10 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if (dvbdev->users == -1) {
wake_up(&fepriv->wait_queue);
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (fe->dvb->mdev && fe->dvb->mdev->disable_source)
+ fe->dvb->mdev->disable_source(dvbdev->entity);
+#endif
if (fe->exit != DVB_FE_NO_EXIT)
wake_up(&dvbdev->wait_queue);
if (fe->ops.ts_bus_ctrl)
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
index 458bcce20e38..9592573a0b41 100644
--- a/drivers/media/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -449,7 +449,8 @@ struct dvb_frontend_ops {
int (*set_frontend)(struct dvb_frontend *fe);
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
- int (*get_frontend)(struct dvb_frontend *fe);
+ int (*get_frontend)(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *props);
int (*read_status)(struct dvb_frontend *fe, enum fe_status *status);
int (*read_ber)(struct dvb_frontend* fe, u32* ber);
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 560450a0b32a..e1684c570e2f 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -58,7 +58,7 @@ static const char * const dnames[] = {
#define DVB_MAX_IDS MAX_DVB_MINORS
#else
#define DVB_MAX_IDS 4
-#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
+#define nums2minor(num, type, id) ((num << 6) | (id << 4) | type)
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
#endif
@@ -85,7 +85,7 @@ static int dvb_device_open(struct inode *inode, struct file *file)
file->private_data = dvbdev;
replace_fops(file, new_fops);
if (file->f_op->open)
- err = file->f_op->open(inode,file);
+ err = file->f_op->open(inode, file);
up_read(&minor_rwsem);
mutex_unlock(&dvbdev_mutex);
return err;
@@ -352,7 +352,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
ret = media_device_register_entity(dvbdev->adapter->mdev,
dvbdev->entity);
if (ret)
- return (ret);
+ return ret;
printk(KERN_DEBUG "%s: media entity '%s' registered.\n",
__func__, dvbdev->entity->name);
@@ -620,8 +620,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
return -ENOMEM;
adap->conn = conn;
- adap->conn_pads = kcalloc(1, sizeof(*adap->conn_pads),
- GFP_KERNEL);
+ adap->conn_pads = kzalloc(sizeof(*adap->conn_pads), GFP_KERNEL);
if (!adap->conn_pads)
return -ENOMEM;
@@ -661,7 +660,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
if (ntuner && ndemod) {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_TUNER,
- tuner, TUNER_PAD_IF_OUTPUT,
+ tuner, TUNER_PAD_OUTPUT,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0, MEDIA_LNK_FL_ENABLED,
false);
@@ -682,7 +681,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
if (demux && ca) {
ret = media_create_pad_link(demux, 1, ca,
0, MEDIA_LNK_FL_ENABLED);
- if (!ret)
+ if (ret)
return -ENOMEM;
}
@@ -868,7 +867,7 @@ int dvb_usercopy(struct file *file,
parg = sbuf;
} else {
/* too big to allocate from stack */
- mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+ mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
if (NULL == mbuf)
return -ENOMEM;
parg = mbuf;
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 310e4b8beae8..a82f77c49bd5 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -73,6 +73,14 @@ config DVB_SI2165
Say Y when you want to support this frontend.
+config DVB_MN88473
+ tristate "Panasonic MN88473"
+ depends on DVB_CORE && I2C
+ select REGMAP_I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
+
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 37ef17b5b995..eb7191f4219d 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_DVB_STV0900) += stv0900.o
obj-$(CONFIG_DVB_STV090x) += stv090x.o
obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
+obj-$(CONFIG_DVB_MN88473) += mn88473.o
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c
index e23197da84af..8bcde336ffd7 100644
--- a/drivers/media/dvb-frontends/af9013.c
+++ b/drivers/media/dvb-frontends/af9013.c
@@ -866,9 +866,9 @@ err:
return ret;
}
-static int af9013_get_frontend(struct dvb_frontend *fe)
+static int af9013_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct af9013_state *state = fe->demodulator_priv;
int ret;
u8 buf[3];
@@ -1344,6 +1344,10 @@ err:
static void af9013_release(struct dvb_frontend *fe)
{
struct af9013_state *state = fe->demodulator_priv;
+
+ /* stop statistics polling */
+ cancel_delayed_work_sync(&state->statistics_work);
+
kfree(state);
}
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
index bc35206a0821..efebe5ce2429 100644
--- a/drivers/media/dvb-frontends/af9033.c
+++ b/drivers/media/dvb-frontends/af9033.c
@@ -691,10 +691,10 @@ err:
return ret;
}
-static int af9033_get_frontend(struct dvb_frontend *fe)
+static int af9033_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct af9033_dev *dev = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[8];
@@ -1372,6 +1372,9 @@ static int af9033_remove(struct i2c_client *client)
dev_dbg(&dev->client->dev, "\n");
+ /* stop statistics polling */
+ cancel_delayed_work_sync(&dev->stat_work);
+
dev->fe.ops.release = NULL;
dev->fe.demodulator_priv = NULL;
kfree(dev);
diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c
index 544c5f65d19a..9412fcd1bddb 100644
--- a/drivers/media/dvb-frontends/as102_fe.c
+++ b/drivers/media/dvb-frontends/as102_fe.c
@@ -190,10 +190,10 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe)
return state->ops->set_tune(state->priv, &tune_args);
}
-static int as102_fe_get_frontend(struct dvb_frontend *fe)
+static int as102_fe_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct as102_state *state = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret = 0;
struct as10x_tps tps = { 0 };
diff --git a/drivers/media/dvb-frontends/atbm8830.c b/drivers/media/dvb-frontends/atbm8830.c
index 8fe552e293ed..47248b868e38 100644
--- a/drivers/media/dvb-frontends/atbm8830.c
+++ b/drivers/media/dvb-frontends/atbm8830.c
@@ -297,9 +297,9 @@ static int atbm8830_set_fe(struct dvb_frontend *fe)
return 0;
}
-static int atbm8830_get_fe(struct dvb_frontend *fe)
+static int atbm8830_get_fe(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
dprintk("%s\n", __func__);
/* TODO: get real readings from device */
diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h
index dde61582c158..78bf3f73e58d 100644
--- a/drivers/media/dvb-frontends/au8522.h
+++ b/drivers/media/dvb-frontends/au8522.h
@@ -89,5 +89,4 @@ enum au8522_audio_input {
AU8522_AUDIO_NONE,
AU8522_AUDIO_SIF,
};
-
#endif /* __AU8522_H__ */
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
index 73612c5353d1..add246382806 100644
--- a/drivers/media/dvb-frontends/au8522_decoder.c
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -763,9 +763,10 @@ static int au8522_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(sd, client, &au8522_ops);
#if defined(CONFIG_MEDIA_CONTROLLER)
- state->pads[AU8522_PAD_INPUT].flags = MEDIA_PAD_FL_SINK;
- state->pads[AU8522_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
- state->pads[AU8522_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[DEMOD_PAD_AUDIO_OUT].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads),
diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c
index 6c1e97640f3f..e676b9461a59 100644
--- a/drivers/media/dvb-frontends/au8522_dig.c
+++ b/drivers/media/dvb-frontends/au8522_dig.c
@@ -816,9 +816,9 @@ static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
return au8522_read_ucblocks(fe, ber);
}
-static int au8522_get_frontend(struct dvb_frontend *fe)
+static int au8522_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct au8522_state *state = fe->demodulator_priv;
c->frequency = state->current_frequency;
diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h
index 404a0cb0ed8d..f5a9438f6ce5 100644
--- a/drivers/media/dvb-frontends/au8522_priv.h
+++ b/drivers/media/dvb-frontends/au8522_priv.h
@@ -30,6 +30,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-mc.h>
#include <linux/i2c.h>
#include "dvb_frontend.h"
#include "au8522.h"
@@ -39,14 +40,6 @@
#define AU8522_DIGITAL_MODE 1
#define AU8522_SUSPEND_MODE 2
-enum au8522_media_pads {
- AU8522_PAD_INPUT,
- AU8522_PAD_VID_OUT,
- AU8522_PAD_VBI_OUT,
-
- AU8522_NUM_PADS
-};
-
struct au8522_state {
struct i2c_client *c;
struct i2c_adapter *i2c;
@@ -78,7 +71,7 @@ struct au8522_state {
struct v4l2_ctrl_handler hdl;
#ifdef CONFIG_MEDIA_CONTROLLER
- struct media_pad pads[AU8522_NUM_PADS];
+ struct media_pad pads[DEMOD_NUM_PADS];
#endif
};
diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c
index d30275f27644..bb698839e477 100644
--- a/drivers/media/dvb-frontends/bcm3510.c
+++ b/drivers/media/dvb-frontends/bcm3510.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2001-5, B2C2 inc.
*
- * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@posteo.de>
*
* This driver is "hard-coded" to be used with the 1st generation of
* Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming
@@ -865,5 +865,5 @@ static struct dvb_frontend_ops bcm3510_ops = {
};
MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver");
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/bcm3510.h b/drivers/media/dvb-frontends/bcm3510.h
index ff66492fb940..961c2eb87c68 100644
--- a/drivers/media/dvb-frontends/bcm3510.h
+++ b/drivers/media/dvb-frontends/bcm3510.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2001-5, B2C2 inc.
*
- * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@posteo.de>
*
* 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
diff --git a/drivers/media/dvb-frontends/bcm3510_priv.h b/drivers/media/dvb-frontends/bcm3510_priv.h
index 3bb1bc2a04f0..67f24686c31b 100644
--- a/drivers/media/dvb-frontends/bcm3510_priv.h
+++ b/drivers/media/dvb-frontends/bcm3510_priv.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2001-5, B2C2 inc.
*
- * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@posteo.de>
*
* 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
diff --git a/drivers/media/dvb-frontends/cx22700.c b/drivers/media/dvb-frontends/cx22700.c
index fd033cca6e11..5cad925609e0 100644
--- a/drivers/media/dvb-frontends/cx22700.c
+++ b/drivers/media/dvb-frontends/cx22700.c
@@ -345,9 +345,9 @@ static int cx22700_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int cx22700_get_frontend(struct dvb_frontend *fe)
+static int cx22700_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx22700_state* state = fe->demodulator_priv;
u8 reg09 = cx22700_readreg (state, 0x09);
diff --git a/drivers/media/dvb-frontends/cx22702.c b/drivers/media/dvb-frontends/cx22702.c
index d2d06dcd7683..c0e54c59cccf 100644
--- a/drivers/media/dvb-frontends/cx22702.c
+++ b/drivers/media/dvb-frontends/cx22702.c
@@ -562,9 +562,9 @@ static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
return 0;
}
-static int cx22702_get_frontend(struct dvb_frontend *fe)
+static int cx22702_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx22702_state *state = fe->demodulator_priv;
u8 reg0C = cx22702_readreg(state, 0x0C);
diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c
index cb36475e322b..6cb81ec12847 100644
--- a/drivers/media/dvb-frontends/cx24110.c
+++ b/drivers/media/dvb-frontends/cx24110.c
@@ -550,9 +550,9 @@ static int cx24110_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int cx24110_get_frontend(struct dvb_frontend *fe)
+static int cx24110_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct cx24110_state *state = fe->demodulator_priv;
s32 afc; unsigned sclk;
diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c
index 5f77bc80a896..a3f7eb4e609d 100644
--- a/drivers/media/dvb-frontends/cx24117.c
+++ b/drivers/media/dvb-frontends/cx24117.c
@@ -1560,10 +1560,10 @@ static int cx24117_get_algo(struct dvb_frontend *fe)
return DVBFE_ALGO_HW;
}
-static int cx24117_get_frontend(struct dvb_frontend *fe)
+static int cx24117_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct cx24117_state *state = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx24117_cmd cmd;
u8 reg, st, inv;
int ret, idx;
diff --git a/drivers/media/dvb-frontends/cx24120.c b/drivers/media/dvb-frontends/cx24120.c
index 3b0ef52bb834..066ee387bf25 100644
--- a/drivers/media/dvb-frontends/cx24120.c
+++ b/drivers/media/dvb-frontends/cx24120.c
@@ -1502,16 +1502,18 @@ static int cx24120_sleep(struct dvb_frontend *fe)
return 0;
}
-static int cx24120_get_frontend(struct dvb_frontend *fe)
+static int cx24120_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx24120_state *state = fe->demodulator_priv;
u8 freq1, freq2, freq3;
+ int status;
dev_dbg(&state->i2c->dev, "\n");
/* don't return empty data if we're not tuned in */
- if ((state->fe_status & FE_HAS_LOCK) == 0)
+ status = cx24120_readreg(state, CX24120_REG_STATUS);
+ if (!(status & CX24120_HAS_LOCK))
return 0;
/* Get frequency */
diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c
index 0fe7fb11124b..113b0949408a 100644
--- a/drivers/media/dvb-frontends/cx24123.c
+++ b/drivers/media/dvb-frontends/cx24123.c
@@ -945,9 +945,9 @@ static int cx24123_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int cx24123_get_frontend(struct dvb_frontend *fe)
+static int cx24123_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct cx24123_state *state = fe->demodulator_priv;
dprintk("\n");
diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c
index 42fad6aa3958..a674a6312c38 100644
--- a/drivers/media/dvb-frontends/cxd2820r_c.c
+++ b/drivers/media/dvb-frontends/cxd2820r_c.c
@@ -101,10 +101,10 @@ error:
return ret;
}
-int cxd2820r_get_frontend_c(struct dvb_frontend *fe)
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[2];
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index 24a457d9d803..314d3b8c1080 100644
--- a/drivers/media/dvb-frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -313,7 +313,8 @@ static int cxd2820r_read_status(struct dvb_frontend *fe, enum fe_status *status)
return ret;
}
-static int cxd2820r_get_frontend(struct dvb_frontend *fe)
+static int cxd2820r_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
@@ -326,13 +327,13 @@ static int cxd2820r_get_frontend(struct dvb_frontend *fe)
switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBT:
- ret = cxd2820r_get_frontend_t(fe);
+ ret = cxd2820r_get_frontend_t(fe, p);
break;
case SYS_DVBT2:
- ret = cxd2820r_get_frontend_t2(fe);
+ ret = cxd2820r_get_frontend_t2(fe, p);
break;
case SYS_DVBC_ANNEX_A:
- ret = cxd2820r_get_frontend_c(fe);
+ ret = cxd2820r_get_frontend_c(fe, p);
break;
default:
ret = -EINVAL;
@@ -606,8 +607,7 @@ static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
static int cxd2820r_gpio_direction_output(struct gpio_chip *chip, unsigned nr,
int val)
{
- struct cxd2820r_priv *priv =
- container_of(chip, struct cxd2820r_priv, gpio_chip);
+ struct cxd2820r_priv *priv = gpiochip_get_data(chip);
u8 gpio[GPIO_COUNT];
dev_dbg(&priv->i2c->dev, "%s: nr=%d val=%d\n", __func__, nr, val);
@@ -620,8 +620,7 @@ static int cxd2820r_gpio_direction_output(struct gpio_chip *chip, unsigned nr,
static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val)
{
- struct cxd2820r_priv *priv =
- container_of(chip, struct cxd2820r_priv, gpio_chip);
+ struct cxd2820r_priv *priv = gpiochip_get_data(chip);
u8 gpio[GPIO_COUNT];
dev_dbg(&priv->i2c->dev, "%s: nr=%d val=%d\n", __func__, nr, val);
@@ -636,8 +635,7 @@ static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val)
static int cxd2820r_gpio_get(struct gpio_chip *chip, unsigned nr)
{
- struct cxd2820r_priv *priv =
- container_of(chip, struct cxd2820r_priv, gpio_chip);
+ struct cxd2820r_priv *priv = gpiochip_get_data(chip);
dev_dbg(&priv->i2c->dev, "%s: nr=%d\n", __func__, nr);
@@ -731,7 +729,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
priv->gpio_chip.base = -1; /* dynamic allocation */
priv->gpio_chip.ngpio = GPIO_COUNT;
priv->gpio_chip.can_sleep = 1;
- ret = gpiochip_add(&priv->gpio_chip);
+ ret = gpiochip_add_data(&priv->gpio_chip, priv);
if (ret)
goto error;
diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h
index a0d53f01a8bf..e31c48e53097 100644
--- a/drivers/media/dvb-frontends/cxd2820r_priv.h
+++ b/drivers/media/dvb-frontends/cxd2820r_priv.h
@@ -76,7 +76,8 @@ int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val);
/* cxd2820r_c.c */
-int cxd2820r_get_frontend_c(struct dvb_frontend *fe);
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p);
int cxd2820r_set_frontend_c(struct dvb_frontend *fe);
@@ -99,7 +100,8 @@ int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
/* cxd2820r_t.c */
-int cxd2820r_get_frontend_t(struct dvb_frontend *fe);
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p);
int cxd2820r_set_frontend_t(struct dvb_frontend *fe);
@@ -122,7 +124,8 @@ int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
/* cxd2820r_t2.c */
-int cxd2820r_get_frontend_t2(struct dvb_frontend *fe);
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p);
int cxd2820r_set_frontend_t2(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c
index 21abf1b4ed4d..75ce7d8ded00 100644
--- a/drivers/media/dvb-frontends/cxd2820r_t.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t.c
@@ -138,10 +138,10 @@ error:
return ret;
}
-int cxd2820r_get_frontend_t(struct dvb_frontend *fe)
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[2];
diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c
index 4e028b41c0d5..704475676234 100644
--- a/drivers/media/dvb-frontends/cxd2820r_t2.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t2.c
@@ -23,8 +23,8 @@
int cxd2820r_set_frontend_t2(struct dvb_frontend *fe)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret, i, bw_i;
u32 if_freq, if_ctl;
u64 num;
@@ -169,10 +169,10 @@ error:
}
-int cxd2820r_get_frontend_t2(struct dvb_frontend *fe)
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[2];
diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c
index fdffb2f0ded8..900186ba8e62 100644
--- a/drivers/media/dvb-frontends/cxd2841er.c
+++ b/drivers/media/dvb-frontends/cxd2841er.c
@@ -2090,13 +2090,13 @@ static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv,
return 0;
}
-static int cxd2841er_get_frontend(struct dvb_frontend *fe)
+static int cxd2841er_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
enum fe_status status = 0;
u16 strength = 0, snr = 0;
u32 errors = 0, ber = 0;
struct cxd2841er_priv *priv = fe->demodulator_priv;
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
if (priv->state == STATE_ACTIVE_S)
diff --git a/drivers/media/dvb-frontends/dib0070.c b/drivers/media/dvb-frontends/dib0070.c
index 0b8fb5dd1889..ee7d66997ccd 100644
--- a/drivers/media/dvb-frontends/dib0070.c
+++ b/drivers/media/dvb-frontends/dib0070.c
@@ -774,6 +774,6 @@ free_mem:
}
EXPORT_SYMBOL(dib0070_attach);
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c
index 47cb72243b9d..dc2d41e144fd 100644
--- a/drivers/media/dvb-frontends/dib0090.c
+++ b/drivers/media/dvb-frontends/dib0090.c
@@ -1115,9 +1115,15 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
dib0090_set_bbramp_pwm(state, bb_ramp);
/* activate the ramp generator using PWM control */
- dprintk("ramp RF gain = %d BAND = %s version = %d", state->rf_ramp[0], (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND", state->identity.version & 0x1f);
-
- if ((state->rf_ramp[0] == 0) || (state->current_band == BAND_CBAND && (state->identity.version & 0x1f) <= P1D_E_F)) {
+ if (state->rf_ramp)
+ dprintk("ramp RF gain = %d BAND = %s version = %d",
+ state->rf_ramp[0],
+ (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND",
+ state->identity.version & 0x1f);
+
+ if (rf_ramp && ((state->rf_ramp[0] == 0) ||
+ (state->current_band == BAND_CBAND &&
+ (state->identity.version & 0x1f) <= P1D_E_F))) {
dprintk("DE-Engage mux for direct gain reg control");
en_pwm_rf_mux = 0;
} else
@@ -2669,7 +2675,7 @@ free_mem:
}
EXPORT_SYMBOL(dib0090_fw_register);
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
+MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>");
MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h
index 6ae9899b5b45..d5dfafb4ef13 100644
--- a/drivers/media/dvb-frontends/dib3000.h
+++ b/drivers/media/dvb-frontends/dib3000.h
@@ -2,11 +2,11 @@
* public header file of the frontend drivers for mobile DVB-T demodulators
* DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/)
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* based on GPL code from DibCom, which has
*
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ * Copyright (C) 2004 Amaury Demol for DiBcom
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -14,7 +14,7 @@
*
* Acknowledgements
*
- * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ * Amaury Demol from DiBcom for providing specs and driver
* sources, on which this driver (and the dvb-dibusb) are based.
*
* see Documentation/dvb/README.dvb-usb for more information
diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c
index 7a61172d0d45..6821ecb53d63 100644
--- a/drivers/media/dvb-frontends/dib3000mb.c
+++ b/drivers/media/dvb-frontends/dib3000mb.c
@@ -2,11 +2,11 @@
* Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B
* DiBcom (http://www.dibcom.fr/)
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* based on GPL code from DibCom, which has
*
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ * Copyright (C) 2004 Amaury Demol for DiBcom
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -14,7 +14,7 @@
*
* Acknowledgements
*
- * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ * Amaury Demol from DiBcom for providing specs and driver
* sources, on which this driver (and the dvb-dibusb) are based.
*
* see Documentation/dvb/README.dvb-usb for more information
@@ -36,7 +36,7 @@
/* Version information */
#define DRIVER_VERSION "0.1"
#define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@posteo.de"
static int debug;
module_param(debug, int, 0644);
@@ -112,7 +112,8 @@ static u16 dib3000_seq[2][2][2] = /* fft,gua, inv */
}
};
-static int dib3000mb_get_frontend(struct dvb_frontend* fe);
+static int dib3000mb_get_frontend(struct dvb_frontend* fe,
+ struct dtv_frontend_properties *c);
static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner)
{
@@ -359,7 +360,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner)
deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count);
if (search_state == 1) {
- if (dib3000mb_get_frontend(fe) == 0) {
+ if (dib3000mb_get_frontend(fe, c) == 0) {
deb_setf("reading tuning data from frontend succeeded.\n");
return dib3000mb_set_frontend(fe, 0);
}
@@ -450,9 +451,9 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
return 0;
}
-static int dib3000mb_get_frontend(struct dvb_frontend* fe)
+static int dib3000mb_get_frontend(struct dvb_frontend* fe,
+ struct dtv_frontend_properties *c)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dib3000_state* state = fe->demodulator_priv;
enum fe_code_rate *cr;
u16 tps_val;
diff --git a/drivers/media/dvb-frontends/dib3000mb_priv.h b/drivers/media/dvb-frontends/dib3000mb_priv.h
index 9dc235aa44b7..0459d5c84314 100644
--- a/drivers/media/dvb-frontends/dib3000mb_priv.h
+++ b/drivers/media/dvb-frontends/dib3000mb_priv.h
@@ -1,7 +1,7 @@
/*
* dib3000mb_priv.h
*
- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/drivers/media/dvb-frontends/dib3000mc.c b/drivers/media/dvb-frontends/dib3000mc.c
index 583d6b7fabed..da0f1dc5aaf7 100644
--- a/drivers/media/dvb-frontends/dib3000mc.c
+++ b/drivers/media/dvb-frontends/dib3000mc.c
@@ -2,7 +2,7 @@
* Driver for DiBcom DiB3000MC/P-demodulator.
*
* Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/)
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* This code is partially based on the previous dib3000mc.c .
*
@@ -636,9 +636,9 @@ struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
-static int dib3000mc_get_frontend(struct dvb_frontend* fe)
+static int dib3000mc_get_frontend(struct dvb_frontend* fe,
+ struct dtv_frontend_properties *fep)
{
- struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dib3000mc_state *state = fe->demodulator_priv;
u16 tps = dib3000mc_read_word(state,458);
@@ -726,7 +726,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend *fe)
if (found == 0 || found == 1)
return 0; // no channel found
- dib3000mc_get_frontend(fe);
+ dib3000mc_get_frontend(fe, fep);
}
ret = dib3000mc_tune(fe);
@@ -939,6 +939,6 @@ static struct dvb_frontend_ops dib3000mc_ops = {
.read_ucblocks = dib3000mc_read_unc_blocks,
};
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib3000mc.h b/drivers/media/dvb-frontends/dib3000mc.h
index 74816f793611..b37e69e6a58c 100644
--- a/drivers/media/dvb-frontends/dib3000mc.h
+++ b/drivers/media/dvb-frontends/dib3000mc.h
@@ -2,7 +2,7 @@
* Driver for DiBcom DiB3000MC/P-demodulator.
*
* Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher\@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* This code is partially based on the previous dib3000mc.c .
*
diff --git a/drivers/media/dvb-frontends/dib7000m.c b/drivers/media/dvb-frontends/dib7000m.c
index 35eb71fe3c2b..b3ddae8885ac 100644
--- a/drivers/media/dvb-frontends/dib7000m.c
+++ b/drivers/media/dvb-frontends/dib7000m.c
@@ -1151,9 +1151,9 @@ static int dib7000m_identify(struct dib7000m_state *state)
}
-static int dib7000m_get_frontend(struct dvb_frontend* fe)
+static int dib7000m_get_frontend(struct dvb_frontend* fe,
+ struct dtv_frontend_properties *fep)
{
- struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dib7000m_state *state = fe->demodulator_priv;
u16 tps = dib7000m_read_word(state,480);
@@ -1246,7 +1246,7 @@ static int dib7000m_set_frontend(struct dvb_frontend *fe)
if (found == 0 || found == 1)
return 0; // no channel found
- dib7000m_get_frontend(fe);
+ dib7000m_get_frontend(fe, fep);
}
ret = dib7000m_tune(fe);
@@ -1465,6 +1465,6 @@ static struct dvb_frontend_ops dib7000m_ops = {
.read_ucblocks = dib7000m_read_unc_blocks,
};
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 33be5d6b9e10..b861d4437f2a 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -1405,9 +1405,9 @@ static int dib7000p_identify(struct dib7000p_state *st)
return 0;
}
-static int dib7000p_get_frontend(struct dvb_frontend *fe)
+static int dib7000p_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *fep)
{
- struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dib7000p_state *state = fe->demodulator_priv;
u16 tps = dib7000p_read_word(state, 463);
@@ -1540,7 +1540,7 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe)
if (found == 0 || found == 1)
return 0;
- dib7000p_get_frontend(fe);
+ dib7000p_get_frontend(fe, fep);
}
ret = dib7000p_tune(fe);
@@ -2834,7 +2834,7 @@ static struct dvb_frontend_ops dib7000p_ops = {
.read_ucblocks = dib7000p_read_unc_blocks,
};
-MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Olivier Grenie <olivie.grenie@parrot.com>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index 94c26270fff0..ddf9c44877a2 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -3382,14 +3382,15 @@ static int dib8000_sleep(struct dvb_frontend *fe)
static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat);
-static int dib8000_get_frontend(struct dvb_frontend *fe)
+static int dib8000_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct dib8000_state *state = fe->demodulator_priv;
u16 i, val = 0;
enum fe_status stat = 0;
u8 index_frontend, sub_index_frontend;
- fe->dtv_property_cache.bandwidth_hz = 6000000;
+ c->bandwidth_hz = 6000000;
/*
* If called to early, get_frontend makes dib8000_tune to either
@@ -3406,7 +3407,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
if (stat&FE_HAS_SYNC) {
dprintk("TMCC lock on the slave%i", index_frontend);
/* synchronize the cache with the other frontends */
- state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
+ state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
if (sub_index_frontend != index_frontend) {
state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
@@ -3426,57 +3427,57 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
}
}
- fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
+ c->isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
if (state->revision == 0x8090)
val = dib8000_read_word(state, 572);
else
val = dib8000_read_word(state, 570);
- fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
+ c->inversion = (val & 0x40) >> 6;
switch ((val & 0x30) >> 4) {
case 1:
- fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
+ c->transmission_mode = TRANSMISSION_MODE_2K;
dprintk("dib8000_get_frontend: transmission mode 2K");
break;
case 2:
- fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K;
+ c->transmission_mode = TRANSMISSION_MODE_4K;
dprintk("dib8000_get_frontend: transmission mode 4K");
break;
case 3:
default:
- fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+ c->transmission_mode = TRANSMISSION_MODE_8K;
dprintk("dib8000_get_frontend: transmission mode 8K");
break;
}
switch (val & 0x3) {
case 0:
- fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
+ c->guard_interval = GUARD_INTERVAL_1_32;
dprintk("dib8000_get_frontend: Guard Interval = 1/32 ");
break;
case 1:
- fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
+ c->guard_interval = GUARD_INTERVAL_1_16;
dprintk("dib8000_get_frontend: Guard Interval = 1/16 ");
break;
case 2:
dprintk("dib8000_get_frontend: Guard Interval = 1/8 ");
- fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+ c->guard_interval = GUARD_INTERVAL_1_8;
break;
case 3:
dprintk("dib8000_get_frontend: Guard Interval = 1/4 ");
- fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
+ c->guard_interval = GUARD_INTERVAL_1_4;
break;
}
val = dib8000_read_word(state, 505);
- fe->dtv_property_cache.isdbt_partial_reception = val & 1;
- dprintk("dib8000_get_frontend: partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
+ c->isdbt_partial_reception = val & 1;
+ dprintk("dib8000_get_frontend: partial_reception = %d ", c->isdbt_partial_reception);
for (i = 0; i < 3; i++) {
int show;
val = dib8000_read_word(state, 493 + i) & 0x0f;
- fe->dtv_property_cache.layer[i].segment_count = val;
+ c->layer[i].segment_count = val;
if (val == 0 || val > 13)
show = 0;
@@ -3485,41 +3486,41 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
if (show)
dprintk("dib8000_get_frontend: Layer %d segments = %d ",
- i, fe->dtv_property_cache.layer[i].segment_count);
+ i, c->layer[i].segment_count);
val = dib8000_read_word(state, 499 + i) & 0x3;
/* Interleaving can be 0, 1, 2 or 4 */
if (val == 3)
val = 4;
- fe->dtv_property_cache.layer[i].interleaving = val;
+ c->layer[i].interleaving = val;
if (show)
dprintk("dib8000_get_frontend: Layer %d time_intlv = %d ",
- i, fe->dtv_property_cache.layer[i].interleaving);
+ i, c->layer[i].interleaving);
val = dib8000_read_word(state, 481 + i);
switch (val & 0x7) {
case 1:
- fe->dtv_property_cache.layer[i].fec = FEC_1_2;
+ c->layer[i].fec = FEC_1_2;
if (show)
dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2 ", i);
break;
case 2:
- fe->dtv_property_cache.layer[i].fec = FEC_2_3;
+ c->layer[i].fec = FEC_2_3;
if (show)
dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3 ", i);
break;
case 3:
- fe->dtv_property_cache.layer[i].fec = FEC_3_4;
+ c->layer[i].fec = FEC_3_4;
if (show)
dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4 ", i);
break;
case 5:
- fe->dtv_property_cache.layer[i].fec = FEC_5_6;
+ c->layer[i].fec = FEC_5_6;
if (show)
dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6 ", i);
break;
default:
- fe->dtv_property_cache.layer[i].fec = FEC_7_8;
+ c->layer[i].fec = FEC_7_8;
if (show)
dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8 ", i);
break;
@@ -3528,23 +3529,23 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
val = dib8000_read_word(state, 487 + i);
switch (val & 0x3) {
case 0:
- fe->dtv_property_cache.layer[i].modulation = DQPSK;
+ c->layer[i].modulation = DQPSK;
if (show)
dprintk("dib8000_get_frontend: Layer %d DQPSK ", i);
break;
case 1:
- fe->dtv_property_cache.layer[i].modulation = QPSK;
+ c->layer[i].modulation = QPSK;
if (show)
dprintk("dib8000_get_frontend: Layer %d QPSK ", i);
break;
case 2:
- fe->dtv_property_cache.layer[i].modulation = QAM_16;
+ c->layer[i].modulation = QAM_16;
if (show)
dprintk("dib8000_get_frontend: Layer %d QAM16 ", i);
break;
case 3:
default:
- fe->dtv_property_cache.layer[i].modulation = QAM_64;
+ c->layer[i].modulation = QAM_64;
if (show)
dprintk("dib8000_get_frontend: Layer %d QAM64 ", i);
break;
@@ -3553,16 +3554,16 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
/* synchronize the cache with the other frontends */
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
- state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
- state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
- state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
- state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
- state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
+ state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = c->isdbt_sb_mode;
+ state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
+ state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
+ state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
+ state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = c->isdbt_partial_reception;
for (i = 0; i < 3; i++) {
- state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
- state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
- state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
- state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
+ state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = c->layer[i].segment_count;
+ state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = c->layer[i].interleaving;
+ state->fe[index_frontend]->dtv_property_cache.layer[i].fec = c->layer[i].fec;
+ state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = c->layer[i].modulation;
}
}
return 0;
@@ -3671,7 +3672,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
if (state->channel_parameters_set == 0) { /* searching */
if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
dprintk("autosearch succeeded on fe%i", index_frontend);
- dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
+ dib8000_get_frontend(state->fe[index_frontend], c); /* we read the channel parameters from the frontend which was successful */
state->channel_parameters_set = 1;
for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
@@ -4516,6 +4517,6 @@ void *dib8000_attach(struct dib8000_ops *ops)
}
EXPORT_SYMBOL(dib8000_attach);
-MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c
index 8f92aca0b073..5897977d2d00 100644
--- a/drivers/media/dvb-frontends/dib9000.c
+++ b/drivers/media/dvb-frontends/dib9000.c
@@ -225,7 +225,7 @@ static u16 to_fw_output_mode(u16 mode)
}
}
-static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32 len, u16 attribute)
+static int dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 *b, u32 len, u16 attribute)
{
u32 chunk_size = 126;
u32 l;
@@ -309,7 +309,7 @@ static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u
#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
-static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute)
+static int dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *buf, u32 len, u16 attribute)
{
u32 chunk_size = 126;
u32 l;
@@ -1889,7 +1889,8 @@ static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_fron
return 0;
}
-static int dib9000_get_frontend(struct dvb_frontend *fe)
+static int dib9000_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct dib9000_state *state = fe->demodulator_priv;
u8 index_frontend, sub_index_frontend;
@@ -1909,7 +1910,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe)
dprintk("TPS lock on the slave%i", index_frontend);
/* synchronize the cache with the other frontends */
- state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
+ state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL);
sub_index_frontend++) {
if (sub_index_frontend != index_frontend) {
@@ -1943,14 +1944,14 @@ static int dib9000_get_frontend(struct dvb_frontend *fe)
/* synchronize the cache with the other frontends */
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
- state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
- state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
- state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
- state->fe[index_frontend]->dtv_property_cache.modulation = fe->dtv_property_cache.modulation;
- state->fe[index_frontend]->dtv_property_cache.hierarchy = fe->dtv_property_cache.hierarchy;
- state->fe[index_frontend]->dtv_property_cache.code_rate_HP = fe->dtv_property_cache.code_rate_HP;
- state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP;
- state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff;
+ state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
+ state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
+ state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
+ state->fe[index_frontend]->dtv_property_cache.modulation = c->modulation;
+ state->fe[index_frontend]->dtv_property_cache.hierarchy = c->hierarchy;
+ state->fe[index_frontend]->dtv_property_cache.code_rate_HP = c->code_rate_HP;
+ state->fe[index_frontend]->dtv_property_cache.code_rate_LP = c->code_rate_LP;
+ state->fe[index_frontend]->dtv_property_cache.rolloff = c->rolloff;
}
ret = 0;
@@ -2083,7 +2084,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe)
/* synchronize all the channel cache */
state->get_frontend_internal = 1;
- dib9000_get_frontend(state->fe[0]);
+ dib9000_get_frontend(state->fe[0], &state->fe[0]->dtv_property_cache);
state->get_frontend_internal = 0;
/* retune the other frontends with the found channel */
@@ -2589,7 +2590,7 @@ static struct dvb_frontend_ops dib9000_ops = {
.read_ucblocks = dib9000_read_unc_blocks,
};
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
+MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>");
MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c
index 43be7238311e..723358d7ca84 100644
--- a/drivers/media/dvb-frontends/dibx000_common.c
+++ b/drivers/media/dvb-frontends/dibx000_common.c
@@ -510,6 +510,6 @@ u32 systime(void)
}
EXPORT_SYMBOL(systime);
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Common function the DiBcom demodulator family");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index b28b5787b39a..e48b741d439e 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -4131,7 +4131,7 @@ int drxj_dap_scu_atomic_read_write_block(struct i2c_device_addr *dev_addr, u32 a
{
struct drxjscu_cmd scu_cmd;
int rc;
- u16 set_param_parameters[15];
+ u16 set_param_parameters[18];
u16 cmd_result[15];
/* Parameter check */
@@ -9597,12 +9597,13 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod)
Precision errors still possible.
*/
- e = post_bit_err_rs * 742686;
- m = fec_oc_period * 100;
- if (fec_oc_period == 0)
+ if (!fec_oc_period) {
qam_post_rs_ber = 0xFFFFFFFF;
- else
+ } else {
+ e = post_bit_err_rs * 742686;
+ m = fec_oc_period * 100;
qam_post_rs_ber = e / m;
+ }
/* fill signal quality data structure */
p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.c b/drivers/media/dvb-frontends/dvb_dummy_fe.c
index 14e996d45fac..e5bd8c62ad3a 100644
--- a/drivers/media/dvb-frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb-frontends/dvb_dummy_fe.c
@@ -70,9 +70,12 @@ static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
}
/*
- * Only needed if it actually reads something from the hardware
+ * Should only be implemented if it actually reads something from the hardware.
+ * Also, it should check for the locks, in order to avoid report wrong data
+ * to userspace.
*/
-static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe)
+static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
return 0;
}
diff --git a/drivers/media/dvb-frontends/hd29l2.c b/drivers/media/dvb-frontends/hd29l2.c
index 40e359f2d17d..1c7eb477e2cd 100644
--- a/drivers/media/dvb-frontends/hd29l2.c
+++ b/drivers/media/dvb-frontends/hd29l2.c
@@ -560,11 +560,11 @@ static int hd29l2_get_frontend_algo(struct dvb_frontend *fe)
return DVBFE_ALGO_CUSTOM;
}
-static int hd29l2_get_frontend(struct dvb_frontend *fe)
+static int hd29l2_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
int ret;
struct hd29l2_priv *priv = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u8 buf[3];
u32 if_ctl;
char *str_constellation, *str_code_rate, *str_constellation_code_rate,
diff --git a/drivers/media/dvb-frontends/l64781.c b/drivers/media/dvb-frontends/l64781.c
index 0977871232a2..2f3d0519e19b 100644
--- a/drivers/media/dvb-frontends/l64781.c
+++ b/drivers/media/dvb-frontends/l64781.c
@@ -243,9 +243,9 @@ static int apply_frontend_param(struct dvb_frontend *fe)
return 0;
}
-static int get_frontend(struct dvb_frontend *fe)
+static int get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct l64781_state* state = fe->demodulator_priv;
int tmp;
diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c
index 7880f71ccd8a..f51a3a0b3949 100644
--- a/drivers/media/dvb-frontends/lg2160.c
+++ b/drivers/media/dvb-frontends/lg2160.c
@@ -942,101 +942,102 @@ static int lg216x_read_rs_err_count(struct lg216x_state *state, u16 *err)
/* ------------------------------------------------------------------------ */
-static int lg216x_get_frontend(struct dvb_frontend *fe)
+static int lg216x_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct lg216x_state *state = fe->demodulator_priv;
int ret;
lg_dbg("\n");
- fe->dtv_property_cache.modulation = VSB_8;
- fe->dtv_property_cache.frequency = state->current_frequency;
- fe->dtv_property_cache.delivery_system = SYS_ATSCMH;
+ c->modulation = VSB_8;
+ c->frequency = state->current_frequency;
+ c->delivery_system = SYS_ATSCMH;
ret = lg216x_get_fic_version(state,
- &fe->dtv_property_cache.atscmh_fic_ver);
+ &c->atscmh_fic_ver);
if (lg_fail(ret))
goto fail;
- if (state->fic_ver != fe->dtv_property_cache.atscmh_fic_ver) {
- state->fic_ver = fe->dtv_property_cache.atscmh_fic_ver;
+ if (state->fic_ver != c->atscmh_fic_ver) {
+ state->fic_ver = c->atscmh_fic_ver;
#if 0
ret = lg2160_get_parade_id(state,
- &fe->dtv_property_cache.atscmh_parade_id);
+ &c->atscmh_parade_id);
if (lg_fail(ret))
goto fail;
/* #else */
- fe->dtv_property_cache.atscmh_parade_id = state->parade_id;
+ c->atscmh_parade_id = state->parade_id;
#endif
ret = lg216x_get_nog(state,
- &fe->dtv_property_cache.atscmh_nog);
+ &c->atscmh_nog);
if (lg_fail(ret))
goto fail;
ret = lg216x_get_tnog(state,
- &fe->dtv_property_cache.atscmh_tnog);
+ &c->atscmh_tnog);
if (lg_fail(ret))
goto fail;
ret = lg216x_get_sgn(state,
- &fe->dtv_property_cache.atscmh_sgn);
+ &c->atscmh_sgn);
if (lg_fail(ret))
goto fail;
ret = lg216x_get_prc(state,
- &fe->dtv_property_cache.atscmh_prc);
+ &c->atscmh_prc);
if (lg_fail(ret))
goto fail;
ret = lg216x_get_rs_frame_mode(state,
(enum atscmh_rs_frame_mode *)
- &fe->dtv_property_cache.atscmh_rs_frame_mode);
+ &c->atscmh_rs_frame_mode);
if (lg_fail(ret))
goto fail;
ret = lg216x_get_rs_frame_ensemble(state,
(enum atscmh_rs_frame_ensemble *)
- &fe->dtv_property_cache.atscmh_rs_frame_ensemble);
+ &c->atscmh_rs_frame_ensemble);
if (lg_fail(ret))
goto fail;
ret = lg216x_get_rs_code_mode(state,
(enum atscmh_rs_code_mode *)
- &fe->dtv_property_cache.atscmh_rs_code_mode_pri,
+ &c->atscmh_rs_code_mode_pri,
(enum atscmh_rs_code_mode *)
- &fe->dtv_property_cache.atscmh_rs_code_mode_sec);
+ &c->atscmh_rs_code_mode_sec);
if (lg_fail(ret))
goto fail;
ret = lg216x_get_sccc_block_mode(state,
(enum atscmh_sccc_block_mode *)
- &fe->dtv_property_cache.atscmh_sccc_block_mode);
+ &c->atscmh_sccc_block_mode);
if (lg_fail(ret))
goto fail;
ret = lg216x_get_sccc_code_mode(state,
(enum atscmh_sccc_code_mode *)
- &fe->dtv_property_cache.atscmh_sccc_code_mode_a,
+ &c->atscmh_sccc_code_mode_a,
(enum atscmh_sccc_code_mode *)
- &fe->dtv_property_cache.atscmh_sccc_code_mode_b,
+ &c->atscmh_sccc_code_mode_b,
(enum atscmh_sccc_code_mode *)
- &fe->dtv_property_cache.atscmh_sccc_code_mode_c,
+ &c->atscmh_sccc_code_mode_c,
(enum atscmh_sccc_code_mode *)
- &fe->dtv_property_cache.atscmh_sccc_code_mode_d);
+ &c->atscmh_sccc_code_mode_d);
if (lg_fail(ret))
goto fail;
}
#if 0
ret = lg216x_read_fic_err_count(state,
- (u8 *)&fe->dtv_property_cache.atscmh_fic_err);
+ (u8 *)&c->atscmh_fic_err);
if (lg_fail(ret))
goto fail;
ret = lg216x_read_crc_err_count(state,
- &fe->dtv_property_cache.atscmh_crc_err);
+ &c->atscmh_crc_err);
if (lg_fail(ret))
goto fail;
ret = lg216x_read_rs_err_count(state,
- &fe->dtv_property_cache.atscmh_rs_err);
+ &c->atscmh_rs_err);
if (lg_fail(ret))
goto fail;
switch (state->cfg->lg_chip) {
case LG2160:
- if (((fe->dtv_property_cache.atscmh_rs_err >= 240) &&
- (fe->dtv_property_cache.atscmh_crc_err >= 240)) &&
+ if (((c->atscmh_rs_err >= 240) &&
+ (c->atscmh_crc_err >= 240)) &&
((jiffies_to_msecs(jiffies) - state->last_reset) > 6000))
ret = lg216x_soft_reset(state);
break;
@@ -1054,14 +1055,17 @@ fail:
static int lg216x_get_property(struct dvb_frontend *fe,
struct dtv_property *tvp)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
return (DTV_ATSCMH_FIC_VER == tvp->cmd) ?
- lg216x_get_frontend(fe) : 0;
+ lg216x_get_frontend(fe, c) : 0;
}
static int lg2160_set_frontend(struct dvb_frontend *fe)
{
struct lg216x_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
lg_dbg("(%d)\n", fe->dtv_property_cache.frequency);
@@ -1129,7 +1133,7 @@ static int lg2160_set_frontend(struct dvb_frontend *fe)
ret = lg216x_enable_fic(state, 1);
lg_fail(ret);
- lg216x_get_frontend(fe);
+ lg216x_get_frontend(fe, c);
fail:
return ret;
}
diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c
index 47121866163d..4503e8852fd1 100644
--- a/drivers/media/dvb-frontends/lgdt3305.c
+++ b/drivers/media/dvb-frontends/lgdt3305.c
@@ -812,9 +812,9 @@ fail:
return ret;
}
-static int lgdt3305_get_frontend(struct dvb_frontend *fe)
+static int lgdt3305_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct lgdt3305_state *state = fe->demodulator_priv;
lg_dbg("\n");
diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
index 721fbc07e9ee..179c26e5eb4e 100644
--- a/drivers/media/dvb-frontends/lgdt3306a.c
+++ b/drivers/media/dvb-frontends/lgdt3306a.c
@@ -1040,10 +1040,10 @@ fail:
return ret;
}
-static int lgdt3306a_get_frontend(struct dvb_frontend *fe)
+static int lgdt3306a_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
struct lgdt3306a_state *state = fe->demodulator_priv;
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
dbg_info("(%u, %d)\n",
state->current_frequency, state->current_modulation);
diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c
index cf3cc20510da..96bf254da21e 100644
--- a/drivers/media/dvb-frontends/lgdt330x.c
+++ b/drivers/media/dvb-frontends/lgdt330x.c
@@ -439,10 +439,11 @@ static int lgdt330x_set_parameters(struct dvb_frontend *fe)
return 0;
}
-static int lgdt330x_get_frontend(struct dvb_frontend *fe)
+static int lgdt330x_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct lgdt330x_state *state = fe->demodulator_priv;
+
p->frequency = state->current_frequency;
return 0;
}
diff --git a/drivers/media/dvb-frontends/lgs8gl5.c b/drivers/media/dvb-frontends/lgs8gl5.c
index 7bbb2c18c2dd..fbfd87b5b803 100644
--- a/drivers/media/dvb-frontends/lgs8gl5.c
+++ b/drivers/media/dvb-frontends/lgs8gl5.c
@@ -336,10 +336,11 @@ lgs8gl5_set_frontend(struct dvb_frontend *fe)
static int
-lgs8gl5_get_frontend(struct dvb_frontend *fe)
+lgs8gl5_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct lgs8gl5_state *state = fe->demodulator_priv;
+
u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
diff --git a/drivers/media/dvb-frontends/lgs8gxx.c b/drivers/media/dvb-frontends/lgs8gxx.c
index e2c191c8b196..919daeb96747 100644
--- a/drivers/media/dvb-frontends/lgs8gxx.c
+++ b/drivers/media/dvb-frontends/lgs8gxx.c
@@ -672,7 +672,7 @@ static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
static int lgs8gxx_set_fe(struct dvb_frontend *fe)
{
-
+ struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
struct lgs8gxx_state *priv = fe->demodulator_priv;
dprintk("%s\n", __func__);
@@ -689,17 +689,7 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe)
msleep(10);
- return 0;
-}
-
-static int lgs8gxx_get_fe(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
- dprintk("%s\n", __func__);
-
/* TODO: get real readings from device */
- /* inversion status */
- fe_params->inversion = INVERSION_OFF;
/* bandwidth */
fe_params->bandwidth_hz = 8000000;
@@ -1016,7 +1006,6 @@ static struct dvb_frontend_ops lgs8gxx_ops = {
.i2c_gate_ctrl = lgs8gxx_i2c_gate_ctrl,
.set_frontend = lgs8gxx_set_fe,
- .get_frontend = lgs8gxx_get_fe,
.get_tune_settings = lgs8gxx_get_tune_settings,
.read_status = lgs8gxx_read_status,
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index ce73a5ec6036..76883600ec6f 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -791,11 +791,11 @@ err:
return ret;
}
-static int m88ds3103_get_frontend(struct dvb_frontend *fe)
+static int m88ds3103_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct m88ds3103_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[3];
diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c
index 9b6f464c48bd..a09b12313a73 100644
--- a/drivers/media/dvb-frontends/m88rs2000.c
+++ b/drivers/media/dvb-frontends/m88rs2000.c
@@ -708,10 +708,11 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int m88rs2000_get_frontend(struct dvb_frontend *fe)
+static int m88rs2000_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct m88rs2000_state *state = fe->demodulator_priv;
+
c->fec_inner = state->fec_inner;
c->frequency = state->tuner_frequency;
c->symbol_rate = state->symbol_rate;
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index cfc005ee11d8..fb88dddaf3a3 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -2028,16 +2028,6 @@ static int mb86a20s_read_signal_strength_from_cache(struct dvb_frontend *fe,
return 0;
}
-static int mb86a20s_get_frontend_dummy(struct dvb_frontend *fe)
-{
- /*
- * get_frontend is now handled together with other stats
- * retrival, when read_status() is called, as some statistics
- * will depend on the layers detection.
- */
- return 0;
-};
-
static int mb86a20s_tune(struct dvb_frontend *fe,
bool re_tune,
unsigned int mode_flags,
@@ -2136,7 +2126,6 @@ static struct dvb_frontend_ops mb86a20s_ops = {
.init = mb86a20s_initfe,
.set_frontend = mb86a20s_set_frontend,
- .get_frontend = mb86a20s_get_frontend_dummy,
.read_status = mb86a20s_read_status_and_stats,
.read_signal_strength = mb86a20s_read_signal_strength_from_cache,
.tune = mb86a20s_tune,
diff --git a/drivers/staging/media/mn88473/mn88473.c b/drivers/media/dvb-frontends/mn88473.c
index a222e99935d2..6c5d592161d4 100644
--- a/drivers/staging/media/mn88473/mn88473.c
+++ b/drivers/media/dvb-frontends/mn88473.c
@@ -29,21 +29,17 @@ static int mn88473_set_frontend(struct dvb_frontend *fe)
struct mn88473_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
+ unsigned int uitmp;
u32 if_frequency;
- u64 tmp;
- u8 delivery_system_val, if_val[3], bw_val[7];
+ u8 delivery_system_val, if_val[3], *conf_val_ptr;
+ u8 reg_bank2_2d_val, reg_bank0_d2_val;
dev_dbg(&client->dev,
"delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n",
- c->delivery_system,
- c->modulation,
- c->frequency,
- c->bandwidth_hz,
- c->symbol_rate,
- c->inversion,
- c->stream_id);
-
- if (!dev->warm) {
+ c->delivery_system, c->modulation, c->frequency,
+ c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id);
+
+ if (!dev->active) {
ret = -EAGAIN;
goto err;
}
@@ -51,30 +47,50 @@ static int mn88473_set_frontend(struct dvb_frontend *fe)
switch (c->delivery_system) {
case SYS_DVBT:
delivery_system_val = 0x02;
+ reg_bank2_2d_val = 0x23;
+ reg_bank0_d2_val = 0x2a;
break;
case SYS_DVBT2:
delivery_system_val = 0x03;
+ reg_bank2_2d_val = 0x3b;
+ reg_bank0_d2_val = 0x29;
break;
case SYS_DVBC_ANNEX_A:
delivery_system_val = 0x04;
+ reg_bank2_2d_val = 0x3b;
+ reg_bank0_d2_val = 0x29;
break;
default:
ret = -EINVAL;
goto err;
}
- if (c->bandwidth_hz <= 6000000) {
- memcpy(bw_val, "\xe9\x55\x55\x1c\x29\x1c\x29", 7);
- } else if (c->bandwidth_hz <= 7000000) {
- memcpy(bw_val, "\xc8\x00\x00\x17\x0a\x17\x0a", 7);
- } else if (c->bandwidth_hz <= 8000000) {
- memcpy(bw_val, "\xaf\x00\x00\x11\xec\x11\xec", 7);
- } else {
- ret = -EINVAL;
- goto err;
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ conf_val_ptr = "\xe9\x55\x55\x1c\x29\x1c\x29";
+ break;
+ case 7000000:
+ conf_val_ptr = "\xc8\x00\x00\x17\x0a\x17\x0a";
+ break;
+ case 8000000:
+ conf_val_ptr = "\xaf\x00\x00\x11\xec\x11\xec";
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+ break;
+ case SYS_DVBC_ANNEX_A:
+ conf_val_ptr = "\x10\xab\x0d\xae\x1d\x9d";
+ break;
+ default:
+ break;
}
- /* program tuner */
+ /* Program tuner */
if (fe->ops.tuner_ops.set_params) {
ret = fe->ops.tuner_ops.set_params(fe);
if (ret)
@@ -86,27 +102,45 @@ static int mn88473_set_frontend(struct dvb_frontend *fe)
if (ret)
goto err;
- dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency);
+ dev_dbg(&client->dev, "get_if_frequency=%u\n", if_frequency);
} else {
- if_frequency = 0;
+ ret = -EINVAL;
+ goto err;
}
- /* Calculate IF registers ( (1<<24)*IF / Xtal ) */
- tmp = div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2),
- dev->xtal);
- if_val[0] = ((tmp >> 16) & 0xff);
- if_val[1] = ((tmp >> 8) & 0xff);
- if_val[2] = ((tmp >> 0) & 0xff);
+ /* Calculate IF registers */
+ uitmp = DIV_ROUND_CLOSEST_ULL((u64) if_frequency * 0x1000000, dev->clk);
+ if_val[0] = (uitmp >> 16) & 0xff;
+ if_val[1] = (uitmp >> 8) & 0xff;
+ if_val[2] = (uitmp >> 0) & 0xff;
ret = regmap_write(dev->regmap[2], 0x05, 0x00);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0xfb, 0x13);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0xef, 0x13);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0xf9, 0x13);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0x00, 0x18);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0x01, 0x01);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0x02, 0x21);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0x0b, 0x00);
+ if (ret)
+ goto err;
for (i = 0; i < sizeof(if_val); i++) {
ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]);
@@ -114,52 +148,85 @@ static int mn88473_set_frontend(struct dvb_frontend *fe)
goto err;
}
- for (i = 0; i < sizeof(bw_val); i++) {
- ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]);
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ for (i = 0; i < 7; i++) {
+ ret = regmap_write(dev->regmap[2], 0x13 + i,
+ conf_val_ptr[i]);
+ if (ret)
+ goto err;
+ }
+ break;
+ case SYS_DVBC_ANNEX_A:
+ ret = regmap_bulk_write(dev->regmap[1], 0x10, conf_val_ptr, 6);
if (ret)
goto err;
+ break;
+ default:
+ break;
}
- ret = regmap_write(dev->regmap[2], 0x2d, 0x3b);
+ ret = regmap_write(dev->regmap[2], 0x2d, reg_bank2_2d_val);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0x2e, 0x00);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[2], 0x56, 0x0d);
- ret = regmap_write(dev->regmap[0], 0x01, 0xba);
- ret = regmap_write(dev->regmap[0], 0x02, 0x13);
- ret = regmap_write(dev->regmap[0], 0x03, 0x80);
- ret = regmap_write(dev->regmap[0], 0x04, 0xba);
- ret = regmap_write(dev->regmap[0], 0x05, 0x91);
- ret = regmap_write(dev->regmap[0], 0x07, 0xe7);
- ret = regmap_write(dev->regmap[0], 0x08, 0x28);
+ if (ret)
+ goto err;
+ ret = regmap_bulk_write(dev->regmap[0], 0x01,
+ "\xba\x13\x80\xba\x91\xdd\xe7\x28", 8);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0x0a, 0x1a);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0x13, 0x1f);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0x19, 0x03);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0x1d, 0xb0);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0x2a, 0x72);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0x2d, 0x00);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0x3c, 0x00);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0x3f, 0xf8);
- ret = regmap_write(dev->regmap[0], 0x40, 0xf4);
- ret = regmap_write(dev->regmap[0], 0x41, 0x08);
- ret = regmap_write(dev->regmap[0], 0xd2, 0x29);
+ if (ret)
+ goto err;
+ ret = regmap_bulk_write(dev->regmap[0], 0x40, "\xf4\x08", 2);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap[0], 0xd2, reg_bank0_d2_val);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0xd4, 0x55);
- ret = regmap_write(dev->regmap[1], 0x10, 0x10);
- ret = regmap_write(dev->regmap[1], 0x11, 0xab);
- ret = regmap_write(dev->regmap[1], 0x12, 0x0d);
- ret = regmap_write(dev->regmap[1], 0x13, 0xae);
- ret = regmap_write(dev->regmap[1], 0x14, 0x1d);
- ret = regmap_write(dev->regmap[1], 0x15, 0x9d);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[1], 0xbe, 0x08);
- ret = regmap_write(dev->regmap[2], 0x09, 0x08);
- ret = regmap_write(dev->regmap[2], 0x08, 0x1d);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0xb2, 0x37);
+ if (ret)
+ goto err;
ret = regmap_write(dev->regmap[0], 0xd7, 0x04);
- ret = regmap_write(dev->regmap[2], 0x32, 0x80);
- ret = regmap_write(dev->regmap[2], 0x36, 0x00);
- ret = regmap_write(dev->regmap[2], 0xf8, 0x9f);
if (ret)
goto err;
- dev->delivery_system = c->delivery_system;
+ /* Reset FSM */
+ ret = regmap_write(dev->regmap[2], 0xf8, 0x9f);
+ if (ret)
+ goto err;
return 0;
err:
@@ -173,51 +240,61 @@ static int mn88473_read_status(struct dvb_frontend *fe, enum fe_status *status)
struct mn88473_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
- unsigned int utmp;
- int lock = 0;
-
- *status = 0;
+ unsigned int uitmp;
- if (!dev->warm) {
+ if (!dev->active) {
ret = -EAGAIN;
goto err;
}
+ *status = 0;
+
switch (c->delivery_system) {
case SYS_DVBT:
- ret = regmap_read(dev->regmap[0], 0x62, &utmp);
+ ret = regmap_read(dev->regmap[0], 0x62, &uitmp);
if (ret)
goto err;
- if (!(utmp & 0xA0)) {
- if ((utmp & 0xF) >= 0x03)
- *status |= FE_HAS_SIGNAL;
- if ((utmp & 0xF) >= 0x09)
- lock = 1;
+
+ if (!(uitmp & 0xa0)) {
+ if ((uitmp & 0x0f) >= 0x09)
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC |
+ FE_HAS_LOCK;
+ else if ((uitmp & 0x0f) >= 0x03)
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
}
break;
case SYS_DVBT2:
- ret = regmap_read(dev->regmap[2], 0x8B, &utmp);
+ ret = regmap_read(dev->regmap[2], 0x8b, &uitmp);
if (ret)
goto err;
- if (!(utmp & 0x40)) {
- if ((utmp & 0xF) >= 0x07)
- *status |= FE_HAS_SIGNAL;
- if ((utmp & 0xF) >= 0x0a)
- *status |= FE_HAS_CARRIER;
- if ((utmp & 0xF) >= 0x0d)
- *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+
+ if (!(uitmp & 0x40)) {
+ if ((uitmp & 0x0f) >= 0x0d)
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC |
+ FE_HAS_LOCK;
+ else if ((uitmp & 0x0f) >= 0x0a)
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI;
+ else if ((uitmp & 0x0f) >= 0x07)
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
}
break;
case SYS_DVBC_ANNEX_A:
- ret = regmap_read(dev->regmap[1], 0x85, &utmp);
+ ret = regmap_read(dev->regmap[1], 0x85, &uitmp);
if (ret)
goto err;
- if (!(utmp & 0x40)) {
- ret = regmap_read(dev->regmap[1], 0x89, &utmp);
+
+ if (!(uitmp & 0x40)) {
+ ret = regmap_read(dev->regmap[1], 0x89, &uitmp);
if (ret)
goto err;
- if (utmp & 0x01)
- lock = 1;
+
+ if (uitmp & 0x01)
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC |
+ FE_HAS_LOCK;
}
break;
default:
@@ -225,10 +302,6 @@ static int mn88473_read_status(struct dvb_frontend *fe, enum fe_status *status)
goto err;
}
- if (lock)
- *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
- FE_HAS_SYNC | FE_HAS_LOCK;
-
return 0;
err:
dev_dbg(&client->dev, "failed=%d\n", ret);
@@ -239,85 +312,76 @@ static int mn88473_init(struct dvb_frontend *fe)
{
struct i2c_client *client = fe->demodulator_priv;
struct mn88473_dev *dev = i2c_get_clientdata(client);
- int ret, len, remaining;
- const struct firmware *fw = NULL;
- u8 *fw_file = MN88473_FIRMWARE;
- unsigned int tmp;
+ int ret, len, remain;
+ unsigned int uitmp;
+ const struct firmware *fw;
+ const char *name = MN88473_FIRMWARE;
dev_dbg(&client->dev, "\n");
- /* set cold state by default */
- dev->warm = false;
-
- /* check if firmware is already running */
- ret = regmap_read(dev->regmap[0], 0xf5, &tmp);
+ /* Check if firmware is already running */
+ ret = regmap_read(dev->regmap[0], 0xf5, &uitmp);
if (ret)
goto err;
- if (!(tmp & 0x1)) {
- dev_info(&client->dev, "firmware already running\n");
- dev->warm = true;
- return 0;
- }
+ if (!(uitmp & 0x01))
+ goto warm;
- /* request the firmware, this will block and timeout */
- ret = request_firmware(&fw, fw_file, &client->dev);
+ /* Request the firmware, this will block and timeout */
+ ret = request_firmware(&fw, name, &client->dev);
if (ret) {
- dev_err(&client->dev, "firmare file '%s' not found\n", fw_file);
- goto err_request_firmware;
+ dev_err(&client->dev, "firmare file '%s' not found\n", name);
+ goto err;
}
- dev_info(&client->dev, "downloading firmware from file '%s'\n",
- fw_file);
+ dev_info(&client->dev, "downloading firmware from file '%s'\n", name);
ret = regmap_write(dev->regmap[0], 0xf5, 0x03);
if (ret)
- goto err;
-
- for (remaining = fw->size; remaining > 0;
- remaining -= (dev->i2c_wr_max - 1)) {
- len = remaining;
- if (len > (dev->i2c_wr_max - 1))
- len = dev->i2c_wr_max - 1;
+ goto err_release_firmware;
+ for (remain = fw->size; remain > 0; remain -= (dev->i2c_wr_max - 1)) {
+ len = min(dev->i2c_wr_max - 1, remain);
ret = regmap_bulk_write(dev->regmap[0], 0xf6,
- &fw->data[fw->size - remaining], len);
+ &fw->data[fw->size - remain], len);
if (ret) {
- dev_err(&client->dev, "firmware download failed=%d\n",
+ dev_err(&client->dev, "firmware download failed %d\n",
ret);
- goto err;
+ goto err_release_firmware;
}
}
- /* parity check of firmware */
- ret = regmap_read(dev->regmap[0], 0xf8, &tmp);
- if (ret) {
- dev_err(&client->dev,
- "parity reg read failed=%d\n", ret);
+ release_firmware(fw);
+
+ /* Parity check of firmware */
+ ret = regmap_read(dev->regmap[0], 0xf8, &uitmp);
+ if (ret)
goto err;
- }
- if (tmp & 0x10) {
- dev_err(&client->dev,
- "firmware parity check failed=0x%x\n", tmp);
+
+ if (uitmp & 0x10) {
+ dev_err(&client->dev, "firmware parity check failed\n");
+ ret = -EINVAL;
goto err;
}
- dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp);
ret = regmap_write(dev->regmap[0], 0xf5, 0x00);
if (ret)
goto err;
+warm:
+ /* TS config */
+ ret = regmap_write(dev->regmap[2], 0x09, 0x08);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap[2], 0x08, 0x1d);
+ if (ret)
+ goto err;
- release_firmware(fw);
- fw = NULL;
-
- /* warm state */
- dev->warm = true;
+ dev->active = true;
return 0;
-
-err:
+err_release_firmware:
release_firmware(fw);
-err_request_firmware:
+err:
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
@@ -330,20 +394,20 @@ static int mn88473_sleep(struct dvb_frontend *fe)
dev_dbg(&client->dev, "\n");
+ dev->active = false;
+
ret = regmap_write(dev->regmap[2], 0x05, 0x3e);
if (ret)
goto err;
- dev->delivery_system = SYS_UNDEFINED;
-
return 0;
err:
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
-static struct dvb_frontend_ops mn88473_ops = {
- .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_AC},
+static const struct dvb_frontend_ops mn88473_ops = {
+ .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
.info = {
.name = "Panasonic MN88473",
.symbol_rate_min = 1000000,
@@ -365,8 +429,7 @@ static struct dvb_frontend_ops mn88473_ops = {
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO |
FE_CAN_MUTE_TS |
- FE_CAN_2G_MODULATION |
- FE_CAN_MULTISTREAM
+ FE_CAN_2G_MODULATION
},
.get_tune_settings = mn88473_get_tune_settings,
@@ -385,7 +448,7 @@ static int mn88473_probe(struct i2c_client *client,
struct mn88473_config *config = client->dev.platform_data;
struct mn88473_dev *dev;
int ret;
- unsigned int utmp;
+ unsigned int uitmp;
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -393,7 +456,7 @@ static int mn88473_probe(struct i2c_client *client,
dev_dbg(&client->dev, "\n");
- /* Caller really need to provide pointer for frontend we create. */
+ /* Caller really need to provide pointer for frontend we create */
if (config->fe == NULL) {
dev_err(&client->dev, "frontend pointer not defined\n");
ret = -EINVAL;
@@ -406,11 +469,15 @@ static int mn88473_probe(struct i2c_client *client,
goto err;
}
- dev->i2c_wr_max = config->i2c_wr_max;
- if (!config->xtal)
- dev->xtal = 25000000;
+ if (config->i2c_wr_max)
+ dev->i2c_wr_max = config->i2c_wr_max;
else
- dev->xtal = config->xtal;
+ dev->i2c_wr_max = ~0;
+
+ if (config->xtal)
+ dev->clk = config->xtal;
+ else
+ dev->clk = 25000000;
dev->client[0] = client;
dev->regmap[0] = regmap_init_i2c(dev->client[0], &regmap_config);
if (IS_ERR(dev->regmap[0])) {
@@ -418,15 +485,25 @@ static int mn88473_probe(struct i2c_client *client,
goto err_kfree;
}
- /* check demod answers to I2C */
- ret = regmap_read(dev->regmap[0], 0x00, &utmp);
+ /* Check demod answers with correct chip id */
+ ret = regmap_read(dev->regmap[0], 0xff, &uitmp);
if (ret)
goto err_regmap_0_regmap_exit;
+ dev_dbg(&client->dev, "chip id=%02x\n", uitmp);
+
+ if (uitmp != 0x03) {
+ ret = -ENODEV;
+ goto err_regmap_0_regmap_exit;
+ }
+
/*
- * Chip has three I2C addresses for different register pages. Used
+ * Chip has three I2C addresses for different register banks. Used
* addresses are 0x18, 0x1a and 0x1c. We register two dummy clients,
- * 0x1a and 0x1c, in order to get own I2C client for each register page.
+ * 0x1a and 0x1c, in order to get own I2C client for each register bank.
+ *
+ * Also, register bank 2 do not support sequential I/O. Only single
+ * register write or read is allowed to that bank.
*/
dev->client[1] = i2c_new_dummy(client->adapter, 0x1a);
if (dev->client[1] == NULL) {
@@ -456,13 +533,19 @@ static int mn88473_probe(struct i2c_client *client,
}
i2c_set_clientdata(dev->client[2], dev);
- /* create dvb_frontend */
- memcpy(&dev->fe.ops, &mn88473_ops, sizeof(struct dvb_frontend_ops));
- dev->fe.demodulator_priv = client;
- *config->fe = &dev->fe;
+ /* Sleep because chip is active by default */
+ ret = regmap_write(dev->regmap[2], 0x05, 0x3e);
+ if (ret)
+ goto err_client_2_i2c_unregister_device;
+
+ /* Create dvb frontend */
+ memcpy(&dev->frontend.ops, &mn88473_ops, sizeof(dev->frontend.ops));
+ dev->frontend.demodulator_priv = client;
+ *config->fe = &dev->frontend;
i2c_set_clientdata(client, dev);
- dev_info(&dev->client[0]->dev, "Panasonic MN88473 successfully attached\n");
+ dev_info(&client->dev, "Panasonic MN88473 successfully identified\n");
+
return 0;
err_client_2_i2c_unregister_device:
@@ -507,7 +590,8 @@ MODULE_DEVICE_TABLE(i2c, mn88473_id_table);
static struct i2c_driver mn88473_driver = {
.driver = {
- .name = "mn88473",
+ .name = "mn88473",
+ .suppress_bind_attrs = true,
},
.probe = mn88473_probe,
.remove = mn88473_remove,
diff --git a/drivers/media/dvb-frontends/mn88473.h b/drivers/media/dvb-frontends/mn88473.h
index c717ebed0e03..2aa5181f3033 100644
--- a/drivers/media/dvb-frontends/mn88473.h
+++ b/drivers/media/dvb-frontends/mn88473.h
@@ -22,10 +22,16 @@
struct mn88473_config {
/*
* Max num of bytes given I2C adapter could write at once.
- * Default: none
+ * Default: unlimited
*/
u16 i2c_wr_max;
+ /*
+ * Xtal frequency Hz.
+ * Default: 25000000
+ */
+ u32 xtal;
+
/* Everything after that is returned by the driver. */
@@ -33,12 +39,6 @@ struct mn88473_config {
* DVB frontend.
*/
struct dvb_frontend **fe;
-
- /*
- * Xtal frequency.
- * Hz
- */
- u32 xtal;
};
#endif
diff --git a/drivers/staging/media/mn88473/mn88473_priv.h b/drivers/media/dvb-frontends/mn88473_priv.h
index 54beb4241ccf..e6c65893e451 100644
--- a/drivers/staging/media/mn88473/mn88473_priv.h
+++ b/drivers/media/dvb-frontends/mn88473_priv.h
@@ -27,11 +27,10 @@
struct mn88473_dev {
struct i2c_client *client[3];
struct regmap *regmap[3];
- struct dvb_frontend fe;
+ struct dvb_frontend frontend;
u16 i2c_wr_max;
- enum fe_delivery_system delivery_system;
- bool warm; /* FW running */
- u32 xtal;
+ bool active;
+ u32 clk;
};
#endif
diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c
index c36e6764eead..fc08429c99b7 100644
--- a/drivers/media/dvb-frontends/mt312.c
+++ b/drivers/media/dvb-frontends/mt312.c
@@ -647,9 +647,9 @@ static int mt312_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int mt312_get_frontend(struct dvb_frontend *fe)
+static int mt312_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mt312_state *state = fe->demodulator_priv;
int ret;
diff --git a/drivers/media/dvb-frontends/mt352.c b/drivers/media/dvb-frontends/mt352.c
index 123bb2f8e4b6..c0bb6328956b 100644
--- a/drivers/media/dvb-frontends/mt352.c
+++ b/drivers/media/dvb-frontends/mt352.c
@@ -311,9 +311,9 @@ static int mt352_set_parameters(struct dvb_frontend *fe)
return 0;
}
-static int mt352_get_parameters(struct dvb_frontend* fe)
+static int mt352_get_parameters(struct dvb_frontend* fe,
+ struct dtv_frontend_properties *op)
{
- struct dtv_frontend_properties *op = &fe->dtv_property_cache;
struct mt352_state* state = fe->demodulator_priv;
u16 tps;
u16 div;
diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c
index 35b1053b3640..a165af990672 100644
--- a/drivers/media/dvb-frontends/or51132.c
+++ b/drivers/media/dvb-frontends/or51132.c
@@ -375,9 +375,9 @@ static int or51132_set_parameters(struct dvb_frontend *fe)
return 0;
}
-static int or51132_get_parameters(struct dvb_frontend* fe)
+static int or51132_get_parameters(struct dvb_frontend* fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct or51132_state* state = fe->demodulator_priv;
int status;
int retry = 1;
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index b792f305cf15..3f96429af0e5 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -279,11 +279,11 @@ err:
return ret;
}
-static int rtl2830_get_frontend(struct dvb_frontend *fe)
+static int rtl2830_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct i2c_client *client = fe->demodulator_priv;
struct rtl2830_dev *dev = i2c_get_clientdata(client);
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[3];
@@ -900,6 +900,9 @@ static int rtl2830_remove(struct i2c_client *client)
dev_dbg(&client->dev, "\n");
+ /* stop statistics polling */
+ cancel_delayed_work_sync(&dev->stat_work);
+
i2c_del_mux_adapter(dev->adapter);
regmap_exit(dev->regmap);
kfree(dev);
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 10f2119935da..7c96f7679669 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -347,6 +347,10 @@ static int rtl2832_init(struct dvb_frontend *fe)
dev_dbg(&client->dev, "\n");
+ ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0);
+ if (ret)
+ goto err;
+
for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
ret = rtl2832_wr_demod_reg(dev, rtl2832_initial_regs[i].reg,
rtl2832_initial_regs[i].value);
@@ -404,8 +408,6 @@ static int rtl2832_init(struct dvb_frontend *fe)
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.len = 1;
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- /* start statistics polling */
- schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
dev->sleeping = false;
return 0;
@@ -423,8 +425,6 @@ static int rtl2832_sleep(struct dvb_frontend *fe)
dev_dbg(&client->dev, "\n");
dev->sleeping = true;
- /* stop statistics polling */
- cancel_delayed_work_sync(&dev->stat_work);
dev->fe_status = 0;
ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
@@ -491,11 +491,6 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe);
- /* PIP mode related */
- ret = rtl2832_bulk_write(client, 0x192, "\x00\x0f\xff", 3);
- if (ret)
- goto err;
-
/* If the frontend has get_if_frequency(), use it */
if (fe->ops.tuner_ops.get_if_frequency) {
u32 if_freq;
@@ -575,11 +570,11 @@ err:
return ret;
}
-static int rtl2832_get_frontend(struct dvb_frontend *fe)
+static int rtl2832_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct rtl2832_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[3];
@@ -692,8 +687,11 @@ static int rtl2832_read_status(struct dvb_frontend *fe, enum fe_status *status)
{
struct rtl2832_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u32 uninitialized_var(tmp);
+ u8 u8tmp, buf[2];
+ u16 u16tmp;
dev_dbg(&client->dev, "\n");
@@ -714,45 +712,6 @@ static int rtl2832_read_status(struct dvb_frontend *fe, enum fe_status *status)
}
dev->fe_status = *status;
- return 0;
-err:
- dev_dbg(&client->dev, "failed=%d\n", ret);
- return ret;
-}
-
-static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
- /* report SNR in resolution of 0.1 dB */
- if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
- *snr = div_s64(c->cnr.stat[0].svalue, 100);
- else
- *snr = 0;
-
- return 0;
-}
-
-static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
- struct rtl2832_dev *dev = fe->demodulator_priv;
-
- *ber = (dev->post_bit_error - dev->post_bit_error_prev);
- dev->post_bit_error_prev = dev->post_bit_error;
-
- return 0;
-}
-
-static void rtl2832_stat_work(struct work_struct *work)
-{
- struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, stat_work.work);
- struct i2c_client *client = dev->client;
- struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
- int ret, tmp;
- u8 u8tmp, buf[2];
- u16 u16tmp;
-
- dev_dbg(&client->dev, "\n");
/* signal strength */
if (dev->fe_status & FE_HAS_SIGNAL) {
@@ -789,11 +748,11 @@ static void rtl2832_stat_work(struct work_struct *work)
constellation = (u8tmp >> 2) & 0x03; /* [3:2] */
if (constellation > CONSTELLATION_NUM - 1)
- goto err_schedule_delayed_work;
+ goto err;
hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */
if (hierarchy > HIERARCHY_NUM - 1)
- goto err_schedule_delayed_work;
+ goto err;
ret = rtl2832_bulk_read(client, 0x40c, buf, 2);
if (ret)
@@ -835,11 +794,33 @@ static void rtl2832_stat_work(struct work_struct *work)
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
}
-err_schedule_delayed_work:
- schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
- return;
+ return 0;
err:
dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ /* report SNR in resolution of 0.1 dB */
+ if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
+ *snr = div_s64(c->cnr.stat[0].svalue, 100);
+ else
+ *snr = 0;
+
+ return 0;
+}
+
+static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+
+ *ber = (dev->post_bit_error - dev->post_bit_error_prev);
+ dev->post_bit_error_prev = dev->post_bit_error;
+
+ return 0;
}
/*
@@ -1081,37 +1062,46 @@ static struct i2c_adapter *rtl2832_get_i2c_adapter(struct i2c_client *client)
return dev->i2c_adapter_tuner;
}
-static int rtl2832_enable_slave_ts(struct i2c_client *client)
+static int rtl2832_slave_ts_ctrl(struct i2c_client *client, bool enable)
{
struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret;
- dev_dbg(&client->dev, "\n");
-
- ret = rtl2832_bulk_write(client, 0x10c, "\x5f\xff", 2);
- if (ret)
- goto err;
-
- ret = rtl2832_wr_demod_reg(dev, DVBT_PIP_ON, 0x1);
- if (ret)
- goto err;
+ dev_dbg(&client->dev, "enable=%d\n", enable);
- ret = rtl2832_bulk_write(client, 0x0bc, "\x18", 1);
- if (ret)
- goto err;
-
- ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3);
- if (ret)
- goto err;
-
- /* soft reset */
- ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
- if (ret)
- goto err;
-
- ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0);
- if (ret)
- goto err;
+ if (enable) {
+ ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0);
+ if (ret)
+ goto err;
+ ret = rtl2832_bulk_write(client, 0x10c, "\x5f\xff", 2);
+ if (ret)
+ goto err;
+ ret = rtl2832_wr_demod_reg(dev, DVBT_PIP_ON, 0x1);
+ if (ret)
+ goto err;
+ ret = rtl2832_bulk_write(client, 0x0bc, "\x18", 1);
+ if (ret)
+ goto err;
+ ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3);
+ if (ret)
+ goto err;
+ } else {
+ ret = rtl2832_bulk_write(client, 0x192, "\x00\x0f\xff", 3);
+ if (ret)
+ goto err;
+ ret = rtl2832_bulk_write(client, 0x0bc, "\x08", 1);
+ if (ret)
+ goto err;
+ ret = rtl2832_wr_demod_reg(dev, DVBT_PIP_ON, 0x0);
+ if (ret)
+ goto err;
+ ret = rtl2832_bulk_write(client, 0x10c, "\x00\x00", 2);
+ if (ret)
+ goto err;
+ ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
+ if (ret)
+ goto err;
+ }
return 0;
err:
@@ -1227,7 +1217,6 @@ static int rtl2832_probe(struct i2c_client *client,
dev->pdata = client->dev.platform_data;
dev->sleeping = true;
INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work);
- INIT_DELAYED_WORK(&dev->stat_work, rtl2832_stat_work);
/* create regmap */
mutex_init(&dev->regmap_mutex);
dev->regmap_config.reg_bits = 8,
@@ -1267,7 +1256,7 @@ static int rtl2832_probe(struct i2c_client *client,
/* setup callbacks */
pdata->get_dvb_frontend = rtl2832_get_dvb_frontend;
pdata->get_i2c_adapter = rtl2832_get_i2c_adapter;
- pdata->enable_slave_ts = rtl2832_enable_slave_ts;
+ pdata->slave_ts_ctrl = rtl2832_slave_ts_ctrl;
pdata->pid_filter = rtl2832_pid_filter;
pdata->pid_filter_ctrl = rtl2832_pid_filter_ctrl;
pdata->bulk_read = rtl2832_bulk_read;
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
index c29a4c2bf71a..6390af64cf45 100644
--- a/drivers/media/dvb-frontends/rtl2832.h
+++ b/drivers/media/dvb-frontends/rtl2832.h
@@ -31,7 +31,7 @@
* @tuner: Used tuner model.
* @get_dvb_frontend: Get DVB frontend.
* @get_i2c_adapter: Get I2C adapter.
- * @enable_slave_ts: Enable slave TS IF.
+ * @slave_ts_ctrl: Control slave TS interface.
* @pid_filter: Set PID to PID filter.
* @pid_filter_ctrl: Control PID filter.
*/
@@ -53,7 +53,7 @@ struct rtl2832_platform_data {
struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *);
- int (*enable_slave_ts)(struct i2c_client *);
+ int (*slave_ts_ctrl)(struct i2c_client *, bool);
int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
int (*pid_filter_ctrl)(struct dvb_frontend *, int);
/* private: Register access for SDR module use only */
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index 5dcd3a41d23f..6b875f462f8b 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -38,7 +38,6 @@ struct rtl2832_dev {
struct regmap *regmap;
struct i2c_adapter *i2c_adapter_tuner;
struct dvb_frontend fe;
- struct delayed_work stat_work;
enum fe_status fe_status;
u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */
u64 post_bit_error;
diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c
index 10964848a2f1..c68965ad97c0 100644
--- a/drivers/media/dvb-frontends/s5h1409.c
+++ b/drivers/media/dvb-frontends/s5h1409.c
@@ -925,9 +925,9 @@ static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
return s5h1409_read_ucblocks(fe, ber);
}
-static int s5h1409_get_frontend(struct dvb_frontend *fe)
+static int s5h1409_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s5h1409_state *state = fe->demodulator_priv;
p->frequency = state->current_frequency;
diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c
index 9afc3f42290e..90f86e82b087 100644
--- a/drivers/media/dvb-frontends/s5h1411.c
+++ b/drivers/media/dvb-frontends/s5h1411.c
@@ -840,9 +840,9 @@ static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber)
return s5h1411_read_ucblocks(fe, ber);
}
-static int s5h1411_get_frontend(struct dvb_frontend *fe)
+static int s5h1411_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s5h1411_state *state = fe->demodulator_priv;
p->frequency = state->current_frequency;
diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c
index 9c22a4c70d87..d7d0b7d57ad7 100644
--- a/drivers/media/dvb-frontends/s5h1420.c
+++ b/drivers/media/dvb-frontends/s5h1420.c
@@ -756,9 +756,9 @@ static int s5h1420_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int s5h1420_get_frontend(struct dvb_frontend* fe)
+static int s5h1420_get_frontend(struct dvb_frontend* fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s5h1420_state* state = fe->demodulator_priv;
p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c
index d6a8fa63040b..b5e3d90eba5e 100644
--- a/drivers/media/dvb-frontends/s921.c
+++ b/drivers/media/dvb-frontends/s921.c
@@ -433,9 +433,9 @@ static int s921_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int s921_get_frontend(struct dvb_frontend *fe)
+static int s921_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s921_state *state = fe->demodulator_priv;
/* FIXME: Probably it is possible to get it from regs f1 and f2 */
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
index 2b93241d4bc1..8bf716a8ea58 100644
--- a/drivers/media/dvb-frontends/si2165.c
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -225,22 +225,18 @@ static int si2165_writereg32(struct si2165_state *state, const u16 reg, u32 val)
static int si2165_writereg_mask8(struct si2165_state *state, const u16 reg,
u8 val, u8 mask)
{
- int ret;
- u8 tmp;
-
if (mask != 0xff) {
- ret = si2165_readreg8(state, reg, &tmp);
+ u8 tmp;
+ int ret = si2165_readreg8(state, reg, &tmp);
+
if (ret < 0)
- goto err;
+ return ret;
val &= mask;
tmp &= ~mask;
val |= tmp;
}
-
- ret = si2165_writereg8(state, reg, val);
-err:
- return ret;
+ return si2165_writereg8(state, reg, val);
}
#define REG16(reg, val) { (reg), (val) & 0xff }, { (reg)+1, (val)>>8 & 0xff }
@@ -825,19 +821,19 @@ static int si2165_set_frontend_dvbt(struct dvb_frontend *fe)
struct si2165_state *state = fe->demodulator_priv;
u32 dvb_rate = 0;
u16 bw10k;
+ u32 bw_hz = p->bandwidth_hz;
dprintk("%s: called\n", __func__);
if (!state->has_dvbt)
return -EINVAL;
- if (p->bandwidth_hz > 0) {
- dvb_rate = p->bandwidth_hz * 8 / 7;
- bw10k = p->bandwidth_hz / 10000;
- } else {
- dvb_rate = 8 * 8 / 7;
- bw10k = 800;
- }
+ /* no bandwidth auto-detection */
+ if (bw_hz == 0)
+ return -EINVAL;
+
+ dvb_rate = bw_hz * 8 / 7;
+ bw10k = bw_hz / 10000;
ret = si2165_adjust_pll_divl(state, 12);
if (ret < 0)
diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c
index 756650f154ab..3d171b0e00c2 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.c
+++ b/drivers/media/dvb-frontends/stb0899_drv.c
@@ -1568,9 +1568,9 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe)
return DVBFE_ALGO_SEARCH_ERROR;
}
-static int stb0899_get_frontend(struct dvb_frontend *fe)
+static int stb0899_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stb0899_state *state = fe->demodulator_priv;
struct stb0899_internal *internal = &state->internal;
diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c
index c978c801c7aa..b9c2511bf019 100644
--- a/drivers/media/dvb-frontends/stb6100.c
+++ b/drivers/media/dvb-frontends/stb6100.c
@@ -346,7 +346,7 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
if (fe->ops.get_frontend) {
dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
- fe->ops.get_frontend(fe);
+ fe->ops.get_frontend(fe, p);
}
srate = p->symbol_rate;
diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c
index 75b4d8b25657..81b27b7c0c96 100644
--- a/drivers/media/dvb-frontends/stv0297.c
+++ b/drivers/media/dvb-frontends/stv0297.c
@@ -615,9 +615,9 @@ timeout:
return 0;
}
-static int stv0297_get_frontend(struct dvb_frontend *fe)
+static int stv0297_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0297_state *state = fe->demodulator_priv;
int reg_00, reg_83;
diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c
index a8177807fb65..7927fa925f2f 100644
--- a/drivers/media/dvb-frontends/stv0299.c
+++ b/drivers/media/dvb-frontends/stv0299.c
@@ -422,7 +422,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long
if (debug_legacy_dish_switch)
printk ("%s switch command: 0x%04lx\n",__func__, cmd);
- nexttime = ktime_get_real();
+ nexttime = ktime_get_boottime();
if (debug_legacy_dish_switch)
tv[0] = nexttime;
stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
@@ -431,7 +431,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long
for (i=0; i<9; i++) {
if (debug_legacy_dish_switch)
- tv[i+1] = ktime_get_real();
+ tv[i+1] = ktime_get_boottime();
if((cmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */
stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50));
@@ -602,9 +602,9 @@ static int stv0299_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int stv0299_get_frontend(struct dvb_frontend *fe)
+static int stv0299_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0299_state* state = fe->demodulator_priv;
s32 derot_freq;
int invval;
diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
index 44cb73f68af6..abc379aea713 100644
--- a/drivers/media/dvb-frontends/stv0367.c
+++ b/drivers/media/dvb-frontends/stv0367.c
@@ -1938,9 +1938,9 @@ static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
return 0;
}
-static int stv0367ter_get_frontend(struct dvb_frontend *fe)
+static int stv0367ter_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0367_state *state = fe->demodulator_priv;
struct stv0367ter_state *ter_state = state->ter_state;
enum stv0367_ter_mode mode;
@@ -3146,9 +3146,9 @@ static int stv0367cab_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int stv0367cab_get_frontend(struct dvb_frontend *fe)
+static int stv0367cab_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0367_state *state = fe->demodulator_priv;
struct stv0367cab_state *cab_state = state->cab_state;
diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c
index fe31dd541955..f667005a6661 100644
--- a/drivers/media/dvb-frontends/stv0900_core.c
+++ b/drivers/media/dvb-frontends/stv0900_core.c
@@ -1087,7 +1087,7 @@ u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode,
s32 pilot, u8 chip_id)
{
u8 aclc_value = 0x29;
- s32 i;
+ s32 i, cllas2_size;
const struct stv0900_car_loop_optim *cls2, *cllqs2, *cllas2;
dprintk("%s\n", __func__);
@@ -1096,14 +1096,17 @@ u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode,
cls2 = FE_STV0900_S2CarLoop;
cllqs2 = FE_STV0900_S2LowQPCarLoopCut30;
cllas2 = FE_STV0900_S2APSKCarLoopCut30;
+ cllas2_size = ARRAY_SIZE(FE_STV0900_S2APSKCarLoopCut30);
} else if (chip_id == 0x20) {
cls2 = FE_STV0900_S2CarLoopCut20;
cllqs2 = FE_STV0900_S2LowQPCarLoopCut20;
cllas2 = FE_STV0900_S2APSKCarLoopCut20;
+ cllas2_size = ARRAY_SIZE(FE_STV0900_S2APSKCarLoopCut20);
} else {
cls2 = FE_STV0900_S2CarLoopCut30;
cllqs2 = FE_STV0900_S2LowQPCarLoopCut30;
cllas2 = FE_STV0900_S2APSKCarLoopCut30;
+ cllas2_size = ARRAY_SIZE(FE_STV0900_S2APSKCarLoopCut30);
}
if (modcode < STV0900_QPSK_12) {
@@ -1178,7 +1181,7 @@ u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode,
aclc_value = cls2[i].car_loop_pilots_off_30;
}
- } else {
+ } else if (i < cllas2_size) {
if (srate <= 3000000)
aclc_value = cllas2[i].car_loop_pilots_on_2;
else if (srate <= 7000000)
@@ -1859,9 +1862,9 @@ static int stv0900_sleep(struct dvb_frontend *fe)
return 0;
}
-static int stv0900_get_frontend(struct dvb_frontend *fe)
+static int stv0900_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0900_state *state = fe->demodulator_priv;
struct stv0900_internal *intp = state->internal;
enum fe_stv0900_demod_num demod = state->demod;
diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c
index e66154e5c1d7..a62c01e454f5 100644
--- a/drivers/media/dvb-frontends/stv6110x.c
+++ b/drivers/media/dvb-frontends/stv6110x.c
@@ -355,7 +355,7 @@ static struct dvb_tuner_ops stv6110x_ops = {
.release = stv6110x_release
};
-static struct stv6110x_devctl stv6110x_ctl = {
+static const struct stv6110x_devctl stv6110x_ctl = {
.tuner_init = stv6110x_init,
.tuner_sleep = stv6110x_sleep,
.tuner_set_mode = stv6110x_set_mode,
@@ -369,7 +369,7 @@ static struct stv6110x_devctl stv6110x_ctl = {
.tuner_get_status = stv6110x_get_status,
};
-struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c)
{
diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h
index 9f7eb251aec3..696b6e5b9e7b 100644
--- a/drivers/media/dvb-frontends/stv6110x.h
+++ b/drivers/media/dvb-frontends/stv6110x.h
@@ -55,12 +55,12 @@ struct stv6110x_devctl {
#if IS_REACHABLE(CONFIG_DVB_STV6110x)
-extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+extern const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c);
#else
-static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+static inline const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c)
{
diff --git a/drivers/media/dvb-frontends/stv6110x_priv.h b/drivers/media/dvb-frontends/stv6110x_priv.h
index 0ec936a660a7..a993aba27b7e 100644
--- a/drivers/media/dvb-frontends/stv6110x_priv.h
+++ b/drivers/media/dvb-frontends/stv6110x_priv.h
@@ -70,7 +70,7 @@ struct stv6110x_state {
const struct stv6110x_config *config;
u8 regs[8];
- struct stv6110x_devctl *devctl;
+ const struct stv6110x_devctl *devctl;
};
#endif /* __STV6110x_PRIV_H */
diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
index 456cdc7fb1e7..31cd32532387 100644
--- a/drivers/media/dvb-frontends/tc90522.c
+++ b/drivers/media/dvb-frontends/tc90522.c
@@ -201,10 +201,10 @@ static const enum fe_code_rate fec_conv_sat[] = {
FEC_2_3, /* for 8PSK. (trellis code) */
};
-static int tc90522s_get_frontend(struct dvb_frontend *fe)
+static int tc90522s_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct tc90522_state *state;
- struct dtv_frontend_properties *c;
struct dtv_fe_stats *stats;
int ret, i;
int layers;
@@ -212,7 +212,6 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe)
u32 cndat;
state = fe->demodulator_priv;
- c = &fe->dtv_property_cache;
c->delivery_system = SYS_ISDBS;
c->symbol_rate = 28860000;
@@ -337,10 +336,10 @@ static const enum fe_modulation mod_conv[] = {
DQPSK, QPSK, QAM_16, QAM_64, 0, 0, 0, 0
};
-static int tc90522t_get_frontend(struct dvb_frontend *fe)
+static int tc90522t_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct tc90522_state *state;
- struct dtv_frontend_properties *c;
struct dtv_fe_stats *stats;
int ret, i;
int layers;
@@ -348,7 +347,6 @@ static int tc90522t_get_frontend(struct dvb_frontend *fe)
u32 cndat;
state = fe->demodulator_priv;
- c = &fe->dtv_property_cache;
c->delivery_system = SYS_ISDBT;
c->bandwidth_hz = 6000000;
mode = 1;
diff --git a/drivers/media/dvb-frontends/tda10021.c b/drivers/media/dvb-frontends/tda10021.c
index a684424e665a..806c56691ca5 100644
--- a/drivers/media/dvb-frontends/tda10021.c
+++ b/drivers/media/dvb-frontends/tda10021.c
@@ -387,9 +387,9 @@ static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int tda10021_get_frontend(struct dvb_frontend *fe)
+static int tda10021_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda10021_state* state = fe->demodulator_priv;
int sync;
s8 afc = 0;
diff --git a/drivers/media/dvb-frontends/tda10023.c b/drivers/media/dvb-frontends/tda10023.c
index 44a55656093f..3b8c7e499d0d 100644
--- a/drivers/media/dvb-frontends/tda10023.c
+++ b/drivers/media/dvb-frontends/tda10023.c
@@ -457,9 +457,9 @@ static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int tda10023_get_frontend(struct dvb_frontend *fe)
+static int tda10023_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda10023_state* state = fe->demodulator_priv;
int sync,inv;
s8 afc = 0;
diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c
index 8451086c563f..c2bf89d0b0b0 100644
--- a/drivers/media/dvb-frontends/tda10048.c
+++ b/drivers/media/dvb-frontends/tda10048.c
@@ -1028,9 +1028,9 @@ static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
return 0;
}
-static int tda10048_get_frontend(struct dvb_frontend *fe)
+static int tda10048_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda10048_state *state = fe->demodulator_priv;
dprintk(1, "%s()\n", __func__);
diff --git a/drivers/media/dvb-frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c
index c6abeb4fba9d..b89848313fb9 100644
--- a/drivers/media/dvb-frontends/tda1004x.c
+++ b/drivers/media/dvb-frontends/tda1004x.c
@@ -899,9 +899,9 @@ static int tda1004x_set_fe(struct dvb_frontend *fe)
return 0;
}
-static int tda1004x_get_fe(struct dvb_frontend *fe)
+static int tda1004x_get_fe(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *fe_params)
{
- struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
struct tda1004x_state* state = fe->demodulator_priv;
int status;
diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
index 119d47596ac8..37ebeef2bbd0 100644
--- a/drivers/media/dvb-frontends/tda10071.c
+++ b/drivers/media/dvb-frontends/tda10071.c
@@ -701,11 +701,11 @@ error:
return ret;
}
-static int tda10071_get_frontend(struct dvb_frontend *fe)
+static int tda10071_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
struct tda10071_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u8 buf[5], tmp;
diff --git a/drivers/media/dvb-frontends/tda10086.c b/drivers/media/dvb-frontends/tda10086.c
index 95a33e187f8e..31d0acb54fe8 100644
--- a/drivers/media/dvb-frontends/tda10086.c
+++ b/drivers/media/dvb-frontends/tda10086.c
@@ -459,9 +459,9 @@ static int tda10086_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int tda10086_get_frontend(struct dvb_frontend *fe)
+static int tda10086_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *fe_params)
{
- struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
struct tda10086_state* state = fe->demodulator_priv;
u8 val;
int tmp;
diff --git a/drivers/media/dvb-frontends/tda8083.c b/drivers/media/dvb-frontends/tda8083.c
index 796543fa2c8d..9072d6463094 100644
--- a/drivers/media/dvb-frontends/tda8083.c
+++ b/drivers/media/dvb-frontends/tda8083.c
@@ -342,9 +342,9 @@ static int tda8083_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int tda8083_get_frontend(struct dvb_frontend *fe)
+static int tda8083_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda8083_state* state = fe->demodulator_priv;
/* FIXME: get symbolrate & frequency offset...*/
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
index 7979e5d6498b..14b410ffe612 100644
--- a/drivers/media/dvb-frontends/ts2020.c
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -712,6 +712,10 @@ static int ts2020_remove(struct i2c_client *client)
dev_dbg(&client->dev, "\n");
+ /* stop statistics polling */
+ if (!dev->dont_poll)
+ cancel_delayed_work_sync(&dev->stat_work);
+
regmap_exit(dev->regmap);
kfree(dev);
return 0;
diff --git a/drivers/media/dvb-frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c
index aacfdda3e005..b09fe88c40f8 100644
--- a/drivers/media/dvb-frontends/ves1820.c
+++ b/drivers/media/dvb-frontends/ves1820.c
@@ -312,9 +312,9 @@ static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int ves1820_get_frontend(struct dvb_frontend *fe)
+static int ves1820_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ves1820_state* state = fe->demodulator_priv;
int sync;
s8 afc = 0;
diff --git a/drivers/media/dvb-frontends/ves1x93.c b/drivers/media/dvb-frontends/ves1x93.c
index 526952396422..ed113e216e14 100644
--- a/drivers/media/dvb-frontends/ves1x93.c
+++ b/drivers/media/dvb-frontends/ves1x93.c
@@ -406,9 +406,9 @@ static int ves1x93_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int ves1x93_get_frontend(struct dvb_frontend *fe)
+static int ves1x93_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ves1x93_state* state = fe->demodulator_priv;
int afc;
diff --git a/drivers/media/dvb-frontends/zl10353.c b/drivers/media/dvb-frontends/zl10353.c
index ef9764a02d4c..1832c2f7695c 100644
--- a/drivers/media/dvb-frontends/zl10353.c
+++ b/drivers/media/dvb-frontends/zl10353.c
@@ -371,9 +371,9 @@ static int zl10353_set_parameters(struct dvb_frontend *fe)
return 0;
}
-static int zl10353_get_parameters(struct dvb_frontend *fe)
+static int zl10353_get_parameters(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct zl10353_state *state = fe->demodulator_priv;
int s6, s9;
u16 tps;
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
index 7e9cbf757e95..fb7ed730d932 100644
--- a/drivers/media/i2c/adp1653.c
+++ b/drivers/media/i2c/adp1653.c
@@ -497,7 +497,7 @@ static int adp1653_probe(struct i2c_client *client,
if (!client->dev.platform_data) {
dev_err(&client->dev,
"Neither DT not platform data provided\n");
- return EINVAL;
+ return -EINVAL;
}
flash->platform_data = client->dev.platform_data;
}
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 471fd23b5c5c..bd822f032b08 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -103,12 +103,14 @@ struct adv7511_state {
u32 ycbcr_enc;
u32 quantization;
u32 xfer_func;
+ u32 content_type;
/* controls */
struct v4l2_ctrl *hdmi_mode_ctrl;
struct v4l2_ctrl *hotplug_ctrl;
struct v4l2_ctrl *rx_sense_ctrl;
struct v4l2_ctrl *have_edid0_ctrl;
struct v4l2_ctrl *rgb_quantization_range_ctrl;
+ struct v4l2_ctrl *content_type_ctrl;
struct i2c_client *i2c_edid;
struct i2c_client *i2c_pktmem;
struct adv7511_state_edid edid;
@@ -400,6 +402,16 @@ static int adv7511_s_ctrl(struct v4l2_ctrl *ctrl)
}
if (state->rgb_quantization_range_ctrl == ctrl)
return adv7511_set_rgb_quantization_mode(sd, ctrl);
+ if (state->content_type_ctrl == ctrl) {
+ u8 itc, cn;
+
+ state->content_type = ctrl->val;
+ itc = state->content_type != V4L2_DV_IT_CONTENT_TYPE_NO_ITC;
+ cn = itc ? state->content_type : V4L2_DV_IT_CONTENT_TYPE_GRAPHICS;
+ adv7511_wr_and_or(sd, 0x57, 0x7f, itc << 7);
+ adv7511_wr_and_or(sd, 0x59, 0xcf, cn << 4);
+ return 0;
+ }
return -EINVAL;
}
@@ -1002,6 +1014,8 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
u8 y = HDMI_COLORSPACE_RGB;
u8 q = HDMI_QUANTIZATION_RANGE_DEFAULT;
u8 yq = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
+ u8 itc = state->content_type != V4L2_DV_IT_CONTENT_TYPE_NO_ITC;
+ u8 cn = itc ? state->content_type : V4L2_DV_IT_CONTENT_TYPE_GRAPHICS;
if (format->pad != 0)
return -EINVAL;
@@ -1115,8 +1129,8 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
adv7511_wr_and_or(sd, 0x4a, 0xbf, 0);
adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5);
adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6);
- adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2));
- adv7511_wr_and_or(sd, 0x59, 0x3f, yq << 6);
+ adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7));
+ adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4));
adv7511_wr_and_or(sd, 0x4a, 0xff, 1);
return 0;
@@ -1161,12 +1175,23 @@ static void adv7511_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, in
}
}
+static void adv7511_notify_no_edid(struct v4l2_subdev *sd)
+{
+ struct adv7511_state *state = get_adv7511_state(sd);
+ struct adv7511_edid_detect ed;
+
+ /* We failed to read the EDID, so send an event for this. */
+ ed.present = false;
+ ed.segment = adv7511_rd(sd, 0xc4);
+ v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
+ v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0);
+}
+
static void adv7511_edid_handler(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct adv7511_state *state = container_of(dwork, struct adv7511_state, edid_handler);
struct v4l2_subdev *sd = &state->sd;
- struct adv7511_edid_detect ed;
v4l2_dbg(1, debug, sd, "%s:\n", __func__);
@@ -1191,9 +1216,7 @@ static void adv7511_edid_handler(struct work_struct *work)
}
/* We failed to read the EDID, so send an event for this. */
- ed.present = false;
- ed.segment = adv7511_rd(sd, 0xc4);
- v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
+ adv7511_notify_no_edid(sd);
v4l2_dbg(1, debug, sd, "%s: no edid found\n", __func__);
}
@@ -1264,7 +1287,6 @@ static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd)
/* update read only ctrls */
v4l2_ctrl_s_ctrl(state->hotplug_ctrl, adv7511_have_hotplug(sd) ? 0x1 : 0x0);
v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, adv7511_have_rx_sense(sd) ? 0x1 : 0x0);
- v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0);
if ((status & MASK_ADV7511_HPD_DETECT) && ((status & MASK_ADV7511_MSEN_DETECT) || state->edid.segments)) {
v4l2_dbg(1, debug, sd, "%s: hotplug and (rx-sense or edid)\n", __func__);
@@ -1294,6 +1316,7 @@ static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd)
}
adv7511_s_power(sd, false);
memset(&state->edid, 0, sizeof(struct adv7511_state_edid));
+ adv7511_notify_no_edid(sd);
}
}
@@ -1370,6 +1393,7 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
}
/* one more segment read ok */
state->edid.segments = segment + 1;
+ v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x1);
if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) {
/* Request next EDID segment */
v4l2_dbg(1, debug, sd, "%s: request segment %d\n", __func__, state->edid.segments);
@@ -1389,7 +1413,6 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
ed.present = true;
ed.segment = 0;
state->edid_detect_counter++;
- v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0);
v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
return ed.present;
}
@@ -1470,6 +1493,10 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops,
V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
0, V4L2_DV_RGB_RANGE_AUTO);
+ state->content_type_ctrl =
+ v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops,
+ V4L2_CID_DV_TX_IT_CONTENT_TYPE, V4L2_DV_IT_CONTENT_TYPE_NO_ITC,
+ 0, V4L2_DV_IT_CONTENT_TYPE_NO_ITC);
sd->ctrl_handler = hdl;
if (hdl->error) {
err = hdl->error;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index f8dd7505b529..41a1bfc5eaa7 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -207,71 +207,22 @@ static bool adv76xx_has_afe(struct adv76xx_state *state)
return state->info->has_afe;
}
-/* Supported CEA and DMT timings */
-static const struct v4l2_dv_timings adv76xx_timings[] = {
- V4L2_DV_BT_CEA_720X480P59_94,
- V4L2_DV_BT_CEA_720X576P50,
- V4L2_DV_BT_CEA_1280X720P24,
- V4L2_DV_BT_CEA_1280X720P25,
- V4L2_DV_BT_CEA_1280X720P50,
- V4L2_DV_BT_CEA_1280X720P60,
- V4L2_DV_BT_CEA_1920X1080P24,
- V4L2_DV_BT_CEA_1920X1080P25,
- V4L2_DV_BT_CEA_1920X1080P30,
- V4L2_DV_BT_CEA_1920X1080P50,
- V4L2_DV_BT_CEA_1920X1080P60,
-
- /* sorted by DMT ID */
- V4L2_DV_BT_DMT_640X350P85,
- V4L2_DV_BT_DMT_640X400P85,
- V4L2_DV_BT_DMT_720X400P85,
- V4L2_DV_BT_DMT_640X480P60,
- V4L2_DV_BT_DMT_640X480P72,
- V4L2_DV_BT_DMT_640X480P75,
- V4L2_DV_BT_DMT_640X480P85,
- V4L2_DV_BT_DMT_800X600P56,
- V4L2_DV_BT_DMT_800X600P60,
- V4L2_DV_BT_DMT_800X600P72,
- V4L2_DV_BT_DMT_800X600P75,
- V4L2_DV_BT_DMT_800X600P85,
- V4L2_DV_BT_DMT_848X480P60,
- V4L2_DV_BT_DMT_1024X768P60,
- V4L2_DV_BT_DMT_1024X768P70,
- V4L2_DV_BT_DMT_1024X768P75,
- V4L2_DV_BT_DMT_1024X768P85,
- V4L2_DV_BT_DMT_1152X864P75,
- V4L2_DV_BT_DMT_1280X768P60_RB,
- V4L2_DV_BT_DMT_1280X768P60,
- V4L2_DV_BT_DMT_1280X768P75,
- V4L2_DV_BT_DMT_1280X768P85,
- V4L2_DV_BT_DMT_1280X800P60_RB,
- V4L2_DV_BT_DMT_1280X800P60,
- V4L2_DV_BT_DMT_1280X800P75,
- V4L2_DV_BT_DMT_1280X800P85,
- V4L2_DV_BT_DMT_1280X960P60,
- V4L2_DV_BT_DMT_1280X960P85,
- V4L2_DV_BT_DMT_1280X1024P60,
- V4L2_DV_BT_DMT_1280X1024P75,
- V4L2_DV_BT_DMT_1280X1024P85,
- V4L2_DV_BT_DMT_1360X768P60,
- V4L2_DV_BT_DMT_1400X1050P60_RB,
- V4L2_DV_BT_DMT_1400X1050P60,
- V4L2_DV_BT_DMT_1400X1050P75,
- V4L2_DV_BT_DMT_1400X1050P85,
- V4L2_DV_BT_DMT_1440X900P60_RB,
- V4L2_DV_BT_DMT_1440X900P60,
- V4L2_DV_BT_DMT_1600X1200P60,
- V4L2_DV_BT_DMT_1680X1050P60_RB,
- V4L2_DV_BT_DMT_1680X1050P60,
- V4L2_DV_BT_DMT_1792X1344P60,
- V4L2_DV_BT_DMT_1856X1392P60,
- V4L2_DV_BT_DMT_1920X1200P60_RB,
- V4L2_DV_BT_DMT_1366X768P60_RB,
- V4L2_DV_BT_DMT_1366X768P60,
- V4L2_DV_BT_DMT_1920X1080P60,
- { },
+/* Unsupported timings. This device cannot support 720p30. */
+static const struct v4l2_dv_timings adv76xx_timings_exceptions[] = {
+ V4L2_DV_BT_CEA_1280X720P30,
+ { }
};
+static bool adv76xx_check_dv_timings(const struct v4l2_dv_timings *t, void *hdl)
+{
+ int i;
+
+ for (i = 0; adv76xx_timings_exceptions[i].bt.width; i++)
+ if (v4l2_match_dv_timings(t, adv76xx_timings_exceptions + i, 0, false))
+ return false;
+ return true;
+}
+
struct adv76xx_video_standards {
struct v4l2_dv_timings timings;
u8 vid_std;
@@ -806,6 +757,36 @@ static inline bool is_digital_input(struct v4l2_subdev *sd)
state->selected_input == ADV7604_PAD_HDMI_PORT_D;
}
+static const struct v4l2_dv_timings_cap adv7604_timings_cap_analog = {
+ .type = V4L2_DV_BT_656_1120,
+ /* keep this initialization for compatibility with GCC < 4.4.6 */
+ .reserved = { 0 },
+ V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
+ V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+ V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
+ V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
+ V4L2_DV_BT_CAP_CUSTOM)
+};
+
+static const struct v4l2_dv_timings_cap adv76xx_timings_cap_digital = {
+ .type = V4L2_DV_BT_656_1120,
+ /* keep this initialization for compatibility with GCC < 4.4.6 */
+ .reserved = { 0 },
+ V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000,
+ V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+ V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
+ V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
+ V4L2_DV_BT_CAP_CUSTOM)
+};
+
+static inline const struct v4l2_dv_timings_cap *
+adv76xx_get_dv_timings_cap(struct v4l2_subdev *sd)
+{
+ return is_digital_input(sd) ? &adv76xx_timings_cap_digital :
+ &adv7604_timings_cap_analog;
+}
+
+
/* ----------------------------------------------------------------------- */
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1216,6 +1197,20 @@ static int adv76xx_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
+static int adv76xx_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd =
+ &container_of(ctrl->handler, struct adv76xx_state, hdl)->sd;
+
+ if (ctrl->id == V4L2_CID_DV_RX_IT_CONTENT_TYPE) {
+ ctrl->val = V4L2_DV_IT_CONTENT_TYPE_NO_ITC;
+ if ((io_read(sd, 0x60) & 1) && (infoframe_read(sd, 0x03) & 0x80))
+ ctrl->val = (infoframe_read(sd, 0x05) >> 4) & 3;
+ return 0;
+ }
+ return -EINVAL;
+}
+
/* ----------------------------------------------------------------------- */
static inline bool no_power(struct v4l2_subdev *sd)
@@ -1330,17 +1325,23 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
u32 pix_clk;
int i;
- for (i = 0; adv76xx_timings[i].bt.height; i++) {
- if (vtotal(&adv76xx_timings[i].bt) != stdi->lcf + 1)
+ for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
+ const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;
+
+ if (!v4l2_valid_dv_timings(&v4l2_dv_timings_presets[i],
+ adv76xx_get_dv_timings_cap(sd),
+ adv76xx_check_dv_timings, NULL))
+ continue;
+ if (vtotal(bt) != stdi->lcf + 1)
continue;
- if (adv76xx_timings[i].bt.vsync != stdi->lcvs)
+ if (bt->vsync != stdi->lcvs)
continue;
- pix_clk = hfreq * htotal(&adv76xx_timings[i].bt);
+ pix_clk = hfreq * htotal(bt);
- if ((pix_clk < adv76xx_timings[i].bt.pixelclock + 1000000) &&
- (pix_clk > adv76xx_timings[i].bt.pixelclock - 1000000)) {
- *timings = adv76xx_timings[i];
+ if ((pix_clk < bt->pixelclock + 1000000) &&
+ (pix_clk > bt->pixelclock - 1000000)) {
+ *timings = v4l2_dv_timings_presets[i];
return 0;
}
}
@@ -1425,15 +1426,11 @@ static int adv76xx_enum_dv_timings(struct v4l2_subdev *sd,
{
struct adv76xx_state *state = to_state(sd);
- if (timings->index >= ARRAY_SIZE(adv76xx_timings) - 1)
- return -EINVAL;
-
if (timings->pad >= state->source_pad)
return -EINVAL;
- memset(timings->reserved, 0, sizeof(timings->reserved));
- timings->timings = adv76xx_timings[timings->index];
- return 0;
+ return v4l2_enum_dv_timings_cap(timings,
+ adv76xx_get_dv_timings_cap(sd), adv76xx_check_dv_timings, NULL);
}
static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd,
@@ -1444,29 +1441,7 @@ static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd,
if (cap->pad >= state->source_pad)
return -EINVAL;
- cap->type = V4L2_DV_BT_656_1120;
- cap->bt.max_width = 1920;
- cap->bt.max_height = 1200;
- cap->bt.min_pixelclock = 25000000;
-
- switch (cap->pad) {
- case ADV76XX_PAD_HDMI_PORT_A:
- case ADV7604_PAD_HDMI_PORT_B:
- case ADV7604_PAD_HDMI_PORT_C:
- case ADV7604_PAD_HDMI_PORT_D:
- cap->bt.max_pixelclock = 225000000;
- break;
- case ADV7604_PAD_VGA_RGB:
- case ADV7604_PAD_VGA_COMP:
- default:
- cap->bt.max_pixelclock = 170000000;
- break;
- }
-
- cap->bt.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
- V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT;
- cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
- V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM;
+ *cap = *adv76xx_get_dv_timings_cap(sd);
return 0;
}
@@ -1475,15 +1450,9 @@ static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd,
static void adv76xx_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings)
{
- int i;
-
- for (i = 0; adv76xx_timings[i].bt.width; i++) {
- if (v4l2_match_dv_timings(timings, &adv76xx_timings[i],
- is_digital_input(sd) ? 250000 : 1000000, false)) {
- *timings = adv76xx_timings[i];
- break;
- }
- }
+ v4l2_find_dv_timings_cap(timings, adv76xx_get_dv_timings_cap(sd),
+ is_digital_input(sd) ? 250000 : 1000000,
+ adv76xx_check_dv_timings, NULL);
}
static unsigned int adv7604_read_hdmi_pixelclock(struct v4l2_subdev *sd)
@@ -1651,12 +1620,9 @@ static int adv76xx_s_dv_timings(struct v4l2_subdev *sd,
bt = &timings->bt;
- if ((is_analog_input(sd) && bt->pixelclock > 170000000) ||
- (is_digital_input(sd) && bt->pixelclock > 225000000)) {
- v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n",
- __func__, (u32)bt->pixelclock);
+ if (!v4l2_valid_dv_timings(timings, adv76xx_get_dv_timings_cap(sd),
+ adv76xx_check_dv_timings, NULL))
return -ERANGE;
- }
adv76xx_fill_optional_dv_timings_fields(sd, timings);
@@ -1884,6 +1850,26 @@ static int adv76xx_get_format(struct v4l2_subdev *sd,
return 0;
}
+static int adv76xx_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct adv76xx_state *state = to_state(sd);
+
+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+ /* Only CROP, CROP_DEFAULT and CROP_BOUNDS are supported */
+ if (sel->target > V4L2_SEL_TGT_CROP_BOUNDS)
+ return -EINVAL;
+
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = state->timings.bt.width;
+ sel->r.height = state->timings.bt.height;
+
+ return 0;
+}
+
static int adv76xx_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
@@ -1960,10 +1946,9 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
}
/* tx 5v detect */
- tx_5v = io_read(sd, 0x70) & info->cable_det_mask;
+ tx_5v = irq_reg_0x70 & info->cable_det_mask;
if (tx_5v) {
v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v);
- io_write(sd, 0x71, tx_5v);
adv76xx_s_detect_tx_5v_ctrl(sd);
if (handled)
*handled = true;
@@ -2110,7 +2095,8 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
rep_write(sd, 0x76, spa_loc & 0xff);
rep_write_clr_set(sd, 0x77, 0x40, (spa_loc & 0x100) >> 2);
} else {
- /* FIXME: Where is the SPA location LSB register ? */
+ /* ADV7612 Software Manual Rev. A, p. 15 */
+ rep_write(sd, 0x70, spa_loc & 0xff);
rep_write_clr_set(sd, 0x71, 0x01, (spa_loc & 0x100) >> 8);
}
@@ -2381,6 +2367,7 @@ static int adv76xx_subscribe_event(struct v4l2_subdev *sd,
static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = {
.s_ctrl = adv76xx_s_ctrl,
+ .g_volatile_ctrl = adv76xx_g_volatile_ctrl,
};
static const struct v4l2_subdev_core_ops adv76xx_core_ops = {
@@ -2404,6 +2391,7 @@ static const struct v4l2_subdev_video_ops adv76xx_video_ops = {
static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = {
.enum_mbus_code = adv76xx_enum_mbus_code,
+ .get_selection = adv76xx_get_selection,
.get_fmt = adv76xx_get_format,
.set_fmt = adv76xx_set_format,
.get_edid = adv76xx_get_edid,
@@ -2799,6 +2787,7 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
struct device_node *endpoint;
struct device_node *np;
unsigned int flags;
+ int ret;
u32 v;
np = state->i2c_clients[ADV76XX_PAGE_IO]->dev.of_node;
@@ -2808,7 +2797,11 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
if (!endpoint)
return -EINVAL;
- v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+ ret = v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+ if (ret) {
+ of_node_put(endpoint);
+ return ret;
+ }
if (!of_property_read_u32(endpoint, "default-input", &v))
state->pdata.default_input = v;
@@ -3010,6 +3003,7 @@ static int adv76xx_probe(struct i2c_client *client,
V4L2_DV_BT_CEA_640X480P59_94;
struct adv76xx_state *state;
struct v4l2_ctrl_handler *hdl;
+ struct v4l2_ctrl *ctrl;
struct v4l2_subdev *sd;
unsigned int i;
unsigned int val, val2;
@@ -3141,6 +3135,11 @@ static int adv76xx_probe(struct i2c_client *client,
V4L2_CID_SATURATION, 0, 255, 1, 128);
v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops,
V4L2_CID_HUE, 0, 128, 1, 0);
+ ctrl = v4l2_ctrl_new_std_menu(hdl, &adv76xx_ctrl_ops,
+ V4L2_CID_DV_RX_IT_CONTENT_TYPE, V4L2_DV_IT_CONTENT_TYPE_NO_ITC,
+ 0, V4L2_DV_IT_CONTENT_TYPE_NO_ITC);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
/* private controls */
state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 5fbb788e7b59..7ccb85d45224 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -1359,6 +1359,19 @@ static int adv7842_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
+static int adv7842_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+
+ if (ctrl->id == V4L2_CID_DV_RX_IT_CONTENT_TYPE) {
+ ctrl->val = V4L2_DV_IT_CONTENT_TYPE_NO_ITC;
+ if ((io_read(sd, 0x60) & 1) && (infoframe_read(sd, 0x03) & 0x80))
+ ctrl->val = (infoframe_read(sd, 0x05) >> 4) & 3;
+ return 0;
+ }
+ return -EINVAL;
+}
+
static inline bool no_power(struct v4l2_subdev *sd)
{
return io_read(sd, 0x0c) & 0x24;
@@ -3022,6 +3035,7 @@ static int adv7842_subscribe_event(struct v4l2_subdev *sd,
static const struct v4l2_ctrl_ops adv7842_ctrl_ops = {
.s_ctrl = adv7842_s_ctrl,
+ .g_volatile_ctrl = adv7842_g_volatile_ctrl,
};
static const struct v4l2_subdev_core_ops adv7842_core_ops = {
@@ -3196,6 +3210,7 @@ static int adv7842_probe(struct i2c_client *client,
V4L2_DV_BT_CEA_640X480P59_94;
struct adv7842_platform_data *pdata = client->dev.platform_data;
struct v4l2_ctrl_handler *hdl;
+ struct v4l2_ctrl *ctrl;
struct v4l2_subdev *sd;
u16 rev;
int err;
@@ -3261,6 +3276,11 @@ static int adv7842_probe(struct i2c_client *client,
V4L2_CID_SATURATION, 0, 255, 1, 128);
v4l2_ctrl_new_std(hdl, &adv7842_ctrl_ops,
V4L2_CID_HUE, 0, 128, 1, 0);
+ ctrl = v4l2_ctrl_new_std_menu(hdl, &adv7842_ctrl_ops,
+ V4L2_CID_DV_RX_IT_CONTENT_TYPE, V4L2_DV_IT_CONTENT_TYPE_NO_ITC,
+ 0, V4L2_DV_IT_CONTENT_TYPE_NO_ITC);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
/* custom controls */
state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index a84561d0d4a8..e016626ebf89 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -688,6 +688,9 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
int msp_revision;
int msp_product, msp_prod_hi, msp_prod_lo;
int msp_rom;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ int ret;
+#endif
if (!id)
strlcpy(client->name, "msp3400", sizeof(client->name));
@@ -704,6 +707,17 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &msp_ops);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ state->pads[IF_AUD_DEC_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->pads[IF_AUD_DEC_PAD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+
+ sd->entity.function = MEDIA_ENT_F_IF_AUD_DECODER;
+
+ ret = media_entity_pads_init(&sd->entity, 2, state->pads);
+ if (ret < 0)
+ return ret;
+#endif
+
state->v4l2_std = V4L2_STD_NTSC;
state->detected_std = V4L2_STD_ALL;
state->audmode = V4L2_TUNER_MODE_STEREO;
diff --git a/drivers/media/i2c/msp3400-driver.h b/drivers/media/i2c/msp3400-driver.h
index 6cae21366ed5..a8702aca187a 100644
--- a/drivers/media/i2c/msp3400-driver.h
+++ b/drivers/media/i2c/msp3400-driver.h
@@ -7,6 +7,7 @@
#include <media/drv-intf/msp3400.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-mc.h>
/* ---------------------------------------------------------------------- */
@@ -102,6 +103,10 @@ struct msp_state {
wait_queue_head_t wq;
unsigned int restart:1;
unsigned int watch_stereo:1;
+
+#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER)
+ struct media_pad pads[IF_AUD_DEC_PAD_NUM_PADS];
+#endif
};
static inline struct msp_state *to_state(struct v4l2_subdev *sd)
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index b9fea11d6b0b..9ed1b26b6549 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -50,6 +50,9 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
struct mt9v011 {
struct v4l2_subdev sd;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_pad pad;
+#endif
struct v4l2_ctrl_handler ctrls;
unsigned width, height;
unsigned xtal;
@@ -493,6 +496,9 @@ static int mt9v011_probe(struct i2c_client *c,
u16 version;
struct mt9v011 *core;
struct v4l2_subdev *sd;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ int ret;
+#endif
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(c->adapter,
@@ -506,6 +512,15 @@ static int mt9v011_probe(struct i2c_client *c,
sd = &core->sd;
v4l2_i2c_subdev_init(sd, c, &mt9v011_ops);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ core->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ ret = media_entity_pads_init(&sd->entity, 1, &core->pad);
+ if (ret < 0)
+ return ret;
+#endif
+
/* Check if the sensor is really a MT9V011 */
version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
if ((version != MT9V011_VERSION) &&
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 2e1d116a64e7..501b37039449 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -14,6 +14,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/log2.h>
#include <linux/mutex.h>
@@ -251,6 +252,8 @@ struct mt9v032 {
struct regmap *regmap;
struct clk *clk;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *standby_gpio;
struct mt9v032_platform_data *pdata;
const struct mt9v032_model_info *model;
@@ -312,16 +315,31 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
struct regmap *map = mt9v032->regmap;
int ret;
+ if (mt9v032->reset_gpio)
+ gpiod_set_value_cansleep(mt9v032->reset_gpio, 1);
+
ret = clk_set_rate(mt9v032->clk, mt9v032->sysclk);
if (ret < 0)
return ret;
+ /* System clock has to be enabled before releasing the reset */
ret = clk_prepare_enable(mt9v032->clk);
if (ret)
return ret;
udelay(1);
+ if (mt9v032->reset_gpio) {
+ gpiod_set_value_cansleep(mt9v032->reset_gpio, 0);
+
+ /* After releasing reset we need to wait 10 clock cycles
+ * before accessing the sensor over I2C. As the minimum SYSCLK
+ * frequency is 13MHz, waiting 1µs will be enough in the worst
+ * case.
+ */
+ udelay(1);
+ }
+
/* Reset the chip and stop data read out */
ret = regmap_write(map, MT9V032_RESET, 1);
if (ret < 0)
@@ -954,6 +972,16 @@ static int mt9v032_probe(struct i2c_client *client,
if (IS_ERR(mt9v032->clk))
return PTR_ERR(mt9v032->clk);
+ mt9v032->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(mt9v032->reset_gpio))
+ return PTR_ERR(mt9v032->reset_gpio);
+
+ mt9v032->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(mt9v032->standby_gpio))
+ return PTR_ERR(mt9v032->standby_gpio);
+
mutex_init(&mt9v032->power_lock);
mt9v032->pdata = pdata;
mt9v032->model = (const void *)did->driver_data;
diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c
index 02b9a3440557..1f999e9c0118 100644
--- a/drivers/media/i2c/ov2659.c
+++ b/drivers/media/i2c/ov2659.c
@@ -1321,10 +1321,6 @@ static int ov2659_detect(struct v4l2_subdev *sd)
}
usleep_range(1000, 2000);
- ret = ov2659_init(sd, 0);
- if (ret < 0)
- return ret;
-
/* Check sensor revision */
ret = ov2659_read(client, REG_SC_CHIP_ID_H, &pid);
if (!ret)
@@ -1338,8 +1334,10 @@ static int ov2659_detect(struct v4l2_subdev *sd)
dev_err(&client->dev,
"Sensor detection failed (%04X, %d)\n",
id, ret);
- else
+ else {
dev_info(&client->dev, "Found OV%04X sensor\n", id);
+ ret = ov2659_init(sd, 0);
+ }
}
return ret;
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index a0b3c9bde53d..be5a7fd4f076 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -1046,8 +1046,8 @@ static int ov965x_initialize_controls(struct ov965x *ov965x)
ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
- v4l2_ctrl_auto_cluster(3, &ctrls->auto_gain, 0, true);
- v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 1, true);
+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
v4l2_ctrl_cluster(2, &ctrls->hflip);
ov965x->sd.ctrl_handler = hdl;
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 57b3d27993a4..08af58fb8e7d 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -1639,8 +1639,10 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state)
return 0;
}
- v4l2_of_parse_endpoint(node_ep, &ep);
+ ret = v4l2_of_parse_endpoint(node_ep, &ep);
of_node_put(node_ep);
+ if (ret)
+ return ret;
if (ep.bus_type != V4L2_MBUS_CSI2) {
dev_err(dev, "unsupported bus type\n");
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
index 7d65b36434b1..72ef9f936e6c 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
@@ -37,7 +37,6 @@ enum spi_direction {
SPI_DIR_RX,
SPI_DIR_TX
};
-MODULE_DEVICE_TABLE(of, s5c73m3_spi_ids);
static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len,
enum spi_direction dir)
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index fc3a5a8e6c9c..db82ed05792e 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -1868,8 +1868,11 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev)
return -EINVAL;
}
- v4l2_of_parse_endpoint(node_ep, &ep);
+ ret = v4l2_of_parse_endpoint(node_ep, &ep);
of_node_put(node_ep);
+ if (ret)
+ return ret;
+
state->bus_type = ep.bus_type;
switch (state->bus_type) {
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index 24d2b76dbe97..d2a1ce2bc7f5 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -46,6 +46,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-mc.h>
#include <media/i2c/saa7115.h>
#include <asm/div64.h>
@@ -74,6 +75,9 @@ enum saa711x_model {
struct saa711x_state {
struct v4l2_subdev sd;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_pad pads[DEMOD_NUM_PADS];
+#endif
struct v4l2_ctrl_handler hdl;
struct {
@@ -1809,6 +1813,9 @@ static int saa711x_probe(struct i2c_client *client,
struct saa7115_platform_data *pdata;
int ident;
char name[CHIP_VER_SIZE + 1];
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ int ret;
+#endif
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -1832,6 +1839,18 @@ static int saa711x_probe(struct i2c_client *client,
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ state->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
+
+ sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
+
+ ret = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, state->pads);
+ if (ret < 0)
+ return ret;
+#endif
+
v4l_info(client, "%s found @ 0x%x (%s)\n", name,
client->addr << 1, client->adapter->name);
hdl = &state->hdl;
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
index 2e14e52ba2e0..69becc358659 100644
--- a/drivers/media/i2c/soc_camera/mt9m001.c
+++ b/drivers/media/i2c/soc_camera/mt9m001.c
@@ -632,7 +632,7 @@ static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
.s_mbus_config = mt9m001_s_mbus_config,
};
-static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
+static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
.g_skip_top_lines = mt9m001_g_skip_top_lines,
};
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c
index 3b6eeed2e2b9..5c8e3ffe3b27 100644
--- a/drivers/media/i2c/soc_camera/mt9t031.c
+++ b/drivers/media/i2c/soc_camera/mt9t031.c
@@ -728,7 +728,7 @@ static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
.s_mbus_config = mt9t031_s_mbus_config,
};
-static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = {
+static const struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = {
.g_skip_top_lines = mt9t031_g_skip_top_lines,
};
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index c2ba1fb3694d..2721e583bfa0 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -860,7 +860,7 @@ static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
.s_mbus_config = mt9v022_s_mbus_config,
};
-static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
+static const struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
.g_skip_top_lines = mt9v022_g_skip_top_lines,
};
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 3397eb99c67b..972e0d47259d 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -59,8 +59,7 @@ MODULE_LICENSE("GPL");
#define EDID_NUM_BLOCKS_MAX 8
#define EDID_BLOCK_SIZE 128
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE (EDID_NUM_BLOCKS_MAX * EDID_BLOCK_SIZE + 2)
+#define I2C_MAX_XFER_SIZE (EDID_BLOCK_SIZE + 2)
static const struct v4l2_dv_timings_cap tc358743_timings_cap = {
.type = V4L2_DV_BT_656_1120,
@@ -97,9 +96,6 @@ struct tc358743_state {
/* edid */
u8 edid_blocks_written;
- /* used by i2c_wr() */
- u8 wr_data[MAX_XFER_SIZE];
-
struct v4l2_dv_timings timings;
u32 mbus_fmt_code;
@@ -149,13 +145,15 @@ static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
{
struct tc358743_state *state = to_state(sd);
struct i2c_client *client = state->i2c_client;
- u8 *data = state->wr_data;
int err, i;
struct i2c_msg msg;
+ u8 data[I2C_MAX_XFER_SIZE];
- if ((2 + n) > sizeof(state->wr_data))
+ if ((2 + n) > I2C_MAX_XFER_SIZE) {
+ n = I2C_MAX_XFER_SIZE - 2;
v4l2_warn(sd, "i2c wr reg=%04x: len=%d is too big!\n",
reg, 2 + n);
+ }
msg.addr = client->addr;
msg.buf = data;
@@ -859,15 +857,16 @@ static void tc358743_format_change(struct v4l2_subdev *sd)
if (tc358743_get_detected_timings(sd, &timings)) {
enable_stream(sd, false);
- v4l2_dbg(1, debug, sd, "%s: Format changed. No signal\n",
+ v4l2_dbg(1, debug, sd, "%s: No signal\n",
__func__);
} else {
if (!v4l2_match_dv_timings(&state->timings, &timings, 0, false))
enable_stream(sd, false);
- v4l2_print_dv_timings(sd->name,
- "tc358743_format_change: Format changed. New format: ",
- &timings, false);
+ if (debug)
+ v4l2_print_dv_timings(sd->name,
+ "tc358743_format_change: New format: ",
+ &timings, false);
}
if (sd->devnode)
@@ -1199,21 +1198,21 @@ static int tc358743_log_status(struct v4l2_subdev *sd)
#ifdef CONFIG_VIDEO_ADV_DEBUG
static void tc358743_print_register_map(struct v4l2_subdev *sd)
{
- v4l2_info(sd, "0x0000–0x00FF: Global Control Register\n");
- v4l2_info(sd, "0x0100–0x01FF: CSI2-TX PHY Register\n");
- v4l2_info(sd, "0x0200–0x03FF: CSI2-TX PPI Register\n");
- v4l2_info(sd, "0x0400–0x05FF: Reserved\n");
- v4l2_info(sd, "0x0600–0x06FF: CEC Register\n");
- v4l2_info(sd, "0x0700–0x84FF: Reserved\n");
- v4l2_info(sd, "0x8500–0x85FF: HDMIRX System Control Register\n");
- v4l2_info(sd, "0x8600–0x86FF: HDMIRX Audio Control Register\n");
- v4l2_info(sd, "0x8700–0x87FF: HDMIRX InfoFrame packet data Register\n");
- v4l2_info(sd, "0x8800–0x88FF: HDMIRX HDCP Port Register\n");
- v4l2_info(sd, "0x8900–0x89FF: HDMIRX Video Output Port & 3D Register\n");
- v4l2_info(sd, "0x8A00–0x8BFF: Reserved\n");
- v4l2_info(sd, "0x8C00–0x8FFF: HDMIRX EDID-RAM (1024bytes)\n");
- v4l2_info(sd, "0x9000–0x90FF: HDMIRX GBD Extraction Control\n");
- v4l2_info(sd, "0x9100–0x92FF: HDMIRX GBD RAM read\n");
+ v4l2_info(sd, "0x0000-0x00FF: Global Control Register\n");
+ v4l2_info(sd, "0x0100-0x01FF: CSI2-TX PHY Register\n");
+ v4l2_info(sd, "0x0200-0x03FF: CSI2-TX PPI Register\n");
+ v4l2_info(sd, "0x0400-0x05FF: Reserved\n");
+ v4l2_info(sd, "0x0600-0x06FF: CEC Register\n");
+ v4l2_info(sd, "0x0700-0x84FF: Reserved\n");
+ v4l2_info(sd, "0x8500-0x85FF: HDMIRX System Control Register\n");
+ v4l2_info(sd, "0x8600-0x86FF: HDMIRX Audio Control Register\n");
+ v4l2_info(sd, "0x8700-0x87FF: HDMIRX InfoFrame packet data Register\n");
+ v4l2_info(sd, "0x8800-0x88FF: HDMIRX HDCP Port Register\n");
+ v4l2_info(sd, "0x8900-0x89FF: HDMIRX Video Output Port & 3D Register\n");
+ v4l2_info(sd, "0x8A00-0x8BFF: Reserved\n");
+ v4l2_info(sd, "0x8C00-0x8FFF: HDMIRX EDID-RAM (1024bytes)\n");
+ v4l2_info(sd, "0x9000-0x90FF: HDMIRX GBD Extraction Control\n");
+ v4l2_info(sd, "0x9100-0x92FF: HDMIRX GBD RAM read\n");
v4l2_info(sd, "0x9300- : Reserved\n");
}
@@ -1581,6 +1580,7 @@ static int tc358743_s_edid(struct v4l2_subdev *sd,
{
struct tc358743_state *state = to_state(sd);
u16 edid_len = edid->blocks * EDID_BLOCK_SIZE;
+ int i;
v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n",
__func__, edid->pad, edid->start_block, edid->blocks);
@@ -1606,7 +1606,8 @@ static int tc358743_s_edid(struct v4l2_subdev *sd,
return 0;
}
- i2c_wr(sd, EDID_RAM, edid->edid, edid_len);
+ for (i = 0; i < edid_len; i += EDID_BLOCK_SIZE)
+ i2c_wr(sd, EDID_RAM + i, edid->edid + i, EDID_BLOCK_SIZE);
state->edid_blocks_written = edid->blocks;
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index 7fa5f1e4fe37..7cdd94842938 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -1001,7 +1001,7 @@ static struct tvp514x_decoder tvp514x_dev = {
static struct tvp514x_platform_data *
tvp514x_get_pdata(struct i2c_client *client)
{
- struct tvp514x_platform_data *pdata;
+ struct tvp514x_platform_data *pdata = NULL;
struct v4l2_of_endpoint bus_cfg;
struct device_node *endpoint;
unsigned int flags;
@@ -1013,11 +1013,13 @@ tvp514x_get_pdata(struct i2c_client *client)
if (!endpoint)
return NULL;
+ if (v4l2_of_parse_endpoint(endpoint, &bus_cfg))
+ goto done;
+
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
goto done;
- v4l2_of_parse_endpoint(endpoint, &bus_cfg);
flags = bus_cfg.bus.parallel.flags;
if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 6c3769d44b75..ff18444e19e4 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1,19 +1,22 @@
/*
- * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver
+ * tvp5150 - Texas Instruments TVP5150A/AM1 and TVP5151 video decoder driver
*
* Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
* This code is placed under the terms of the GNU General Public License v2
*/
+#include <dt-bindings/media/tvp5150.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
-#include <media/i2c/tvp5150.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-mc.h>
#include "tvp5150_reg.h"
@@ -24,7 +27,7 @@
#define TVP5150_MAX_CROP_TOP 127
#define TVP5150_CROP_SHIFT 2
-MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
+MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
@@ -35,6 +38,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
struct tvp5150 {
struct v4l2_subdev sd;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_pad pads[DEMOD_NUM_PADS];
+ struct media_entity input_ent[TVP5150_INPUT_NUM];
+ struct media_pad input_pad[TVP5150_INPUT_NUM];
+#endif
struct v4l2_ctrl_handler hdl;
struct v4l2_rect rect;
@@ -42,6 +50,11 @@ struct tvp5150 {
u32 input;
u32 output;
int enable;
+
+ u16 dev_id;
+ u16 rom_ver;
+
+ enum v4l2_mbus_type mbus_type;
};
static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
@@ -246,8 +259,12 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd)
int input = 0;
int val;
- if ((decoder->output & TVP5150_BLACK_SCREEN) || !decoder->enable)
- input = 8;
+ /* Only tvp5150am1 and tvp5151 have signal generator support */
+ if ((decoder->dev_id == 0x5150 && decoder->rom_ver == 0x0400) ||
+ (decoder->dev_id == 0x5151 && decoder->rom_ver == 0x0100)) {
+ if (!decoder->enable)
+ input = 8;
+ }
switch (decoder->input) {
case TVP5150_COMPOSITE1:
@@ -772,12 +789,17 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
v4l2_ctrl_handler_setup(&decoder->hdl);
tvp5150_set_std(sd, decoder->norm);
+
+ if (decoder->mbus_type == V4L2_MBUS_PARALLEL)
+ tvp5150_write(sd, TVP5150_DATA_RATE_SEL, 0x40);
+
return 0;
};
static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_sd(ctrl);
+ struct tvp5150 *decoder = to_tvp5150(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -791,6 +813,9 @@ static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
case V4L2_CID_HUE:
tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val);
+ case V4L2_CID_TEST_PATTERN:
+ decoder->enable = ctrl->val ? false : true;
+ tvp5150_selmux(sd);
return 0;
}
return -EINVAL;
@@ -818,17 +843,6 @@ static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
}
}
-static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->pad || code->index)
- return -EINVAL;
-
- code->code = MEDIA_BUS_FMT_UYVY8_2X8;
- return 0;
-}
-
static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
@@ -844,10 +858,10 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
tvp5150_reset(sd, 0);
f->width = decoder->rect.width;
- f->height = decoder->rect.height;
+ f->height = decoder->rect.height / 2;
f->code = MEDIA_BUS_FMT_UYVY8_2X8;
- f->field = V4L2_FIELD_SEQ_TB;
+ f->field = V4L2_FIELD_ALTERNATE;
f->colorspace = V4L2_COLORSPACE_SMPTE170M;
v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width,
@@ -948,10 +962,110 @@ static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
return 0;
}
+static int tvp5150_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+
+ cfg->type = decoder->mbus_type;
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING
+ | V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH;
+
+ return 0;
+}
+
+/****************************************************************************
+ V4L2 subdev pad ops
+ ****************************************************************************/
+static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->pad || code->index)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ return 0;
+}
+
+static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+
+ if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
+ return -EINVAL;
+
+ fse->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fse->min_width = decoder->rect.width;
+ fse->max_width = decoder->rect.width;
+ fse->min_height = decoder->rect.height / 2;
+ fse->max_height = decoder->rect.height / 2;
+
+ return 0;
+}
+
+/****************************************************************************
+ Media entity ops
+ ****************************************************************************/
+
+static int tvp5150_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ int i;
+
+ for (i = 0; i < TVP5150_INPUT_NUM; i++) {
+ if (remote->entity == &decoder->input_ent[i])
+ break;
+ }
+
+ /* Do nothing for entities that are not input connectors */
+ if (i == TVP5150_INPUT_NUM)
+ return 0;
+
+ decoder->input = i;
+
+ tvp5150_selmux(sd);
+#endif
+
+ return 0;
+}
+
+static const struct media_entity_operations tvp5150_sd_media_ops = {
+ .link_setup = tvp5150_link_setup,
+};
+
/****************************************************************************
I2C Command
****************************************************************************/
+static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ /* Output format: 8-bit ITU-R BT.656 with embedded syncs */
+ int val = 0x09;
+
+ /* Output format: 8-bit 4:2:2 YUV with discrete sync */
+ if (decoder->mbus_type == V4L2_MBUS_PARALLEL)
+ val = 0x0d;
+
+ /* Initializes TVP5150 to its default values */
+ /* # set PCLK (27MHz) */
+ tvp5150_write(sd, TVP5150_CONF_SHARED_PIN, 0x00);
+
+ if (enable)
+ tvp5150_write(sd, TVP5150_MISC_CTL, val);
+ else
+ tvp5150_write(sd, TVP5150_MISC_CTL, 0x00);
+
+ return 0;
+}
+
static int tvp5150_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
@@ -959,6 +1073,12 @@ static int tvp5150_s_routing(struct v4l2_subdev *sd,
decoder->input = input;
decoder->output = output;
+
+ if (output == TVP5150_BLACK_SCREEN)
+ decoder->enable = false;
+ else
+ decoder->enable = true;
+
tvp5150_selmux(sd);
return 0;
}
@@ -1052,6 +1172,42 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
+static int tvp5150_registered_async(struct v4l2_subdev *sd)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < TVP5150_INPUT_NUM; i++) {
+ struct media_entity *input = &decoder->input_ent[i];
+ struct media_pad *pad = &decoder->input_pad[i];
+
+ if (!input->name)
+ continue;
+
+ decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(input, 1, pad);
+ if (ret < 0)
+ return ret;
+
+ ret = media_device_register_entity(sd->v4l2_dev->mdev, input);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(input, 0, &sd->entity,
+ DEMOD_PAD_IF_INPUT, 0);
+ if (ret < 0) {
+ media_device_unregister_entity(input);
+ return ret;
+ }
+ }
+#endif
+
+ return 0;
+}
+
/* ----------------------------------------------------------------------- */
static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
@@ -1065,6 +1221,7 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
.g_register = tvp5150_g_register,
.s_register = tvp5150_s_register,
#endif
+ .registered_async = tvp5150_registered_async,
};
static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
@@ -1073,10 +1230,12 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
.s_std = tvp5150_s_std,
+ .s_stream = tvp5150_s_stream,
.s_routing = tvp5150_s_routing,
.s_crop = tvp5150_s_crop,
.g_crop = tvp5150_g_crop,
.cropcap = tvp5150_cropcap,
+ .g_mbus_config = tvp5150_g_mbus_config,
};
static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
@@ -1088,6 +1247,7 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
.enum_mbus_code = tvp5150_enum_mbus_code,
+ .enum_frame_size = tvp5150_enum_frame_size,
.set_fmt = tvp5150_fill_fmt,
.get_fmt = tvp5150_fill_fmt,
};
@@ -1105,63 +1265,239 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
I2C Client & Driver
****************************************************************************/
+static int tvp5150_detect_version(struct tvp5150 *core)
+{
+ struct v4l2_subdev *sd = &core->sd;
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
+ unsigned int i;
+ u8 regs[4];
+ int res;
+
+ /*
+ * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
+ * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER
+ */
+ for (i = 0; i < 4; i++) {
+ res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i);
+ if (res < 0)
+ return res;
+ regs[i] = res;
+ }
+
+ core->dev_id = (regs[0] << 8) | regs[1];
+ core->rom_ver = (regs[2] << 8) | regs[3];
+
+ v4l2_info(sd, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n",
+ core->dev_id, regs[2], regs[3], c->addr << 1,
+ c->adapter->name);
+
+ if (core->dev_id == 0x5150 && core->rom_ver == 0x0321) {
+ v4l2_info(sd, "tvp5150a detected.\n");
+ } else if (core->dev_id == 0x5150 && core->rom_ver == 0x0400) {
+ v4l2_info(sd, "tvp5150am1 detected.\n");
+
+ /* ITU-T BT.656.4 timing */
+ tvp5150_write(sd, TVP5150_REV_SELECT, 0);
+ } else if (core->dev_id == 0x5151 && core->rom_ver == 0x0100) {
+ v4l2_info(sd, "tvp5151 detected.\n");
+ } else {
+ v4l2_info(sd, "*** unknown tvp%04x chip detected.\n",
+ core->dev_id);
+ }
+
+ return 0;
+}
+
+static int tvp5150_init(struct i2c_client *c)
+{
+ struct gpio_desc *pdn_gpio;
+ struct gpio_desc *reset_gpio;
+
+ pdn_gpio = devm_gpiod_get_optional(&c->dev, "pdn", GPIOD_OUT_HIGH);
+ if (IS_ERR(pdn_gpio))
+ return PTR_ERR(pdn_gpio);
+
+ if (pdn_gpio) {
+ gpiod_set_value_cansleep(pdn_gpio, 0);
+ /* Delay time between power supplies active and reset */
+ msleep(20);
+ }
+
+ reset_gpio = devm_gpiod_get_optional(&c->dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpio))
+ return PTR_ERR(reset_gpio);
+
+ if (reset_gpio) {
+ /* RESETB pulse duration */
+ ndelay(500);
+ gpiod_set_value_cansleep(reset_gpio, 0);
+ /* Delay time between end of reset to I2C active */
+ usleep_range(200, 250);
+ }
+
+ return 0;
+}
+
+static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
+{
+ struct v4l2_of_endpoint bus_cfg;
+ struct device_node *ep;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct device_node *connectors, *child;
+ struct media_entity *input;
+ const char *name;
+ u32 input_type;
+#endif
+ unsigned int flags;
+ int ret = 0;
+
+ ep = of_graph_get_next_endpoint(np, NULL);
+ if (!ep)
+ return -EINVAL;
+
+ ret = v4l2_of_parse_endpoint(ep, &bus_cfg);
+ if (ret)
+ goto err;
+
+ flags = bus_cfg.bus.parallel.flags;
+
+ if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
+ !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
+ flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
+ flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ decoder->mbus_type = bus_cfg.bus_type;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ connectors = of_get_child_by_name(np, "connectors");
+
+ if (!connectors)
+ goto err;
+
+ for_each_available_child_of_node(connectors, child) {
+ ret = of_property_read_u32(child, "input", &input_type);
+ if (ret) {
+ v4l2_err(&decoder->sd,
+ "missing type property in node %s\n",
+ child->name);
+ goto err_connector;
+ }
+
+ if (input_type >= TVP5150_INPUT_NUM) {
+ ret = -EINVAL;
+ goto err_connector;
+ }
+
+ input = &decoder->input_ent[input_type];
+
+ /* Each input connector can only be defined once */
+ if (input->name) {
+ v4l2_err(&decoder->sd,
+ "input %s with same type already exists\n",
+ input->name);
+ ret = -EINVAL;
+ goto err_connector;
+ }
+
+ switch (input_type) {
+ case TVP5150_COMPOSITE0:
+ case TVP5150_COMPOSITE1:
+ input->function = MEDIA_ENT_F_CONN_COMPOSITE;
+ break;
+ case TVP5150_SVIDEO:
+ input->function = MEDIA_ENT_F_CONN_SVIDEO;
+ break;
+ }
+
+ input->flags = MEDIA_ENT_FL_CONNECTOR;
+
+ ret = of_property_read_string(child, "label", &name);
+ if (ret < 0) {
+ v4l2_err(&decoder->sd,
+ "missing label property in node %s\n",
+ child->name);
+ goto err_connector;
+ }
+
+ input->name = name;
+ }
+
+err_connector:
+ of_node_put(connectors);
+#endif
+err:
+ of_node_put(ep);
+ return ret;
+}
+
+static const char * const tvp5150_test_patterns[2] = {
+ "Disabled",
+ "Black screen"
+};
+
static int tvp5150_probe(struct i2c_client *c,
const struct i2c_device_id *id)
{
struct tvp5150 *core;
struct v4l2_subdev *sd;
- int tvp5150_id[4];
- int i, res;
+ struct device_node *np = c->dev.of_node;
+ int res;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(c->adapter,
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EIO;
+ res = tvp5150_init(c);
+ if (res)
+ return res;
+
core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL);
if (!core)
return -ENOMEM;
+
sd = &core->sd;
- v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
- /*
- * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
- * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER
- */
- for (i = 0; i < 4; i++) {
- res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i);
- if (res < 0)
+ if (IS_ENABLED(CONFIG_OF) && np) {
+ res = tvp5150_parse_dt(core, np);
+ if (res) {
+ v4l2_err(sd, "DT parsing error: %d\n", res);
return res;
- tvp5150_id[i] = res;
+ }
+ } else {
+ /* Default to BT.656 embedded sync */
+ core->mbus_type = V4L2_MBUS_BT656;
}
- v4l_info(c, "chip found @ 0x%02x (%s)\n",
- c->addr << 1, c->adapter->name);
+ v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- if (tvp5150_id[2] == 4 && tvp5150_id[3] == 0) { /* Is TVP5150AM1 */
- v4l2_info(sd, "tvp%02x%02xam1 detected.\n",
- tvp5150_id[0], tvp5150_id[1]);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ core->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ core->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ core->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
- /* ITU-T BT.656.4 timing */
- tvp5150_write(sd, TVP5150_REV_SELECT, 0);
- } else {
- /* Is TVP5150A */
- if (tvp5150_id[2] == 3 || tvp5150_id[3] == 0x21) {
- v4l2_info(sd, "tvp%02x%02xa detected.\n",
- tvp5150_id[0], tvp5150_id[1]);
- } else {
- v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
- tvp5150_id[0], tvp5150_id[1]);
- v4l2_info(sd, "*** Rom ver is %d.%d\n",
- tvp5150_id[2], tvp5150_id[3]);
- }
- }
+ sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
+
+ res = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, core->pads);
+ if (res < 0)
+ return res;
+
+ sd->entity.ops = &tvp5150_sd_media_ops;
+#endif
+
+ res = tvp5150_detect_version(core);
+ if (res < 0)
+ return res;
core->norm = V4L2_STD_ALL; /* Default is autodetect */
core->input = TVP5150_COMPOSITE1;
- core->enable = 1;
+ core->enable = true;
- v4l2_ctrl_handler_init(&core->hdl, 4);
+ v4l2_ctrl_handler_init(&core->hdl, 5);
v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
@@ -1170,6 +1506,13 @@ static int tvp5150_probe(struct i2c_client *c,
V4L2_CID_SATURATION, 0, 255, 1, 128);
v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
V4L2_CID_HUE, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, 27000000,
+ 27000000, 1, 27000000);
+ v4l2_ctrl_new_std_menu_items(&core->hdl, &tvp5150_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(tvp5150_test_patterns),
+ 0, 0, tvp5150_test_patterns);
sd->ctrl_handler = &core->hdl;
if (core->hdl.error) {
res = core->hdl.error;
@@ -1221,8 +1564,17 @@ static const struct i2c_device_id tvp5150_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tvp5150_id);
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tvp5150_of_match[] = {
+ { .compatible = "ti,tvp5150", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, tvp5150_of_match);
+#endif
+
static struct i2c_driver tvp5150_driver = {
.driver = {
+ .of_match_table = of_match_ptr(tvp5150_of_match),
.name = "tvp5150",
},
.probe = tvp5150_probe,
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index 83c79fa5f61d..4df640c3aa40 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -894,7 +894,7 @@ static struct tvp7002_config *
tvp7002_get_pdata(struct i2c_client *client)
{
struct v4l2_of_endpoint bus_cfg;
- struct tvp7002_config *pdata;
+ struct tvp7002_config *pdata = NULL;
struct device_node *endpoint;
unsigned int flags;
@@ -905,11 +905,13 @@ tvp7002_get_pdata(struct i2c_client *client)
if (!endpoint)
return NULL;
+ if (v4l2_of_parse_endpoint(endpoint, &bus_cfg))
+ goto done;
+
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
goto done;
- v4l2_of_parse_endpoint(endpoint, &bus_cfg);
flags = bus_cfg.bus.parallel.flags;
if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
diff --git a/drivers/media/i2c/vpx3220.c b/drivers/media/i2c/vpx3220.c
index 4b564f17f618..90b693f4e2ab 100644
--- a/drivers/media/i2c/vpx3220.c
+++ b/drivers/media/i2c/vpx3220.c
@@ -124,7 +124,7 @@ static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
return 0;
}
-static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
+static int vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
s16 data;
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 7dae0ac0f3ae..6e43c95629ea 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -20,6 +20,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/* We need to access legacy defines from linux/media.h */
+#define __NEED_MEDIA_LEGACY_API
+
#include <linux/compat.h>
#include <linux/export.h>
#include <linux/idr.h>
@@ -27,6 +30,8 @@
#include <linux/media.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/usb.h>
#include <media/media-device.h>
#include <media/media-devnode.h>
@@ -38,6 +43,11 @@
* Userspace API
*/
+static inline void __user *media_get_uptr(__u64 arg)
+{
+ return (void __user *)(uintptr_t)arg;
+}
+
static int media_device_open(struct file *filp)
{
return 0;
@@ -55,7 +65,11 @@ static int media_device_get_info(struct media_device *dev,
memset(&info, 0, sizeof(info));
- strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver));
+ if (dev->driver_name[0])
+ strlcpy(info.driver, dev->driver_name, sizeof(info.driver));
+ else
+ strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver));
+
strlcpy(info.model, dev->model, sizeof(info.model));
strlcpy(info.serial, dev->serial, sizeof(info.serial));
strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info));
@@ -115,6 +129,26 @@ static long media_device_enum_entities(struct media_device *mdev,
u_ent.group_id = 0; /* Unused */
u_ent.pads = ent->num_pads;
u_ent.links = ent->num_links - ent->num_backlinks;
+
+ /*
+ * Workaround for a bug at media-ctl <= v1.10 that makes it to
+ * do the wrong thing if the entity function doesn't belong to
+ * either MEDIA_ENT_F_OLD_BASE or MEDIA_ENT_F_OLD_SUBDEV_BASE
+ * Ranges.
+ *
+ * Non-subdevices are expected to be at the MEDIA_ENT_F_OLD_BASE,
+ * or, otherwise, will be silently ignored by media-ctl when
+ * printing the graphviz diagram. So, map them into the devnode
+ * old range.
+ */
+ if (ent->function < MEDIA_ENT_F_OLD_BASE ||
+ ent->function > MEDIA_ENT_T_DEVNODE_UNKNOWN) {
+ if (is_media_entity_v4l2_subdev(ent))
+ u_ent.type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ else if (ent->function != MEDIA_ENT_F_IO_V4L)
+ u_ent.type = MEDIA_ENT_T_DEVNODE_UNKNOWN;
+ }
+
memcpy(&u_ent.raw, &ent->info, sizeof(ent->info));
if (copy_to_user(uent, &u_ent, sizeof(u_ent)))
return -EFAULT;
@@ -234,7 +268,6 @@ static long media_device_setup_link(struct media_device *mdev,
return ret;
}
-#if 0 /* Let's postpone it to Kernel 4.6 */
static long __media_device_get_topology(struct media_device *mdev,
struct media_v2_topology *topo)
{
@@ -242,10 +275,10 @@ static long __media_device_get_topology(struct media_device *mdev,
struct media_interface *intf;
struct media_pad *pad;
struct media_link *link;
- struct media_v2_entity kentity, *uentity;
- struct media_v2_interface kintf, *uintf;
- struct media_v2_pad kpad, *upad;
- struct media_v2_link klink, *ulink;
+ struct media_v2_entity kentity, __user *uentity;
+ struct media_v2_interface kintf, __user *uintf;
+ struct media_v2_pad kpad, __user *upad;
+ struct media_v2_link klink, __user *ulink;
unsigned int i;
int ret = 0;
@@ -390,7 +423,6 @@ static long media_device_get_topology(struct media_device *mdev,
return 0;
}
-#endif
static long media_device_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
@@ -424,14 +456,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
mutex_unlock(&dev->graph_mutex);
break;
-#if 0 /* Let's postpone it to Kernel 4.6 */
case MEDIA_IOC_G_TOPOLOGY:
mutex_lock(&dev->graph_mutex);
ret = media_device_get_topology(dev,
(struct media_v2_topology __user *)arg);
mutex_unlock(&dev->graph_mutex);
break;
-#endif
+
default:
ret = -ENOIOCTLCMD;
}
@@ -480,9 +511,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
case MEDIA_IOC_DEVICE_INFO:
case MEDIA_IOC_ENUM_ENTITIES:
case MEDIA_IOC_SETUP_LINK:
-#if 0 /* Let's postpone it to Kernel 4.6 */
case MEDIA_IOC_G_TOPOLOGY:
-#endif
return media_device_ioctl(filp, cmd, arg);
case MEDIA_IOC_ENUM_LINKS32:
@@ -541,6 +570,7 @@ static void media_device_release(struct media_devnode *mdev)
int __must_check media_device_register_entity(struct media_device *mdev,
struct media_entity *entity)
{
+ struct media_entity_notify *notify, *next;
unsigned int i;
int ret;
@@ -580,8 +610,33 @@ int __must_check media_device_register_entity(struct media_device *mdev,
media_gobj_create(mdev, MEDIA_GRAPH_PAD,
&entity->pads[i].graph_obj);
+ /* invoke entity_notify callbacks */
+ list_for_each_entry_safe(notify, next, &mdev->entity_notify, list) {
+ (notify)->notify(entity, notify->notify_data);
+ }
+
spin_unlock(&mdev->lock);
+ mutex_lock(&mdev->graph_mutex);
+ if (mdev->entity_internal_idx_max
+ >= mdev->pm_count_walk.ent_enum.idx_max) {
+ struct media_entity_graph new = { .top = 0 };
+
+ /*
+ * Initialise the new graph walk before cleaning up
+ * the old one in order not to spoil the graph walk
+ * object of the media device if graph walk init fails.
+ */
+ ret = media_entity_graph_walk_init(&new, mdev);
+ if (ret) {
+ mutex_unlock(&mdev->graph_mutex);
+ return ret;
+ }
+ media_entity_graph_walk_cleanup(&mdev->pm_count_walk);
+ mdev->pm_count_walk = new;
+ }
+ mutex_unlock(&mdev->graph_mutex);
+
return 0;
}
EXPORT_SYMBOL_GPL(media_device_register_entity);
@@ -613,6 +668,8 @@ static void __media_device_unregister_entity(struct media_entity *entity)
/* Remove the entity */
media_gobj_destroy(&entity->graph_obj);
+ /* invoke entity_notify callbacks to handle entity removal?? */
+
entity->graph_obj.mdev = NULL;
}
@@ -645,6 +702,7 @@ void media_device_init(struct media_device *mdev)
INIT_LIST_HEAD(&mdev->interfaces);
INIT_LIST_HEAD(&mdev->pads);
INIT_LIST_HEAD(&mdev->links);
+ INIT_LIST_HEAD(&mdev->entity_notify);
spin_lock_init(&mdev->lock);
mutex_init(&mdev->graph_mutex);
ida_init(&mdev->entity_internal_idx);
@@ -657,6 +715,7 @@ void media_device_cleanup(struct media_device *mdev)
{
ida_destroy(&mdev->entity_internal_idx);
mdev->entity_internal_idx_max = 0;
+ media_entity_graph_walk_cleanup(&mdev->pm_count_walk);
mutex_destroy(&mdev->graph_mutex);
}
EXPORT_SYMBOL_GPL(media_device_cleanup);
@@ -690,11 +749,40 @@ int __must_check __media_device_register(struct media_device *mdev,
}
EXPORT_SYMBOL_GPL(__media_device_register);
+int __must_check media_device_register_entity_notify(struct media_device *mdev,
+ struct media_entity_notify *nptr)
+{
+ spin_lock(&mdev->lock);
+ list_add_tail(&nptr->list, &mdev->entity_notify);
+ spin_unlock(&mdev->lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(media_device_register_entity_notify);
+
+/*
+ * Note: Should be called with mdev->lock held.
+ */
+static void __media_device_unregister_entity_notify(struct media_device *mdev,
+ struct media_entity_notify *nptr)
+{
+ list_del(&nptr->list);
+}
+
+void media_device_unregister_entity_notify(struct media_device *mdev,
+ struct media_entity_notify *nptr)
+{
+ spin_lock(&mdev->lock);
+ __media_device_unregister_entity_notify(mdev, nptr);
+ spin_unlock(&mdev->lock);
+}
+EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify);
+
void media_device_unregister(struct media_device *mdev)
{
struct media_entity *entity;
struct media_entity *next;
struct media_interface *intf, *tmp_intf;
+ struct media_entity_notify *notify, *nextp;
if (mdev == NULL)
return;
@@ -711,6 +799,10 @@ void media_device_unregister(struct media_device *mdev)
list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list)
__media_device_unregister_entity(entity);
+ /* Remove all entity_notify callbacks from the media device */
+ list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list)
+ __media_device_unregister_entity_notify(mdev, notify);
+
/* Remove all interfaces from the media device */
list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces,
graph_obj.list) {
@@ -754,4 +846,58 @@ struct media_device *media_device_find_devres(struct device *dev)
}
EXPORT_SYMBOL_GPL(media_device_find_devres);
+void media_device_pci_init(struct media_device *mdev,
+ struct pci_dev *pci_dev,
+ const char *name)
+{
+#ifdef CONFIG_PCI
+ mdev->dev = &pci_dev->dev;
+
+ if (name)
+ strlcpy(mdev->model, name, sizeof(mdev->model));
+ else
+ strlcpy(mdev->model, pci_name(pci_dev), sizeof(mdev->model));
+
+ sprintf(mdev->bus_info, "PCI:%s", pci_name(pci_dev));
+
+ mdev->hw_revision = (pci_dev->subsystem_vendor << 16)
+ | pci_dev->subsystem_device;
+
+ mdev->driver_version = LINUX_VERSION_CODE;
+
+ media_device_init(mdev);
+#endif
+}
+EXPORT_SYMBOL_GPL(media_device_pci_init);
+
+void __media_device_usb_init(struct media_device *mdev,
+ struct usb_device *udev,
+ const char *board_name,
+ const char *driver_name)
+{
+#ifdef CONFIG_USB
+ mdev->dev = &udev->dev;
+
+ if (driver_name)
+ strlcpy(mdev->driver_name, driver_name,
+ sizeof(mdev->driver_name));
+
+ if (board_name)
+ strlcpy(mdev->model, board_name, sizeof(mdev->model));
+ else if (udev->product)
+ strlcpy(mdev->model, udev->product, sizeof(mdev->model));
+ else
+ strlcpy(mdev->model, "unknown model", sizeof(mdev->model));
+ if (udev->serial)
+ strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
+ usb_make_path(udev, mdev->bus_info, sizeof(mdev->bus_info));
+ mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+ mdev->driver_version = LINUX_VERSION_CODE;
+
+ media_device_init(mdev);
+#endif
+}
+EXPORT_SYMBOL_GPL(__media_device_usb_init);
+
+
#endif /* CONFIG_MEDIA_CONTROLLER */
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index cea35bf20011..29409f440f1c 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -181,6 +181,7 @@ static int media_open(struct inode *inode, struct file *filp)
ret = mdev->fops->open(filp);
if (ret) {
put_device(&mdev->dev);
+ filp->private_data = NULL;
return ret;
}
}
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index e89d85a7d31b..e95070b3a3d4 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -46,25 +46,41 @@ static inline const char *intf_type(struct media_interface *intf)
{
switch (intf->type) {
case MEDIA_INTF_T_DVB_FE:
- return "frontend";
+ return "dvb-frontend";
case MEDIA_INTF_T_DVB_DEMUX:
- return "demux";
+ return "dvb-demux";
case MEDIA_INTF_T_DVB_DVR:
- return "DVR";
+ return "dvb-dvr";
case MEDIA_INTF_T_DVB_CA:
- return "CA";
+ return "dvb-ca";
case MEDIA_INTF_T_DVB_NET:
- return "dvbnet";
+ return "dvb-net";
case MEDIA_INTF_T_V4L_VIDEO:
- return "video";
+ return "v4l-video";
case MEDIA_INTF_T_V4L_VBI:
- return "vbi";
+ return "v4l-vbi";
case MEDIA_INTF_T_V4L_RADIO:
- return "radio";
+ return "v4l-radio";
case MEDIA_INTF_T_V4L_SUBDEV:
- return "v4l2-subdev";
+ return "v4l-subdev";
case MEDIA_INTF_T_V4L_SWRADIO:
- return "swradio";
+ return "v4l-swradio";
+ case MEDIA_INTF_T_ALSA_PCM_CAPTURE:
+ return "alsa-pcm-capture";
+ case MEDIA_INTF_T_ALSA_PCM_PLAYBACK:
+ return "alsa-pcm-playback";
+ case MEDIA_INTF_T_ALSA_CONTROL:
+ return "alsa-control";
+ case MEDIA_INTF_T_ALSA_COMPRESS:
+ return "alsa-compress";
+ case MEDIA_INTF_T_ALSA_RAWMIDI:
+ return "alsa-rawmidi";
+ case MEDIA_INTF_T_ALSA_HWDEP:
+ return "alsa-hwdep";
+ case MEDIA_INTF_T_ALSA_SEQUENCER:
+ return "alsa-sequencer";
+ case MEDIA_INTF_T_ALSA_TIMER:
+ return "alsa-timer";
default:
return "unknown-intf";
}
@@ -73,8 +89,9 @@ static inline const char *intf_type(struct media_interface *intf)
__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
int idx_max)
{
- ent_enum->bmap = kcalloc(DIV_ROUND_UP(idx_max, BITS_PER_LONG),
- sizeof(long), GFP_KERNEL);
+ idx_max = ALIGN(idx_max, BITS_PER_LONG);
+ ent_enum->bmap = kcalloc(idx_max / BITS_PER_LONG, sizeof(long),
+ GFP_KERNEL);
if (!ent_enum->bmap)
return -ENOMEM;
@@ -349,8 +366,8 @@ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
* Pipeline management
*/
-__must_check int media_entity_pipeline_start(struct media_entity *entity,
- struct media_pipeline *pipe)
+__must_check int __media_entity_pipeline_start(struct media_entity *entity,
+ struct media_pipeline *pipe)
{
struct media_device *mdev = entity->graph_obj.mdev;
struct media_entity_graph *graph = &pipe->graph;
@@ -358,8 +375,6 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
struct media_link *link;
int ret;
- mutex_lock(&mdev->graph_mutex);
-
if (!pipe->streaming_count++) {
ret = media_entity_graph_walk_init(&pipe->graph, mdev);
if (ret)
@@ -440,8 +455,6 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
}
}
- mutex_unlock(&mdev->graph_mutex);
-
return 0;
error:
@@ -452,9 +465,12 @@ error:
media_entity_graph_walk_start(graph, entity_err);
while ((entity_err = media_entity_graph_walk_next(graph))) {
- entity_err->stream_count--;
- if (entity_err->stream_count == 0)
- entity_err->pipe = NULL;
+ /* don't let the stream_count go negative */
+ if (entity->stream_count > 0) {
+ entity_err->stream_count--;
+ if (entity_err->stream_count == 0)
+ entity_err->pipe = NULL;
+ }
/*
* We haven't increased stream_count further than this
@@ -468,32 +484,53 @@ error_graph_walk_start:
if (!--pipe->streaming_count)
media_entity_graph_walk_cleanup(graph);
- mutex_unlock(&mdev->graph_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__media_entity_pipeline_start);
+__must_check int media_entity_pipeline_start(struct media_entity *entity,
+ struct media_pipeline *pipe)
+{
+ struct media_device *mdev = entity->graph_obj.mdev;
+ int ret;
+
+ mutex_lock(&mdev->graph_mutex);
+ ret = __media_entity_pipeline_start(entity, pipe);
+ mutex_unlock(&mdev->graph_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
-void media_entity_pipeline_stop(struct media_entity *entity)
+void __media_entity_pipeline_stop(struct media_entity *entity)
{
- struct media_device *mdev = entity->graph_obj.mdev;
struct media_entity_graph *graph = &entity->pipe->graph;
struct media_pipeline *pipe = entity->pipe;
- mutex_lock(&mdev->graph_mutex);
WARN_ON(!pipe->streaming_count);
media_entity_graph_walk_start(graph, entity);
while ((entity = media_entity_graph_walk_next(graph))) {
- entity->stream_count--;
- if (entity->stream_count == 0)
- entity->pipe = NULL;
+ /* don't let the stream_count go negative */
+ if (entity->stream_count > 0) {
+ entity->stream_count--;
+ if (entity->stream_count == 0)
+ entity->pipe = NULL;
+ }
}
if (!--pipe->streaming_count)
media_entity_graph_walk_cleanup(graph);
+}
+EXPORT_SYMBOL_GPL(__media_entity_pipeline_stop);
+
+void media_entity_pipeline_stop(struct media_entity *entity)
+{
+ struct media_device *mdev = entity->graph_obj.mdev;
+
+ mutex_lock(&mdev->graph_mutex);
+ __media_entity_pipeline_stop(entity);
mutex_unlock(&mdev->graph_mutex);
}
EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
@@ -783,6 +820,7 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
return ret;
}
+EXPORT_SYMBOL_GPL(__media_entity_setup_link);
int media_entity_setup_link(struct media_link *link, u32 flags)
{
diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c
index 8b5e0b3a92a0..4cac1fc233f2 100644
--- a/drivers/media/pci/b2c2/flexcop-pci.c
+++ b/drivers/media/pci/b2c2/flexcop-pci.c
@@ -39,7 +39,7 @@ MODULE_PARM_DESC(debug,
#define DRIVER_VERSION "0.1"
#define DRIVER_NAME "flexcop-pci"
-#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@posteo.de>"
struct flexcop_pci {
struct pci_dev *pdev;
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 9400e996087b..df54e17ef864 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -186,7 +186,7 @@ MODULE_VERSION(BTTV_VERSION);
static ssize_t show_card(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vfd = container_of(cd, struct video_device, dev);
+ struct video_device *vfd = to_video_device(cd);
struct bttv *btv = video_get_drvdata(vfd);
return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
}
@@ -1726,22 +1726,15 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id id)
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
unsigned int i;
- int err = 0;
for (i = 0; i < BTTV_TVNORMS; i++)
if (id & bttv_tvnorms[i].v4l2_id)
break;
- if (i == BTTV_TVNORMS) {
- err = -EINVAL;
- goto err;
- }
-
+ if (i == BTTV_TVNORMS)
+ return -EINVAL;
btv->std = id;
set_tvnorm(btv, i);
-
-err:
-
- return err;
+ return 0;
}
static int bttv_g_std(struct file *file, void *priv, v4l2_std_id *id)
@@ -1770,12 +1763,9 @@ static int bttv_enum_input(struct file *file, void *priv,
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- int rc = 0;
- if (i->index >= bttv_tvcards[btv->c.type].video_inputs) {
- rc = -EINVAL;
- goto err;
- }
+ if (i->index >= bttv_tvcards[btv->c.type].video_inputs)
+ return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
i->audioset = 0;
@@ -1799,10 +1789,7 @@ static int bttv_enum_input(struct file *file, void *priv,
}
i->std = BTTV_NORMS;
-
-err:
-
- return rc;
+ return 0;
}
static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
@@ -2334,6 +2321,19 @@ static int bttv_g_fmt_vid_overlay(struct file *file, void *priv,
return 0;
}
+static void bttv_get_width_mask_vid_cap(const struct bttv_format *fmt,
+ unsigned int *width_mask,
+ unsigned int *width_bias)
+{
+ if (fmt->flags & FORMAT_FLAGS_PLANAR) {
+ *width_mask = ~15; /* width must be a multiple of 16 pixels */
+ *width_bias = 8; /* nearest */
+ } else {
+ *width_mask = ~3; /* width must be a multiple of 4 pixels */
+ *width_bias = 2; /* nearest */
+ }
+}
+
static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -2343,6 +2343,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
enum v4l2_field field;
__s32 width, height;
__s32 height2;
+ unsigned int width_mask, width_bias;
int rc;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -2375,9 +2376,9 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
width = f->fmt.pix.width;
height = f->fmt.pix.height;
+ bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias);
rc = limit_scaled_size_lock(fh, &width, &height, field,
- /* width_mask: 4 pixels */ ~3,
- /* width_bias: nearest */ 2,
+ width_mask, width_bias,
/* adjust_size */ 1,
/* adjust_crop */ 0);
if (0 != rc)
@@ -2410,6 +2411,7 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
__s32 width, height;
+ unsigned int width_mask, width_bias;
enum v4l2_field field;
retval = bttv_switch_type(fh, f->type);
@@ -2424,9 +2426,10 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
height = f->fmt.pix.height;
field = f->fmt.pix.field;
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias);
retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field,
- /* width_mask: 4 pixels */ ~3,
- /* width_bias: nearest */ 2,
+ width_mask, width_bias,
/* adjust_size */ 1,
/* adjust_crop */ 1);
if (0 != retval)
@@ -2434,8 +2437,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.field = field;
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-
/* update our state informations */
fh->fmt = fmt;
fh->cap.field = f->fmt.pix.field;
diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c
index 4a90eee5e3bb..35bc9b2287b4 100644
--- a/drivers/media/pci/bt8xx/dst.c
+++ b/drivers/media/pci/bt8xx/dst.c
@@ -1688,9 +1688,9 @@ static int dst_get_tuning_algo(struct dvb_frontend *fe)
return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW;
}
-static int dst_get_frontend(struct dvb_frontend *fe)
+static int dst_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dst_state *state = fe->demodulator_priv;
p->frequency = state->decode_freq;
diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c
index d407244fd1bc..e69d338ab9be 100644
--- a/drivers/media/pci/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c
@@ -318,7 +318,7 @@ static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const s
return request_firmware(fw, name, &bt->bt->dev->dev);
}
-static struct sp887x_config microtune_mt7202dtf_config = {
+static const struct sp887x_config microtune_mt7202dtf_config = {
.demod_address = 0x70,
.request_firmware = microtune_mt7202dtf_request_firmware,
};
@@ -458,7 +458,7 @@ static void or51211_sleep(struct dvb_frontend * fe)
bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000);
}
-static struct or51211_config or51211_config = {
+static const struct or51211_config or51211_config = {
.demod_address = 0x15,
.request_firmware = or51211_request_firmware,
.setmode = or51211_setmode,
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 80319bb73d94..f041b6931ba8 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -1139,7 +1139,7 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port)
u8 eeprom[256]; /* 24C02 i2c eeprom */
struct sp2_config sp2_config;
struct i2c_board_info info;
- struct cx23885_i2c *i2c_bus2 = &dev->i2c_bus[1];
+ struct cx23885_i2c *i2c_bus = &dev->i2c_bus[0];
/* attach CI */
memset(&sp2_config, 0, sizeof(sp2_config));
@@ -1151,7 +1151,7 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port)
info.addr = 0x40;
info.platform_data = &sp2_config;
request_module(info.type);
- client_ci = i2c_new_device(&i2c_bus2->i2c_adap, &info);
+ client_ci = i2c_new_device(&i2c_bus->i2c_adap, &info);
if (client_ci == NULL || client_ci->dev.driver == NULL)
return -ENODEV;
if (!try_module_get(client_ci->dev.driver->owner)) {
@@ -1988,8 +1988,8 @@ static int dvb_register(struct cx23885_tsport *port)
break;
case CX23885_BOARD_DVBSKY_T980C:
case CX23885_BOARD_TT_CT2_4500_CI:
- i2c_bus = &dev->i2c_bus[1];
- i2c_bus2 = &dev->i2c_bus[0];
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
/* attach frontend */
memset(&si2168_config, 0, sizeof(si2168_config));
@@ -2001,7 +2001,7 @@ static int dvb_register(struct cx23885_tsport *port)
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module(info.type);
- client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+ client_demod = i2c_new_device(&i2c_bus2->i2c_adap, &info);
if (client_demod == NULL || client_demod->dev.driver == NULL)
goto frontend_detach;
if (!try_module_get(client_demod->dev.driver->owner)) {
@@ -2030,13 +2030,13 @@ static int dvb_register(struct cx23885_tsport *port)
port->i2c_client_tuner = client_tuner;
break;
case CX23885_BOARD_DVBSKY_S950C:
- i2c_bus = &dev->i2c_bus[1];
- i2c_bus2 = &dev->i2c_bus[0];
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
/* attach frontend */
fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
&dvbsky_s950c_m88ds3103_config,
- &i2c_bus->i2c_adap, &adapter);
+ &i2c_bus2->i2c_adap, &adapter);
if (fe0->dvb.frontend == NULL)
break;
@@ -2301,7 +2301,8 @@ static int dvb_register(struct cx23885_tsport *port)
/* register everything */
ret = vb2_dvb_register_bus(&port->frontends, THIS_MODULE, port,
- &dev->pci->dev, adapter_nr, mfe_shared);
+ &dev->pci->dev, NULL,
+ adapter_nr, mfe_shared);
if (ret)
goto frontend_detach;
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index afb20756d7a5..851d2a9caed3 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -1642,7 +1642,8 @@ static int dvb_register(struct cx8802_dev *dev)
/* register everything */
res = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
- &dev->pci->dev, adapter_nr, mfe_shared);
+ &dev->pci->dev, NULL, adapter_nr,
+ mfe_shared);
if (res)
goto frontend_detach;
return res;
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 9d5b314142f1..6e995ef8c37e 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -690,7 +690,7 @@ static int tuner_attach_stv6110(struct ddb_input *input, int type)
struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
struct stv6110x_config *tunerconf = (input->nr & 1) ?
&stv6110b : &stv6110a;
- struct stv6110x_devctl *ctl;
+ const struct stv6110x_devctl *ctl;
ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c);
if (!ctl) {
diff --git a/drivers/media/pci/ivtv/ivtv-queue.c b/drivers/media/pci/ivtv/ivtv-queue.c
index 7fde36e6d227..2128c2a8d7fd 100644
--- a/drivers/media/pci/ivtv/ivtv-queue.c
+++ b/drivers/media/pci/ivtv/ivtv-queue.c
@@ -141,7 +141,7 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_
spin_unlock_irqrestore(&s->qlock, flags);
return -ENOMEM;
}
- while (bytes_available < needed_bytes) {
+ while (steal && bytes_available < needed_bytes) {
struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
u16 dma_xfer_cnt = buf->dma_xfer_cnt;
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
index 525ebfefeee8..2b667b315913 100644
--- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
+++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
@@ -462,8 +462,8 @@ static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev,
}
if (vb2_dvb_register_bus(&ndev->frontends[num],
- THIS_MODULE, NULL,
- &ndev->pci_dev->dev, adapter_nr, 1)) {
+ THIS_MODULE, NULL,
+ &ndev->pci_dev->dev, NULL, adapter_nr, 1)) {
dev_dbg(&ndev->pci_dev->dev,
"%s(): unable to register DVB bus %d\n",
__func__, num);
@@ -771,10 +771,9 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev,
/* allocate device context */
ndev = kzalloc(sizeof(*ndev), GFP_KERNEL);
-
if (!ndev)
goto dev_alloc_err;
- memset(ndev, 0, sizeof(*ndev));
+
ndev->old_fw = old_firmware;
ndev->wq = create_singlethread_workqueue(NETUP_UNIDVB_NAME);
if (!ndev->wq) {
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
index 039bed3cc919..4e783a68bf4a 100644
--- a/drivers/media/pci/ngene/ngene-cards.c
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -57,7 +57,7 @@ static int tuner_attach_stv6110(struct ngene_channel *chan)
chan->dev->card_info->fe_config[chan->number];
struct stv6110x_config *tunerconf = (struct stv6110x_config *)
chan->dev->card_info->tuner_config[chan->number];
- struct stv6110x_devctl *ctl;
+ const struct stv6110x_devctl *ctl;
/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
if (chan->number < 2)
diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c
index 0d2e2b217121..eff5e9f51ace 100644
--- a/drivers/media/pci/pt3/pt3.c
+++ b/drivers/media/pci/pt3/pt3.c
@@ -395,7 +395,8 @@ static int pt3_attach_fe(struct pt3_board *pt3, int i)
if (!try_module_get(cl->dev.driver->owner))
goto err_demod_i2c_unregister_device;
- if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) {
+ if (!strncmp(cl->name, TC90522_I2C_DEV_SAT,
+ strlen(TC90522_I2C_DEV_SAT))) {
struct qm1d1c0042_config tcfg;
tcfg = adap_conf[i].tuner_cfg.qm1d1c0042;
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index 29d2094c42a0..c480a7e87593 100644
--- a/drivers/media/pci/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -36,17 +36,23 @@
#include "xc5000.h"
#include "s5h1411.h"
-/* commly used strings */
-static char name_mute[] = "mute";
-static char name_radio[] = "Radio";
-static char name_tv[] = "Television";
-static char name_tv_mono[] = "TV (mono only)";
-static char name_comp[] = "Composite";
-static char name_comp1[] = "Composite1";
-static char name_comp2[] = "Composite2";
-static char name_comp3[] = "Composite3";
-static char name_comp4[] = "Composite4";
-static char name_svideo[] = "S-Video";
+/* Input names */
+const char * const saa7134_input_name[] = {
+ [SAA7134_INPUT_MUTE] = "mute",
+ [SAA7134_INPUT_RADIO] = "Radio",
+ [SAA7134_INPUT_TV] = "Television",
+ [SAA7134_INPUT_TV_MONO] = "TV (mono only)",
+ [SAA7134_INPUT_COMPOSITE] = "Composite",
+ [SAA7134_INPUT_COMPOSITE0] = "Composite0",
+ [SAA7134_INPUT_COMPOSITE1] = "Composite1",
+ [SAA7134_INPUT_COMPOSITE2] = "Composite2",
+ [SAA7134_INPUT_COMPOSITE3] = "Composite3",
+ [SAA7134_INPUT_COMPOSITE4] = "Composite4",
+ [SAA7134_INPUT_SVIDEO] = "S-Video",
+ [SAA7134_INPUT_SVIDEO0] = "S-Video0",
+ [SAA7134_INPUT_SVIDEO1] = "S-Video1",
+ [SAA7134_INPUT_COMPOSITE_OVER_SVIDEO] = "Composite over S-Video",
+};
/* ------------------------------------------------------------------ */
/* board config info */
@@ -69,7 +75,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = "default",
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 0,
.amux = LINE1,
}},
@@ -84,22 +90,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -114,40 +118,38 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 0xe000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
.gpio = 0x8000,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
.gpio = 0x0000,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
.gpio = 0x4000,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
.gpio = 0x4000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x4000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x2000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x8000,
},
@@ -163,34 +165,33 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 0xe000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
.gpio = 0x0000,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
.gpio = 0x4000,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
.gpio = 0x4000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x4000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x2000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE2,
.gpio = 0x8000,
},
@@ -205,20 +206,19 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1, /* Composite signal on S-Video input */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -235,40 +235,38 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 0x1E000, /* Set GP16 and unused 15,14,13 to Output */
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
.gpio = 0x10000, /* GP16=1 selects TV input */
- .tv = 1,
},{
-/* .name = name_tv_mono,
+/* .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
.gpio = 0x0000,
- .tv = 1,
},{
-*/ .name = name_comp1, /* Composite signal on S-Video input */
+*/ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE2,
/* .gpio = 0x4000, */
},{
- .name = name_comp2, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 3,
.amux = LINE2,
/* .gpio = 0x4000, */
},{
- .name = name_svideo, /* S-Video signal on S-Video input */
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
/* .gpio = 0x4000, */
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x00000, /* GP16=0 selects FM radio antenna */
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x10000,
},
@@ -285,40 +283,38 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0xe000,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
.gpio = 0x8000,
- .tv = 1,
}, {
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
.gpio = 0x0000,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
.gpio = 0x4000,
}, {
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
.gpio = 0x4000,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x4000,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x2000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x8000,
},
@@ -334,21 +330,20 @@ struct saa7134_board saa7134_boards[] = {
.empress_addr = 0x20,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
.mpeg = SAA7134_MPEG_EMPRESS,
@@ -364,21 +359,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -390,35 +384,33 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
/* workaround for problems with normal TV sound */
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
},
},
@@ -432,32 +424,30 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = "CVid over SVid",
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -472,24 +462,23 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x820000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x20000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x20000,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x20000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x20000,
},
@@ -504,20 +493,19 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 4,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp2, /* CVideo over SVideo Connector */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE1,
}}
@@ -531,31 +519,29 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
/* workaround for problems with normal TV sound */
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -567,18 +553,17 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}},
},
[SAA7134_BOARD_CINERGY600] = {
@@ -590,25 +575,24 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 4,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp2, /* CVideo over SVideo Connector */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -622,25 +606,24 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
},
},
@@ -655,21 +638,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -681,18 +663,17 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 4,
.amux = LINE2,
- .tv = 1,
}},
},
[SAA7134_BOARD_ELSA_500TV] = {
@@ -703,19 +684,17 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 7,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 8,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 8,
.amux = LINE2,
- .tv = 1,
}},
},
[SAA7134_BOARD_ELSA_700TV] = {
@@ -726,21 +705,20 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 4,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 6,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 7,
.amux = LINE1,
}},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
},
},
@@ -753,21 +731,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 4,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
},
},
@@ -780,29 +757,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
.gpio = 0x0000,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 4,
.amux = LINE2,
.gpio = 0x0000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE2,
.gpio = 0x0000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x200000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.gpio = 0x0000,
},
@@ -815,18 +791,17 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}},
},
[SAA7134_BOARD_10MOONSTVMASTER] = {
@@ -839,34 +814,33 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0xe000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
.gpio = 0x0000,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
.gpio = 0x4000,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
.gpio = 0x4000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x4000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x2000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE2,
.gpio = 0x8000,
},
@@ -881,23 +855,23 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.empress_addr = 0x20,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 4,
.amux = LINE1,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_comp3,
+ .type = SAA7134_INPUT_COMPOSITE3,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_comp4,
+ .type = SAA7134_INPUT_COMPOSITE4,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -912,18 +886,17 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}},
},
[SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = {
@@ -935,21 +908,20 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x06c00012,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x0ac20012,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
.gpio = 0x08c20012,
- .tv = 1,
}}, /* radio and probably mute is missing */
},
[SAA7134_BOARD_CRONOS_PLUS] = {
@@ -968,23 +940,23 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0xcf00,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.gpio = 2 << 14,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.gpio = 1 << 14,
},{
- .name = name_comp3,
+ .type = SAA7134_INPUT_COMPOSITE3,
.vmux = 0,
.gpio = 0 << 14,
},{
- .name = name_comp4,
+ .type = SAA7134_INPUT_COMPOSITE4,
.vmux = 0,
.gpio = 3 << 14,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.gpio = 2 << 14,
}},
@@ -999,34 +971,33 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x03,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x00,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x02,
}, {
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.amux = LINE1,
.gpio = 0x02,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x02,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
.gpio = 0x01,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x00,
},
@@ -1041,18 +1012,17 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.empress_addr = 0x20,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}},
.mpeg = SAA7134_MPEG_EMPRESS,
.video_out = CCIR656,
@@ -1068,22 +1038,21 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 4,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
},
},
@@ -1096,20 +1065,19 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER | TDA9887_PORT2_INACTIVE,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 1,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -1123,21 +1091,20 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -1150,21 +1117,20 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
},
@@ -1177,16 +1143,15 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -1199,30 +1164,28 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = "CVid over SVid",
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -1234,30 +1197,28 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = "CVid over SVid",
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -1270,30 +1231,28 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = "CVid over SVid",
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -1306,30 +1265,28 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x200000,
},
@@ -1343,10 +1300,10 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
}},
},
@@ -1360,10 +1317,9 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
} },
},
[SAA7134_BOARD_NOVAC_PRIMETV7133] = {
@@ -1375,15 +1331,14 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
}},
},
@@ -1396,29 +1351,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
},
@@ -1432,29 +1386,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
}, {
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
},
@@ -1467,12 +1420,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 7,
.amux = TV,
- .tv = 1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 7,
.amux = LINE1,
}},
@@ -1486,21 +1438,20 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -1512,25 +1463,24 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 4,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp2, /* CVideo over SVideo Connector */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE1,
}},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE2,
},
},
@@ -1544,29 +1494,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x808c0080,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x00080,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x00080,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2_LEFT,
- .tv = 1,
.gpio = 0x00080,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x80000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE2,
.gpio = 0x40000,
},
@@ -1580,21 +1529,20 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -1607,18 +1555,17 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}},
},
[SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE] = {
@@ -1631,29 +1578,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x4000,
.inputs = {{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
.gpio = 0x8000,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x8000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
.gpio = 0x8000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
.gpio = 0x8000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio =0x8000,
}
@@ -1672,29 +1618,28 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x03,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x00,
},{
- .name = name_comp,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 3,
.amux = LINE1,
.gpio = 0x02,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x02,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
.gpio = 0x01,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
.gpio = 0x00,
},
@@ -1709,29 +1654,28 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 0x00300003,
/* .gpiomask = 0x8c240003, */
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x01,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
.gpio = 0x02,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
.gpio = 0x02,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x00300001,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x01,
},
@@ -1745,21 +1689,20 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
},
},
@@ -1774,24 +1717,23 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x08000000,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x08000000,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x08000000,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x08000000,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x00000000,
},
@@ -1805,21 +1747,19 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -1834,25 +1774,24 @@ struct saa7134_board saa7134_boards[] = {
.rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 4,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp2, /* CVideo over SVideo Connector */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -1866,29 +1805,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x1ce780,
.inputs = {{
- .name = name_svideo,
- .vmux = 0, /* CVideo over SVideo Connector - ok? */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
.amux = LINE1,
.gpio = 0x008080,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x008080,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x008080,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x80000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE2,
.gpio = 0x0c8000,
},
@@ -1903,20 +1841,19 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER | TDA9887_PORT2_INACTIVE,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 1,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -1931,22 +1868,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -1961,25 +1896,24 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
},
@@ -1995,26 +1929,25 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 0x00200000,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
.gpio = 0x200000, /* GPIO21=High for TV input */
- .tv = 1,
},{
- .name = name_comp1, /* Composite signal on S-Video input */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo, /* S-Video signal on S-Video input */
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
},
@@ -2028,11 +1961,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -2049,20 +1982,19 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -2075,16 +2007,15 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -2098,29 +2029,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x0700,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x000,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x200, /* gpio by DScaler */
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 0,
.amux = LINE1,
.gpio = 0x200,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
.gpio = 0x100,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x000,
},
@@ -2135,26 +2065,25 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x00200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
.gpio = 0x200000, /* GPIO21=High for TV input */
- .tv = 1,
},{
- .name = name_svideo, /* S-Video signal on S-Video input */
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
},{
- .name = name_comp1, /* Composite signal on S-Video input */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
},
@@ -2168,29 +2097,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = 0x60,
.gpiomask = 0x8c1880,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 0,
.amux = LINE1,
.gpio = 0x800800,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x801000,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x800000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x880000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE2,
.gpio = 0x840000,
},
@@ -2213,29 +2141,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = 0x60,
.gpiomask = 0x0700,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x000,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x200, /* gpio by DScaler */
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 0,
.amux = LINE1,
.gpio = 0x200,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
.gpio = 0x100,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x000,
},
@@ -2248,30 +2175,28 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.radio = {
- .name = name_radio, /* radio unconfirmed */
+ .type = SAA7134_INPUT_RADIO, /* radio unconfirmed */
.amux = LINE2,
},
},
@@ -2286,24 +2211,23 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 1 << 21,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
.gpio = 0x0000000,
- .tv = 1,
},{
- .name = name_comp1, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
.gpio = 0x0000000,
},{
- .name = name_svideo, /* S-Video input */
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x0000000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -2322,29 +2246,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr= ADDR_UNSET,
.gpiomask = 0x00010003,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x01,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
.gpio = 0x02,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE2,
.gpio = 0x02,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
.gpio = 0x00010003,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x01,
},
@@ -2362,21 +2285,20 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -2392,34 +2314,33 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00200003,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x00200003,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
.gpio = 0x00200003,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x00200003,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x00200003,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x00200003,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x00200003,
},
@@ -2434,16 +2355,15 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -2458,16 +2378,15 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -2481,11 +2400,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -2499,27 +2418,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.empress_addr = 0x21,
.inputs = {{
- .name = "Composite 0",
+ .type = SAA7134_INPUT_COMPOSITE0,
.vmux = 0,
.amux = LINE1,
},{
- .name = "Composite 1",
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE2,
},{
- .name = "Composite 2",
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 2,
.amux = LINE1,
},{
- .name = "Composite 3",
+ .type = SAA7134_INPUT_COMPOSITE3,
.vmux = 3,
.amux = LINE2,
},{
- .name = "S-Video 0",
+ .type = SAA7134_INPUT_SVIDEO0,
+
.vmux = 8,
.amux = LINE1,
},{
- .name = "S-Video 1",
+ .type = SAA7134_INPUT_SVIDEO1,
.vmux = 9,
.amux = LINE2,
}},
@@ -2538,27 +2458,27 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = "Composite 0",
+ .type = SAA7134_INPUT_COMPOSITE0,
.vmux = 0,
.amux = LINE1,
},{
- .name = "Composite 1",
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE2,
},{
- .name = "Composite 2",
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 2,
.amux = LINE1,
},{
- .name = "Composite 3",
+ .type = SAA7134_INPUT_COMPOSITE3,
.vmux = 3,
.amux = LINE2,
},{
- .name = "S-Video 0",
+ .type = SAA7134_INPUT_SVIDEO0,
.vmux = 8,
.amux = LINE1,
},{
- .name = "S-Video 1",
+ .type = SAA7134_INPUT_SVIDEO1,
.vmux = 9,
.amux = LINE2,
}},
@@ -2572,20 +2492,19 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1, /* Composite signal on S-Video input */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -2604,11 +2523,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -2622,16 +2541,15 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
}},
@@ -2645,25 +2563,24 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x080200000,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 4,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE2,
}, {
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -2678,29 +2595,28 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 1 << 21,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x0000000,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
.gpio = 0x0200000,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.amux = LINE2,
.gpio = 0x0200000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x0200000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -2717,21 +2633,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0xe880c0,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -2745,16 +2660,15 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -2770,21 +2684,20 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -2798,25 +2711,24 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 1 << 21,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 3,
.amux = LINE2, /* unconfirmed, taken from Philips driver */
},{
- .name = name_comp2,
- .vmux = 0, /* untested, Composite over S-Video */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0, /* untested */
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -2834,17 +2746,16 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x80200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_svideo, /* NOT tested */
+ .type = SAA7134_INPUT_SVIDEO, /* NOT tested */
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -2861,26 +2772,25 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 0x00200000,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv, /* Analog broadcast/cable TV */
+ .type = SAA7134_INPUT_TV, /* Analog broadcast/cable TV */
.vmux = 1,
.amux = TV,
.gpio = 0x200000, /* GPIO21=High for TV input */
- .tv = 1,
},{
- .name = name_svideo, /* S-Video signal on S-Video input */
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
},{
- .name = name_comp1, /* Composite signal on S-Video input */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
},
@@ -2894,11 +2804,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -2914,11 +2824,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_comp1, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo, /* S-Video signal on S-Video input */
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -2933,10 +2843,9 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x00200000,
}},
},
@@ -2950,25 +2859,24 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 1 << 21,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -2983,21 +2891,20 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 1 << 21,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -3012,16 +2919,15 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -3052,17 +2958,16 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0xca60000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 4,
.amux = TV,
- .tv = 1,
.gpio = 0x04a61000,
},{
- .name = name_comp2, /* Composite SVIDEO (B/W if signal is carried with SVIDEO) */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 1,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 9, /* 9 is correct as S-VIDEO1 according to a169.inf! */
.amux = LINE1,
}},
@@ -3086,26 +2991,25 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
.gpio = 0x200000, /* GPIO21=High for TV input */
- .tv = 1,
},{
- .name = name_svideo, /* S-Video signal on S-Video input */
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
},{
- .name = name_comp1, /* Composite signal on S-Video input */
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 3,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
},
@@ -3121,40 +3025,38 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 0xe000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
.gpio = 0x8000,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
.gpio = 0x0000,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
.gpio = 0x4000,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
.gpio = 0x4000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x4000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x2000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x8000,
},
@@ -3168,16 +3070,15 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -3193,11 +3094,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_comp1, /* Composite input */
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo, /* S-Video signal on S-Video input */
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -3211,25 +3112,24 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
},
@@ -3244,21 +3144,20 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
},
},
@@ -3272,21 +3171,20 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT| TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 4,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
},
},
@@ -3301,25 +3199,24 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x000200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 4,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE2,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -3335,34 +3232,33 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x03,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x00,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
.gpio = 0x00,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
.gpio = 0x00,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x00,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x01,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
.gpio = 0x00,
},
@@ -3378,16 +3274,15 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
}},
@@ -3405,22 +3300,21 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200100,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x0000100,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200100,
},
@@ -3438,22 +3332,21 @@ struct saa7134_board saa7134_boards[] = {
.ts_force_val = 1,
.gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x0000100,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0800100, /* GPIO 23 HI for FM */
},
@@ -3470,22 +3363,21 @@ struct saa7134_board saa7134_boards[] = {
.ts_type = SAA7134_MPEG_TS_SERIAL,
.gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x0000100,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0800100, /* GPIO 23 HI for FM */
},
@@ -3499,16 +3391,15 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
}},
@@ -3523,33 +3414,31 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = 3,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 7,
.amux = 4,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = 2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 0,
.amux = 2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
/* .gpio = 0x00300001,*/
.gpio = 0x20000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = 0,
},
},
@@ -3562,32 +3451,30 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = 3,
- .tv = 1,
},{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 7,
.amux = 4,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = 2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 0,
.amux = 2,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x20000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = 0,
},
},
@@ -3600,29 +3487,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x7000,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = 1,
- .tv = 1,
.gpio = 0x50000,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = 2,
.gpio = 0x2000,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = 2,
.gpio = 0x2000,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.vmux = 1,
.amux = 1,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.gpio = 0xf000,
.amux = 0,
},
@@ -3635,26 +3521,25 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = 0x61,
.radio_addr = 0x60,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.vmux = 1,
.amux = LINE1,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
.gpio = 0x43000,
},
@@ -3668,16 +3553,15 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
}},
@@ -3693,21 +3577,20 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -3721,16 +3604,15 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 1<<21,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE2,
}},
@@ -3746,10 +3628,9 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x0200000,
}},
},
@@ -3764,29 +3645,28 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 1 << 21,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x0000000,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
.gpio = 0x0200000,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.amux = LINE2,
.gpio = 0x0200000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x0200000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -3800,26 +3680,25 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 1 << 21,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x0000000,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
}, {
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -3832,25 +3711,24 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
},
},
@@ -3864,24 +3742,23 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x7000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
.gpio = 0x0000,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x2000,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x2000,
}},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE2,
.gpio = 0x3000,
},
@@ -3896,10 +3773,9 @@ struct saa7134_board saa7134_boards[] = {
.tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv, /* FIXME: analog tv untested */
+ .type = SAA7134_INPUT_TV, /* FIXME: analog tv untested */
.vmux = 1,
.amux = TV,
- .tv = 1,
}},
},
[SAA7134_BOARD_AVERMEDIA_M135A] = {
@@ -3912,26 +3788,25 @@ struct saa7134_board saa7134_boards[] = {
.tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
.gpiomask = 0x020200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x00200000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x01,
},
@@ -3946,26 +3821,25 @@ struct saa7134_board saa7134_boards[] = {
.tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
.gpiomask = 0x020200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x00200000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x01,
},
@@ -3981,21 +3855,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
},
@@ -4010,18 +3883,17 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}},
},
[SAA7134_BOARD_BEHOLD_403FM] = {
@@ -4035,21 +3907,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4065,18 +3936,17 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}},
},
[SAA7134_BOARD_BEHOLD_405FM] = {
@@ -4092,21 +3962,20 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4122,20 +3991,19 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0xc0c000,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
.gpio = 0xc0c000,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
.gpio = 0xc0c000,
}},
},
@@ -4151,24 +4019,23 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0xc0c000,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
.gpio = 0xc0c000,
},{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
.gpio = 0xc0c000,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0xc0c000,
},
@@ -4185,16 +4052,15 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
@@ -4211,25 +4077,24 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4246,25 +4111,24 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4280,21 +4144,20 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4311,21 +4174,20 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4342,21 +4204,20 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4372,24 +4233,23 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x000A8004,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
.gpio = 0x000A8004,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
.gpio = 0x000A8000,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x000A8000,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x000A8000,
},
@@ -4404,21 +4264,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4432,21 +4291,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4460,21 +4318,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4488,21 +4345,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4517,21 +4373,20 @@ struct saa7134_board saa7134_boards[] = {
.rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4546,21 +4401,20 @@ struct saa7134_board saa7134_boards[] = {
.rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4575,21 +4429,20 @@ struct saa7134_board saa7134_boards[] = {
.rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4604,21 +4457,20 @@ struct saa7134_board saa7134_boards[] = {
.rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
},{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
},{
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -4636,21 +4488,20 @@ struct saa7134_board saa7134_boards[] = {
.empress_addr = 0x20,
.tda9887_conf = TDA9887_PRESENT,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
.mpeg = SAA7134_MPEG_EMPRESS,
@@ -4673,21 +4524,20 @@ struct saa7134_board saa7134_boards[] = {
.empress_addr = 0x20,
.tda9887_conf = TDA9887_PRESENT,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
.mpeg = SAA7134_MPEG_EMPRESS,
@@ -4712,21 +4562,20 @@ struct saa7134_board saa7134_boards[] = {
.empress_addr = 0x20,
.tda9887_conf = TDA9887_PRESENT,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
.mpeg = SAA7134_MPEG_EMPRESS,
@@ -4747,21 +4596,20 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8, /* untested */
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -4776,30 +4624,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0xf000,
.inputs = {{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE2,
.gpio = 0x0000,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x2000,
- .tv = 1
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x2000,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x1000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE2,
.gpio = 0x6000,
},
@@ -4813,11 +4659,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
@@ -4832,16 +4678,15 @@ struct saa7134_board saa7134_boards[] = {
.tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
@@ -4857,21 +4702,20 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -4885,21 +4729,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
},
},
@@ -4912,21 +4755,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
}, {
- .name = name_comp,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 0,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
},
},
@@ -4938,16 +4780,15 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
@@ -4962,21 +4803,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
}
},
@@ -4990,11 +4830,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = { {
- .name = name_comp,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
} },
@@ -5009,21 +4849,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 4,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
},
},
@@ -5038,21 +4877,20 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -5067,21 +4905,20 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 1 << 21,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 0,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -5097,21 +4934,20 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 1 << 21,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 0,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -5125,29 +4961,28 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x801a8087,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
.gpio = 0x624000,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
.gpio = 0x624000,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 1,
.amux = LINE1,
.gpio = 0x624000,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x624001,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
},
},
@@ -5161,16 +4996,15 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.mpeg = SAA7134_MPEG_DVB,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 4,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
@@ -5186,25 +5020,24 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
}, {
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 0,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0200000,
},
@@ -5218,30 +5051,29 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = 0x60,
.gpiomask = 0x80000700,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
.gpio = 0x100,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x200,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x200,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.vmux = 1,
.amux = LINE1,
.gpio = 0x100,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.vmux = 8,
.amux = 2,
},
@@ -5257,18 +5089,17 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.ts_type = SAA7134_MPEG_TS_PARALLEL,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
#if 0 /* FIXME */
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x200,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x200,
@@ -5276,14 +5107,14 @@ struct saa7134_board saa7134_boards[] = {
} },
#if 0
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.vmux = 1,
.amux = LINE1,
.gpio = 0x100,
},
#endif
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.vmux = 0,
.amux = TV,
},
@@ -5298,24 +5129,23 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 0x00300003,
/* .gpiomask = 0x8c240003, */
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x01,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
.gpio = 0x02,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x00300001,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
.gpio = 0x01,
},
@@ -5331,29 +5161,28 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x03,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x00,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x00,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x00,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
.gpio = 0x01,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
.gpio = 0x00,
},
@@ -5368,11 +5197,11 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = { {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8, /* Not tested */
.amux = LINE1
} },
@@ -5387,21 +5216,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 2,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 9,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
},
},
@@ -5416,13 +5244,12 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.ts_type = SAA7134_MPEG_TS_PARALLEL,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
} },
.radio = { /* untested */
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
},
},
@@ -5436,16 +5263,15 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
.mpeg = SAA7134_MPEG_DVB,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 4,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
@@ -5459,10 +5285,10 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
.inputs = { {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
} },
},
@@ -5479,25 +5305,24 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE2,
},
},
@@ -5512,7 +5337,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x389c00,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x01fc00,
@@ -5529,21 +5354,20 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.ts_type = SAA7134_MPEG_TS_PARALLEL,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 2,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 9,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
},
},
@@ -5556,21 +5380,20 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 2,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 9,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
},
},
@@ -5584,16 +5407,15 @@ struct saa7134_board saa7134_boards[] = {
.tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
@@ -5607,25 +5429,24 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = 0x60,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = TV,
},
},
@@ -5642,29 +5463,28 @@ struct saa7134_board saa7134_boards[] = {
.mpeg = SAA7134_MPEG_DVB,
.ts_type = SAA7134_MPEG_TS_PARALLEL,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
.gpio = 0x00050000,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x00050000,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
.gpio = 0x00050000,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x00050000,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.vmux = 0,
.amux = TV,
.gpio = 0x00050000,
@@ -5681,21 +5501,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x00008000,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
},
@@ -5710,21 +5529,20 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x00008000,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = LINE2,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 1,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
},
@@ -5736,15 +5554,15 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE1,
}, {
- .name = name_comp3,
+ .type = SAA7134_INPUT_COMPOSITE3,
.vmux = 2,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
@@ -5760,21 +5578,20 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 1 << 21,
.ts_type = SAA7134_MPEG_TS_PARALLEL,
.inputs = { {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 3,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0000000,
},
@@ -5790,7 +5607,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x618E700,
.inputs = {{
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE1,
.gpio = 0x6010000,
@@ -5809,21 +5626,20 @@ struct saa7134_board saa7134_boards[] = {
.gpiomask = 1 << 11,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = TV,
- .tv = 1,
}, {
- .name = name_comp,
+ .type = SAA7134_INPUT_COMPOSITE,
.vmux = 4,
.amux = LINE1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE1,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = TV,
.gpio = 0x0000800,
},
@@ -5837,16 +5653,15 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_GO7007,
.inputs = { {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
}, {
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 3,
.amux = TV,
- .tv = 1,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 6,
.amux = LINE1,
} },
@@ -5862,25 +5677,24 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .type = SAA7134_INPUT_TV,
.vmux = 1,
.amux = LINE2,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 0,
.amux = LINE2,
}, {
- .name = name_comp2,
+ .type = SAA7134_INPUT_COMPOSITE2,
.vmux = 3,
.amux = LINE2,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
} },
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
},
},
@@ -5893,34 +5707,62 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
.gpiomask = 0x0d,
.inputs = {{
- .name = name_tv_mono,
+ .type = SAA7134_INPUT_TV_MONO,
.vmux = 1,
.amux = LINE1,
.gpio = 0x00,
- .tv = 1,
}, {
- .name = name_comp1,
+ .type = SAA7134_INPUT_COMPOSITE1,
.vmux = 3,
.amux = LINE2,
.gpio = 0x08,
}, {
- .name = name_svideo,
+ .type = SAA7134_INPUT_SVIDEO,
.vmux = 8,
.amux = LINE2,
.gpio = 0x08,
} },
.radio = {
- .name = name_radio,
+ .type = SAA7134_INPUT_RADIO,
.amux = LINE1,
.gpio = 0x04,
},
.mute = {
- .name = name_mute,
+ .type = SAA7134_INPUT_MUTE,
.amux = LINE1,
.gpio = 0x08,
},
},
-
+ [SAA7134_BOARD_SNAZIO_TVPVR_PRO] = {
+ .name = "SnaZio* TVPVR PRO",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 1 << 21,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x0000000,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x0000000,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -7191,6 +7033,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x6f3a,
.driver_data = SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1779, /* V One Multimedia PTE Ltd */
+ .subdevice = 0x13cf,
+ .driver_data = SAA7134_BOARD_SNAZIO_TVPVR_PRO,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -7721,6 +7569,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_H7:
case SAA7134_BOARD_BEHOLD_A7:
case SAA7134_BOARD_KWORLD_PC150U:
+ case SAA7134_BOARD_SNAZIO_TVPVR_PRO:
dev->has_remote = SAA7134_REMOTE_I2C;
break;
case SAA7134_BOARD_AVERMEDIA_A169_B:
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index e227b02cc122..c0e1780ec831 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -112,7 +112,7 @@ int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
printk(KERN_DEBUG pr_fmt("irq: " fmt), ## arg); \
} while (0)
-void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
+void saa7134_track_gpio(struct saa7134_dev *dev, const char *msg)
{
unsigned long mode,status;
@@ -806,6 +806,154 @@ static void must_configure_manually(int has_eeprom)
}
}
+static void saa7134_unregister_media_device(struct saa7134_dev *dev)
+{
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (!dev->media_dev)
+ return;
+ media_device_unregister(dev->media_dev);
+ media_device_cleanup(dev->media_dev);
+ kfree(dev->media_dev);
+ dev->media_dev = NULL;
+#endif
+}
+
+static void saa7134_media_release(struct saa7134_dev *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ int i;
+
+ for (i = 0; i < SAA7134_INPUT_MAX + 1; i++)
+ media_device_unregister_entity(&dev->input_ent[i]);
+#endif
+}
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static void saa7134_create_entities(struct saa7134_dev *dev)
+{
+ int ret, i;
+ struct media_entity *entity;
+ struct media_entity *decoder = NULL;
+
+ /* Check if it is using an external analog TV demod */
+ media_device_for_each_entity(entity, dev->media_dev) {
+ if (entity->function == MEDIA_ENT_F_ATV_DECODER) {
+ decoder = entity;
+ break;
+ }
+ }
+
+ /*
+ * saa713x is not using an external ATV demod.
+ * Register the internal one
+ */
+ if (!decoder) {
+ dev->demod.name = "saa713x";
+ dev->demod_pad[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ dev->demod_pad[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ dev->demod_pad[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ dev->demod.function = MEDIA_ENT_F_ATV_DECODER;
+
+ ret = media_entity_pads_init(&dev->demod, DEMOD_NUM_PADS,
+ dev->demod_pad);
+ if (ret < 0)
+ pr_err("failed to initialize demod pad!\n");
+
+ ret = media_device_register_entity(dev->media_dev, &dev->demod);
+ if (ret < 0)
+ pr_err("failed to register demod entity!\n");
+
+ dev->decoder = &dev->demod;
+ } else {
+ dev->decoder = decoder;
+ }
+
+ /* Initialize Video, VBI and Radio pads */
+ dev->video_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&dev->video_dev->entity, 1,
+ &dev->video_pad);
+ if (ret < 0)
+ pr_err("failed to initialize video media entity!\n");
+
+ dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&dev->vbi_dev->entity, 1,
+ &dev->vbi_pad);
+ if (ret < 0)
+ pr_err("failed to initialize vbi media entity!\n");
+
+ /* Create entities for each input connector */
+ for (i = 0; i < SAA7134_INPUT_MAX; i++) {
+ struct media_entity *ent = &dev->input_ent[i];
+ struct saa7134_input *in = &card_in(dev, i);
+
+ if (in->type == SAA7134_NO_INPUT)
+ break;
+
+ /* This input uses the S-Video connector */
+ if (in->type == SAA7134_INPUT_COMPOSITE_OVER_SVIDEO)
+ continue;
+
+ ent->name = saa7134_input_name[in->type];
+ ent->flags = MEDIA_ENT_FL_CONNECTOR;
+ dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ switch (in->type) {
+ case SAA7134_INPUT_COMPOSITE:
+ case SAA7134_INPUT_COMPOSITE0:
+ case SAA7134_INPUT_COMPOSITE1:
+ case SAA7134_INPUT_COMPOSITE2:
+ case SAA7134_INPUT_COMPOSITE3:
+ case SAA7134_INPUT_COMPOSITE4:
+ ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
+ break;
+ case SAA7134_INPUT_SVIDEO:
+ case SAA7134_INPUT_SVIDEO0:
+ case SAA7134_INPUT_SVIDEO1:
+ ent->function = MEDIA_ENT_F_CONN_SVIDEO;
+ break;
+ default:
+ /*
+ * SAA7134_INPUT_TV and SAA7134_INPUT_TV_MONO.
+ *
+ * Please notice that neither SAA7134_INPUT_MUTE or
+ * SAA7134_INPUT_RADIO are defined at
+ * saa7134_board.input.
+ */
+ ent->function = MEDIA_ENT_F_CONN_RF;
+ break;
+ }
+
+ ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
+ if (ret < 0)
+ pr_err("failed to initialize input pad[%d]!\n", i);
+
+ ret = media_device_register_entity(dev->media_dev, ent);
+ if (ret < 0)
+ pr_err("failed to register input entity %d!\n", i);
+ }
+
+ /* Create input for Radio RF connector */
+ if (card_has_radio(dev)) {
+ struct saa7134_input *in = &saa7134_boards[dev->board].radio;
+ struct media_entity *ent = &dev->input_ent[i];
+
+ ent->name = saa7134_input_name[in->type];
+ ent->flags = MEDIA_ENT_FL_CONNECTOR;
+ dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+ ent->function = MEDIA_ENT_F_CONN_RF;
+
+ ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
+ if (ret < 0)
+ pr_err("failed to initialize input pad[%d]!\n", i);
+
+ ret = media_device_register_entity(dev->media_dev, ent);
+ if (ret < 0)
+ pr_err("failed to register input entity %d!\n", i);
+ }
+}
+#endif
+
static struct video_device *vdev_init(struct saa7134_dev *dev,
struct video_device *template,
char *type)
@@ -826,6 +974,8 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
static void saa7134_unregister_video(struct saa7134_dev *dev)
{
+ saa7134_media_release(dev);
+
if (dev->video_dev) {
if (video_is_registered(dev->video_dev))
video_unregister_device(dev->video_dev);
@@ -889,6 +1039,19 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
if (NULL == dev)
return -ENOMEM;
+ dev->nr = saa7134_devcount;
+ sprintf(dev->name, "saa%x[%d]", pci_dev->device, dev->nr);
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->media_dev = kzalloc(sizeof(*dev->media_dev), GFP_KERNEL);
+ if (!dev->media_dev) {
+ err = -ENOMEM;
+ goto fail0;
+ }
+ media_device_pci_init(dev->media_dev, pci_dev, dev->name);
+ dev->v4l2_dev.mdev = dev->media_dev;
+#endif
+
err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
if (err)
goto fail0;
@@ -900,9 +1063,6 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
goto fail1;
}
- dev->nr = saa7134_devcount;
- sprintf(dev->name,"saa%x[%d]",pci_dev->device,dev->nr);
-
/* pci quirks */
if (pci_pci_problems) {
if (pci_pci_problems & PCIPCI_TRITON)
@@ -1102,6 +1262,15 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->name, video_device_node_name(dev->radio_dev));
}
+#ifdef CONFIG_MEDIA_CONTROLLER
+ saa7134_create_entities(dev);
+
+ err = v4l2_mc_create_media_graph(dev->media_dev);
+ if (err) {
+ pr_err("failed to create media graph\n");
+ goto fail5;
+ }
+#endif
/* everything worked */
saa7134_devcount++;
@@ -1109,6 +1278,18 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
saa7134_dmasound_init(dev);
request_submodules(dev);
+
+ /*
+ * Do it at the end, to reduce dynamic configuration changes during
+ * the device init. Yet, as request_modules() can be async, the
+ * topology will likely change after load the saa7134 subdrivers.
+ */
+#ifdef CONFIG_MEDIA_CONTROLLER
+ err = media_device_register(dev->media_dev);
+ if (err)
+ goto fail5;
+#endif
+
return 0;
fail5:
@@ -1126,6 +1307,9 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
fail1:
v4l2_device_unregister(&dev->v4l2_dev);
fail0:
+#ifdef CONFIG_MEDIA_CONTROLLER
+ kfree(dev->media_dev);
+#endif
kfree(dev);
return err;
}
@@ -1188,9 +1372,10 @@ static void saa7134_finidev(struct pci_dev *pci_dev)
release_mem_region(pci_resource_start(pci_dev,0),
pci_resource_len(pci_dev,0));
-
v4l2_device_unregister(&dev->v4l2_dev);
+ saa7134_unregister_media_device(dev);
+
/* free memory */
kfree(dev);
}
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
index 101ba8729416..db987e5b93eb 100644
--- a/drivers/media/pci/saa7134/saa7134-dvb.c
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -1883,8 +1883,15 @@ static int dvb_init(struct saa7134_dev *dev)
fe0->dvb.frontend->callback = saa7134_tuner_callback;
/* register everything else */
+#ifndef CONFIG_MEDIA_CONTROLLER_DVB
ret = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
- &dev->pci->dev, adapter_nr, 0);
+ &dev->pci->dev, NULL,
+ adapter_nr, 0);
+#else
+ ret = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ &dev->pci->dev, dev->media_dev,
+ adapter_nr, 0);
+#endif
/* this sequence is necessary to make the tda1004x load its firmware
* and to enter analog mode of hybrid boards
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 56b932c97196..ca417a454d67 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -189,6 +189,7 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = {
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_frequency = saa7134_g_frequency,
@@ -286,7 +287,7 @@ static int empress_init(struct saa7134_dev *dev)
* transfers that do not start at the beginning of a page. A USERPTR
* can start anywhere in a page, so USERPTR support is a no-go.
*/
- q->io_modes = VB2_MMAP | VB2_READ;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
q->drv_priv = &dev->ts_q;
q->ops = &saa7134_empress_qops;
q->gfp_flags = GFP_DMA32;
diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c
index 8a2abb34186b..2799538e2d7e 100644
--- a/drivers/media/pci/saa7134/saa7134-go7007.c
+++ b/drivers/media/pci/saa7134/saa7134-go7007.c
@@ -378,7 +378,7 @@ static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
return 0;
}
-static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
+static const struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
.interface_reset = saa7134_go7007_interface_reset,
.write_interrupt = saa7134_go7007_write_interrupt,
.read_interrupt = saa7134_go7007_read_interrupt,
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 69d32d3fa32c..c8042c3888cd 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -975,6 +975,27 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
msg_msi.addr, dev->i2c_adap.name,
(1 == rc) ? "yes" : "no");
break;
+ case SAA7134_BOARD_SNAZIO_TVPVR_PRO:
+ dev->init_data.name = "SnaZio* TVPVR PRO";
+ dev->init_data.get_key = get_key_msi_tvanywhere_plus;
+ dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS;
+ /*
+ * MSI TV@nyware Plus requires more frequent polling
+ * otherwise it will miss some keypresses
+ */
+ dev->init_data.polling_interval = 50;
+ info.addr = 0x30;
+ /*
+ * MSI TV@nywhere Plus controller doesn't seem to
+ * respond to probes unless we read something from
+ * an existing device. Weird...
+ * REVISIT: might no longer be needed
+ */
+ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+ input_dbg("probe 0x%02x @ %s: %s\n",
+ msg_msi.addr, dev->i2c_adap.name,
+ (rc == 1) ? "yes" : "no");
+ break;
case SAA7134_BOARD_KWORLD_PC150U:
/* copied and modified from MSI TV@nywhere Plus */
dev->init_data.name = "Kworld PC150-U";
diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c
index 21a579309575..38f94b742e28 100644
--- a/drivers/media/pci/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -192,7 +192,7 @@ static void mute_input_7134(struct saa7134_dev *dev)
in = dev->input;
mute = (dev->ctl_mute ||
(dev->automute && (&card(dev).radio) != in));
- if (card(dev).mute.name) {
+ if (card(dev).mute.type) {
/*
* 7130 - we'll mute using some unconnected audio input
* 7134 - we'll probably should switch external mux with gpio
@@ -204,13 +204,14 @@ static void mute_input_7134(struct saa7134_dev *dev)
if (dev->hw_mute == mute &&
dev->hw_input == in && !dev->insuspend) {
audio_dbg(1, "mute/input: nothing to do [mute=%d,input=%s]\n",
- mute, in->name);
+ mute, saa7134_input_name[in->type]);
return;
}
audio_dbg(1, "ctl_mute=%d automute=%d input=%s => mute=%d input=%s\n",
dev->ctl_mute, dev->automute,
- dev->input->name, mute, in->name);
+ saa7134_input_name[dev->input->type], mute,
+ saa7134_input_name[in->type]);
dev->hw_mute = mute;
dev->hw_input = in;
@@ -245,7 +246,7 @@ static void mute_input_7134(struct saa7134_dev *dev)
mask = card(dev).gpiomask;
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
- saa7134_track_gpio(dev,in->name);
+ saa7134_track_gpio(dev, saa7134_input_name[in->type]);
}
static void tvaudio_setmode(struct saa7134_dev *dev,
@@ -756,14 +757,14 @@ static int mute_input_7133(struct saa7134_dev *dev)
if (0 != card(dev).gpiomask) {
mask = card(dev).gpiomask;
- if (card(dev).mute.name && dev->ctl_mute)
+ if (card(dev).mute.type && dev->ctl_mute)
in = &card(dev).mute;
else
in = dev->input;
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
- saa7134_track_gpio(dev,in->name);
+ saa7134_track_gpio(dev, saa7134_input_name[in->type]);
}
return 0;
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index a63c1366a64e..ffa39543eb65 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -409,7 +409,8 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
static void video_mux(struct saa7134_dev *dev, int input)
{
- video_dbg("video input = %d [%s]\n", input, card_in(dev, input).name);
+ video_dbg("video input = %d [%s]\n",
+ input, saa7134_input_name[card_in(dev, input).type]);
dev->ctl_input = input;
set_tvnorm(dev, dev->tvnorm);
saa7134_tvaudio_setinput(dev, &card_in(dev, input));
@@ -478,8 +479,7 @@ void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
{
saa7134_set_decoder(dev);
- if (card_in(dev, dev->ctl_input).tv)
- saa_call_all(dev, video, s_std, dev->tvnorm->id);
+ saa_call_all(dev, video, s_std, dev->tvnorm->id);
/* Set the correct norm for the saa6752hs. This function
does nothing if there is no saa6752hs. */
saa_call_empress(dev, video, s_std, dev->tvnorm->id);
@@ -785,6 +785,63 @@ static int stop_preview(struct saa7134_dev *dev)
return 0;
}
+/*
+ * Media Controller helper functions
+ */
+
+static int saa7134_enable_analog_tuner(struct saa7134_dev *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev = dev->media_dev;
+ struct media_entity *source;
+ struct media_link *link, *found_link = NULL;
+ int ret, active_links = 0;
+
+ if (!mdev || !dev->decoder)
+ return 0;
+
+ /*
+ * This will find the tuner that is connected into the decoder.
+ * Technically, this is not 100% correct, as the device may be
+ * using an analog input instead of the tuner. However, as we can't
+ * do DVB streaming while the DMA engine is being used for V4L2,
+ * this should be enough for the actual needs.
+ */
+ list_for_each_entry(link, &dev->decoder->links, list) {
+ if (link->sink->entity == dev->decoder) {
+ found_link = link;
+ if (link->flags & MEDIA_LNK_FL_ENABLED)
+ active_links++;
+ break;
+ }
+ }
+
+ if (active_links == 1 || !found_link)
+ return 0;
+
+ source = found_link->source->entity;
+ list_for_each_entry(link, &source->links, list) {
+ struct media_entity *sink;
+ int flags = 0;
+
+ sink = link->sink->entity;
+
+ if (sink == dev->decoder)
+ flags = MEDIA_LNK_FL_ENABLED;
+
+ ret = media_entity_setup_link(link, flags);
+ if (ret) {
+ pr_err("Couldn't change link %s->%s to %s. Error %d\n",
+ source->name, sink->name,
+ flags ? "enabled" : "disabled",
+ ret);
+ return ret;
+ }
+ }
+#endif
+ return 0;
+}
+
/* ------------------------------------------------------------------ */
static int buffer_activate(struct saa7134_dev *dev,
@@ -924,6 +981,9 @@ static int queue_setup(struct vb2_queue *q,
*nplanes = 1;
sizes[0] = size;
alloc_ctxs[0] = dev->alloc_ctx;
+
+ saa7134_enable_analog_tuner(dev);
+
return 0;
}
@@ -1219,10 +1279,13 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.height = dev->height;
f->fmt.pix.field = dev->field;
f->fmt.pix.pixelformat = dev->fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * dev->fmt->depth) >> 3;
+ if (dev->fmt->planar)
+ f->fmt.pix.bytesperline = f->fmt.pix.width;
+ else
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * dev->fmt->depth) / 8;
f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ (f->fmt.pix.height * f->fmt.pix.width * dev->fmt->depth) / 8;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
@@ -1298,10 +1361,13 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
if (f->fmt.pix.height > maxh)
f->fmt.pix.height = maxh;
f->fmt.pix.width &= ~0x03;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
+ if (fmt->planar)
+ f->fmt.pix.bytesperline = f->fmt.pix.width;
+ else
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) / 8;
f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ (f->fmt.pix.height * f->fmt.pix.width * fmt->depth) / 8;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
@@ -1381,13 +1447,19 @@ int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i)
n = i->index;
if (n >= SAA7134_INPUT_MAX)
return -EINVAL;
- if (NULL == card_in(dev, i->index).name)
+ if (card_in(dev, i->index).type == SAA7134_NO_INPUT)
return -EINVAL;
i->index = n;
- i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name, card_in(dev, n).name);
- if (card_in(dev, n).tv)
+ strcpy(i->name, saa7134_input_name[card_in(dev, n).type]);
+ switch (card_in(dev, n).type) {
+ case SAA7134_INPUT_TV:
+ case SAA7134_INPUT_TV_MONO:
i->type = V4L2_INPUT_TYPE_TUNER;
+ break;
+ default:
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ break;
+ }
if (n == dev->ctl_input) {
int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
@@ -1419,7 +1491,7 @@ int saa7134_s_input(struct file *file, void *priv, unsigned int i)
if (i >= SAA7134_INPUT_MAX)
return -EINVAL;
- if (NULL == card_in(dev, i).name)
+ if (card_in(dev, i).type == SAA7134_NO_INPUT)
return -EINVAL;
video_mux(dev, i);
return 0;
@@ -1656,12 +1728,13 @@ int saa7134_g_tuner(struct file *file, void *priv,
return -EINVAL;
memset(t, 0, sizeof(*t));
for (n = 0; n < SAA7134_INPUT_MAX; n++) {
- if (card_in(dev, n).tv)
+ if (card_in(dev, n).type == SAA7134_INPUT_TV ||
+ card_in(dev, n).type == SAA7134_INPUT_TV_MONO)
break;
}
if (n == SAA7134_INPUT_MAX)
return -EINVAL;
- if (NULL != card_in(dev, n).name) {
+ if (card_in(dev, n).type != SAA7134_NO_INPUT) {
strcpy(t->name, "Television");
t->type = V4L2_TUNER_ANALOG_TV;
saa_call_all(dev, tuner, g_tuner, t);
@@ -1906,6 +1979,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_s_std = saa7134_s_std,
.vidioc_g_std = saa7134_g_std,
.vidioc_querystd = saa7134_querystd,
@@ -2089,7 +2163,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
* USERPTR support is a no-go unless the application knows about these
* limitations and has special support for this.
*/
- q->io_modes = VB2_MMAP | VB2_READ;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
if (saa7134_userptr)
q->io_modes |= VB2_USERPTR;
q->drv_priv = &dev->video_q;
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 5938bc781999..69a9bbf22d4d 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -343,6 +343,7 @@ struct saa7134_card_ir {
#define SAA7134_BOARD_WIS_VOYAGER 193
#define SAA7134_BOARD_AVERMEDIA_505 194
#define SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM 195
+#define SAA7134_BOARD_SNAZIO_TVPVR_PRO 196
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -361,12 +362,29 @@ struct saa7134_card_ir {
#define SET_CLOCK_INVERTED (1 << 2)
#define SET_VSYNC_OFF (1 << 3)
+enum saa7134_input_types {
+ SAA7134_NO_INPUT = 0,
+ SAA7134_INPUT_MUTE,
+ SAA7134_INPUT_RADIO,
+ SAA7134_INPUT_TV,
+ SAA7134_INPUT_TV_MONO,
+ SAA7134_INPUT_COMPOSITE,
+ SAA7134_INPUT_COMPOSITE0,
+ SAA7134_INPUT_COMPOSITE1,
+ SAA7134_INPUT_COMPOSITE2,
+ SAA7134_INPUT_COMPOSITE3,
+ SAA7134_INPUT_COMPOSITE4,
+ SAA7134_INPUT_SVIDEO,
+ SAA7134_INPUT_SVIDEO0,
+ SAA7134_INPUT_SVIDEO1,
+ SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+};
+
struct saa7134_input {
- char *name;
- unsigned int vmux;
- enum saa7134_audio_in amux;
- unsigned int gpio;
- unsigned int tv:1;
+ enum saa7134_input_types type;
+ unsigned int vmux;
+ enum saa7134_audio_in amux;
+ unsigned int gpio;
};
enum saa7134_mpeg_type {
@@ -410,7 +428,7 @@ struct saa7134_board {
unsigned int ts_force_val:1;
};
-#define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name)
+#define card_has_radio(dev) (SAA7134_NO_INPUT != saa7134_boards[dev->board].radio.type)
#define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
#define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg)
#define card_is_go7007(dev) (SAA7134_MPEG_GO7007 == saa7134_boards[dev->board].mpeg)
@@ -654,6 +672,19 @@ struct saa7134_dev {
/* I2C keyboard data */
struct IR_i2c_init_data init_data;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *media_dev;
+
+ struct media_entity input_ent[SAA7134_INPUT_MAX + 1];
+ struct media_pad input_pad[SAA7134_INPUT_MAX + 1];
+
+ struct media_entity demod;
+ struct media_pad demod_pad[DEMOD_NUM_PADS];
+
+ struct media_pad video_pad, vbi_pad;
+ struct media_entity *decoder;
+#endif
+
#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
/* SAA7134_MPEG_DVB only */
struct vb2_dvb_frontends frontends;
@@ -727,7 +758,7 @@ extern struct mutex saa7134_devlist_lock;
extern int saa7134_no_overlay;
extern bool saa7134_userptr;
-void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
+void saa7134_track_gpio(struct saa7134_dev *dev, const char *msg);
void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
#define SAA7134_PGTABLE_SIZE 4096
@@ -760,6 +791,7 @@ extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
/* saa7134-cards.c */
extern struct saa7134_board saa7134_boards[];
+extern const char * const saa7134_input_name[];
extern const unsigned int saa7134_bcount;
extern struct pci_device_id saa7134_pci_tbl[];
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index a69dc6a0752b..382caf200ba1 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -1739,7 +1739,7 @@ static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct fir
#endif
}
-static struct sp8870_config alps_tdlb7_config = {
+static const struct sp8870_config alps_tdlb7_config = {
.demod_address = 0x71,
.request_firmware = alps_tdlb7_request_firmware,
@@ -2198,13 +2198,18 @@ static int frontend_init(struct av7110 *av7110)
break;
case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
+ {
+ struct dvb_frontend *fe;
+
// try ALPS TDLB7 first, then Grundig 29504-401
- av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap);
- if (av7110->fe) {
- av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+ fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+ av7110->fe = fe;
break;
}
- /* fall-thru */
+ }
+ /* fall-thru */
case 0x0008: // Hauppauge/TT DVB-T
// Grundig 29504-401
diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c
index de54310a2660..fb8ede5a1531 100644
--- a/drivers/media/pci/ttpci/budget.c
+++ b/drivers/media/pci/ttpci/budget.c
@@ -615,36 +615,50 @@ static void frontend_init(struct budget *budget)
break;
case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
- budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
- if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
+ {
+ struct dvb_frontend *fe;
+
+ fe = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
+ budget->dvb_frontend = fe;
+ if (dvb_attach(lnbp21_attach, fe, &budget->i2c_adap,
+ 0, 0) == NULL) {
printk("%s: No LNBP21 found!\n", __func__);
goto error_out;
}
break;
}
-
+ }
+ /* fall through */
case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)
+ {
+ struct dvb_frontend *fe;
+
// gpio2 is connected to CLB - reset it + leave it high
saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
msleep(1);
saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
msleep(1);
- budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)
+ fe = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
+ if (fe) {
+ budget->dvb_frontend = fe;
+ if (dvb_attach(tda826x_attach, fe, 0x60,
+ &budget->i2c_adap, 0) == NULL)
printk("%s: No tda826x found!\n", __func__);
- if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
+ if (dvb_attach(lnbp21_attach, fe,
+ &budget->i2c_adap, 0, 0) == NULL) {
printk("%s: No LNBP21 found!\n", __func__);
goto error_out;
}
break;
}
+ }
+ /* fall through */
case 0x101c: { /* TT S2-1600 */
- struct stv6110x_devctl *ctl;
+ const struct stv6110x_devctl *ctl;
saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
msleep(50);
saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
@@ -697,7 +711,7 @@ static void frontend_init(struct budget *budget)
break;
case 0x1020: { /* Omicom S2 */
- struct stv6110x_devctl *ctl;
+ const struct stv6110x_devctl *ctl;
saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
msleep(50);
saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 8b89ebe16d94..201f5c296a95 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -54,15 +54,6 @@ config VIDEO_VIU
Say Y here if you want to enable VIU device on MPC5121e Rev2+.
In doubt, say N.
-config VIDEO_TIMBERDALE
- tristate "Support for timberdale Video In/LogiWIN"
- depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && HAS_DMA
- depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST
- select VIDEO_ADV7180
- select VIDEOBUF_DMA_CONTIG
- ---help---
- Add support for the Video In peripherial of the timberdale FPGA.
-
config VIDEO_M32R_AR
tristate "AR devices"
depends on VIDEO_V4L2
@@ -120,6 +111,19 @@ source "drivers/media/platform/s5p-tv/Kconfig"
source "drivers/media/platform/am437x/Kconfig"
source "drivers/media/platform/xilinx/Kconfig"
+config VIDEO_TI_CAL
+ tristate "TI CAL (Camera Adaptation Layer) driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on SOC_DRA7XX || COMPILE_TEST
+ depends on HAS_DMA
+ select VIDEOBUF2_DMA_CONTIG
+ default n
+ ---help---
+ Support for the TI CAL (Camera Adaptation Layer) block
+ found on DRA72X SoC.
+ In TI Technical Reference Manual this module is referred as
+ Camera Interface Subsystem (CAMSS).
+
endif # V4L_PLATFORM_DRIVERS
menuconfig V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index efa0295af87b..bbb7bd1eb268 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -2,7 +2,6 @@
# Makefile for the video capture/playback device drivers.
#
-obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
@@ -18,6 +17,8 @@ obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o
obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe/
+obj-$(CONFIG_VIDEO_TI_CAL) += ti-vpe/
+
obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
obj-$(CONFIG_VIDEO_CODA) += coda/
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 7d28899f89ce..b6625047250d 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -1342,7 +1342,7 @@ static void coda_finish_encode(struct coda_ctx *ctx)
/* Calculate bytesused field */
if (dst_buf->sequence == 0) {
- vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr +
ctx->vpu_header_size[0] +
ctx->vpu_header_size[1] +
ctx->vpu_header_size[2]);
@@ -1455,9 +1455,9 @@ static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx,
return 0;
ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2);
- ctx->bitstream.vaddr = dma_alloc_writecombine(
- &ctx->dev->plat_dev->dev, ctx->bitstream.size,
- &ctx->bitstream.paddr, GFP_KERNEL);
+ ctx->bitstream.vaddr = dma_alloc_wc(&ctx->dev->plat_dev->dev,
+ ctx->bitstream.size,
+ &ctx->bitstream.paddr, GFP_KERNEL);
if (!ctx->bitstream.vaddr) {
v4l2_err(&ctx->dev->v4l2_dev,
"failed to allocate bitstream ringbuffer");
@@ -1474,8 +1474,8 @@ static void coda_free_bitstream_buffer(struct coda_ctx *ctx)
if (ctx->bitstream.vaddr == NULL)
return;
- dma_free_writecombine(&ctx->dev->plat_dev->dev, ctx->bitstream.size,
- ctx->bitstream.vaddr, ctx->bitstream.paddr);
+ dma_free_wc(&ctx->dev->plat_dev->dev, ctx->bitstream.size,
+ ctx->bitstream.vaddr, ctx->bitstream.paddr);
ctx->bitstream.vaddr = NULL;
kfifo_init(&ctx->bitstream_fifo, NULL, 0);
}
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 2d782ce94a67..133ab9f70f85 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -1950,16 +1950,76 @@ static int coda_register_device(struct coda_dev *dev, int i)
return video_register_device(vfd, VFL_TYPE_GRABBER, 0);
}
+static void coda_copy_firmware(struct coda_dev *dev, const u8 * const buf,
+ size_t size)
+{
+ u32 *src = (u32 *)buf;
+
+ /* Check if the firmware has a 16-byte Freescale header, skip it */
+ if (buf[0] == 'M' && buf[1] == 'X')
+ src += 4;
+ /*
+ * Check whether the firmware is in native order or pre-reordered for
+ * memory access. The first instruction opcode always is 0xe40e.
+ */
+ if (__le16_to_cpup((__le16 *)src) == 0xe40e) {
+ u32 *dst = dev->codebuf.vaddr;
+ int i;
+
+ /* Firmware in native order, reorder while copying */
+ if (dev->devtype->product == CODA_DX6) {
+ for (i = 0; i < (size - 16) / 4; i++)
+ dst[i] = (src[i] << 16) | (src[i] >> 16);
+ } else {
+ for (i = 0; i < (size - 16) / 4; i += 2) {
+ dst[i] = (src[i + 1] << 16) | (src[i + 1] >> 16);
+ dst[i + 1] = (src[i] << 16) | (src[i] >> 16);
+ }
+ }
+ } else {
+ /* Copy the already reordered firmware image */
+ memcpy(dev->codebuf.vaddr, src, size);
+ }
+}
+
+static void coda_fw_callback(const struct firmware *fw, void *context);
+
+static int coda_firmware_request(struct coda_dev *dev)
+{
+ char *fw = dev->devtype->firmware[dev->firmware];
+
+ dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
+ coda_product_name(dev->devtype->product));
+
+ return request_firmware_nowait(THIS_MODULE, true, fw,
+ &dev->plat_dev->dev, GFP_KERNEL, dev,
+ coda_fw_callback);
+}
+
static void coda_fw_callback(const struct firmware *fw, void *context)
{
struct coda_dev *dev = context;
struct platform_device *pdev = dev->plat_dev;
int i, ret;
- if (!fw) {
+ if (!fw && dev->firmware == 1) {
v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
goto put_pm;
}
+ if (!fw) {
+ dev->firmware = 1;
+ coda_firmware_request(dev);
+ return;
+ }
+ if (dev->firmware == 1) {
+ /*
+ * Since we can't suppress warnings for failed asynchronous
+ * firmware requests, report that the fallback firmware was
+ * found.
+ */
+ dev_info(&pdev->dev, "Using fallback firmware %s\n",
+ dev->devtype->firmware[dev->firmware]);
+ }
/* allocate auxiliary per-device code buffer for the BIT processor */
ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf",
@@ -1967,8 +2027,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
if (ret < 0)
goto put_pm;
- /* Copy the whole firmware image to the code buffer */
- memcpy(dev->codebuf.vaddr, fw->data, fw->size);
+ coda_copy_firmware(dev, fw->data, fw->size);
release_firmware(fw);
ret = coda_hw_init(dev);
@@ -2019,17 +2078,6 @@ put_pm:
pm_runtime_put_sync(&pdev->dev);
}
-static int coda_firmware_request(struct coda_dev *dev)
-{
- char *fw = dev->devtype->firmware;
-
- dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
- coda_product_name(dev->devtype->product));
-
- return request_firmware_nowait(THIS_MODULE, true,
- fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
-}
-
enum coda_platform {
CODA_IMX27,
CODA_IMX53,
@@ -2039,7 +2087,10 @@ enum coda_platform {
static const struct coda_devtype coda_devdata[] = {
[CODA_IMX27] = {
- .firmware = "v4l-codadx6-imx27.bin",
+ .firmware = {
+ "vpu_fw_imx27_TO2.bin",
+ "v4l-codadx6-imx27.bin"
+ },
.product = CODA_DX6,
.codecs = codadx6_codecs,
.num_codecs = ARRAY_SIZE(codadx6_codecs),
@@ -2049,7 +2100,10 @@ static const struct coda_devtype coda_devdata[] = {
.iram_size = 0xb000,
},
[CODA_IMX53] = {
- .firmware = "v4l-coda7541-imx53.bin",
+ .firmware = {
+ "vpu_fw_imx53.bin",
+ "v4l-coda7541-imx53.bin"
+ },
.product = CODA_7541,
.codecs = coda7_codecs,
.num_codecs = ARRAY_SIZE(coda7_codecs),
@@ -2060,7 +2114,10 @@ static const struct coda_devtype coda_devdata[] = {
.iram_size = 0x14000,
},
[CODA_IMX6Q] = {
- .firmware = "v4l-coda960-imx6q.bin",
+ .firmware = {
+ "vpu_fw_imx6q.bin",
+ "v4l-coda960-imx6q.bin"
+ },
.product = CODA_960,
.codecs = coda9_codecs,
.num_codecs = ARRAY_SIZE(coda9_codecs),
@@ -2071,7 +2128,10 @@ static const struct coda_devtype coda_devdata[] = {
.iram_size = 0x21000,
},
[CODA_IMX6DL] = {
- .firmware = "v4l-coda960-imx6dl.bin",
+ .firmware = {
+ "vpu_fw_imx6d.bin",
+ "v4l-coda960-imx6dl.bin"
+ },
.product = CODA_960,
.codecs = coda9_codecs,
.num_codecs = ARRAY_SIZE(coda9_codecs),
@@ -2118,14 +2178,12 @@ static int coda_probe(struct platform_device *pdev)
pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
- if (of_id) {
+ if (of_id)
dev->devtype = of_id->data;
- } else if (pdev_id) {
+ else if (pdev_id)
dev->devtype = &coda_devdata[pdev_id->driver_data];
- } else {
- ret = -EINVAL;
- goto err_v4l2_register;
- }
+ else
+ return -EINVAL;
spin_lock_init(&dev->irqlock);
INIT_LIST_HEAD(&dev->instances);
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index d08e9843e9f2..8f2c71e06966 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -50,7 +50,7 @@ enum coda_product {
struct coda_video_device;
struct coda_devtype {
- char *firmware;
+ char *firmware[2];
enum coda_product product;
const struct coda_codec *codecs;
unsigned int num_codecs;
@@ -74,6 +74,7 @@ struct coda_dev {
struct video_device vfd[5];
struct platform_device *plat_dev;
const struct coda_devtype *devtype;
+ int firmware;
void __iomem *regs_base;
struct clk *clk_per;
diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c
index ffbefdff6b5e..6fba32bec974 100644
--- a/drivers/media/platform/davinci/dm644x_ccdc.c
+++ b/drivers/media/platform/davinci/dm644x_ccdc.c
@@ -261,7 +261,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
*/
if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
if (fpc_physaddr != NULL) {
- free_pages((unsigned long)fpc_physaddr,
+ free_pages((unsigned long)fpc_virtaddr,
get_order
(config_params->fault_pxl.fp_num *
FP_NUM_BYTES));
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index 93782f15b825..a600e32e2543 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -700,7 +700,7 @@ static unsigned int gsc_m2m_poll(struct file *file,
{
struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
struct gsc_dev *gsc = ctx->gsc_dev;
- int ret;
+ unsigned int ret;
if (mutex_lock_interruptible(&gsc->lock))
return -ERESTARTSYS;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index e85649147dc8..dc1b929f7a33 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -992,10 +992,6 @@ static int fimc_lite_link_setup(struct media_entity *entity,
switch (local->index) {
case FLITE_SD_PAD_SINK:
- if (!is_media_entity_v4l2_subdev(remote->entity)) {
- ret = -EINVAL;
- break;
- }
if (flags & MEDIA_LNK_FL_ENABLED) {
if (fimc->source_subdev_grp_id == 0)
fimc->source_subdev_grp_id = sd->grp_id;
@@ -1010,19 +1006,15 @@ static int fimc_lite_link_setup(struct media_entity *entity,
case FLITE_SD_PAD_SOURCE_DMA:
if (!(flags & MEDIA_LNK_FL_ENABLED))
atomic_set(&fimc->out_path, FIMC_IO_NONE);
- else if (is_media_entity_v4l2_io(remote->entity))
- atomic_set(&fimc->out_path, FIMC_IO_DMA);
else
- ret = -EINVAL;
+ atomic_set(&fimc->out_path, FIMC_IO_DMA);
break;
case FLITE_SD_PAD_SOURCE_ISP:
if (!(flags & MEDIA_LNK_FL_ENABLED))
atomic_set(&fimc->out_path, FIMC_IO_NONE);
- else if (is_media_entity_v4l2_subdev(remote->entity))
- atomic_set(&fimc->out_path, FIMC_IO_ISP);
else
- ret = -EINVAL;
+ atomic_set(&fimc->out_path, FIMC_IO_ISP);
break;
default:
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index e79ddbb1e14f..feb521f28e14 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -389,13 +389,19 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
struct fimc_source_info *pd = &fmd->sensor[index].pdata;
struct device_node *rem, *ep, *np;
struct v4l2_of_endpoint endpoint;
+ int ret;
/* Assume here a port node can have only one endpoint node. */
ep = of_get_next_child(port, NULL);
if (!ep)
return 0;
- v4l2_of_parse_endpoint(ep, &endpoint);
+ ret = v4l2_of_parse_endpoint(ep, &endpoint);
+ if (ret) {
+ of_node_put(ep);
+ return ret;
+ }
+
if (WARN_ON(endpoint.base.port == 0) || index >= FIMC_MAX_SENSORS)
return -EINVAL;
@@ -486,8 +492,10 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
continue;
ret = fimc_md_parse_port_node(fmd, port, index);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(node);
goto rpm_put;
+ }
index++;
}
@@ -498,8 +506,10 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
for_each_child_of_node(ports, node) {
ret = fimc_md_parse_port_node(fmd, node, index);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(node);
break;
+ }
index++;
}
rpm_put:
@@ -707,8 +717,10 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd,
ret = fimc_md_register_platform_entity(fmd, pdev,
plat_entity);
put_device(&pdev->dev);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(node);
break;
+ }
}
return ret;
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index ac5e50e595be..bd5c46c3d4b7 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -736,6 +736,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
{
struct device_node *node = pdev->dev.of_node;
struct v4l2_of_endpoint endpoint;
+ int ret;
if (of_property_read_u32(node, "clock-frequency",
&state->clk_frequency))
@@ -751,7 +752,9 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
return -EINVAL;
}
/* Get port node and validate MIPI-CSI channel id. */
- v4l2_of_parse_endpoint(node, &endpoint);
+ ret = v4l2_of_parse_endpoint(node, &endpoint);
+ if (ret)
+ goto err;
state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0;
if (state->index >= CSIS_MAX_ENTITIES)
@@ -764,9 +767,10 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
"samsung,csis-wclk");
state->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes;
- of_node_put(node);
- return 0;
+err:
+ of_node_put(node);
+ return ret;
}
static int s5pcsis_pm_resume(struct device *dev, bool runtime);
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 0bcfa553c1aa..5d54e2c6c16b 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -64,6 +64,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-mc.h>
#include <media/v4l2-of.h>
#include "isp.h"
@@ -449,7 +450,7 @@ void omap3isp_configure_bridge(struct isp_device *isp,
case CCDC_INPUT_PARALLEL:
ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
ispctrl_val |= parcfg->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
- shift += parcfg->data_lane_shift * 2;
+ shift += parcfg->data_lane_shift;
break;
case CCDC_INPUT_CSI2A:
@@ -657,216 +658,6 @@ static irqreturn_t isp_isr(int irq, void *_isp)
}
/* -----------------------------------------------------------------------------
- * Pipeline power management
- *
- * Entities must be powered up when part of a pipeline that contains at least
- * one open video device node.
- *
- * To achieve this use the entity use_count field to track the number of users.
- * For entities corresponding to video device nodes the use_count field stores
- * the users count of the node. For entities corresponding to subdevs the
- * use_count field stores the total number of users of all video device nodes
- * in the pipeline.
- *
- * The omap3isp_pipeline_pm_use() function must be called in the open() and
- * close() handlers of video device nodes. It increments or decrements the use
- * count of all subdev entities in the pipeline.
- *
- * To react to link management on powered pipelines, the link setup notification
- * callback updates the use count of all entities in the source and sink sides
- * of the link.
- */
-
-/*
- * isp_pipeline_pm_use_count - Count the number of users of a pipeline
- * @entity: The entity
- *
- * Return the total number of users of all video device nodes in the pipeline.
- */
-static int isp_pipeline_pm_use_count(struct media_entity *entity,
- struct media_entity_graph *graph)
-{
- int use = 0;
-
- media_entity_graph_walk_start(graph, entity);
-
- while ((entity = media_entity_graph_walk_next(graph))) {
- if (is_media_entity_v4l2_io(entity))
- use += entity->use_count;
- }
-
- return use;
-}
-
-/*
- * isp_pipeline_pm_power_one - Apply power change to an entity
- * @entity: The entity
- * @change: Use count change
- *
- * Change the entity use count by @change. If the entity is a subdev update its
- * power state by calling the core::s_power operation when the use count goes
- * from 0 to != 0 or from != 0 to 0.
- *
- * Return 0 on success or a negative error code on failure.
- */
-static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
-{
- struct v4l2_subdev *subdev;
- int ret;
-
- subdev = is_media_entity_v4l2_subdev(entity)
- ? media_entity_to_v4l2_subdev(entity) : NULL;
-
- if (entity->use_count == 0 && change > 0 && subdev != NULL) {
- ret = v4l2_subdev_call(subdev, core, s_power, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
- }
-
- entity->use_count += change;
- WARN_ON(entity->use_count < 0);
-
- if (entity->use_count == 0 && change < 0 && subdev != NULL)
- v4l2_subdev_call(subdev, core, s_power, 0);
-
- return 0;
-}
-
-/*
- * isp_pipeline_pm_power - Apply power change to all entities in a pipeline
- * @entity: The entity
- * @change: Use count change
- *
- * Walk the pipeline to update the use count and the power state of all non-node
- * entities.
- *
- * Return 0 on success or a negative error code on failure.
- */
-static int isp_pipeline_pm_power(struct media_entity *entity, int change,
- struct media_entity_graph *graph)
-{
- struct media_entity *first = entity;
- int ret = 0;
-
- if (!change)
- return 0;
-
- media_entity_graph_walk_start(graph, entity);
-
- while (!ret && (entity = media_entity_graph_walk_next(graph)))
- if (is_media_entity_v4l2_subdev(entity))
- ret = isp_pipeline_pm_power_one(entity, change);
-
- if (!ret)
- return ret;
-
- media_entity_graph_walk_start(graph, first);
-
- while ((first = media_entity_graph_walk_next(graph))
- && first != entity)
- if (is_media_entity_v4l2_subdev(first))
- isp_pipeline_pm_power_one(first, -change);
-
- return ret;
-}
-
-/*
- * omap3isp_pipeline_pm_use - Update the use count of an entity
- * @entity: The entity
- * @use: Use (1) or stop using (0) the entity
- *
- * Update the use count of all entities in the pipeline and power entities on or
- * off accordingly.
- *
- * Return 0 on success or a negative error code on failure. Powering entities
- * off is assumed to never fail. No failure can occur when the use parameter is
- * set to 0.
- */
-int omap3isp_pipeline_pm_use(struct media_entity *entity, int use,
- struct media_entity_graph *graph)
-{
- int change = use ? 1 : -1;
- int ret;
-
- mutex_lock(&entity->graph_obj.mdev->graph_mutex);
-
- /* Apply use count to node. */
- entity->use_count += change;
- WARN_ON(entity->use_count < 0);
-
- /* Apply power change to connected non-nodes. */
- ret = isp_pipeline_pm_power(entity, change, graph);
- if (ret < 0)
- entity->use_count -= change;
-
- mutex_unlock(&entity->graph_obj.mdev->graph_mutex);
-
- return ret;
-}
-
-/*
- * isp_pipeline_link_notify - Link management notification callback
- * @link: The link
- * @flags: New link flags that will be applied
- * @notification: The link's state change notification type (MEDIA_DEV_NOTIFY_*)
- *
- * React to link management on powered pipelines by updating the use count of
- * all entities in the source and sink sides of the link. Entities are powered
- * on or off accordingly.
- *
- * Return 0 on success or a negative error code on failure. Powering entities
- * off is assumed to never fail. This function will not fail for disconnection
- * events.
- */
-static int isp_pipeline_link_notify(struct media_link *link, u32 flags,
- unsigned int notification)
-{
- struct media_entity_graph *graph =
- &container_of(link->graph_obj.mdev, struct isp_device,
- media_dev)->pm_count_graph;
- struct media_entity *source = link->source->entity;
- struct media_entity *sink = link->sink->entity;
- int source_use;
- int sink_use;
- int ret = 0;
-
- if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
- ret = media_entity_graph_walk_init(graph,
- link->graph_obj.mdev);
- if (ret)
- return ret;
- }
-
- source_use = isp_pipeline_pm_use_count(source, graph);
- sink_use = isp_pipeline_pm_use_count(sink, graph);
-
- if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
- !(flags & MEDIA_LNK_FL_ENABLED)) {
- /* Powering off entities is assumed to never fail. */
- isp_pipeline_pm_power(source, -sink_use, graph);
- isp_pipeline_pm_power(sink, -source_use, graph);
- return 0;
- }
-
- if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
- (flags & MEDIA_LNK_FL_ENABLED)) {
-
- ret = isp_pipeline_pm_power(source, sink_use, graph);
- if (ret < 0)
- return ret;
-
- ret = isp_pipeline_pm_power(sink, source_use, graph);
- if (ret < 0)
- isp_pipeline_pm_power(source, -sink_use, graph);
- }
-
- if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH)
- media_entity_graph_walk_cleanup(graph);
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
* Pipeline stream management
*/
@@ -1889,7 +1680,7 @@ static int isp_register_entities(struct isp_device *isp)
strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
sizeof(isp->media_dev.model));
isp->media_dev.hw_revision = isp->revision;
- isp->media_dev.link_notify = isp_pipeline_link_notify;
+ isp->media_dev.link_notify = v4l2_pipeline_link_notify;
media_device_init(&isp->media_dev);
isp->v4l2_dev.mdev = &isp->media_dev;
@@ -2235,8 +2026,11 @@ static int isp_of_parse_node(struct device *dev, struct device_node *node,
struct isp_bus_cfg *buscfg = &isd->bus;
struct v4l2_of_endpoint vep;
unsigned int i;
+ int ret;
- v4l2_of_parse_endpoint(node, &vep);
+ ret = v4l2_of_parse_endpoint(node, &vep);
+ if (ret)
+ return ret;
dev_dbg(dev, "parsing endpoint %s, interface %u\n", node->full_name,
vep.base.port);
@@ -2528,12 +2322,13 @@ static int isp_probe(struct platform_device *pdev)
}
/* Interrupt */
- isp->irq_num = platform_get_irq(pdev, 0);
- if (isp->irq_num <= 0) {
+ ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
dev_err(isp->dev, "No IRQ resource\n");
ret = -ENODEV;
goto error_iommu;
}
+ isp->irq_num = ret;
if (devm_request_irq(isp->dev, isp->irq_num, isp_isr, IRQF_SHARED,
"OMAP3 ISP", isp)) {
@@ -2599,6 +2394,7 @@ static const struct of_device_id omap3isp_of_table[] = {
{ .compatible = "ti,omap3-isp" },
{ },
};
+MODULE_DEVICE_TABLE(of, omap3isp_of_table);
static struct platform_driver omap3isp_driver = {
.probe = isp_probe,
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
index 49b7f71ac968..7e6f6638433b 100644
--- a/drivers/media/platform/omap3isp/isp.h
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -177,7 +177,6 @@ struct isp_device {
struct v4l2_device v4l2_dev;
struct v4l2_async_notifier notifier;
struct media_device media_dev;
- struct media_entity_graph pm_count_graph;
struct device *dev;
u32 revision;
@@ -267,9 +266,6 @@ void omap3isp_subclk_enable(struct isp_device *isp,
void omap3isp_subclk_disable(struct isp_device *isp,
enum isp_subclk_resource res);
-int omap3isp_pipeline_pm_use(struct media_entity *entity, int use,
- struct media_entity_graph *graph);
-
int omap3isp_register_entities(struct platform_device *pdev,
struct v4l2_device *v4l2_dev);
void omap3isp_unregister_entities(struct platform_device *pdev);
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index bb3974c98e37..882310eb45cc 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -2421,7 +2421,7 @@ static int ccdc_link_validate(struct v4l2_subdev *sd,
&((struct isp_bus_cfg *)
media_entity_to_v4l2_subdev(link->source->entity)
->host_priv)->bus.parallel;
- parallel_shift = parcfg->data_lane_shift * 2;
+ parallel_shift = parcfg->data_lane_shift;
} else {
parallel_shift = 0;
}
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 84a96670e2e7..ac30a0f83780 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -1480,13 +1480,6 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
struct isp_buffer *buffer;
int restart = 0;
- if (prev->input == PREVIEW_INPUT_MEMORY) {
- buffer = omap3isp_video_buffer_next(&prev->video_in);
- if (buffer != NULL)
- preview_set_inaddr(prev, buffer->dma);
- pipe->state |= ISP_PIPELINE_IDLE_INPUT;
- }
-
if (prev->output & PREVIEW_OUTPUT_MEMORY) {
buffer = omap3isp_video_buffer_next(&prev->video_out);
if (buffer != NULL) {
@@ -1496,6 +1489,13 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
}
+ if (prev->input == PREVIEW_INPUT_MEMORY) {
+ buffer = omap3isp_video_buffer_next(&prev->video_in);
+ if (buffer != NULL)
+ preview_set_inaddr(prev, buffer->dma);
+ pipe->state |= ISP_PIPELINE_IDLE_INPUT;
+ }
+
switch (prev->state) {
case ISP_PIPELINE_STREAM_SINGLESHOT:
if (isp_pipeline_ready(pipe))
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 994dfc0813f6..ac76d2901501 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -22,8 +22,10 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
#include <media/videobuf2-dma-contig.h>
#include "ispvideo.h"
@@ -434,10 +436,68 @@ static void isp_video_buffer_queue(struct vb2_buffer *buf)
}
}
+/*
+ * omap3isp_video_return_buffers - Return all queued buffers to videobuf2
+ * @video: ISP video object
+ * @state: new state for the returned buffers
+ *
+ * Return all buffers queued on the video node to videobuf2 in the given state.
+ * The buffer state should be VB2_BUF_STATE_QUEUED if called due to an error
+ * when starting the stream, or VB2_BUF_STATE_ERROR otherwise.
+ *
+ * The function must be called with the video irqlock held.
+ */
+static void omap3isp_video_return_buffers(struct isp_video *video,
+ enum vb2_buffer_state state)
+{
+ while (!list_empty(&video->dmaqueue)) {
+ struct isp_buffer *buf;
+
+ buf = list_first_entry(&video->dmaqueue,
+ struct isp_buffer, irqlist);
+ list_del(&buf->irqlist);
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
+}
+
+static int isp_video_start_streaming(struct vb2_queue *queue,
+ unsigned int count)
+{
+ struct isp_video_fh *vfh = vb2_get_drv_priv(queue);
+ struct isp_video *video = vfh->video;
+ struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+ unsigned long flags;
+ int ret;
+
+ /* In sensor-to-memory mode, the stream can be started synchronously
+ * to the stream on command. In memory-to-memory mode, it will be
+ * started when buffers are queued on both the input and output.
+ */
+ if (pipe->input)
+ return 0;
+
+ ret = omap3isp_pipeline_set_stream(pipe,
+ ISP_PIPELINE_STREAM_CONTINUOUS);
+ if (ret < 0) {
+ spin_lock_irqsave(&video->irqlock, flags);
+ omap3isp_video_return_buffers(video, VB2_BUF_STATE_QUEUED);
+ spin_unlock_irqrestore(&video->irqlock, flags);
+ return ret;
+ }
+
+ spin_lock_irqsave(&video->irqlock, flags);
+ if (list_empty(&video->dmaqueue))
+ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+ spin_unlock_irqrestore(&video->irqlock, flags);
+
+ return 0;
+}
+
static const struct vb2_ops isp_video_queue_ops = {
.queue_setup = isp_video_queue_setup,
.buf_prepare = isp_video_buffer_prepare,
.buf_queue = isp_video_buffer_queue,
+ .start_streaming = isp_video_start_streaming,
};
/*
@@ -459,7 +519,7 @@ static const struct vb2_ops isp_video_queue_ops = {
struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
{
struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
- enum isp_pipeline_state state;
+ enum vb2_buffer_state vb_state;
struct isp_buffer *buf;
unsigned long flags;
@@ -495,17 +555,19 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
/* Report pipeline errors to userspace on the capture device side. */
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
- state = VB2_BUF_STATE_ERROR;
+ vb_state = VB2_BUF_STATE_ERROR;
pipe->error = false;
} else {
- state = VB2_BUF_STATE_DONE;
+ vb_state = VB2_BUF_STATE_DONE;
}
- vb2_buffer_done(&buf->vb.vb2_buf, state);
+ vb2_buffer_done(&buf->vb.vb2_buf, vb_state);
spin_lock_irqsave(&video->irqlock, flags);
if (list_empty(&video->dmaqueue)) {
+ enum isp_pipeline_state state;
+
spin_unlock_irqrestore(&video->irqlock, flags);
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -541,26 +603,16 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
* omap3isp_video_cancel_stream - Cancel stream on a video node
* @video: ISP video object
*
- * Cancelling a stream mark all buffers on the video node as erroneous and makes
- * sure no new buffer can be queued.
+ * Cancelling a stream returns all buffers queued on the video node to videobuf2
+ * in the erroneous state and makes sure no new buffer can be queued.
*/
void omap3isp_video_cancel_stream(struct isp_video *video)
{
unsigned long flags;
spin_lock_irqsave(&video->irqlock, flags);
-
- while (!list_empty(&video->dmaqueue)) {
- struct isp_buffer *buf;
-
- buf = list_first_entry(&video->dmaqueue,
- struct isp_buffer, irqlist);
- list_del(&buf->irqlist);
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- }
-
+ omap3isp_video_return_buffers(video, VB2_BUF_STATE_ERROR);
video->error = true;
-
spin_unlock_irqrestore(&video->irqlock, flags);
}
@@ -1087,29 +1139,10 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
if (ret < 0)
goto err_check_format;
- /* In sensor-to-memory mode, the stream can be started synchronously
- * to the stream on command. In memory-to-memory mode, it will be
- * started when buffers are queued on both the input and output.
- */
- if (pipe->input == NULL) {
- ret = omap3isp_pipeline_set_stream(pipe,
- ISP_PIPELINE_STREAM_CONTINUOUS);
- if (ret < 0)
- goto err_set_stream;
- spin_lock_irqsave(&video->irqlock, flags);
- if (list_empty(&video->dmaqueue))
- video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
- spin_unlock_irqrestore(&video->irqlock, flags);
- }
-
mutex_unlock(&video->stream_lock);
return 0;
-err_set_stream:
- mutex_lock(&video->queue_lock);
- vb2_streamoff(&vfh->queue, type);
- mutex_unlock(&video->queue_lock);
err_check_format:
media_entity_pipeline_stop(&video->video.entity);
err_pipeline_start:
@@ -1261,12 +1294,7 @@ static int isp_video_open(struct file *file)
goto done;
}
- ret = media_entity_graph_walk_init(&handle->graph,
- &video->isp->media_dev);
- if (ret)
- goto done;
-
- ret = omap3isp_pipeline_pm_use(&video->video.entity, 1, &handle->graph);
+ ret = v4l2_pipeline_pm_use(&video->video.entity, 1);
if (ret < 0) {
omap3isp_put(video->isp);
goto done;
@@ -1297,7 +1325,6 @@ static int isp_video_open(struct file *file)
done:
if (ret < 0) {
v4l2_fh_del(&handle->vfh);
- media_entity_graph_walk_cleanup(&handle->graph);
kfree(handle);
}
@@ -1317,8 +1344,7 @@ static int isp_video_release(struct file *file)
vb2_queue_release(&handle->queue);
mutex_unlock(&video->queue_lock);
- omap3isp_pipeline_pm_use(&video->video.entity, 0, &handle->graph);
- media_entity_graph_walk_cleanup(&handle->graph);
+ v4l2_pipeline_pm_use(&video->video.entity, 0);
/* Release the file handle. */
v4l2_fh_del(vfh);
diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
index 156429878d64..6a48d5879c56 100644
--- a/drivers/media/platform/omap3isp/ispvideo.h
+++ b/drivers/media/platform/omap3isp/ispvideo.h
@@ -189,7 +189,6 @@ struct isp_video_fh {
struct vb2_queue queue;
struct v4l2_format format;
struct v4l2_fract timeperframe;
- struct media_entity_graph graph;
};
#define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh)
diff --git a/drivers/media/platform/omap3isp/omap3isp.h b/drivers/media/platform/omap3isp/omap3isp.h
index 190e259a6a2d..443e8f7673e2 100644
--- a/drivers/media/platform/omap3isp/omap3isp.h
+++ b/drivers/media/platform/omap3isp/omap3isp.h
@@ -33,9 +33,9 @@ enum isp_interface_type {
* struct isp_parallel_cfg - Parallel interface configuration
* @data_lane_shift: Data lane shifter
* 0 - CAMEXT[13:0] -> CAM[13:0]
- * 1 - CAMEXT[13:2] -> CAM[11:0]
- * 2 - CAMEXT[13:4] -> CAM[9:0]
- * 3 - CAMEXT[13:6] -> CAM[7:0]
+ * 2 - CAMEXT[13:2] -> CAM[11:0]
+ * 4 - CAMEXT[13:4] -> CAM[9:0]
+ * 6 - CAMEXT[13:6] -> CAM[7:0]
* @clk_pol: Pixel clock polarity
* 0 - Sample on rising edge, 1 - Sample on falling edge
* @hs_pol: Horizontal synchronization polarity
@@ -48,7 +48,7 @@ enum isp_interface_type {
* 0 - Normal, 1 - One's complement
*/
struct isp_parallel_cfg {
- unsigned int data_lane_shift:2;
+ unsigned int data_lane_shift:3;
unsigned int clk_pol:1;
unsigned int hs_pol:1;
unsigned int vs_pol:1;
diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c
index 485f5259acb0..552789a69c86 100644
--- a/drivers/media/platform/rcar_jpu.c
+++ b/drivers/media/platform/rcar_jpu.c
@@ -1613,6 +1613,7 @@ static const struct of_device_id jpu_dt_ids[] = {
{ .compatible = "renesas,jpu-r8a7791" }, /* M2-W */
{ .compatible = "renesas,jpu-r8a7792" }, /* V2H */
{ .compatible = "renesas,jpu-r8a7793" }, /* M2-N */
+ { .compatible = "renesas,rcar-gen2-jpu" },
{ },
};
MODULE_DEVICE_TABLE(of, jpu_dt_ids);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 0434f02a7175..034b5c1d35a1 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -212,6 +212,14 @@ static struct mfc_control controls[] = {
.menu_skip_mask = 0,
},
{
+ .id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
.id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
@@ -1423,6 +1431,10 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
ctx->force_frame_type = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
+ ctx->force_frame_type =
+ V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME;
+ break;
case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
p->vbv_size = ctrl->val;
break;
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig
index f2776cd415ca..355298989dd8 100644
--- a/drivers/media/platform/soc_camera/Kconfig
+++ b/drivers/media/platform/soc_camera/Kconfig
@@ -17,19 +17,11 @@ config SOC_CAMERA_PLATFORM
help
This is a generic SoC camera platform driver, useful for testing
-config VIDEO_MX3
- tristate "i.MX3x Camera Sensor Interface driver"
- depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
- depends on MX3_IPU || COMPILE_TEST
- depends on HAS_DMA
- select VIDEOBUF2_DMA_CONTIG
- ---help---
- This is a v4l2 driver for the i.MX3x Camera Sensor Interface
-
config VIDEO_PXA27x
tristate "PXA27x Quick Capture Interface driver"
depends on VIDEO_DEV && PXA27x && SOC_CAMERA
select VIDEOBUF_DMA_SG
+ select SG_SPLIT
---help---
This is a v4l2 driver for the PXA27x Quick Capture Interface
@@ -60,25 +52,6 @@ config VIDEO_SH_MOBILE_CEU
---help---
This is a v4l2 driver for the SuperH Mobile CEU Interface
-config VIDEO_OMAP1
- tristate "OMAP1 Camera Interface driver"
- depends on VIDEO_DEV && SOC_CAMERA
- depends on ARCH_OMAP1
- depends on HAS_DMA
- select VIDEOBUF_DMA_CONTIG
- select VIDEOBUF_DMA_SG
- ---help---
- This is a v4l2 driver for the TI OMAP1 camera interface
-
-config VIDEO_MX2
- tristate "i.MX27 Camera Sensor Interface driver"
- depends on VIDEO_DEV && SOC_CAMERA
- depends on SOC_IMX27 || COMPILE_TEST
- depends on HAS_DMA
- select VIDEOBUF2_DMA_CONTIG
- ---help---
- This is a v4l2 driver for the i.MX27 Camera Sensor Interface
-
config VIDEO_ATMEL_ISI
tristate "ATMEL Image Sensor Interface (ISI) support"
depends on VIDEO_DEV && SOC_CAMERA
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile
index 2826382dc9f8..7ee71ae231c7 100644
--- a/drivers/media/platform/soc_camera/Makefile
+++ b/drivers/media/platform/soc_camera/Makefile
@@ -7,9 +7,6 @@ obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
# soc-camera host drivers have to be linked after camera drivers
obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
-obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o
-obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
-obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 1af779ee3c74..ab2d9b9b1f5d 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -1026,7 +1026,7 @@ static int atmel_isi_parse_dt(struct atmel_isi *isi,
static int atmel_isi_probe(struct platform_device *pdev)
{
- unsigned int irq;
+ int irq;
struct atmel_isi *isi;
struct resource *regs;
int ret, i;
@@ -1086,7 +1086,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
isi->width_flags |= 1 << 9;
irq = platform_get_irq(pdev, 0);
- if (IS_ERR_VALUE(irq)) {
+ if (irq < 0) {
ret = irq;
goto err_req_irq;
}
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index 415f3bda60bf..2aaf4a8f71a0 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -28,6 +28,9 @@
#include <linux/clk.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma/pxa-dma.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
@@ -38,7 +41,6 @@
#include <linux/videodev2.h>
-#include <mach/dma.h>
#include <linux/platform_data/media/camera-pxa.h>
#define PXA_CAM_VERSION "0.0.6"
@@ -175,21 +177,16 @@ enum pxa_camera_active_dma {
DMA_V = 0x4,
};
-/* descriptor needed for the PXA DMA engine */
-struct pxa_cam_dma {
- dma_addr_t sg_dma;
- struct pxa_dma_desc *sg_cpu;
- size_t sg_size;
- int sglen;
-};
-
/* buffer for one video frame */
struct pxa_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
u32 code;
/* our descriptor lists for Y, U and V channels */
- struct pxa_cam_dma dmas[3];
+ struct dma_async_tx_descriptor *descs[3];
+ dma_cookie_t cookie[3];
+ struct scatterlist *sg[3];
+ int sg_len[3];
int inwork;
enum pxa_camera_active_dma active_dma;
};
@@ -207,7 +204,7 @@ struct pxa_camera_dev {
void __iomem *base;
int channels;
- unsigned int dma_chans[3];
+ struct dma_chan *dma_chans[3];
struct pxacamera_platform_data *pdata;
struct resource *res;
@@ -222,7 +219,7 @@ struct pxa_camera_dev {
spinlock_t lock;
struct pxa_buffer *active;
- struct pxa_dma_desc *sg_tail[3];
+ struct tasklet_struct task_eof;
u32 save_cicr[5];
};
@@ -258,7 +255,6 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
{
struct soc_camera_device *icd = vq->priv_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
int i;
@@ -272,42 +268,45 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
* longer in STATE_QUEUED or STATE_ACTIVE
*/
videobuf_waiton(vq, &buf->vb, 0, 0);
- videobuf_dma_unmap(vq->dev, dma);
- videobuf_dma_free(dma);
- for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
- if (buf->dmas[i].sg_cpu)
- dma_free_coherent(ici->v4l2_dev.dev,
- buf->dmas[i].sg_size,
- buf->dmas[i].sg_cpu,
- buf->dmas[i].sg_dma);
- buf->dmas[i].sg_cpu = NULL;
+ for (i = 0; i < 3 && buf->descs[i]; i++) {
+ dmaengine_desc_free(buf->descs[i]);
+ kfree(buf->sg[i]);
+ buf->descs[i] = NULL;
+ buf->sg[i] = NULL;
+ buf->sg_len[i] = 0;
}
+ videobuf_dma_unmap(vq->dev, dma);
+ videobuf_dma_free(dma);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
+
+ dev_dbg(icd->parent, "%s end (vb=0x%p) 0x%08lx %d\n", __func__,
+ &buf->vb, buf->vb.baddr, buf->vb.bsize);
}
-static int calculate_dma_sglen(struct scatterlist *sglist, int sglen,
- int sg_first_ofs, int size)
+static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev,
+ enum pxa_camera_active_dma act_dma);
+
+static void pxa_camera_dma_irq_y(void *data)
{
- int i, offset, dma_len, xfer_len;
- struct scatterlist *sg;
+ struct pxa_camera_dev *pcdev = data;
- offset = sg_first_ofs;
- for_each_sg(sglist, sg, sglen, i) {
- dma_len = sg_dma_len(sg);
+ pxa_camera_dma_irq(pcdev, DMA_Y);
+}
- /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
- xfer_len = roundup(min(dma_len - offset, size), 8);
+static void pxa_camera_dma_irq_u(void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
- size = max(0, size - xfer_len);
- offset = 0;
- if (size == 0)
- break;
- }
+ pxa_camera_dma_irq(pcdev, DMA_U);
+}
+
+static void pxa_camera_dma_irq_v(void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
- BUG_ON(size != 0);
- return i + 1;
+ pxa_camera_dma_irq(pcdev, DMA_V);
}
/**
@@ -318,93 +317,53 @@ static int calculate_dma_sglen(struct scatterlist *sglist, int sglen,
* @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V')
* @cibr: camera Receive Buffer Register
* @size: bytes to transfer
- * @sg_first: first element of sg_list
- * @sg_first_ofs: offset in first element of sg_list
+ * @offset: offset in videobuffer of the first byte to transfer
*
* Prepares the pxa dma descriptors to transfer one camera channel.
- * Beware sg_first and sg_first_ofs are both input and output parameters.
*
- * Returns 0 or -ENOMEM if no coherent memory is available
+ * Returns 0 if success or -ENOMEM if no memory is available
*/
static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
struct pxa_buffer *buf,
struct videobuf_dmabuf *dma, int channel,
- int cibr, int size,
- struct scatterlist **sg_first, int *sg_first_ofs)
+ int cibr, int size, int offset)
{
- struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
- struct device *dev = pcdev->soc_host.v4l2_dev.dev;
- struct scatterlist *sg;
- int i, offset, sglen;
- int dma_len = 0, xfer_len = 0;
-
- if (pxa_dma->sg_cpu)
- dma_free_coherent(dev, pxa_dma->sg_size,
- pxa_dma->sg_cpu, pxa_dma->sg_dma);
-
- sglen = calculate_dma_sglen(*sg_first, dma->sglen,
- *sg_first_ofs, size);
-
- pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
- pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size,
- &pxa_dma->sg_dma, GFP_KERNEL);
- if (!pxa_dma->sg_cpu)
- return -ENOMEM;
-
- pxa_dma->sglen = sglen;
- offset = *sg_first_ofs;
-
- dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
- *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
-
-
- for_each_sg(*sg_first, sg, sglen, i) {
- dma_len = sg_dma_len(sg);
-
- /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
- xfer_len = roundup(min(dma_len - offset, size), 8);
-
- size = max(0, size - xfer_len);
-
- pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr;
- pxa_dma->sg_cpu[i].dtadr = sg_dma_address(sg) + offset;
- pxa_dma->sg_cpu[i].dcmd =
- DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len;
-#ifdef DEBUG
- if (!i)
- pxa_dma->sg_cpu[i].dcmd |= DCMD_STARTIRQEN;
-#endif
- pxa_dma->sg_cpu[i].ddadr =
- pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
-
- dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
- pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
- sg_dma_address(sg) + offset, xfer_len);
- offset = 0;
-
- if (size == 0)
- break;
+ struct dma_chan *dma_chan = pcdev->dma_chans[channel];
+ struct scatterlist *sg = buf->sg[channel];
+ int sglen = buf->sg_len[channel];
+ struct dma_async_tx_descriptor *tx;
+
+ tx = dmaengine_prep_slave_sg(dma_chan, sg, sglen, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_REUSE);
+ if (!tx) {
+ dev_err(pcdev->soc_host.v4l2_dev.dev,
+ "dmaengine_prep_slave_sg failed\n");
+ goto fail;
}
- pxa_dma->sg_cpu[sglen].ddadr = DDADR_STOP;
- pxa_dma->sg_cpu[sglen].dcmd = DCMD_FLOWSRC | DCMD_BURST8 | DCMD_ENDIRQEN;
-
- /*
- * Handle 1 special case :
- * - in 3 planes (YUV422P format), we might finish with xfer_len equal
- * to dma_len (end on PAGE boundary). In this case, the sg element
- * for next plane should be the next after the last used to store the
- * last scatter gather RAM page
- */
- if (xfer_len >= dma_len) {
- *sg_first_ofs = xfer_len - dma_len;
- *sg_first = sg_next(sg);
- } else {
- *sg_first_ofs = xfer_len;
- *sg_first = sg;
+ tx->callback_param = pcdev;
+ switch (channel) {
+ case 0:
+ tx->callback = pxa_camera_dma_irq_y;
+ break;
+ case 1:
+ tx->callback = pxa_camera_dma_irq_u;
+ break;
+ case 2:
+ tx->callback = pxa_camera_dma_irq_v;
+ break;
}
+ buf->descs[channel] = tx;
return 0;
+fail:
+ kfree(sg);
+
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s (vb=0x%p) dma_tx=%p\n",
+ __func__, &buf->vb, tx);
+
+ return -ENOMEM;
}
static void pxa_videobuf_set_actdma(struct pxa_camera_dev *pcdev,
@@ -431,6 +390,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
int ret;
int size_y, size_u = 0, size_v = 0;
+ size_t sizes[3];
dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
@@ -473,13 +433,11 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
if (vb->state == VIDEOBUF_NEEDS_INIT) {
int size = vb->size;
- int next_ofs = 0;
struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
- struct scatterlist *sg;
ret = videobuf_iolock(vq, vb, NULL);
if (ret)
- goto fail;
+ goto out;
if (pcdev->channels == 3) {
size_y = size / 2;
@@ -488,11 +446,19 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
size_y = size;
}
- sg = dma->sglist;
+ sizes[0] = size_y;
+ sizes[1] = size_u;
+ sizes[2] = size_v;
+ ret = sg_split(dma->sglist, dma->sglen, 0, pcdev->channels,
+ sizes, buf->sg, buf->sg_len, GFP_KERNEL);
+ if (ret < 0) {
+ dev_err(dev, "sg_split failed: %d\n", ret);
+ goto fail;
+ }
/* init DMA for Y channel */
- ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
- &sg, &next_ofs);
+ ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0,
+ size_y, 0);
if (ret) {
dev_err(dev, "DMA initialization for Y/RGB failed\n");
goto fail;
@@ -501,19 +467,19 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
/* init DMA for U channel */
if (size_u)
ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
- size_u, &sg, &next_ofs);
+ size_u, size_y);
if (ret) {
dev_err(dev, "DMA initialization for U failed\n");
- goto fail_u;
+ goto fail;
}
/* init DMA for V channel */
if (size_v)
ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
- size_v, &sg, &next_ofs);
+ size_v, size_y + size_u);
if (ret) {
dev_err(dev, "DMA initialization for V failed\n");
- goto fail_v;
+ goto fail;
}
vb->state = VIDEOBUF_PREPARED;
@@ -524,12 +490,6 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
return 0;
-fail_v:
- dma_free_coherent(dev, buf->dmas[1].sg_size,
- buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
-fail_u:
- dma_free_coherent(dev, buf->dmas[0].sg_size,
- buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
fail:
free_buffer(vq, buf);
out:
@@ -553,10 +513,8 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev)
for (i = 0; i < pcdev->channels; i++) {
dev_dbg(pcdev->soc_host.v4l2_dev.dev,
- "%s (channel=%d) ddadr=%08x\n", __func__,
- i, active->dmas[i].sg_dma);
- DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma;
- DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+ "%s (channel=%d)\n", __func__, i);
+ dma_async_issue_pending(pcdev->dma_chans[i]);
}
}
@@ -567,7 +525,7 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev)
for (i = 0; i < pcdev->channels; i++) {
dev_dbg(pcdev->soc_host.v4l2_dev.dev,
"%s (channel=%d)\n", __func__, i);
- DCSR(pcdev->dma_chans[i]) = 0;
+ dmaengine_terminate_all(pcdev->dma_chans[i]);
}
}
@@ -575,18 +533,12 @@ static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev,
struct pxa_buffer *buf)
{
int i;
- struct pxa_dma_desc *buf_last_desc;
for (i = 0; i < pcdev->channels; i++) {
- buf_last_desc = buf->dmas[i].sg_cpu + buf->dmas[i].sglen;
- buf_last_desc->ddadr = DDADR_STOP;
-
- if (pcdev->sg_tail[i])
- /* Link the new buffer to the old tail */
- pcdev->sg_tail[i]->ddadr = buf->dmas[i].sg_dma;
-
- /* Update the channel tail */
- pcdev->sg_tail[i] = buf_last_desc;
+ buf->cookie[i] = dmaengine_submit(buf->descs[i]);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s (channel=%d) : submit vb=%p cookie=%d\n",
+ __func__, i, buf, buf->descs[i]->cookie);
}
}
@@ -603,6 +555,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev)
unsigned long cicr0;
dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
+ __raw_writel(__raw_readl(pcdev->base + CISR), pcdev->base + CISR);
/* Enable End-Of-Frame Interrupt */
cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB;
cicr0 &= ~CICR0_EOFM;
@@ -677,8 +630,6 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
struct videobuf_buffer *vb,
struct pxa_buffer *buf)
{
- int i;
-
/* _init is used to debug races, see comment in pxa_camera_reqbufs() */
list_del_init(&vb->queue);
vb->state = VIDEOBUF_DONE;
@@ -690,8 +641,6 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
if (list_empty(&pcdev->capture)) {
pxa_camera_stop_capture(pcdev);
- for (i = 0; i < pcdev->channels; i++)
- pcdev->sg_tail[i] = NULL;
return;
}
@@ -715,50 +664,41 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
*
* Context: should only be called within the dma irq handler
*/
-static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
+static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev,
+ dma_cookie_t last_submitted,
+ dma_cookie_t last_issued)
{
- int i, is_dma_stopped = 1;
+ bool is_dma_stopped = last_submitted != last_issued;
- for (i = 0; i < pcdev->channels; i++)
- if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP)
- is_dma_stopped = 0;
dev_dbg(pcdev->soc_host.v4l2_dev.dev,
- "%s : top queued buffer=%p, dma_stopped=%d\n",
+ "%s : top queued buffer=%p, is_dma_stopped=%d\n",
__func__, pcdev->active, is_dma_stopped);
+
if (pcdev->active && is_dma_stopped)
pxa_camera_start_capture(pcdev);
}
-static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
+static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev,
enum pxa_camera_active_dma act_dma)
{
struct device *dev = pcdev->soc_host.v4l2_dev.dev;
- struct pxa_buffer *buf;
+ struct pxa_buffer *buf, *last_buf;
unsigned long flags;
- u32 status, camera_status, overrun;
+ u32 camera_status, overrun;
+ int chan;
struct videobuf_buffer *vb;
+ enum dma_status last_status;
+ dma_cookie_t last_issued;
spin_lock_irqsave(&pcdev->lock, flags);
- status = DCSR(channel);
- DCSR(channel) = status;
-
camera_status = __raw_readl(pcdev->base + CISR);
+ dev_dbg(dev, "camera dma irq, cisr=0x%x dma=%d\n",
+ camera_status, act_dma);
overrun = CISR_IFO_0;
if (pcdev->channels == 3)
overrun |= CISR_IFO_1 | CISR_IFO_2;
- if (status & DCSR_BUSERR) {
- dev_err(dev, "DMA Bus Error IRQ!\n");
- goto out;
- }
-
- if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) {
- dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n",
- status);
- goto out;
- }
-
/*
* pcdev->active should not be NULL in DMA irq handler.
*
@@ -778,52 +718,47 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
buf = container_of(vb, struct pxa_buffer, vb);
WARN_ON(buf->inwork || list_empty(&vb->queue));
- dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
- __func__, channel, status & DCSR_STARTINTR ? "SOF " : "",
- status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel));
-
- if (status & DCSR_ENDINTR) {
- /*
- * It's normal if the last frame creates an overrun, as there
- * are no more DMA descriptors to fetch from QCI fifos
- */
- if (camera_status & overrun &&
- !list_is_last(pcdev->capture.next, &pcdev->capture)) {
- dev_dbg(dev, "FIFO overrun! CISR: %x\n",
- camera_status);
- pxa_camera_stop_capture(pcdev);
- pxa_camera_start_capture(pcdev);
- goto out;
- }
- buf->active_dma &= ~act_dma;
- if (!buf->active_dma) {
- pxa_camera_wakeup(pcdev, vb, buf);
- pxa_camera_check_link_miss(pcdev);
- }
+ /*
+ * It's normal if the last frame creates an overrun, as there
+ * are no more DMA descriptors to fetch from QCI fifos
+ */
+ switch (act_dma) {
+ case DMA_U:
+ chan = 1;
+ break;
+ case DMA_V:
+ chan = 2;
+ break;
+ default:
+ chan = 0;
+ break;
+ }
+ last_buf = list_entry(pcdev->capture.prev,
+ struct pxa_buffer, vb.queue);
+ last_status = dma_async_is_tx_complete(pcdev->dma_chans[chan],
+ last_buf->cookie[chan],
+ NULL, &last_issued);
+ if (camera_status & overrun &&
+ last_status != DMA_COMPLETE) {
+ dev_dbg(dev, "FIFO overrun! CISR: %x\n",
+ camera_status);
+ pxa_camera_stop_capture(pcdev);
+ list_for_each_entry(buf, &pcdev->capture, vb.queue)
+ pxa_dma_add_tail_buf(pcdev, buf);
+ pxa_camera_start_capture(pcdev);
+ goto out;
+ }
+ buf->active_dma &= ~act_dma;
+ if (!buf->active_dma) {
+ pxa_camera_wakeup(pcdev, vb, buf);
+ pxa_camera_check_link_miss(pcdev, last_buf->cookie[chan],
+ last_issued);
}
out:
spin_unlock_irqrestore(&pcdev->lock, flags);
}
-static void pxa_camera_dma_irq_y(int channel, void *data)
-{
- struct pxa_camera_dev *pcdev = data;
- pxa_camera_dma_irq(channel, pcdev, DMA_Y);
-}
-
-static void pxa_camera_dma_irq_u(int channel, void *data)
-{
- struct pxa_camera_dev *pcdev = data;
- pxa_camera_dma_irq(channel, pcdev, DMA_U);
-}
-
-static void pxa_camera_dma_irq_v(int channel, void *data)
-{
- struct pxa_camera_dev *pcdev = data;
- pxa_camera_dma_irq(channel, pcdev, DMA_V);
-}
-
static struct videobuf_queue_ops pxa_videobuf_ops = {
.buf_setup = pxa_videobuf_setup,
.buf_prepare = pxa_videobuf_prepare,
@@ -920,13 +855,35 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
clk_disable_unprepare(pcdev->clk);
}
-static irqreturn_t pxa_camera_irq(int irq, void *data)
+static void pxa_camera_eof(unsigned long arg)
{
- struct pxa_camera_dev *pcdev = data;
- unsigned long status, cifr, cicr0;
+ struct pxa_camera_dev *pcdev = (struct pxa_camera_dev *)arg;
+ unsigned long cifr;
struct pxa_buffer *buf;
struct videobuf_buffer *vb;
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "Camera interrupt status 0x%x\n",
+ __raw_readl(pcdev->base + CISR));
+
+ /* Reset the FIFOs */
+ cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
+ __raw_writel(cifr, pcdev->base + CIFR);
+
+ pcdev->active = list_first_entry(&pcdev->capture,
+ struct pxa_buffer, vb.queue);
+ vb = &pcdev->active->vb;
+ buf = container_of(vb, struct pxa_buffer, vb);
+ pxa_videobuf_set_actdma(pcdev, buf);
+
+ pxa_dma_start_channels(pcdev);
+}
+
+static irqreturn_t pxa_camera_irq(int irq, void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ unsigned long status, cicr0;
+
status = __raw_readl(pcdev->base + CISR);
dev_dbg(pcdev->soc_host.v4l2_dev.dev,
"Camera interrupt status 0x%lx\n", status);
@@ -937,20 +894,9 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
__raw_writel(status, pcdev->base + CISR);
if (status & CISR_EOF) {
- /* Reset the FIFOs */
- cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
- __raw_writel(cifr, pcdev->base + CIFR);
-
- pcdev->active = list_first_entry(&pcdev->capture,
- struct pxa_buffer, vb.queue);
- vb = &pcdev->active->vb;
- buf = container_of(vb, struct pxa_buffer, vb);
- pxa_videobuf_set_actdma(pcdev, buf);
-
- pxa_dma_start_channels(pcdev);
-
cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM;
__raw_writel(cicr0, pcdev->base + CICR0);
+ tasklet_schedule(&pcdev->task_eof);
}
return IRQ_HANDLED;
@@ -993,10 +939,7 @@ static void pxa_camera_clock_stop(struct soc_camera_host *ici)
__raw_writel(0x3ff, pcdev->base + CICR0);
/* Stop DMA engine */
- DCSR(pcdev->dma_chans[0]) = 0;
- DCSR(pcdev->dma_chans[1]) = 0;
- DCSR(pcdev->dma_chans[2]) = 0;
-
+ pxa_dma_stop_channels(pcdev);
pxa_camera_deactivate(pcdev);
}
@@ -1623,10 +1566,6 @@ static int pxa_camera_resume(struct device *dev)
struct pxa_camera_dev *pcdev = ici->priv;
int i = 0, ret = 0;
- DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
- DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
- DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
-
__raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0);
__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR1);
__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR2);
@@ -1732,8 +1671,15 @@ static int pxa_camera_probe(struct platform_device *pdev)
struct pxa_camera_dev *pcdev;
struct resource *res;
void __iomem *base;
+ struct dma_slave_config config = {
+ .src_addr_width = 0,
+ .src_maxburst = 8,
+ .direction = DMA_DEV_TO_MEM,
+ };
+ dma_cap_mask_t mask;
+ struct pxad_param params;
int irq;
- int err = 0;
+ int err = 0, i;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
@@ -1801,36 +1747,47 @@ static int pxa_camera_probe(struct platform_device *pdev)
pcdev->base = base;
/* request dma */
- err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
- pxa_camera_dma_irq_y, pcdev);
- if (err < 0) {
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+
+ params.prio = 0;
+ params.drcmr = 68;
+ pcdev->dma_chans[0] =
+ dma_request_slave_channel_compat(mask, pxad_filter_fn,
+ &params, &pdev->dev, "CI_Y");
+ if (!pcdev->dma_chans[0]) {
dev_err(&pdev->dev, "Can't request DMA for Y\n");
- return err;
+ return -ENODEV;
}
- pcdev->dma_chans[0] = err;
- dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
- err = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
- pxa_camera_dma_irq_u, pcdev);
- if (err < 0) {
- dev_err(&pdev->dev, "Can't request DMA for U\n");
+ params.drcmr = 69;
+ pcdev->dma_chans[1] =
+ dma_request_slave_channel_compat(mask, pxad_filter_fn,
+ &params, &pdev->dev, "CI_U");
+ if (!pcdev->dma_chans[1]) {
+ dev_err(&pdev->dev, "Can't request DMA for Y\n");
goto exit_free_dma_y;
}
- pcdev->dma_chans[1] = err;
- dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
- err = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
- pxa_camera_dma_irq_v, pcdev);
- if (err < 0) {
+ params.drcmr = 70;
+ pcdev->dma_chans[2] =
+ dma_request_slave_channel_compat(mask, pxad_filter_fn,
+ &params, &pdev->dev, "CI_V");
+ if (!pcdev->dma_chans[2]) {
dev_err(&pdev->dev, "Can't request DMA for V\n");
goto exit_free_dma_u;
}
- pcdev->dma_chans[2] = err;
- dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
- DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
- DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
- DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
+ for (i = 0; i < 3; i++) {
+ config.src_addr = pcdev->res->start + CIBR0 + i * 8;
+ err = dmaengine_slave_config(pcdev->dma_chans[i], &config);
+ if (err < 0) {
+ dev_err(&pdev->dev, "dma slave config failed: %d\n",
+ err);
+ goto exit_free_dma;
+ }
+ }
/* request irq */
err = devm_request_irq(&pdev->dev, pcdev->irq, pxa_camera_irq, 0,
@@ -1845,6 +1802,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
pcdev->soc_host.priv = pcdev;
pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
pcdev->soc_host.nr = pdev->id;
+ tasklet_init(&pcdev->task_eof, pxa_camera_eof, (unsigned long)pcdev);
err = soc_camera_host_register(&pcdev->soc_host);
if (err)
@@ -1853,11 +1811,11 @@ static int pxa_camera_probe(struct platform_device *pdev)
return 0;
exit_free_dma:
- pxa_free_dma(pcdev->dma_chans[2]);
+ dma_release_channel(pcdev->dma_chans[2]);
exit_free_dma_u:
- pxa_free_dma(pcdev->dma_chans[1]);
+ dma_release_channel(pcdev->dma_chans[1]);
exit_free_dma_y:
- pxa_free_dma(pcdev->dma_chans[0]);
+ dma_release_channel(pcdev->dma_chans[0]);
return err;
}
@@ -1867,9 +1825,9 @@ static int pxa_camera_remove(struct platform_device *pdev)
struct pxa_camera_dev *pcdev = container_of(soc_host,
struct pxa_camera_dev, soc_host);
- pxa_free_dma(pcdev->dma_chans[0]);
- pxa_free_dma(pcdev->dma_chans[1]);
- pxa_free_dma(pcdev->dma_chans[2]);
+ dma_release_channel(pcdev->dma_chans[0]);
+ dma_release_channel(pcdev->dma_chans[1]);
+ dma_release_channel(pcdev->dma_chans[2]);
soc_camera_host_unregister(soc_host);
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index b7fd695b9ed5..3b8edf458964 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -124,7 +124,7 @@
#define VNDMR_EXRGB (1 << 8)
#define VNDMR_BPSM (1 << 4)
#define VNDMR_DTMD_YCSEP (1 << 1)
-#define VNDMR_DTMD_ARGB1555 (1 << 0)
+#define VNDMR_DTMD_ARGB (1 << 0)
/* Video n Data Mode Register 2 bits */
#define VNDMR2_VPS (1 << 30)
@@ -143,6 +143,7 @@
#define RCAR_VIN_BT656 (1 << 3)
enum chip_id {
+ RCAR_GEN3,
RCAR_GEN2,
RCAR_H1,
RCAR_M1,
@@ -642,21 +643,26 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
output_is_yuv = true;
break;
case V4L2_PIX_FMT_RGB555X:
- dmr = VNDMR_DTMD_ARGB1555;
+ dmr = VNDMR_DTMD_ARGB;
break;
case V4L2_PIX_FMT_RGB565:
dmr = 0;
break;
case V4L2_PIX_FMT_RGB32:
- if (priv->chip == RCAR_GEN2 || priv->chip == RCAR_H1 ||
- priv->chip == RCAR_E1) {
- dmr = VNDMR_EXRGB;
- break;
- }
+ if (priv->chip != RCAR_GEN2 && priv->chip != RCAR_H1 &&
+ priv->chip != RCAR_E1)
+ goto e_format;
+
+ dmr = VNDMR_EXRGB;
+ break;
+ case V4L2_PIX_FMT_ARGB32:
+ if (priv->chip != RCAR_GEN3)
+ goto e_format;
+
+ dmr = VNDMR_EXRGB | VNDMR_DTMD_ARGB;
+ break;
default:
- dev_warn(icd->parent, "Invalid fourcc format (0x%x)\n",
- icd->current_fmt->host_fmt->fourcc);
- return -EINVAL;
+ goto e_format;
}
/* Always update on field change */
@@ -678,6 +684,11 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
iowrite32(vnmc | VNMC_ME, priv->base + VNMC_REG);
return 0;
+
+e_format:
+ dev_warn(icd->parent, "Invalid fourcc format (0x%x)\n",
+ icd->current_fmt->host_fmt->fourcc);
+ return -EINVAL;
}
static void rcar_vin_capture(struct rcar_vin_priv *priv)
@@ -1303,6 +1314,14 @@ static const struct soc_mbus_pixelfmt rcar_vin_formats[] = {
.order = SOC_MBUS_ORDER_LE,
.layout = SOC_MBUS_LAYOUT_PACKED,
},
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB32,
+ .name = "ARGB8888",
+ .bits_per_sample = 32,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
};
static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
@@ -1610,6 +1629,7 @@ static int rcar_vin_set_fmt(struct soc_camera_device *icd,
case V4L2_PIX_FMT_RGB32:
can_scale = priv->chip != RCAR_E1;
break;
+ case V4L2_PIX_FMT_ARGB32:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_RGB565:
@@ -1818,6 +1838,7 @@ static struct soc_camera_host_ops rcar_vin_host_ops = {
#ifdef CONFIG_OF
static const struct of_device_id rcar_vin_of_table[] = {
+ { .compatible = "renesas,vin-r8a7795", .data = (void *)RCAR_GEN3 },
{ .compatible = "renesas,vin-r8a7794", .data = (void *)RCAR_GEN2 },
{ .compatible = "renesas,vin-r8a7793", .data = (void *)RCAR_GEN2 },
{ .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 },
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index 90c87f2b4ec0..b9f369c0fb94 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -213,8 +213,7 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
unsigned int *count, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
- struct soc_camera_device *icd = container_of(vq,
- struct soc_camera_device, vb2_vidq);
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
@@ -361,8 +360,7 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct soc_camera_device *icd = container_of(vb->vb2_queue,
- struct soc_camera_device, vb2_vidq);
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vbuf);
@@ -413,8 +411,7 @@ error:
static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct soc_camera_device *icd = container_of(vb->vb2_queue,
- struct soc_camera_device, vb2_vidq);
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vbuf);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
@@ -444,8 +441,7 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct soc_camera_device *icd = container_of(vb->vb2_queue,
- struct soc_camera_device, vb2_vidq);
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
@@ -460,7 +456,7 @@ static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
static void sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
{
- struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq);
+ struct soc_camera_device *icd = soc_camera_from_vb2q(q);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
struct list_head *buf_head, *tmp;
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
index 69d7fe4471c2..2c0015b1264d 100644
--- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
+++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
@@ -118,7 +118,7 @@ int c8sectpfe_frontend_attach(struct dvb_frontend **fe,
struct channel_info *tsin, int chan_num)
{
struct tda18212_config *tda18212;
- struct stv6110x_devctl *fe2;
+ const struct stv6110x_devctl *fe2;
struct i2c_client *client;
struct i2c_board_info tda18212_info = {
.type = "tda18212",
diff --git a/drivers/media/platform/ti-vpe/Makefile b/drivers/media/platform/ti-vpe/Makefile
index be680f839e77..e236059a60ad 100644
--- a/drivers/media/platform/ti-vpe/Makefile
+++ b/drivers/media/platform/ti-vpe/Makefile
@@ -3,3 +3,7 @@ obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o
ti-vpe-y := vpe.o sc.o csc.o vpdma.o
ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG
+
+obj-$(CONFIG_VIDEO_TI_CAL) += ti-cal.o
+
+ti-cal-y := cal.o
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
new file mode 100644
index 000000000000..82001e6b5553
--- /dev/null
+++ b/drivers/media/platform/ti-vpe/cal.c
@@ -0,0 +1,1947 @@
+/*
+ * TI CAL camera interface driver
+ *
+ * Copyright (c) 2015 Texas Instruments Inc.
+ * Benoit Parrot, <bparrot@ti.com>
+ *
+ * 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 published by
+ * the Free Software Foundation
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+
+#include <media/v4l2-of.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include "cal_regs.h"
+
+#define CAL_MODULE_NAME "cal"
+
+#define MAX_WIDTH 1920
+#define MAX_HEIGHT 1200
+
+#define CAL_VERSION "0.1.0"
+
+MODULE_DESCRIPTION("TI CAL driver");
+MODULE_AUTHOR("Benoit Parrot, <bparrot@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(CAL_VERSION);
+
+static unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
+
+static unsigned debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+/* timeperframe: min/max and default */
+static const struct v4l2_fract
+ tpf_default = {.numerator = 1001, .denominator = 30000};
+
+#define cal_dbg(level, caldev, fmt, arg...) \
+ v4l2_dbg(level, debug, &caldev->v4l2_dev, fmt, ##arg)
+#define cal_info(caldev, fmt, arg...) \
+ v4l2_info(&caldev->v4l2_dev, fmt, ##arg)
+#define cal_err(caldev, fmt, arg...) \
+ v4l2_err(&caldev->v4l2_dev, fmt, ##arg)
+
+#define ctx_dbg(level, ctx, fmt, arg...) \
+ v4l2_dbg(level, debug, &ctx->v4l2_dev, fmt, ##arg)
+#define ctx_info(ctx, fmt, arg...) \
+ v4l2_info(&ctx->v4l2_dev, fmt, ##arg)
+#define ctx_err(ctx, fmt, arg...) \
+ v4l2_err(&ctx->v4l2_dev, fmt, ##arg)
+
+#define CAL_NUM_INPUT 1
+#define CAL_NUM_CONTEXT 2
+
+#define bytes_per_line(pixel, bpp) (ALIGN(pixel * bpp, 16))
+
+#define reg_read(dev, offset) ioread32(dev->base + offset)
+#define reg_write(dev, offset, val) iowrite32(val, dev->base + offset)
+
+#define reg_read_field(dev, offset, mask) get_field(reg_read(dev, offset), \
+ mask)
+#define reg_write_field(dev, offset, field, mask) { \
+ u32 val = reg_read(dev, offset); \
+ set_field(&val, field, mask); \
+ reg_write(dev, offset, val); }
+
+/* ------------------------------------------------------------------
+ * Basic structures
+ * ------------------------------------------------------------------
+ */
+
+struct cal_fmt {
+ u32 fourcc;
+ u32 code;
+ u8 depth;
+};
+
+static struct cal_fmt cal_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
+ .code = MEDIA_BUS_FMT_RGB888_2X12_LE,
+ .depth = 24,
+ }, {
+ .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
+ .code = MEDIA_BUS_FMT_RGB888_2X12_BE,
+ .depth = 24,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
+ .code = MEDIA_BUS_FMT_ARGB8888_1X32,
+ .depth = 32,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .depth = 8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .depth = 8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .depth = 8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .depth = 8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .depth = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .depth = 16,
+ },
+};
+
+/* Print Four-character-code (FOURCC) */
+static char *fourcc_to_str(u32 fmt)
+{
+ static char code[5];
+
+ code[0] = (unsigned char)(fmt & 0xff);
+ code[1] = (unsigned char)((fmt >> 8) & 0xff);
+ code[2] = (unsigned char)((fmt >> 16) & 0xff);
+ code[3] = (unsigned char)((fmt >> 24) & 0xff);
+ code[4] = '\0';
+
+ return code;
+}
+
+/* buffer for one video frame */
+struct cal_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_v4l2_buffer vb;
+ struct list_head list;
+ const struct cal_fmt *fmt;
+};
+
+struct cal_dmaqueue {
+ struct list_head active;
+
+ /* Counters to control fps rate */
+ int frame;
+ int ini_jiffies;
+};
+
+struct cm_data {
+ void __iomem *base;
+ struct resource *res;
+
+ unsigned int camerrx_control;
+
+ struct platform_device *pdev;
+};
+
+struct cc_data {
+ void __iomem *base;
+ struct resource *res;
+
+ struct platform_device *pdev;
+};
+
+/*
+ * there is one cal_dev structure in the driver, it is shared by
+ * all instances.
+ */
+struct cal_dev {
+ int irq;
+ void __iomem *base;
+ struct resource *res;
+ struct platform_device *pdev;
+ struct v4l2_device v4l2_dev;
+
+ /* Control Module handle */
+ struct cm_data *cm;
+ /* Camera Core Module handle */
+ struct cc_data *cc[CAL_NUM_CSI2_PORTS];
+
+ struct cal_ctx *ctx[CAL_NUM_CONTEXT];
+};
+
+/*
+ * There is one cal_ctx structure for each camera core context.
+ */
+struct cal_ctx {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct video_device vdev;
+ struct v4l2_async_notifier notifier;
+ struct v4l2_subdev *sensor;
+ struct v4l2_of_endpoint endpoint;
+
+ struct v4l2_async_subdev asd;
+ struct v4l2_async_subdev *asd_list[1];
+
+ struct v4l2_fh fh;
+ struct cal_dev *dev;
+ struct cc_data *cc;
+
+ /* v4l2_ioctl mutex */
+ struct mutex mutex;
+ /* v4l2 buffers lock */
+ spinlock_t slock;
+
+ /* Several counters */
+ unsigned long jiffies;
+
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct cal_dmaqueue vidq;
+
+ /* Input Number */
+ int input;
+
+ /* video capture */
+ const struct cal_fmt *fmt;
+ /* Used to store current pixel format */
+ struct v4l2_format v_fmt;
+ /* Used to store current mbus frame format */
+ struct v4l2_mbus_framefmt m_fmt;
+
+ /* Current subdev enumerated format */
+ struct cal_fmt *active_fmt[ARRAY_SIZE(cal_formats)];
+ int num_active_fmt;
+
+ struct v4l2_fract timeperframe;
+ unsigned int sequence;
+ unsigned int external_rate;
+ struct vb2_queue vb_vidq;
+ unsigned int seq_count;
+ unsigned int csi2_port;
+ unsigned int virtual_channel;
+
+ /* Pointer pointing to current v4l2_buffer */
+ struct cal_buffer *cur_frm;
+ /* Pointer pointing to next v4l2_buffer */
+ struct cal_buffer *next_frm;
+};
+
+static const struct cal_fmt *find_format_by_pix(struct cal_ctx *ctx,
+ u32 pixelformat)
+{
+ const struct cal_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < ctx->num_active_fmt; k++) {
+ fmt = ctx->active_fmt[k];
+ if (fmt->fourcc == pixelformat)
+ return fmt;
+ }
+
+ return NULL;
+}
+
+static const struct cal_fmt *find_format_by_code(struct cal_ctx *ctx,
+ u32 code)
+{
+ const struct cal_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < ctx->num_active_fmt; k++) {
+ fmt = ctx->active_fmt[k];
+ if (fmt->code == code)
+ return fmt;
+ }
+
+ return NULL;
+}
+
+static inline struct cal_ctx *notifier_to_ctx(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct cal_ctx, notifier);
+}
+
+static inline int get_field(u32 value, u32 mask)
+{
+ return (value & mask) >> __ffs(mask);
+}
+
+static inline void set_field(u32 *valp, u32 field, u32 mask)
+{
+ u32 val = *valp;
+
+ val &= ~mask;
+ val |= (field << __ffs(mask)) & mask;
+ *valp = val;
+}
+
+/*
+ * Control Module block access
+ */
+static struct cm_data *cm_create(struct cal_dev *dev)
+{
+ struct platform_device *pdev = dev->pdev;
+ struct cm_data *cm;
+
+ cm = devm_kzalloc(&pdev->dev, sizeof(*cm), GFP_KERNEL);
+ if (!cm)
+ return ERR_PTR(-ENOMEM);
+
+ cm->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "camerrx_control");
+ cm->base = devm_ioremap_resource(&pdev->dev, cm->res);
+ if (IS_ERR(cm->base)) {
+ cal_err(dev, "failed to ioremap\n");
+ return ERR_CAST(cm->base);
+ }
+
+ cal_dbg(1, dev, "ioresource %s at %pa - %pa\n",
+ cm->res->name, &cm->res->start, &cm->res->end);
+
+ return cm;
+}
+
+static void camerarx_phy_enable(struct cal_ctx *ctx)
+{
+ u32 val;
+
+ if (!ctx->dev->cm->base) {
+ ctx_err(ctx, "cm not mapped\n");
+ return;
+ }
+
+ val = reg_read(ctx->dev->cm, CM_CTRL_CORE_CAMERRX_CONTROL);
+ if (ctx->csi2_port == 1) {
+ set_field(&val, 1, CM_CAMERRX_CTRL_CSI0_CTRLCLKEN_MASK);
+ set_field(&val, 0, CM_CAMERRX_CTRL_CSI0_CAMMODE_MASK);
+ /* enable all lanes by default */
+ set_field(&val, 0xf, CM_CAMERRX_CTRL_CSI0_LANEENABLE_MASK);
+ set_field(&val, 1, CM_CAMERRX_CTRL_CSI0_MODE_MASK);
+ } else if (ctx->csi2_port == 2) {
+ set_field(&val, 1, CM_CAMERRX_CTRL_CSI1_CTRLCLKEN_MASK);
+ set_field(&val, 0, CM_CAMERRX_CTRL_CSI1_CAMMODE_MASK);
+ /* enable all lanes by default */
+ set_field(&val, 0x3, CM_CAMERRX_CTRL_CSI1_LANEENABLE_MASK);
+ set_field(&val, 1, CM_CAMERRX_CTRL_CSI1_MODE_MASK);
+ }
+ reg_write(ctx->dev->cm, CM_CTRL_CORE_CAMERRX_CONTROL, val);
+}
+
+static void camerarx_phy_disable(struct cal_ctx *ctx)
+{
+ u32 val;
+
+ if (!ctx->dev->cm->base) {
+ ctx_err(ctx, "cm not mapped\n");
+ return;
+ }
+
+ val = reg_read(ctx->dev->cm, CM_CTRL_CORE_CAMERRX_CONTROL);
+ if (ctx->csi2_port == 1)
+ set_field(&val, 0x0, CM_CAMERRX_CTRL_CSI0_CTRLCLKEN_MASK);
+ else if (ctx->csi2_port == 2)
+ set_field(&val, 0x0, CM_CAMERRX_CTRL_CSI1_CTRLCLKEN_MASK);
+ reg_write(ctx->dev->cm, CM_CTRL_CORE_CAMERRX_CONTROL, val);
+}
+
+/*
+ * Camera Instance access block
+ */
+static struct cc_data *cc_create(struct cal_dev *dev, unsigned int core)
+{
+ struct platform_device *pdev = dev->pdev;
+ struct cc_data *cc;
+
+ cc = devm_kzalloc(&pdev->dev, sizeof(*cc), GFP_KERNEL);
+ if (!cc)
+ return ERR_PTR(-ENOMEM);
+
+ cc->res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM,
+ (core == 0) ?
+ "cal_rx_core0" :
+ "cal_rx_core1");
+ cc->base = devm_ioremap_resource(&pdev->dev, cc->res);
+ if (IS_ERR(cc->base)) {
+ cal_err(dev, "failed to ioremap\n");
+ return ERR_CAST(cc->base);
+ }
+
+ cal_dbg(1, dev, "ioresource %s at %pa - %pa\n",
+ cc->res->name, &cc->res->start, &cc->res->end);
+
+ return cc;
+}
+
+/*
+ * Get Revision and HW info
+ */
+static void cal_get_hwinfo(struct cal_dev *dev)
+{
+ u32 revision = 0;
+ u32 hwinfo = 0;
+
+ revision = reg_read(dev, CAL_HL_REVISION);
+ cal_dbg(3, dev, "CAL_HL_REVISION = 0x%08x (expecting 0x40000200)\n",
+ revision);
+
+ hwinfo = reg_read(dev, CAL_HL_HWINFO);
+ cal_dbg(3, dev, "CAL_HL_HWINFO = 0x%08x (expecting 0xA3C90469)\n",
+ hwinfo);
+}
+
+static inline int cal_runtime_get(struct cal_dev *dev)
+{
+ int r;
+
+ r = pm_runtime_get_sync(&dev->pdev->dev);
+
+ return r;
+}
+
+static inline void cal_runtime_put(struct cal_dev *dev)
+{
+ pm_runtime_put_sync(&dev->pdev->dev);
+}
+
+static void cal_quickdump_regs(struct cal_dev *dev)
+{
+ cal_info(dev, "CAL Registers @ 0x%pa:\n", &dev->res->start);
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
+ (__force const void *)dev->base,
+ resource_size(dev->res), false);
+
+ if (dev->ctx[0]) {
+ cal_info(dev, "CSI2 Core 0 Registers @ %pa:\n",
+ &dev->ctx[0]->cc->res->start);
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
+ (__force const void *)dev->ctx[0]->cc->base,
+ resource_size(dev->ctx[0]->cc->res),
+ false);
+ }
+
+ if (dev->ctx[1]) {
+ cal_info(dev, "CSI2 Core 1 Registers @ %pa:\n",
+ &dev->ctx[1]->cc->res->start);
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
+ (__force const void *)dev->ctx[1]->cc->base,
+ resource_size(dev->ctx[1]->cc->res),
+ false);
+ }
+
+ cal_info(dev, "CAMERRX_Control Registers @ %pa:\n",
+ &dev->cm->res->start);
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
+ (__force const void *)dev->cm->base,
+ resource_size(dev->cm->res), false);
+}
+
+/*
+ * Enable the expected IRQ sources
+ */
+static void enable_irqs(struct cal_ctx *ctx)
+{
+ /* Enable IRQ_WDMA_END 0/1 */
+ reg_write_field(ctx->dev,
+ CAL_HL_IRQENABLE_SET(2),
+ CAL_HL_IRQ_ENABLE,
+ CAL_HL_IRQ_MASK(ctx->csi2_port));
+ /* Enable IRQ_WDMA_START 0/1 */
+ reg_write_field(ctx->dev,
+ CAL_HL_IRQENABLE_SET(3),
+ CAL_HL_IRQ_ENABLE,
+ CAL_HL_IRQ_MASK(ctx->csi2_port));
+ /* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */
+ reg_write(ctx->dev, CAL_CSI2_VC_IRQENABLE(1), 0xFF000000);
+}
+
+static void disable_irqs(struct cal_ctx *ctx)
+{
+ /* Disable IRQ_WDMA_END 0/1 */
+ reg_write_field(ctx->dev,
+ CAL_HL_IRQENABLE_CLR(2),
+ CAL_HL_IRQ_CLEAR,
+ CAL_HL_IRQ_MASK(ctx->csi2_port));
+ /* Disable IRQ_WDMA_START 0/1 */
+ reg_write_field(ctx->dev,
+ CAL_HL_IRQENABLE_CLR(3),
+ CAL_HL_IRQ_CLEAR,
+ CAL_HL_IRQ_MASK(ctx->csi2_port));
+ /* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */
+ reg_write(ctx->dev, CAL_CSI2_VC_IRQENABLE(1), 0);
+}
+
+static void csi2_init(struct cal_ctx *ctx)
+{
+ int i;
+ u32 val;
+
+ val = reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port));
+ set_field(&val, CAL_GEN_ENABLE,
+ CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK);
+ set_field(&val, CAL_GEN_ENABLE,
+ CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK);
+ set_field(&val, CAL_GEN_DISABLE,
+ CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK);
+ set_field(&val, 407, CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK);
+ reg_write(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port), val);
+ ctx_dbg(3, ctx, "CAL_CSI2_TIMING(%d) = 0x%08x\n", ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port)));
+
+ val = reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port));
+ set_field(&val, CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL,
+ CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK);
+ set_field(&val, CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON,
+ CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK);
+ reg_write(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), val);
+ for (i = 0; i < 10; i++) {
+ if (reg_read_field(ctx->dev,
+ CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port),
+ CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK) ==
+ CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_ON)
+ break;
+ usleep_range(1000, 1100);
+ }
+ ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x\n", ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port)));
+
+ val = reg_read(ctx->dev, CAL_CTRL);
+ set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, CAL_CTRL_BURSTSIZE_MASK);
+ set_field(&val, 0xF, CAL_CTRL_TAGCNT_MASK);
+ set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED,
+ CAL_CTRL_POSTED_WRITES_MASK);
+ set_field(&val, 0xFF, CAL_CTRL_MFLAGL_MASK);
+ set_field(&val, 0xFF, CAL_CTRL_MFLAGH_MASK);
+ reg_write(ctx->dev, CAL_CTRL, val);
+ ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", reg_read(ctx->dev, CAL_CTRL));
+}
+
+static void csi2_lane_config(struct cal_ctx *ctx)
+{
+ u32 val = reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port));
+ u32 lane_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK;
+ u32 polarity_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK;
+ struct v4l2_of_bus_mipi_csi2 *mipi_csi2 = &ctx->endpoint.bus.mipi_csi2;
+ int lane;
+
+ set_field(&val, mipi_csi2->clock_lane + 1, lane_mask);
+ set_field(&val, mipi_csi2->lane_polarities[0], polarity_mask);
+ for (lane = 0; lane < mipi_csi2->num_data_lanes; lane++) {
+ /*
+ * Every lane are one nibble apart starting with the
+ * clock followed by the data lanes so shift masks by 4.
+ */
+ lane_mask <<= 4;
+ polarity_mask <<= 4;
+ set_field(&val, mipi_csi2->data_lanes[lane] + 1, lane_mask);
+ set_field(&val, mipi_csi2->lane_polarities[lane + 1],
+ polarity_mask);
+ }
+
+ reg_write(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), val);
+ ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x\n",
+ ctx->csi2_port, val);
+}
+
+static void csi2_ppi_enable(struct cal_ctx *ctx)
+{
+ reg_write_field(ctx->dev, CAL_CSI2_PPI_CTRL(ctx->csi2_port),
+ CAL_GEN_ENABLE, CAL_CSI2_PPI_CTRL_IF_EN_MASK);
+}
+
+static void csi2_ppi_disable(struct cal_ctx *ctx)
+{
+ reg_write_field(ctx->dev, CAL_CSI2_PPI_CTRL(ctx->csi2_port),
+ CAL_GEN_DISABLE, CAL_CSI2_PPI_CTRL_IF_EN_MASK);
+}
+
+static void csi2_ctx_config(struct cal_ctx *ctx)
+{
+ u32 val;
+
+ val = reg_read(ctx->dev, CAL_CSI2_CTX0(ctx->csi2_port));
+ set_field(&val, ctx->csi2_port, CAL_CSI2_CTX_CPORT_MASK);
+ /*
+ * DT type: MIPI CSI-2 Specs
+ * 0x1: All - DT filter is disabled
+ * 0x24: RGB888 1 pixel = 3 bytes
+ * 0x2B: RAW10 4 pixels = 5 bytes
+ * 0x2A: RAW8 1 pixel = 1 byte
+ * 0x1E: YUV422 2 pixels = 4 bytes
+ */
+ set_field(&val, 0x1, CAL_CSI2_CTX_DT_MASK);
+ /* Virtual Channel from the CSI2 sensor usually 0! */
+ set_field(&val, ctx->virtual_channel, CAL_CSI2_CTX_VC_MASK);
+ /* NUM_LINES_PER_FRAME => 0 means auto detect */
+ set_field(&val, 0, CAL_CSI2_CTX_LINES_MASK);
+ set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK);
+ set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE,
+ CAL_CSI2_CTX_PACK_MODE_MASK);
+ reg_write(ctx->dev, CAL_CSI2_CTX0(ctx->csi2_port), val);
+ ctx_dbg(3, ctx, "CAL_CSI2_CTX0(%d) = 0x%08x\n", ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_CTX0(ctx->csi2_port)));
+}
+
+static void pix_proc_config(struct cal_ctx *ctx)
+{
+ u32 val;
+
+ val = reg_read(ctx->dev, CAL_PIX_PROC(ctx->csi2_port));
+ set_field(&val, CAL_PIX_PROC_EXTRACT_B8, CAL_PIX_PROC_EXTRACT_MASK);
+ set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK);
+ set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK);
+ set_field(&val, CAL_PIX_PROC_PACK_B8, CAL_PIX_PROC_PACK_MASK);
+ set_field(&val, ctx->csi2_port, CAL_PIX_PROC_CPORT_MASK);
+ set_field(&val, CAL_GEN_ENABLE, CAL_PIX_PROC_EN_MASK);
+ reg_write(ctx->dev, CAL_PIX_PROC(ctx->csi2_port), val);
+ ctx_dbg(3, ctx, "CAL_PIX_PROC(%d) = 0x%08x\n", ctx->csi2_port,
+ reg_read(ctx->dev, CAL_PIX_PROC(ctx->csi2_port)));
+}
+
+static void cal_wr_dma_config(struct cal_ctx *ctx,
+ unsigned int width)
+{
+ u32 val;
+
+ val = reg_read(ctx->dev, CAL_WR_DMA_CTRL(ctx->csi2_port));
+ set_field(&val, ctx->csi2_port, CAL_WR_DMA_CTRL_CPORT_MASK);
+ set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT,
+ CAL_WR_DMA_CTRL_DTAG_MASK);
+ set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST,
+ CAL_WR_DMA_CTRL_MODE_MASK);
+ set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR,
+ CAL_WR_DMA_CTRL_PATTERN_MASK);
+ set_field(&val, CAL_GEN_ENABLE, CAL_WR_DMA_CTRL_STALL_RD_MASK);
+ reg_write(ctx->dev, CAL_WR_DMA_CTRL(ctx->csi2_port), val);
+ ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->csi2_port,
+ reg_read(ctx->dev, CAL_WR_DMA_CTRL(ctx->csi2_port)));
+
+ /*
+ * width/16 not sure but giving it a whirl.
+ * zero does not work right
+ */
+ reg_write_field(ctx->dev,
+ CAL_WR_DMA_OFST(ctx->csi2_port),
+ (width / 16),
+ CAL_WR_DMA_OFST_MASK);
+ ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->csi2_port,
+ reg_read(ctx->dev, CAL_WR_DMA_OFST(ctx->csi2_port)));
+
+ val = reg_read(ctx->dev, CAL_WR_DMA_XSIZE(ctx->csi2_port));
+ /* 64 bit word means no skipping */
+ set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK);
+ /*
+ * (width*8)/64 this should be size of an entire line
+ * in 64bit word but 0 means all data until the end
+ * is detected automagically
+ */
+ set_field(&val, (width / 8), CAL_WR_DMA_XSIZE_MASK);
+ reg_write(ctx->dev, CAL_WR_DMA_XSIZE(ctx->csi2_port), val);
+ ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->csi2_port,
+ reg_read(ctx->dev, CAL_WR_DMA_XSIZE(ctx->csi2_port)));
+}
+
+static void cal_wr_dma_addr(struct cal_ctx *ctx, unsigned int dmaaddr)
+{
+ reg_write(ctx->dev, CAL_WR_DMA_ADDR(ctx->csi2_port), dmaaddr);
+}
+
+/*
+ * TCLK values are OK at their reset values
+ */
+#define TCLK_TERM 0
+#define TCLK_MISS 1
+#define TCLK_SETTLE 14
+#define THS_SETTLE 15
+
+static void csi2_phy_config(struct cal_ctx *ctx)
+{
+ unsigned int reg0, reg1;
+ unsigned int ths_term, ths_settle;
+ unsigned int ddrclkperiod_us;
+
+ /*
+ * THS_TERM: Programmed value = floor(20 ns/DDRClk period) - 2.
+ */
+ ddrclkperiod_us = ctx->external_rate / 2000000;
+ ddrclkperiod_us = 1000000 / ddrclkperiod_us;
+ ctx_dbg(1, ctx, "ddrclkperiod_us: %d\n", ddrclkperiod_us);
+
+ ths_term = 20000 / ddrclkperiod_us;
+ ths_term = (ths_term >= 2) ? ths_term - 2 : ths_term;
+ ctx_dbg(1, ctx, "ths_term: %d (0x%02x)\n", ths_term, ths_term);
+
+ /*
+ * THS_SETTLE: Programmed value = floor(176.3 ns/CtrlClk period) - 1.
+ * Since CtrlClk is fixed at 96Mhz then we get
+ * ths_settle = floor(176.3 / 10.416) - 1 = 15
+ * If we ever switch to a dynamic clock then this code might be useful
+ *
+ * unsigned int ctrlclkperiod_us;
+ * ctrlclkperiod_us = 96000000 / 1000000;
+ * ctrlclkperiod_us = 1000000 / ctrlclkperiod_us;
+ * ctx_dbg(1, ctx, "ctrlclkperiod_us: %d\n", ctrlclkperiod_us);
+
+ * ths_settle = 176300 / ctrlclkperiod_us;
+ * ths_settle = (ths_settle > 1) ? ths_settle - 1 : ths_settle;
+ */
+
+ ths_settle = THS_SETTLE;
+ ctx_dbg(1, ctx, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle);
+
+ reg0 = reg_read(ctx->cc, CAL_CSI2_PHY_REG0);
+ set_field(&reg0, CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE,
+ CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK);
+ set_field(&reg0, ths_term, CAL_CSI2_PHY_REG0_THS_TERM_MASK);
+ set_field(&reg0, ths_settle, CAL_CSI2_PHY_REG0_THS_SETTLE_MASK);
+
+ ctx_dbg(1, ctx, "CSI2_%d_REG0 = 0x%08x\n", (ctx->csi2_port - 1), reg0);
+ reg_write(ctx->cc, CAL_CSI2_PHY_REG0, reg0);
+
+ reg1 = reg_read(ctx->cc, CAL_CSI2_PHY_REG1);
+ set_field(&reg1, TCLK_TERM, CAL_CSI2_PHY_REG1_TCLK_TERM_MASK);
+ set_field(&reg1, 0xb8, CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK);
+ set_field(&reg1, TCLK_MISS, CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK);
+ set_field(&reg1, TCLK_SETTLE, CAL_CSI2_PHY_REG1_TCLK_SETTLE_MASK);
+
+ ctx_dbg(1, ctx, "CSI2_%d_REG1 = 0x%08x\n", (ctx->csi2_port - 1), reg1);
+ reg_write(ctx->cc, CAL_CSI2_PHY_REG1, reg1);
+}
+
+static int cal_get_external_info(struct cal_ctx *ctx)
+{
+ struct v4l2_ctrl *ctrl;
+
+ if (!ctx->sensor)
+ return -ENODEV;
+
+ ctrl = v4l2_ctrl_find(ctx->sensor->ctrl_handler, V4L2_CID_PIXEL_RATE);
+ if (!ctrl) {
+ ctx_err(ctx, "no pixel rate control in subdev: %s\n",
+ ctx->sensor->name);
+ return -EPIPE;
+ }
+
+ ctx->external_rate = v4l2_ctrl_g_ctrl_int64(ctrl);
+ ctx_dbg(3, ctx, "sensor Pixel Rate: %d\n", ctx->external_rate);
+
+ return 0;
+}
+
+static inline void cal_schedule_next_buffer(struct cal_ctx *ctx)
+{
+ struct cal_dmaqueue *dma_q = &ctx->vidq;
+ struct cal_buffer *buf;
+ unsigned long addr;
+
+ buf = list_entry(dma_q->active.next, struct cal_buffer, list);
+ ctx->next_frm = buf;
+ list_del(&buf->list);
+
+ addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+ cal_wr_dma_addr(ctx, addr);
+}
+
+static inline void cal_process_buffer_complete(struct cal_ctx *ctx)
+{
+ ctx->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
+ ctx->cur_frm->vb.field = ctx->m_fmt.field;
+ ctx->cur_frm->vb.sequence = ctx->sequence++;
+
+ vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ ctx->cur_frm = ctx->next_frm;
+}
+
+#define isvcirqset(irq, vc, ff) (irq & \
+ (CAL_CSI2_VC_IRQENABLE_ ##ff ##_IRQ_##vc ##_MASK))
+
+#define isportirqset(irq, port) (irq & CAL_HL_IRQ_MASK(port))
+
+static irqreturn_t cal_irq(int irq_cal, void *data)
+{
+ struct cal_dev *dev = (struct cal_dev *)data;
+ struct cal_ctx *ctx;
+ struct cal_dmaqueue *dma_q;
+ u32 irqst2, irqst3;
+
+ /* Check which DMA just finished */
+ irqst2 = reg_read(dev, CAL_HL_IRQSTATUS(2));
+ if (irqst2) {
+ /* Clear Interrupt status */
+ reg_write(dev, CAL_HL_IRQSTATUS(2), irqst2);
+
+ /* Need to check both port */
+ if (isportirqset(irqst2, 1)) {
+ ctx = dev->ctx[0];
+
+ if (ctx->cur_frm != ctx->next_frm)
+ cal_process_buffer_complete(ctx);
+ }
+
+ if (isportirqset(irqst2, 2)) {
+ ctx = dev->ctx[1];
+
+ if (ctx->cur_frm != ctx->next_frm)
+ cal_process_buffer_complete(ctx);
+ }
+ }
+
+ /* Check which DMA just started */
+ irqst3 = reg_read(dev, CAL_HL_IRQSTATUS(3));
+ if (irqst3) {
+ /* Clear Interrupt status */
+ reg_write(dev, CAL_HL_IRQSTATUS(3), irqst3);
+
+ /* Need to check both port */
+ if (isportirqset(irqst3, 1)) {
+ ctx = dev->ctx[0];
+ dma_q = &ctx->vidq;
+
+ spin_lock(&ctx->slock);
+ if (!list_empty(&dma_q->active) &&
+ ctx->cur_frm == ctx->next_frm)
+ cal_schedule_next_buffer(ctx);
+ spin_unlock(&ctx->slock);
+ }
+
+ if (isportirqset(irqst3, 2)) {
+ ctx = dev->ctx[1];
+ dma_q = &ctx->vidq;
+
+ spin_lock(&ctx->slock);
+ if (!list_empty(&dma_q->active) &&
+ ctx->cur_frm == ctx->next_frm)
+ cal_schedule_next_buffer(ctx);
+ spin_unlock(&ctx->slock);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * video ioctls
+ */
+static int cal_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cal_ctx *ctx = video_drvdata(file);
+
+ strlcpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card));
+
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", ctx->v4l2_dev.name);
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int cal_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct cal_ctx *ctx = video_drvdata(file);
+ const struct cal_fmt *fmt = NULL;
+
+ if (f->index >= ctx->num_active_fmt)
+ return -EINVAL;
+
+ fmt = ctx->active_fmt[f->index];
+
+ f->pixelformat = fmt->fourcc;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ return 0;
+}
+
+static int __subdev_get_format(struct cal_ctx *ctx,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct v4l2_subdev_format sd_fmt;
+ struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
+ int ret;
+
+ sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ sd_fmt.pad = 0;
+
+ ret = v4l2_subdev_call(ctx->sensor, pad, get_fmt, NULL, &sd_fmt);
+ if (ret)
+ return ret;
+
+ *fmt = *mbus_fmt;
+
+ ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__,
+ fmt->width, fmt->height, fmt->code);
+
+ return 0;
+}
+
+static int __subdev_set_format(struct cal_ctx *ctx,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct v4l2_subdev_format sd_fmt;
+ struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
+ int ret;
+
+ sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ sd_fmt.pad = 0;
+ *mbus_fmt = *fmt;
+
+ ret = v4l2_subdev_call(ctx->sensor, pad, set_fmt, NULL, &sd_fmt);
+ if (ret)
+ return ret;
+
+ ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__,
+ fmt->width, fmt->height, fmt->code);
+
+ return 0;
+}
+
+static int cal_calc_format_size(struct cal_ctx *ctx,
+ const struct cal_fmt *fmt,
+ struct v4l2_format *f)
+{
+ if (!fmt) {
+ ctx_dbg(3, ctx, "No cal_fmt provided!\n");
+ return -EINVAL;
+ }
+
+ v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
+ &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
+ f->fmt.pix.bytesperline = bytes_per_line(f->fmt.pix.width,
+ fmt->depth >> 3);
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+
+ ctx_dbg(3, ctx, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n",
+ __func__, fourcc_to_str(f->fmt.pix.pixelformat),
+ f->fmt.pix.width, f->fmt.pix.height,
+ f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
+
+ return 0;
+}
+
+static int cal_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cal_ctx *ctx = video_drvdata(file);
+
+ *f = ctx->v_fmt;
+
+ return 0;
+}
+
+static int cal_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cal_ctx *ctx = video_drvdata(file);
+ const struct cal_fmt *fmt;
+ struct v4l2_subdev_frame_size_enum fse;
+ int ret, found;
+
+ fmt = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
+ if (!fmt) {
+ ctx_dbg(3, ctx, "Fourcc format (0x%08x) not found.\n",
+ f->fmt.pix.pixelformat);
+
+ /* Just get the first one enumerated */
+ fmt = ctx->active_fmt[0];
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ }
+
+ f->fmt.pix.field = ctx->v_fmt.fmt.pix.field;
+
+ /* check for/find a valid width/height */
+ ret = 0;
+ found = false;
+ fse.pad = 0;
+ fse.code = fmt->code;
+ fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ for (fse.index = 0; ; fse.index++) {
+ ret = v4l2_subdev_call(ctx->sensor, pad, enum_frame_size,
+ NULL, &fse);
+ if (ret)
+ break;
+
+ if ((f->fmt.pix.width == fse.max_width) &&
+ (f->fmt.pix.height == fse.max_height)) {
+ found = true;
+ break;
+ } else if ((f->fmt.pix.width >= fse.min_width) &&
+ (f->fmt.pix.width <= fse.max_width) &&
+ (f->fmt.pix.height >= fse.min_height) &&
+ (f->fmt.pix.height <= fse.max_height)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* use existing values as default */
+ f->fmt.pix.width = ctx->v_fmt.fmt.pix.width;
+ f->fmt.pix.height = ctx->v_fmt.fmt.pix.height;
+ }
+
+ /*
+ * Use current colorspace for now, it will get
+ * updated properly during s_fmt
+ */
+ f->fmt.pix.colorspace = ctx->v_fmt.fmt.pix.colorspace;
+ return cal_calc_format_size(ctx, fmt, f);
+}
+
+static int cal_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cal_ctx *ctx = video_drvdata(file);
+ struct vb2_queue *q = &ctx->vb_vidq;
+ const struct cal_fmt *fmt;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ int ret;
+
+ if (vb2_is_busy(q)) {
+ ctx_dbg(3, ctx, "%s device busy\n", __func__);
+ return -EBUSY;
+ }
+
+ ret = cal_try_fmt_vid_cap(file, priv, f);
+ if (ret < 0)
+ return ret;
+
+ fmt = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
+
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code);
+
+ ret = __subdev_set_format(ctx, &mbus_fmt);
+ if (ret)
+ return ret;
+
+ /* Just double check nothing has gone wrong */
+ if (mbus_fmt.code != fmt->code) {
+ ctx_dbg(3, ctx,
+ "%s subdev changed format on us, this should not happen\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt);
+ ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ctx->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
+ cal_calc_format_size(ctx, fmt, &ctx->v_fmt);
+ ctx->fmt = fmt;
+ ctx->m_fmt = mbus_fmt;
+ *f = ctx->v_fmt;
+
+ return 0;
+}
+
+static int cal_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct cal_ctx *ctx = video_drvdata(file);
+ const struct cal_fmt *fmt;
+ struct v4l2_subdev_frame_size_enum fse;
+ int ret;
+
+ /* check for valid format */
+ fmt = find_format_by_pix(ctx, fsize->pixel_format);
+ if (!fmt) {
+ ctx_dbg(3, ctx, "Invalid pixel code: %x\n",
+ fsize->pixel_format);
+ return -EINVAL;
+ }
+
+ fse.index = fsize->index;
+ fse.pad = 0;
+ fse.code = fmt->code;
+
+ ret = v4l2_subdev_call(ctx->sensor, pad, enum_frame_size, NULL, &fse);
+ if (ret)
+ return ret;
+
+ ctx_dbg(1, ctx, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
+ __func__, fse.index, fse.code, fse.min_width, fse.max_width,
+ fse.min_height, fse.max_height);
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = fse.max_width;
+ fsize->discrete.height = fse.max_height;
+
+ return 0;
+}
+
+static int cal_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index >= CAL_NUM_INPUT)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ sprintf(inp->name, "Camera %u", inp->index);
+ return 0;
+}
+
+static int cal_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct cal_ctx *ctx = video_drvdata(file);
+
+ *i = ctx->input;
+ return 0;
+}
+
+static int cal_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct cal_ctx *ctx = video_drvdata(file);
+
+ if (i >= CAL_NUM_INPUT)
+ return -EINVAL;
+
+ ctx->input = i;
+ return 0;
+}
+
+/* timeperframe is arbitrary and continuous */
+static int cal_enum_frameintervals(struct file *file, void *priv,
+ struct v4l2_frmivalenum *fival)
+{
+ struct cal_ctx *ctx = video_drvdata(file);
+ const struct cal_fmt *fmt;
+ struct v4l2_subdev_frame_interval_enum fie = {
+ .index = fival->index,
+ .width = fival->width,
+ .height = fival->height,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ int ret;
+
+ fmt = find_format_by_pix(ctx, fival->pixel_format);
+ if (!fmt)
+ return -EINVAL;
+
+ fie.code = fmt->code;
+ ret = v4l2_subdev_call(ctx->sensor, pad, enum_frame_interval,
+ NULL, &fie);
+ if (ret)
+ return ret;
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete = fie.interval;
+
+ return 0;
+}
+
+/*
+ * Videobuf operations
+ */
+static int cal_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct cal_ctx *ctx = vb2_get_drv_priv(vq);
+ unsigned size = ctx->v_fmt.fmt.pix.sizeimage;
+
+ if (vq->num_buffers + *nbuffers < 3)
+ *nbuffers = 3 - vq->num_buffers;
+ alloc_ctxs[0] = ctx->alloc_ctx;
+
+ if (*nplanes) {
+ if (sizes[0] < size)
+ return -EINVAL;
+ size = sizes[0];
+ }
+
+ *nplanes = 1;
+ sizes[0] = size;
+
+ ctx_dbg(3, ctx, "nbuffers=%d, size=%d\n", *nbuffers, sizes[0]);
+
+ return 0;
+}
+
+static int cal_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct cal_buffer *buf = container_of(vb, struct cal_buffer,
+ vb.vb2_buf);
+ unsigned long size;
+
+ if (WARN_ON(!ctx->fmt))
+ return -EINVAL;
+
+ size = ctx->v_fmt.fmt.pix.sizeimage;
+ if (vb2_plane_size(vb, 0) < size) {
+ ctx_err(ctx,
+ "data will not fit into plane (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
+ return 0;
+}
+
+static void cal_buffer_queue(struct vb2_buffer *vb)
+{
+ struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct cal_buffer *buf = container_of(vb, struct cal_buffer,
+ vb.vb2_buf);
+ struct cal_dmaqueue *vidq = &ctx->vidq;
+ unsigned long flags = 0;
+
+ /* recheck locking */
+ spin_lock_irqsave(&ctx->slock, flags);
+ list_add_tail(&buf->list, &vidq->active);
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct cal_ctx *ctx = vb2_get_drv_priv(vq);
+ struct cal_dmaqueue *dma_q = &ctx->vidq;
+ struct cal_buffer *buf, *tmp;
+ unsigned long addr = 0;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ if (list_empty(&dma_q->active)) {
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ ctx_dbg(3, ctx, "buffer queue is empty\n");
+ return -EIO;
+ }
+
+ buf = list_entry(dma_q->active.next, struct cal_buffer, list);
+ ctx->cur_frm = buf;
+ ctx->next_frm = buf;
+ list_del(&buf->list);
+ spin_unlock_irqrestore(&ctx->slock, flags);
+
+ addr = vb2_dma_contig_plane_dma_addr(&ctx->cur_frm->vb.vb2_buf, 0);
+ ctx->sequence = 0;
+
+ ret = cal_get_external_info(ctx);
+ if (ret < 0)
+ goto err;
+
+ cal_runtime_get(ctx->dev);
+
+ enable_irqs(ctx);
+ camerarx_phy_enable(ctx);
+ csi2_init(ctx);
+ csi2_phy_config(ctx);
+ csi2_lane_config(ctx);
+ csi2_ctx_config(ctx);
+ pix_proc_config(ctx);
+ cal_wr_dma_config(ctx, ctx->v_fmt.fmt.pix.bytesperline);
+ cal_wr_dma_addr(ctx, addr);
+ csi2_ppi_enable(ctx);
+
+ ret = v4l2_subdev_call(ctx->sensor, video, s_stream, 1);
+ if (ret) {
+ ctx_err(ctx, "stream on failed in subdev\n");
+ cal_runtime_put(ctx->dev);
+ goto err;
+ }
+
+ if (debug >= 4)
+ cal_quickdump_regs(ctx->dev);
+
+ return 0;
+
+err:
+ list_for_each_entry_safe(buf, tmp, &dma_q->active, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
+ }
+ return ret;
+}
+
+static void cal_stop_streaming(struct vb2_queue *vq)
+{
+ struct cal_ctx *ctx = vb2_get_drv_priv(vq);
+ struct cal_dmaqueue *dma_q = &ctx->vidq;
+ struct cal_buffer *buf, *tmp;
+ unsigned long flags;
+
+ if (v4l2_subdev_call(ctx->sensor, video, s_stream, 0))
+ ctx_err(ctx, "stream off failed in subdev\n");
+
+ csi2_ppi_disable(ctx);
+ disable_irqs(ctx);
+
+ /* Release all active buffers */
+ spin_lock_irqsave(&ctx->slock, flags);
+ list_for_each_entry_safe(buf, tmp, &dma_q->active, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ if (ctx->cur_frm == ctx->next_frm) {
+ vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ } else {
+ vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ vb2_buffer_done(&ctx->next_frm->vb.vb2_buf,
+ VB2_BUF_STATE_ERROR);
+ }
+ ctx->cur_frm = NULL;
+ ctx->next_frm = NULL;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+
+ cal_runtime_put(ctx->dev);
+}
+
+static struct vb2_ops cal_video_qops = {
+ .queue_setup = cal_queue_setup,
+ .buf_prepare = cal_buffer_prepare,
+ .buf_queue = cal_buffer_queue,
+ .start_streaming = cal_start_streaming,
+ .stop_streaming = cal_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static const struct v4l2_file_operations cal_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = vb2_fop_mmap,
+};
+
+static const struct v4l2_ioctl_ops cal_ioctl_ops = {
+ .vidioc_querycap = cal_querycap,
+ .vidioc_enum_fmt_vid_cap = cal_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = cal_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = cal_s_fmt_vid_cap,
+ .vidioc_enum_framesizes = cal_enum_framesizes,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_enum_input = cal_enum_input,
+ .vidioc_g_input = cal_g_input,
+ .vidioc_s_input = cal_s_input,
+ .vidioc_enum_frameintervals = cal_enum_frameintervals,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static struct video_device cal_videodev = {
+ .name = CAL_MODULE_NAME,
+ .fops = &cal_fops,
+ .ioctl_ops = &cal_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release_empty,
+};
+
+/* -----------------------------------------------------------------
+ * Initialization and module stuff
+ * ------------------------------------------------------------------
+ */
+static int cal_complete_ctx(struct cal_ctx *ctx);
+
+static int cal_async_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct cal_ctx *ctx = notifier_to_ctx(notifier);
+ struct v4l2_subdev_mbus_code_enum mbus_code;
+ int ret = 0;
+ int i, j, k;
+
+ if (ctx->sensor) {
+ ctx_info(ctx, "Rejecting subdev %s (Already set!!)",
+ subdev->name);
+ return 0;
+ }
+
+ ctx->sensor = subdev;
+ ctx_dbg(1, ctx, "Using sensor %s for capture\n", subdev->name);
+
+ /* Enumerate sub device formats and enable all matching local formats */
+ ctx->num_active_fmt = 0;
+ for (j = 0, i = 0; ret != -EINVAL; ++j) {
+ struct cal_fmt *fmt;
+
+ memset(&mbus_code, 0, sizeof(mbus_code));
+ mbus_code.index = j;
+ ret = v4l2_subdev_call(subdev, pad, enum_mbus_code,
+ NULL, &mbus_code);
+ if (ret)
+ continue;
+
+ ctx_dbg(2, ctx,
+ "subdev %s: code: %04x idx: %d\n",
+ subdev->name, mbus_code.code, j);
+
+ for (k = 0; k < ARRAY_SIZE(cal_formats); k++) {
+ fmt = &cal_formats[k];
+
+ if (mbus_code.code == fmt->code) {
+ ctx->active_fmt[i] = fmt;
+ ctx_dbg(2, ctx,
+ "matched fourcc: %s: code: %04x idx: %d\n",
+ fourcc_to_str(fmt->fourcc),
+ fmt->code, i);
+ ctx->num_active_fmt = ++i;
+ }
+ }
+ }
+
+ if (i == 0) {
+ ctx_err(ctx, "No suitable format reported by subdev %s\n",
+ subdev->name);
+ return -EINVAL;
+ }
+
+ cal_complete_ctx(ctx);
+
+ return 0;
+}
+
+static int cal_async_complete(struct v4l2_async_notifier *notifier)
+{
+ struct cal_ctx *ctx = notifier_to_ctx(notifier);
+ const struct cal_fmt *fmt;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ int ret;
+
+ ret = __subdev_get_format(ctx, &mbus_fmt);
+ if (ret)
+ return ret;
+
+ fmt = find_format_by_code(ctx, mbus_fmt.code);
+ if (!fmt) {
+ ctx_dbg(3, ctx, "mbus code format (0x%08x) not found.\n",
+ mbus_fmt.code);
+ return -EINVAL;
+ }
+
+ /* Save current subdev format */
+ v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt);
+ ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ctx->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
+ cal_calc_format_size(ctx, fmt, &ctx->v_fmt);
+ ctx->fmt = fmt;
+ ctx->m_fmt = mbus_fmt;
+
+ return 0;
+}
+
+static int cal_complete_ctx(struct cal_ctx *ctx)
+{
+ struct video_device *vfd;
+ struct vb2_queue *q;
+ int ret;
+
+ ctx->timeperframe = tpf_default;
+ ctx->external_rate = 192000000;
+
+ /* initialize locks */
+ spin_lock_init(&ctx->slock);
+ mutex_init(&ctx->mutex);
+
+ /* initialize queue */
+ q = &ctx->vb_vidq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ q->drv_priv = ctx;
+ q->buf_struct_size = sizeof(struct cal_buffer);
+ q->ops = &cal_video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &ctx->mutex;
+ q->min_buffers_needed = 3;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&ctx->vidq.active);
+
+ vfd = &ctx->vdev;
+ *vfd = cal_videodev;
+ vfd->v4l2_dev = &ctx->v4l2_dev;
+ vfd->queue = q;
+
+ /*
+ * Provide a mutex to v4l2 core. It will be used to protect
+ * all fops and v4l2 ioctls.
+ */
+ vfd->lock = &ctx->mutex;
+ video_set_drvdata(vfd, ctx);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+ if (ret < 0)
+ return ret;
+
+ v4l2_info(&ctx->v4l2_dev, "V4L2 device registered as %s\n",
+ video_device_node_name(vfd));
+
+ ctx->alloc_ctx = vb2_dma_contig_init_ctx(vfd->v4l2_dev->dev);
+ if (IS_ERR(ctx->alloc_ctx)) {
+ ctx_err(ctx, "Failed to alloc vb2 context\n");
+ ret = PTR_ERR(ctx->alloc_ctx);
+ goto vdev_unreg;
+ }
+
+ return 0;
+
+vdev_unreg:
+ video_unregister_device(vfd);
+ return ret;
+}
+
+static struct device_node *
+of_get_next_port(const struct device_node *parent,
+ struct device_node *prev)
+{
+ struct device_node *port = NULL;
+
+ if (!parent)
+ return NULL;
+
+ if (!prev) {
+ struct device_node *ports;
+ /*
+ * It's the first call, we have to find a port subnode
+ * within this node or within an optional 'ports' node.
+ */
+ ports = of_get_child_by_name(parent, "ports");
+ if (ports)
+ parent = ports;
+
+ port = of_get_child_by_name(parent, "port");
+
+ /* release the 'ports' node */
+ of_node_put(ports);
+ } else {
+ struct device_node *ports;
+
+ ports = of_get_parent(prev);
+ if (!ports)
+ return NULL;
+
+ do {
+ port = of_get_next_child(ports, prev);
+ if (!port) {
+ of_node_put(ports);
+ return NULL;
+ }
+ prev = port;
+ } while (of_node_cmp(port->name, "port") != 0);
+ }
+
+ return port;
+}
+
+static struct device_node *
+of_get_next_endpoint(const struct device_node *parent,
+ struct device_node *prev)
+{
+ struct device_node *ep = NULL;
+
+ if (!parent)
+ return NULL;
+
+ do {
+ ep = of_get_next_child(parent, prev);
+ if (!ep)
+ return NULL;
+ prev = ep;
+ } while (of_node_cmp(ep->name, "endpoint") != 0);
+
+ return ep;
+}
+
+static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
+{
+ struct platform_device *pdev = ctx->dev->pdev;
+ struct device_node *ep_node, *port, *remote_ep,
+ *sensor_node, *parent;
+ struct v4l2_of_endpoint *endpoint;
+ struct v4l2_async_subdev *asd;
+ u32 regval = 0;
+ int ret, index, found_port = 0, lane;
+
+ parent = pdev->dev.of_node;
+
+ asd = &ctx->asd;
+ endpoint = &ctx->endpoint;
+
+ ep_node = NULL;
+ port = NULL;
+ remote_ep = NULL;
+ sensor_node = NULL;
+ ret = -EINVAL;
+
+ ctx_dbg(3, ctx, "Scanning Port node for csi2 port: %d\n", inst);
+ for (index = 0; index < CAL_NUM_CSI2_PORTS; index++) {
+ port = of_get_next_port(parent, port);
+ if (!port) {
+ ctx_dbg(1, ctx, "No port node found for csi2 port:%d\n",
+ index);
+ goto cleanup_exit;
+ }
+
+ /* Match the slice number with <REG> */
+ of_property_read_u32(port, "reg", &regval);
+ ctx_dbg(3, ctx, "port:%d inst:%d <reg>:%d\n",
+ index, inst, regval);
+ if ((regval == inst) && (index == inst)) {
+ found_port = 1;
+ break;
+ }
+ }
+
+ if (!found_port) {
+ ctx_dbg(1, ctx, "No port node matches csi2 port:%d\n",
+ inst);
+ goto cleanup_exit;
+ }
+
+ ctx_dbg(3, ctx, "Scanning sub-device for csi2 port: %d\n",
+ inst);
+
+ ep_node = of_get_next_endpoint(port, ep_node);
+ if (!ep_node) {
+ ctx_dbg(3, ctx, "can't get next endpoint\n");
+ goto cleanup_exit;
+ }
+
+ sensor_node = of_graph_get_remote_port_parent(ep_node);
+ if (!sensor_node) {
+ ctx_dbg(3, ctx, "can't get remote parent\n");
+ goto cleanup_exit;
+ }
+ asd->match_type = V4L2_ASYNC_MATCH_OF;
+ asd->match.of.node = sensor_node;
+
+ remote_ep = of_parse_phandle(ep_node, "remote-endpoint", 0);
+ if (!remote_ep) {
+ ctx_dbg(3, ctx, "can't get remote-endpoint\n");
+ goto cleanup_exit;
+ }
+ v4l2_of_parse_endpoint(remote_ep, endpoint);
+
+ if (endpoint->bus_type != V4L2_MBUS_CSI2) {
+ ctx_err(ctx, "Port:%d sub-device %s is not a CSI2 device\n",
+ inst, sensor_node->name);
+ goto cleanup_exit;
+ }
+
+ /* Store Virtual Channel number */
+ ctx->virtual_channel = endpoint->base.id;
+
+ ctx_dbg(3, ctx, "Port:%d v4l2-endpoint: CSI2\n", inst);
+ ctx_dbg(3, ctx, "Virtual Channel=%d\n", ctx->virtual_channel);
+ ctx_dbg(3, ctx, "flags=0x%08x\n", endpoint->bus.mipi_csi2.flags);
+ ctx_dbg(3, ctx, "clock_lane=%d\n", endpoint->bus.mipi_csi2.clock_lane);
+ ctx_dbg(3, ctx, "num_data_lanes=%d\n",
+ endpoint->bus.mipi_csi2.num_data_lanes);
+ ctx_dbg(3, ctx, "data_lanes= <\n");
+ for (lane = 0; lane < endpoint->bus.mipi_csi2.num_data_lanes; lane++)
+ ctx_dbg(3, ctx, "\t%d\n",
+ endpoint->bus.mipi_csi2.data_lanes[lane]);
+ ctx_dbg(3, ctx, "\t>\n");
+
+ ctx_dbg(1, ctx, "Port: %d found sub-device %s\n",
+ inst, sensor_node->name);
+
+ ctx->asd_list[0] = asd;
+ ctx->notifier.subdevs = ctx->asd_list;
+ ctx->notifier.num_subdevs = 1;
+ ctx->notifier.bound = cal_async_bound;
+ ctx->notifier.complete = cal_async_complete;
+ ret = v4l2_async_notifier_register(&ctx->v4l2_dev,
+ &ctx->notifier);
+ if (ret) {
+ ctx_err(ctx, "Error registering async notifier\n");
+ ret = -EINVAL;
+ }
+
+cleanup_exit:
+ if (!remote_ep)
+ of_node_put(remote_ep);
+ if (!sensor_node)
+ of_node_put(sensor_node);
+ if (!ep_node)
+ of_node_put(ep_node);
+ if (!port)
+ of_node_put(port);
+
+ return ret;
+}
+
+static struct cal_ctx *cal_create_instance(struct cal_dev *dev, int inst)
+{
+ struct cal_ctx *ctx;
+ struct v4l2_ctrl_handler *hdl;
+ int ret;
+
+ ctx = devm_kzalloc(&dev->pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ /* save the cal_dev * for future ref */
+ ctx->dev = dev;
+
+ snprintf(ctx->v4l2_dev.name, sizeof(ctx->v4l2_dev.name),
+ "%s-%03d", CAL_MODULE_NAME, inst);
+ ret = v4l2_device_register(&dev->pdev->dev, &ctx->v4l2_dev);
+ if (ret)
+ goto err_exit;
+
+ hdl = &ctx->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(hdl, 11);
+ if (ret) {
+ ctx_err(ctx, "Failed to init ctrl handler\n");
+ goto unreg_dev;
+ }
+ ctx->v4l2_dev.ctrl_handler = hdl;
+
+ /* Make sure Camera Core H/W register area is available */
+ ctx->cc = dev->cc[inst];
+
+ /* Store the instance id */
+ ctx->csi2_port = inst + 1;
+
+ ret = of_cal_create_instance(ctx, inst);
+ if (ret) {
+ ret = -EINVAL;
+ goto free_hdl;
+ }
+ return ctx;
+
+free_hdl:
+ v4l2_ctrl_handler_free(hdl);
+unreg_dev:
+ v4l2_device_unregister(&ctx->v4l2_dev);
+err_exit:
+ return NULL;
+}
+
+static int cal_probe(struct platform_device *pdev)
+{
+ struct cal_dev *dev;
+ int ret;
+ int irq;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ /* set pseudo v4l2 device name so we can use v4l2_printk */
+ strlcpy(dev->v4l2_dev.name, CAL_MODULE_NAME,
+ sizeof(dev->v4l2_dev.name));
+
+ /* save pdev pointer */
+ dev->pdev = pdev;
+
+ dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "cal_top");
+ dev->base = devm_ioremap_resource(&pdev->dev, dev->res);
+ if (IS_ERR(dev->base))
+ return PTR_ERR(dev->base);
+
+ cal_dbg(1, dev, "ioresource %s at %pa - %pa\n",
+ dev->res->name, &dev->res->start, &dev->res->end);
+
+ irq = platform_get_irq(pdev, 0);
+ cal_dbg(1, dev, "got irq# %d\n", irq);
+ ret = devm_request_irq(&pdev->dev, irq, cal_irq, 0, CAL_MODULE_NAME,
+ dev);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, dev);
+
+ dev->cm = cm_create(dev);
+ if (IS_ERR(dev->cm))
+ return PTR_ERR(dev->cm);
+
+ dev->cc[0] = cc_create(dev, 0);
+ if (IS_ERR(dev->cc[0]))
+ return PTR_ERR(dev->cc[0]);
+
+ dev->cc[1] = cc_create(dev, 1);
+ if (IS_ERR(dev->cc[1]))
+ return PTR_ERR(dev->cc[1]);
+
+ dev->ctx[0] = NULL;
+ dev->ctx[1] = NULL;
+
+ dev->ctx[0] = cal_create_instance(dev, 0);
+ dev->ctx[1] = cal_create_instance(dev, 1);
+ if (!dev->ctx[0] && !dev->ctx[1]) {
+ cal_err(dev, "Neither port is configured, no point in staying up\n");
+ return -ENODEV;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = cal_runtime_get(dev);
+ if (ret)
+ goto runtime_disable;
+
+ /* Just check we can actually access the module */
+ cal_get_hwinfo(dev);
+
+ cal_runtime_put(dev);
+
+ return 0;
+
+runtime_disable:
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+}
+
+static int cal_remove(struct platform_device *pdev)
+{
+ struct cal_dev *dev =
+ (struct cal_dev *)platform_get_drvdata(pdev);
+ struct cal_ctx *ctx;
+ int i;
+
+ cal_dbg(1, dev, "Removing %s\n", CAL_MODULE_NAME);
+
+ cal_runtime_get(dev);
+
+ for (i = 0; i < CAL_NUM_CONTEXT; i++) {
+ ctx = dev->ctx[i];
+ if (ctx) {
+ ctx_dbg(1, ctx, "unregistering %s\n",
+ video_device_node_name(&ctx->vdev));
+ camerarx_phy_disable(ctx);
+ v4l2_async_notifier_unregister(&ctx->notifier);
+ vb2_dma_contig_cleanup_ctx(ctx->alloc_ctx);
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ v4l2_device_unregister(&ctx->v4l2_dev);
+ video_unregister_device(&ctx->vdev);
+ }
+ }
+
+ cal_runtime_put(dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id cal_of_match[] = {
+ { .compatible = "ti,dra72-cal", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cal_of_match);
+#endif
+
+static struct platform_driver cal_pdrv = {
+ .probe = cal_probe,
+ .remove = cal_remove,
+ .driver = {
+ .name = CAL_MODULE_NAME,
+ .of_match_table = of_match_ptr(cal_of_match),
+ },
+};
+
+module_platform_driver(cal_pdrv);
diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h
new file mode 100644
index 000000000000..82b3dcf87128
--- /dev/null
+++ b/drivers/media/platform/ti-vpe/cal_regs.h
@@ -0,0 +1,479 @@
+/*
+ * TI CAL camera interface driver
+ *
+ * Copyright (c) 2015 Texas Instruments Inc.
+ *
+ * Benoit Parrot, <bparrot@ti.com>
+ *
+ * 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 published by
+ * the Free Software Foundation.
+ */
+
+#ifndef __TI_CAL_REGS_H
+#define __TI_CAL_REGS_H
+
+#define CAL_NUM_CSI2_PORTS 2
+
+/* CAL register offsets */
+
+#define CAL_HL_REVISION 0x0000
+#define CAL_HL_HWINFO 0x0004
+#define CAL_HL_SYSCONFIG 0x0010
+#define CAL_HL_IRQ_EOI 0x001c
+#define CAL_HL_IRQSTATUS_RAW(m) (0x20U + ((m-1) * 0x10U))
+#define CAL_HL_IRQSTATUS(m) (0x24U + ((m-1) * 0x10U))
+#define CAL_HL_IRQENABLE_SET(m) (0x28U + ((m-1) * 0x10U))
+#define CAL_HL_IRQENABLE_CLR(m) (0x2cU + ((m-1) * 0x10U))
+#define CAL_PIX_PROC(m) (0xc0U + ((m-1) * 0x4U))
+#define CAL_CTRL 0x100
+#define CAL_CTRL1 0x104
+#define CAL_LINE_NUMBER_EVT 0x108
+#define CAL_VPORT_CTRL1 0x120
+#define CAL_VPORT_CTRL2 0x124
+#define CAL_BYS_CTRL1 0x130
+#define CAL_BYS_CTRL2 0x134
+#define CAL_RD_DMA_CTRL 0x140
+#define CAL_RD_DMA_PIX_ADDR 0x144
+#define CAL_RD_DMA_PIX_OFST 0x148
+#define CAL_RD_DMA_XSIZE 0x14c
+#define CAL_RD_DMA_YSIZE 0x150
+#define CAL_RD_DMA_INIT_ADDR 0x154
+#define CAL_RD_DMA_INIT_OFST 0x168
+#define CAL_RD_DMA_CTRL2 0x16c
+#define CAL_WR_DMA_CTRL(m) (0x200U + ((m-1) * 0x10U))
+#define CAL_WR_DMA_ADDR(m) (0x204U + ((m-1) * 0x10U))
+#define CAL_WR_DMA_OFST(m) (0x208U + ((m-1) * 0x10U))
+#define CAL_WR_DMA_XSIZE(m) (0x20cU + ((m-1) * 0x10U))
+#define CAL_CSI2_PPI_CTRL(m) (0x300U + ((m-1) * 0x80U))
+#define CAL_CSI2_COMPLEXIO_CFG(m) (0x304U + ((m-1) * 0x80U))
+#define CAL_CSI2_COMPLEXIO_IRQSTATUS(m) (0x308U + ((m-1) * 0x80U))
+#define CAL_CSI2_SHORT_PACKET(m) (0x30cU + ((m-1) * 0x80U))
+#define CAL_CSI2_COMPLEXIO_IRQENABLE(m) (0x310U + ((m-1) * 0x80U))
+#define CAL_CSI2_TIMING(m) (0x314U + ((m-1) * 0x80U))
+#define CAL_CSI2_VC_IRQENABLE(m) (0x318U + ((m-1) * 0x80U))
+#define CAL_CSI2_VC_IRQSTATUS(m) (0x328U + ((m-1) * 0x80U))
+#define CAL_CSI2_CTX0(m) (0x330U + ((m-1) * 0x80U))
+#define CAL_CSI2_CTX1(m) (0x334U + ((m-1) * 0x80U))
+#define CAL_CSI2_CTX2(m) (0x338U + ((m-1) * 0x80U))
+#define CAL_CSI2_CTX3(m) (0x33cU + ((m-1) * 0x80U))
+#define CAL_CSI2_CTX4(m) (0x340U + ((m-1) * 0x80U))
+#define CAL_CSI2_CTX5(m) (0x344U + ((m-1) * 0x80U))
+#define CAL_CSI2_CTX6(m) (0x348U + ((m-1) * 0x80U))
+#define CAL_CSI2_CTX7(m) (0x34cU + ((m-1) * 0x80U))
+#define CAL_CSI2_STATUS0(m) (0x350U + ((m-1) * 0x80U))
+#define CAL_CSI2_STATUS1(m) (0x354U + ((m-1) * 0x80U))
+#define CAL_CSI2_STATUS2(m) (0x358U + ((m-1) * 0x80U))
+#define CAL_CSI2_STATUS3(m) (0x35cU + ((m-1) * 0x80U))
+#define CAL_CSI2_STATUS4(m) (0x360U + ((m-1) * 0x80U))
+#define CAL_CSI2_STATUS5(m) (0x364U + ((m-1) * 0x80U))
+#define CAL_CSI2_STATUS6(m) (0x368U + ((m-1) * 0x80U))
+#define CAL_CSI2_STATUS7(m) (0x36cU + ((m-1) * 0x80U))
+
+/* CAL CSI2 PHY register offsets */
+#define CAL_CSI2_PHY_REG0 0x000
+#define CAL_CSI2_PHY_REG1 0x004
+#define CAL_CSI2_PHY_REG2 0x008
+
+/* CAL Control Module Core Camerrx Control register offsets */
+#define CM_CTRL_CORE_CAMERRX_CONTROL 0x000
+
+/*********************************************************************
+* Generic value used in various field below
+*********************************************************************/
+
+#define CAL_GEN_DISABLE 0
+#define CAL_GEN_ENABLE 1
+#define CAL_GEN_FALSE 0
+#define CAL_GEN_TRUE 1
+
+/*********************************************************************
+* Field Definition Macros
+*********************************************************************/
+
+#define CAL_HL_REVISION_MINOR_MASK GENMASK(5, 0)
+#define CAL_HL_REVISION_CUSTOM_MASK GENMASK(7, 6)
+#define CAL_HL_REVISION_MAJOR_MASK GENMASK(10, 8)
+#define CAL_HL_REVISION_RTL_MASK GENMASK(15, 11)
+#define CAL_HL_REVISION_FUNC_MASK GENMASK(27, 16)
+#define CAL_HL_REVISION_SCHEME_MASK GENMASK(31, 30)
+#define CAL_HL_REVISION_SCHEME_H08 1
+#define CAL_HL_REVISION_SCHEME_LEGACY 0
+
+#define CAL_HL_HWINFO_WFIFO_MASK GENMASK(3, 0)
+#define CAL_HL_HWINFO_RFIFO_MASK GENMASK(7, 4)
+#define CAL_HL_HWINFO_PCTX_MASK GENMASK(12, 8)
+#define CAL_HL_HWINFO_WCTX_MASK GENMASK(18, 13)
+#define CAL_HL_HWINFO_VFIFO_MASK GENMASK(22, 19)
+#define CAL_HL_HWINFO_NCPORT_MASK GENMASK(27, 23)
+#define CAL_HL_HWINFO_NPPI_CTXS0_MASK GENMASK(29, 28)
+#define CAL_HL_HWINFO_NPPI_CTXS1_MASK GENMASK(31, 30)
+#define CAL_HL_HWINFO_NPPI_CONTEXTS_ZERO 0
+#define CAL_HL_HWINFO_NPPI_CONTEXTS_FOUR 1
+#define CAL_HL_HWINFO_NPPI_CONTEXTS_EIGHT 2
+#define CAL_HL_HWINFO_NPPI_CONTEXTS_RESERVED 3
+
+#define CAL_HL_SYSCONFIG_SOFTRESET_MASK BIT_MASK(0)
+#define CAL_HL_SYSCONFIG_SOFTRESET_DONE 0x0
+#define CAL_HL_SYSCONFIG_SOFTRESET_PENDING 0x1
+#define CAL_HL_SYSCONFIG_SOFTRESET_NOACTION 0x0
+#define CAL_HL_SYSCONFIG_SOFTRESET_RESET 0x1
+#define CAL_HL_SYSCONFIG_IDLE_MASK GENMASK(3, 2)
+#define CAL_HL_SYSCONFIG_IDLEMODE_FORCE 0
+#define CAL_HL_SYSCONFIG_IDLEMODE_NO 1
+#define CAL_HL_SYSCONFIG_IDLEMODE_SMART1 2
+#define CAL_HL_SYSCONFIG_IDLEMODE_SMART2 3
+
+#define CAL_HL_IRQ_EOI_LINE_NUMBER_MASK BIT_MASK(0)
+#define CAL_HL_IRQ_EOI_LINE_NUMBER_READ0 0
+#define CAL_HL_IRQ_EOI_LINE_NUMBER_EOI0 0
+
+#define CAL_HL_IRQ_MASK(m) BIT_MASK(m-1)
+#define CAL_HL_IRQ_NOACTION 0x0
+#define CAL_HL_IRQ_ENABLE 0x1
+#define CAL_HL_IRQ_CLEAR 0x1
+#define CAL_HL_IRQ_DISABLED 0x0
+#define CAL_HL_IRQ_ENABLED 0x1
+#define CAL_HL_IRQ_PENDING 0x1
+
+#define CAL_PIX_PROC_EN_MASK BIT_MASK(0)
+#define CAL_PIX_PROC_EXTRACT_MASK GENMASK(4, 1)
+#define CAL_PIX_PROC_EXTRACT_B6 0x0
+#define CAL_PIX_PROC_EXTRACT_B7 0x1
+#define CAL_PIX_PROC_EXTRACT_B8 0x2
+#define CAL_PIX_PROC_EXTRACT_B10 0x3
+#define CAL_PIX_PROC_EXTRACT_B10_MIPI 0x4
+#define CAL_PIX_PROC_EXTRACT_B12 0x5
+#define CAL_PIX_PROC_EXTRACT_B12_MIPI 0x6
+#define CAL_PIX_PROC_EXTRACT_B14 0x7
+#define CAL_PIX_PROC_EXTRACT_B14_MIPI 0x8
+#define CAL_PIX_PROC_EXTRACT_B16_BE 0x9
+#define CAL_PIX_PROC_EXTRACT_B16_LE 0xa
+#define CAL_PIX_PROC_DPCMD_MASK GENMASK(9, 5)
+#define CAL_PIX_PROC_DPCMD_BYPASS 0x0
+#define CAL_PIX_PROC_DPCMD_DPCM_10_8_1 0x2
+#define CAL_PIX_PROC_DPCMD_DPCM_12_8_1 0x8
+#define CAL_PIX_PROC_DPCMD_DPCM_10_7_1 0x4
+#define CAL_PIX_PROC_DPCMD_DPCM_10_7_2 0x5
+#define CAL_PIX_PROC_DPCMD_DPCM_10_6_1 0x6
+#define CAL_PIX_PROC_DPCMD_DPCM_10_6_2 0x7
+#define CAL_PIX_PROC_DPCMD_DPCM_12_7_1 0xa
+#define CAL_PIX_PROC_DPCMD_DPCM_12_6_1 0xc
+#define CAL_PIX_PROC_DPCMD_DPCM_14_10 0xe
+#define CAL_PIX_PROC_DPCMD_DPCM_14_8_1 0x10
+#define CAL_PIX_PROC_DPCMD_DPCM_16_12_1 0x12
+#define CAL_PIX_PROC_DPCMD_DPCM_16_10_1 0x14
+#define CAL_PIX_PROC_DPCMD_DPCM_16_8_1 0x16
+#define CAL_PIX_PROC_DPCME_MASK GENMASK(15, 11)
+#define CAL_PIX_PROC_DPCME_BYPASS 0x0
+#define CAL_PIX_PROC_DPCME_DPCM_10_8_1 0x2
+#define CAL_PIX_PROC_DPCME_DPCM_12_8_1 0x8
+#define CAL_PIX_PROC_DPCME_DPCM_14_10 0xe
+#define CAL_PIX_PROC_DPCME_DPCM_14_8_1 0x10
+#define CAL_PIX_PROC_DPCME_DPCM_16_12_1 0x12
+#define CAL_PIX_PROC_DPCME_DPCM_16_10_1 0x14
+#define CAL_PIX_PROC_DPCME_DPCM_16_8_1 0x16
+#define CAL_PIX_PROC_PACK_MASK GENMASK(18, 16)
+#define CAL_PIX_PROC_PACK_B8 0x0
+#define CAL_PIX_PROC_PACK_B10_MIPI 0x2
+#define CAL_PIX_PROC_PACK_B12 0x3
+#define CAL_PIX_PROC_PACK_B12_MIPI 0x4
+#define CAL_PIX_PROC_PACK_B16 0x5
+#define CAL_PIX_PROC_PACK_ARGB 0x6
+#define CAL_PIX_PROC_CPORT_MASK GENMASK(23, 19)
+
+#define CAL_CTRL_POSTED_WRITES_MASK BIT_MASK(0)
+#define CAL_CTRL_POSTED_WRITES_NONPOSTED 0
+#define CAL_CTRL_POSTED_WRITES 1
+#define CAL_CTRL_TAGCNT_MASK GENMASK(4, 1)
+#define CAL_CTRL_BURSTSIZE_MASK GENMASK(6, 5)
+#define CAL_CTRL_BURSTSIZE_BURST16 0x0
+#define CAL_CTRL_BURSTSIZE_BURST32 0x1
+#define CAL_CTRL_BURSTSIZE_BURST64 0x2
+#define CAL_CTRL_BURSTSIZE_BURST128 0x3
+#define CAL_CTRL_LL_FORCE_STATE_MASK GENMASK(12, 7)
+#define CAL_CTRL_MFLAGL_MASK GENMASK(20, 13)
+#define CAL_CTRL_PWRSCPCLK_MASK BIT_MASK(21)
+#define CAL_CTRL_PWRSCPCLK_AUTO 0
+#define CAL_CTRL_PWRSCPCLK_FORCE 1
+#define CAL_CTRL_RD_DMA_STALL_MASK BIT_MASK(22)
+#define CAL_CTRL_MFLAGH_MASK GENMASK(31, 24)
+
+#define CAL_CTRL1_PPI_GROUPING_MASK GENMASK(1, 0)
+#define CAL_CTRL1_PPI_GROUPING_DISABLED 0
+#define CAL_CTRL1_PPI_GROUPING_RESERVED 1
+#define CAL_CTRL1_PPI_GROUPING_0 2
+#define CAL_CTRL1_PPI_GROUPING_1 3
+#define CAL_CTRL1_INTERLEAVE01_MASK GENMASK(3, 2)
+#define CAL_CTRL1_INTERLEAVE01_DISABLED 0
+#define CAL_CTRL1_INTERLEAVE01_PIX1 1
+#define CAL_CTRL1_INTERLEAVE01_PIX4 2
+#define CAL_CTRL1_INTERLEAVE01_RESERVED 3
+#define CAL_CTRL1_INTERLEAVE23_MASK GENMASK(5, 4)
+#define CAL_CTRL1_INTERLEAVE23_DISABLED 0
+#define CAL_CTRL1_INTERLEAVE23_PIX1 1
+#define CAL_CTRL1_INTERLEAVE23_PIX4 2
+#define CAL_CTRL1_INTERLEAVE23_RESERVED 3
+
+#define CAL_LINE_NUMBER_EVT_CPORT_MASK GENMASK(4, 0)
+#define CAL_LINE_NUMBER_EVT_MASK GENMASK(29, 16)
+
+#define CAL_VPORT_CTRL1_PCLK_MASK GENMASK(16, 0)
+#define CAL_VPORT_CTRL1_XBLK_MASK GENMASK(24, 17)
+#define CAL_VPORT_CTRL1_YBLK_MASK GENMASK(30, 25)
+#define CAL_VPORT_CTRL1_WIDTH_MASK BIT_MASK(31)
+#define CAL_VPORT_CTRL1_WIDTH_ONE 0
+#define CAL_VPORT_CTRL1_WIDTH_TWO 1
+
+#define CAL_VPORT_CTRL2_CPORT_MASK GENMASK(4, 0)
+#define CAL_VPORT_CTRL2_FREERUNNING_MASK BIT_MASK(15)
+#define CAL_VPORT_CTRL2_FREERUNNING_GATED 0
+#define CAL_VPORT_CTRL2_FREERUNNING_FREE 1
+#define CAL_VPORT_CTRL2_FS_RESETS_MASK BIT_MASK(16)
+#define CAL_VPORT_CTRL2_FS_RESETS_NO 0
+#define CAL_VPORT_CTRL2_FS_RESETS_YES 1
+#define CAL_VPORT_CTRL2_FSM_RESET_MASK BIT_MASK(17)
+#define CAL_VPORT_CTRL2_FSM_RESET_NOEFFECT 0
+#define CAL_VPORT_CTRL2_FSM_RESET 1
+#define CAL_VPORT_CTRL2_RDY_THR_MASK GENMASK(31, 18)
+
+#define CAL_BYS_CTRL1_PCLK_MASK GENMASK(16, 0)
+#define CAL_BYS_CTRL1_XBLK_MASK GENMASK(24, 17)
+#define CAL_BYS_CTRL1_YBLK_MASK GENMASK(30, 25)
+#define CAL_BYS_CTRL1_BYSINEN_MASK BIT_MASK(31)
+
+#define CAL_BYS_CTRL2_CPORTIN_MASK GENMASK(4, 0)
+#define CAL_BYS_CTRL2_CPORTOUT_MASK GENMASK(9, 5)
+#define CAL_BYS_CTRL2_DUPLICATEDDATA_MASK BIT_MASK(10)
+#define CAL_BYS_CTRL2_DUPLICATEDDATA_NO 0
+#define CAL_BYS_CTRL2_DUPLICATEDDATA_YES 1
+#define CAL_BYS_CTRL2_FREERUNNING_MASK BIT_MASK(11)
+#define CAL_BYS_CTRL2_FREERUNNING_NO 0
+#define CAL_BYS_CTRL2_FREERUNNING_YES 1
+
+#define CAL_RD_DMA_CTRL_GO_MASK BIT_MASK(0)
+#define CAL_RD_DMA_CTRL_GO_DIS 0
+#define CAL_RD_DMA_CTRL_GO_EN 1
+#define CAL_RD_DMA_CTRL_GO_IDLE 0
+#define CAL_RD_DMA_CTRL_GO_BUSY 1
+#define CAL_RD_DMA_CTRL_INIT_MASK BIT_MASK(1)
+#define CAL_RD_DMA_CTRL_BW_LIMITER_MASK GENMASK(10, 2)
+#define CAL_RD_DMA_CTRL_OCP_TAG_CNT_MASK GENMASK(14, 11)
+#define CAL_RD_DMA_CTRL_PCLK_MASK GENMASK(31, 15)
+
+#define CAL_RD_DMA_PIX_ADDR_MASK GENMASK(31, 3)
+
+#define CAL_RD_DMA_PIX_OFST_MASK GENMASK(31, 4)
+
+#define CAL_RD_DMA_XSIZE_MASK GENMASK(31, 19)
+
+#define CAL_RD_DMA_YSIZE_MASK GENMASK(29, 16)
+
+#define CAL_RD_DMA_INIT_ADDR_MASK GENMASK(31, 3)
+
+#define CAL_RD_DMA_INIT_OFST_MASK GENMASK(31, 3)
+
+#define CAL_RD_DMA_CTRL2_CIRC_MODE_MASK GENMASK(2, 0)
+#define CAL_RD_DMA_CTRL2_CIRC_MODE_DIS 0
+#define CAL_RD_DMA_CTRL2_CIRC_MODE_ONE 1
+#define CAL_RD_DMA_CTRL2_CIRC_MODE_FOUR 2
+#define CAL_RD_DMA_CTRL2_CIRC_MODE_SIXTEEN 3
+#define CAL_RD_DMA_CTRL2_CIRC_MODE_SIXTYFOUR 4
+#define CAL_RD_DMA_CTRL2_CIRC_MODE_RESERVED 5
+#define CAL_RD_DMA_CTRL2_ICM_CSTART_MASK BIT_MASK(3)
+#define CAL_RD_DMA_CTRL2_PATTERN_MASK GENMASK(5, 4)
+#define CAL_RD_DMA_CTRL2_PATTERN_LINEAR 0
+#define CAL_RD_DMA_CTRL2_PATTERN_YUV420 1
+#define CAL_RD_DMA_CTRL2_PATTERN_RD2SKIP2 2
+#define CAL_RD_DMA_CTRL2_PATTERN_RD2SKIP4 3
+#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_MASK BIT_MASK(6)
+#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_FREERUNNING 0
+#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_WAITFORBYSOUT 1
+#define CAL_RD_DMA_CTRL2_CIRC_SIZE_MASK GENMASK(29, 16)
+
+#define CAL_WR_DMA_CTRL_MODE_MASK GENMASK(2, 0)
+#define CAL_WR_DMA_CTRL_MODE_DIS 0
+#define CAL_WR_DMA_CTRL_MODE_SHD 1
+#define CAL_WR_DMA_CTRL_MODE_CNT 2
+#define CAL_WR_DMA_CTRL_MODE_CNT_INIT 3
+#define CAL_WR_DMA_CTRL_MODE_CONST 4
+#define CAL_WR_DMA_CTRL_MODE_RESERVED 5
+#define CAL_WR_DMA_CTRL_PATTERN_MASK GENMASK(4, 3)
+#define CAL_WR_DMA_CTRL_PATTERN_LINEAR 0
+#define CAL_WR_DMA_CTRL_PATTERN_WR2SKIP2 2
+#define CAL_WR_DMA_CTRL_PATTERN_WR2SKIP4 3
+#define CAL_WR_DMA_CTRL_PATTERN_RESERVED 1
+#define CAL_WR_DMA_CTRL_ICM_PSTART_MASK BIT_MASK(5)
+#define CAL_WR_DMA_CTRL_DTAG_MASK GENMASK(8, 6)
+#define CAL_WR_DMA_CTRL_DTAG_ATT_HDR 0
+#define CAL_WR_DMA_CTRL_DTAG_ATT_DAT 1
+#define CAL_WR_DMA_CTRL_DTAG 2
+#define CAL_WR_DMA_CTRL_DTAG_PIX_HDR 3
+#define CAL_WR_DMA_CTRL_DTAG_PIX_DAT 4
+#define CAL_WR_DMA_CTRL_DTAG_D5 5
+#define CAL_WR_DMA_CTRL_DTAG_D6 6
+#define CAL_WR_DMA_CTRL_DTAG_D7 7
+#define CAL_WR_DMA_CTRL_CPORT_MASK GENMASK(13, 9)
+#define CAL_WR_DMA_CTRL_STALL_RD_MASK BIT_MASK(14)
+#define CAL_WR_DMA_CTRL_YSIZE_MASK GENMASK(31, 18)
+
+#define CAL_WR_DMA_ADDR_MASK GENMASK(31, 4)
+
+#define CAL_WR_DMA_OFST_MASK GENMASK(18, 4)
+#define CAL_WR_DMA_OFST_CIRC_MODE_MASK GENMASK(23, 22)
+#define CAL_WR_DMA_OFST_CIRC_MODE_ONE 1
+#define CAL_WR_DMA_OFST_CIRC_MODE_FOUR 2
+#define CAL_WR_DMA_OFST_CIRC_MODE_SIXTYFOUR 3
+#define CAL_WR_DMA_OFST_CIRC_MODE_DISABLED 0
+#define CAL_WR_DMA_OFST_CIRC_SIZE_MASK GENMASK(31, 24)
+
+#define CAL_WR_DMA_XSIZE_XSKIP_MASK GENMASK(15, 3)
+#define CAL_WR_DMA_XSIZE_MASK GENMASK(31, 19)
+
+#define CAL_CSI2_PPI_CTRL_IF_EN_MASK BIT_MASK(0)
+#define CAL_CSI2_PPI_CTRL_ECC_EN_MASK BIT_MASK(2)
+#define CAL_CSI2_PPI_CTRL_FRAME_MASK BIT_MASK(3)
+#define CAL_CSI2_PPI_CTRL_FRAME_IMMEDIATE 0
+#define CAL_CSI2_PPI_CTRL_FRAME 1
+
+#define CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK GENMASK(2, 0)
+#define CAL_CSI2_COMPLEXIO_CFG_POSITION_5 5
+#define CAL_CSI2_COMPLEXIO_CFG_POSITION_4 4
+#define CAL_CSI2_COMPLEXIO_CFG_POSITION_3 3
+#define CAL_CSI2_COMPLEXIO_CFG_POSITION_2 2
+#define CAL_CSI2_COMPLEXIO_CFG_POSITION_1 1
+#define CAL_CSI2_COMPLEXIO_CFG_POSITION_NOT_USED 0
+#define CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK BIT_MASK(3)
+#define CAL_CSI2_COMPLEXIO_CFG_POL_PLUSMINUS 0
+#define CAL_CSI2_COMPLEXIO_CFG_POL_MINUSPLUS 1
+#define CAL_CSI2_COMPLEXIO_CFG_DATA1_POSITION_MASK GENMASK(6, 4)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA1_POL_MASK BIT_MASK(7)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA2_POSITION_MASK GENMASK(10, 8)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA2_POL_MASK BIT_MASK(11)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA3_POSITION_MASK GENMASK(14, 12)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA3_POL_MASK BIT_MASK(15)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA4_POSITION_MASK GENMASK(18, 16)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA4_POL_MASK BIT_MASK(19)
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_AUTO_MASK BIT_MASK(24)
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK GENMASK(26, 25)
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_OFF 0
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_ON 1
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_ULP 2
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK GENMASK(28, 27)
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF 0
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON 1
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ULP 2
+#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK BIT_MASK(29)
+#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED 1
+#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING 0
+#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK BIT_MASK(30)
+#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL 0
+#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL 1
+
+#define CAL_CSI2_SHORT_PACKET_MASK GENMASK(23, 0)
+
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS1_MASK BIT_MASK(0)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS2_MASK BIT_MASK(1)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS3_MASK BIT_MASK(2)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS4_MASK BIT_MASK(3)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS5_MASK BIT_MASK(4)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1_MASK BIT_MASK(5)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2_MASK BIT_MASK(6)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3_MASK BIT_MASK(7)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4_MASK BIT_MASK(8)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5_MASK BIT_MASK(9)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC1_MASK BIT_MASK(10)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC2_MASK BIT_MASK(11)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC3_MASK BIT_MASK(12)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC4_MASK BIT_MASK(13)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC5_MASK BIT_MASK(14)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL1_MASK BIT_MASK(15)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL2_MASK BIT_MASK(16)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL3_MASK BIT_MASK(17)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL4_MASK BIT_MASK(18)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL5_MASK BIT_MASK(19)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM1_MASK BIT_MASK(20)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM2_MASK BIT_MASK(21)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM3_MASK BIT_MASK(22)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM4_MASK BIT_MASK(23)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM5_MASK BIT_MASK(24)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER_MASK BIT_MASK(25)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT_MASK BIT_MASK(26)
+#define CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK BIT_MASK(27)
+#define CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK BIT_MASK(28)
+#define CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK BIT_MASK(30)
+
+#define CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK GENMASK(12, 0)
+#define CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK BIT_MASK(13)
+#define CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK BIT_MASK(14)
+#define CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK BIT_MASK(15)
+
+#define CAL_CSI2_VC_IRQ_FS_IRQ_0_MASK BIT_MASK(0)
+#define CAL_CSI2_VC_IRQ_FE_IRQ_0_MASK BIT_MASK(1)
+#define CAL_CSI2_VC_IRQ_LS_IRQ_0_MASK BIT_MASK(2)
+#define CAL_CSI2_VC_IRQ_LE_IRQ_0_MASK BIT_MASK(3)
+#define CAL_CSI2_VC_IRQ_CS_IRQ_0_MASK BIT_MASK(4)
+#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_0_MASK BIT_MASK(5)
+#define CAL_CSI2_VC_IRQ_FS_IRQ_1_MASK BIT_MASK(8)
+#define CAL_CSI2_VC_IRQ_FE_IRQ_1_MASK BIT_MASK(9)
+#define CAL_CSI2_VC_IRQ_LS_IRQ_1_MASK BIT_MASK(10)
+#define CAL_CSI2_VC_IRQ_LE_IRQ_1_MASK BIT_MASK(11)
+#define CAL_CSI2_VC_IRQ_CS_IRQ_1_MASK BIT_MASK(12)
+#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_1_MASK BIT_MASK(13)
+#define CAL_CSI2_VC_IRQ_FS_IRQ_2_MASK BIT_MASK(16)
+#define CAL_CSI2_VC_IRQ_FE_IRQ_2_MASK BIT_MASK(17)
+#define CAL_CSI2_VC_IRQ_LS_IRQ_2_MASK BIT_MASK(18)
+#define CAL_CSI2_VC_IRQ_LE_IRQ_2_MASK BIT_MASK(19)
+#define CAL_CSI2_VC_IRQ_CS_IRQ_2_MASK BIT_MASK(20)
+#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_2_MASK BIT_MASK(21)
+#define CAL_CSI2_VC_IRQ_FS_IRQ_3_MASK BIT_MASK(24)
+#define CAL_CSI2_VC_IRQ_FE_IRQ_3_MASK BIT_MASK(25)
+#define CAL_CSI2_VC_IRQ_LS_IRQ_3_MASK BIT_MASK(26)
+#define CAL_CSI2_VC_IRQ_LE_IRQ_3_MASK BIT_MASK(27)
+#define CAL_CSI2_VC_IRQ_CS_IRQ_3_MASK BIT_MASK(28)
+#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_3_MASK BIT_MASK(29)
+
+#define CAL_CSI2_CTX_DT_MASK GENMASK(5, 0)
+#define CAL_CSI2_CTX_VC_MASK GENMASK(7, 6)
+#define CAL_CSI2_CTX_CPORT_MASK GENMASK(12, 8)
+#define CAL_CSI2_CTX_ATT_MASK BIT_MASK(13)
+#define CAL_CSI2_CTX_ATT_PIX 0
+#define CAL_CSI2_CTX_ATT 1
+#define CAL_CSI2_CTX_PACK_MODE_MASK BIT_MASK(14)
+#define CAL_CSI2_CTX_PACK_MODE_LINE 0
+#define CAL_CSI2_CTX_PACK_MODE_FRAME 1
+#define CAL_CSI2_CTX_LINES_MASK GENMASK(29, 16)
+
+#define CAL_CSI2_STATUS_FRAME_MASK GENMASK(15, 0)
+
+#define CAL_CSI2_PHY_REG0_THS_SETTLE_MASK GENMASK(7, 0)
+#define CAL_CSI2_PHY_REG0_THS_TERM_MASK GENMASK(15, 8)
+#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK BIT_MASK(24)
+#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE 1
+#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_ENABLE 0
+
+#define CAL_CSI2_PHY_REG1_TCLK_SETTLE_MASK GENMASK(7, 0)
+#define CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK GENMASK(9, 8)
+#define CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK GENMASK(17, 10)
+#define CAL_CSI2_PHY_REG1_TCLK_TERM_MASK GENMASK(24, 18)
+#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_MASK BIT_MASK(25)
+#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_ERROR 1
+#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_SUCCESS 0
+#define CAL_CSI2_PHY_REG1_RESET_DONE_STATUS_MASK GENMASK(29, 28)
+
+#define CAL_CSI2_PHY_REG2_CCP2_SYNC_PATTERN_MASK GENMASK(23, 0)
+#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC3_MASK GENMASK(25, 24)
+#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC2_MASK GENMASK(27, 26)
+#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC1_MASK GENMASK(29, 28)
+#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC0_MASK GENMASK(31, 30)
+
+#define CM_CAMERRX_CTRL_CSI1_CTRLCLKEN_MASK BIT_MASK(0)
+#define CM_CAMERRX_CTRL_CSI1_CAMMODE_MASK GENMASK(2, 1)
+#define CM_CAMERRX_CTRL_CSI1_LANEENABLE_MASK GENMASK(4, 3)
+#define CM_CAMERRX_CTRL_CSI1_MODE_MASK BIT_MASK(5)
+#define CM_CAMERRX_CTRL_CSI0_CTRLCLKEN_MASK BIT_MASK(10)
+#define CM_CAMERRX_CTRL_CSI0_CAMMODE_MASK GENMASK(12, 11)
+#define CM_CAMERRX_CTRL_CSI0_LANEENABLE_MASK GENMASK(16, 13)
+#define CM_CAMERRX_CTRL_CSI0_MODE_MASK BIT_MASK(17)
+
+#endif
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index 418113c99801..c4b5fab83666 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -1074,7 +1074,7 @@ static int __init vim2m_init(void)
if (ret)
platform_device_unregister(&vim2m_pdev);
- return 0;
+ return ret;
}
module_init(vim2m_init);
diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c
index e15eef6a94e5..bdc380b14e0c 100644
--- a/drivers/media/platform/vivid/vivid-osd.c
+++ b/drivers/media/platform/vivid/vivid-osd.c
@@ -360,7 +360,7 @@ void vivid_fb_release_buffers(struct vivid_dev *dev)
/* Release pseudo palette */
kfree(dev->fb_info.pseudo_palette);
- kfree((void *)dev->video_vbase);
+ kfree(dev->video_vbase);
}
/* Initialize the specified card */
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
index 14256141f905..da862bb2e5f8 100644
--- a/drivers/media/platform/vivid/vivid-tpg.c
+++ b/drivers/media/platform/vivid/vivid-tpg.c
@@ -251,6 +251,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
tpg->planes = 3;
tpg->is_yuv = true;
break;
+ case V4L2_PIX_FMT_YUV422M:
+ case V4L2_PIX_FMT_YVU422M:
+ tpg->buffers = 3;
+ /* fall through */
case V4L2_PIX_FMT_YUV422P:
tpg->vdownsampling[1] = 1;
tpg->vdownsampling[2] = 1;
@@ -283,6 +287,16 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
tpg->planes = 2;
tpg->is_yuv = true;
break;
+ case V4L2_PIX_FMT_YUV444M:
+ case V4L2_PIX_FMT_YVU444M:
+ tpg->buffers = 3;
+ tpg->planes = 3;
+ tpg->vdownsampling[1] = 1;
+ tpg->vdownsampling[2] = 1;
+ tpg->hdownsampling[1] = 1;
+ tpg->hdownsampling[2] = 1;
+ tpg->is_yuv = true;
+ break;
case V4L2_PIX_FMT_NV24:
case V4L2_PIX_FMT_NV42:
tpg->vdownsampling[1] = 1;
@@ -368,6 +382,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
tpg->twopixelsize[0] = 4;
tpg->twopixelsize[1] = 4;
break;
+ case V4L2_PIX_FMT_YUV444M:
+ case V4L2_PIX_FMT_YVU444M:
+ case V4L2_PIX_FMT_YUV422M:
+ case V4L2_PIX_FMT_YVU422M:
case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
@@ -933,6 +951,7 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset] = r_y;
buf[0][offset+1] = r_y == 0xff ? r_y : 0;
break;
+ case V4L2_PIX_FMT_YUV422M:
case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YUV420M:
@@ -947,6 +966,7 @@ static void gen_twopix(struct tpg_data *tpg,
buf[1][0] = g_u;
buf[2][0] = b_v;
break;
+ case V4L2_PIX_FMT_YVU422M:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YVU420M:
buf[0][offset] = r_y;
@@ -988,6 +1008,18 @@ static void gen_twopix(struct tpg_data *tpg,
buf[1][1] = g_u;
break;
+ case V4L2_PIX_FMT_YUV444M:
+ buf[0][offset] = r_y;
+ buf[1][offset] = g_u;
+ buf[2][offset] = b_v;
+ break;
+
+ case V4L2_PIX_FMT_YVU444M:
+ buf[0][offset] = r_y;
+ buf[1][offset] = b_v;
+ buf[2][offset] = g_u;
+ break;
+
case V4L2_PIX_FMT_NV24:
buf[0][offset] = r_y;
buf[1][2 * offset] = g_u;
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
index 9baed6a10334..93fbaee69675 100644
--- a/drivers/media/platform/vivid/vivid-tpg.h
+++ b/drivers/media/platform/vivid/vivid-tpg.h
@@ -418,6 +418,8 @@ static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsi
tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p];
}
+ if (tpg_g_interleaved(tpg))
+ tpg->bytesperline[1] = tpg->bytesperline[0];
}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index 1678b730dba2..b0d4e3a0acf0 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -445,6 +445,9 @@ struct vivid_fmt vivid_formats[] = {
.planes = 1,
.buffers = 1,
},
+
+ /* Multiplanar formats */
+
{
.fourcc = V4L2_PIX_FMT_NV16M,
.vdownsampling = { 1, 1 },
@@ -495,10 +498,42 @@ struct vivid_fmt vivid_formats[] = {
.planes = 2,
.buffers = 2,
},
+ {
+ .fourcc = V4L2_PIX_FMT_YUV422M,
+ .vdownsampling = { 1, 1, 1 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 3,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU422M,
+ .vdownsampling = { 1, 1, 1 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 3,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV444M,
+ .vdownsampling = { 1, 1, 1 },
+ .bit_depth = { 8, 8, 8 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 3,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU444M,
+ .vdownsampling = { 1, 1, 1 },
+ .bit_depth = { 8, 8, 8 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 3,
+ },
};
-/* There are 6 multiplanar formats in the list */
-#define VIVID_MPLANAR_FORMATS 6
+/* There are this many multiplanar formats in the list */
+#define VIVID_MPLANAR_FORMATS 10
const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
{
diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile
index 6a93f928dfde..95b3ac2ea7ef 100644
--- a/drivers/media/platform/vsp1/Makefile
+++ b/drivers/media/platform/vsp1/Makefile
@@ -1,4 +1,5 @@
-vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o
+vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_pipe.o
+vsp1-y += vsp1_dl.o vsp1_drm.o vsp1_video.o
vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o
vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o
vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 989e96f7e360..910d6b8e8b50 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -26,6 +26,9 @@
struct clk;
struct device;
+struct vsp1_dl;
+struct vsp1_drm;
+struct vsp1_entity;
struct vsp1_platform_data;
struct vsp1_bru;
struct vsp1_hsit;
@@ -42,17 +45,21 @@ struct vsp1_uds;
#define VSP1_HAS_LIF (1 << 0)
#define VSP1_HAS_LUT (1 << 1)
#define VSP1_HAS_SRU (1 << 2)
+#define VSP1_HAS_BRU (1 << 3)
-struct vsp1_platform_data {
+struct vsp1_device_info {
+ u32 version;
unsigned int features;
unsigned int rpf_count;
unsigned int uds_count;
unsigned int wpf_count;
+ unsigned int num_bru_inputs;
+ bool uapi;
};
struct vsp1_device {
struct device *dev;
- struct vsp1_platform_data pdata;
+ const struct vsp1_device_info *info;
void __iomem *mmio;
struct clk *clock;
@@ -71,14 +78,22 @@ struct vsp1_device {
struct vsp1_rwpf *wpf[VSP1_MAX_WPF];
struct list_head entities;
+ struct list_head videos;
struct v4l2_device v4l2_dev;
struct media_device media_dev;
+ struct media_entity_operations media_ops;
+
+ struct vsp1_drm *drm;
+
+ bool use_dl;
};
int vsp1_device_get(struct vsp1_device *vsp1);
void vsp1_device_put(struct vsp1_device *vsp1);
+int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index);
+
static inline u32 vsp1_read(struct vsp1_device *vsp1, u32 reg)
{
return ioread32(vsp1->mmio + reg);
@@ -89,4 +104,14 @@ static inline void vsp1_write(struct vsp1_device *vsp1, u32 reg, u32 data)
iowrite32(data, vsp1->mmio + reg);
}
+#include "vsp1_dl.h"
+
+static inline void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
+{
+ if (e->vsp1->use_dl)
+ vsp1_dl_add(e, reg, data);
+ else
+ vsp1_write(e->vsp1, reg, data);
+}
+
#endif /* __VSP1_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 7dd763311c0f..cb0dbc15ddad 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -19,6 +19,7 @@
#include "vsp1.h"
#include "vsp1_bru.h"
#include "vsp1_rwpf.h"
+#include "vsp1_video.h"
#define BRU_MIN_SIZE 1U
#define BRU_MAX_SIZE 8190U
@@ -27,14 +28,9 @@
* Device Access
*/
-static inline u32 vsp1_bru_read(struct vsp1_bru *bru, u32 reg)
-{
- return vsp1_read(bru->entity.vsp1, reg);
-}
-
static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data)
{
- vsp1_write(bru->entity.vsp1, reg, data);
+ vsp1_mod_write(&bru->entity, reg, data);
}
/* -----------------------------------------------------------------------------
@@ -83,7 +79,7 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
if (!enable)
return 0;
- format = &bru->entity.formats[BRU_PAD_SOURCE];
+ format = &bru->entity.formats[bru->entity.source_pad];
/* The hardware is extremely flexible but we have no userspace API to
* expose all the parameters, nor is it clear whether we would have use
@@ -94,7 +90,7 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
/* Disable dithering and enable color data normalization unless the
* format at the pipeline output is premultiplied.
*/
- flags = pipe->output ? pipe->output->video.format.flags : 0;
+ flags = pipe->output ? pipe->output->format.flags : 0;
vsp1_bru_write(bru, VI6_BRU_INCTRL,
flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
0 : VI6_BRU_INCTRL_NRM);
@@ -113,7 +109,7 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
VI6_BRU_ROP_AROP(VI6_ROP_NOP));
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < bru->entity.source_pad; ++i) {
bool premultiplied = false;
u32 ctrl = 0;
@@ -125,7 +121,7 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
if (bru->inputs[i].rpf) {
ctrl |= VI6_BRU_CTRL_RBC;
- premultiplied = bru->inputs[i].rpf->video.format.flags
+ premultiplied = bru->inputs[i].rpf->format.flags
& V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
} else {
ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
@@ -295,7 +291,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
*format = fmt->format;
/* Reset the compose rectangle */
- if (fmt->pad != BRU_PAD_SOURCE) {
+ if (fmt->pad != bru->entity.source_pad) {
struct v4l2_rect *compose;
compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which);
@@ -309,7 +305,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
if (fmt->pad == BRU_PAD_SINK(0)) {
unsigned int i;
- for (i = 0; i <= BRU_PAD_SOURCE; ++i) {
+ for (i = 0; i <= bru->entity.source_pad; ++i) {
format = vsp1_entity_get_pad_format(&bru->entity, cfg,
i, fmt->which);
format->code = fmt->format.code;
@@ -325,7 +321,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev,
{
struct vsp1_bru *bru = to_bru(subdev);
- if (sel->pad == BRU_PAD_SOURCE)
+ if (sel->pad == bru->entity.source_pad)
return -EINVAL;
switch (sel->target) {
@@ -353,7 +349,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *compose;
- if (sel->pad == BRU_PAD_SOURCE)
+ if (sel->pad == bru->entity.source_pad)
return -EINVAL;
if (sel->target != V4L2_SEL_TGT_COMPOSE)
@@ -362,8 +358,8 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
/* The compose rectangle top left corner must be inside the output
* frame.
*/
- format = vsp1_entity_get_pad_format(&bru->entity, cfg, BRU_PAD_SOURCE,
- sel->which);
+ format = vsp1_entity_get_pad_format(&bru->entity, cfg,
+ bru->entity.source_pad, sel->which);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -419,7 +415,8 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
bru->entity.type = VSP1_ENTITY_BRU;
- ret = vsp1_entity_init(vsp1, &bru->entity, 5);
+ ret = vsp1_entity_init(vsp1, &bru->entity,
+ vsp1->info->num_bru_inputs + 1);
if (ret < 0)
return ERR_PTR(ret);
@@ -427,7 +424,7 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
subdev = &bru->entity.subdev;
v4l2_subdev_init(subdev, &bru_ops);
- subdev->entity.ops = &vsp1_media_ops;
+ subdev->entity.ops = &vsp1->media_ops;
subdev->internal_ops = &vsp1_subdev_internal_ops;
snprintf(subdev->name, sizeof(subdev->name), "%s bru",
dev_name(vsp1->dev));
diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h
index 16b1c6554911..dbac9686ea69 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.h
+++ b/drivers/media/platform/vsp1/vsp1_bru.h
@@ -23,7 +23,6 @@ struct vsp1_device;
struct vsp1_rwpf;
#define BRU_PAD_SINK(n) (n)
-#define BRU_PAD_SOURCE 4
struct vsp1_bru {
struct vsp1_entity entity;
@@ -33,7 +32,7 @@ struct vsp1_bru {
struct {
struct vsp1_rwpf *rpf;
struct v4l2_rect compose;
- } inputs[4];
+ } inputs[VSP1_MAX_RPF];
};
static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev)
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
new file mode 100644
index 000000000000..7dc27ac6bd02
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -0,0 +1,305 @@
+/*
+ * vsp1_dl.h -- R-Car VSP1 Display List
+ *
+ * Copyright (C) 2015 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+
+#include "vsp1.h"
+#include "vsp1_dl.h"
+#include "vsp1_pipe.h"
+
+/*
+ * Global resources
+ *
+ * - Display-related interrupts (can be used for vblank evasion ?)
+ * - Display-list enable
+ * - Header-less for WPF0
+ * - DL swap
+ */
+
+#define VSP1_DL_BODY_SIZE (2 * 4 * 256)
+#define VSP1_DL_NUM_LISTS 3
+
+struct vsp1_dl_entry {
+ u32 addr;
+ u32 data;
+} __attribute__((__packed__));
+
+struct vsp1_dl_list {
+ size_t size;
+ int reg_count;
+
+ bool in_use;
+
+ struct vsp1_dl_entry *body;
+ dma_addr_t dma;
+};
+
+/**
+ * struct vsp1_dl - Display List manager
+ * @vsp1: the VSP1 device
+ * @lock: protects the active, queued and pending lists
+ * @lists.all: array of all allocate display lists
+ * @lists.active: list currently being processed (loaded) by hardware
+ * @lists.queued: list queued to the hardware (written to the DL registers)
+ * @lists.pending: list waiting to be queued to the hardware
+ * @lists.write: list being written to by software
+ */
+struct vsp1_dl {
+ struct vsp1_device *vsp1;
+
+ spinlock_t lock;
+
+ size_t size;
+ dma_addr_t dma;
+ void *mem;
+
+ struct {
+ struct vsp1_dl_list all[VSP1_DL_NUM_LISTS];
+
+ struct vsp1_dl_list *active;
+ struct vsp1_dl_list *queued;
+ struct vsp1_dl_list *pending;
+ struct vsp1_dl_list *write;
+ } lists;
+};
+
+/* -----------------------------------------------------------------------------
+ * Display List Transaction Management
+ */
+
+static void vsp1_dl_free_list(struct vsp1_dl_list *list)
+{
+ if (!list)
+ return;
+
+ list->in_use = false;
+}
+
+void vsp1_dl_reset(struct vsp1_dl *dl)
+{
+ unsigned int i;
+
+ dl->lists.active = NULL;
+ dl->lists.queued = NULL;
+ dl->lists.pending = NULL;
+ dl->lists.write = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i)
+ dl->lists.all[i].in_use = false;
+}
+
+void vsp1_dl_begin(struct vsp1_dl *dl)
+{
+ struct vsp1_dl_list *list = NULL;
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&dl->lock, flags);
+
+ for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) {
+ if (!dl->lists.all[i].in_use) {
+ list = &dl->lists.all[i];
+ break;
+ }
+ }
+
+ if (!list) {
+ list = dl->lists.pending;
+ dl->lists.pending = NULL;
+ }
+
+ spin_unlock_irqrestore(&dl->lock, flags);
+
+ dl->lists.write = list;
+
+ list->in_use = true;
+ list->reg_count = 0;
+}
+
+void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data)
+{
+ struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
+ struct vsp1_dl *dl = pipe->dl;
+ struct vsp1_dl_list *list = dl->lists.write;
+
+ list->body[list->reg_count].addr = reg;
+ list->body[list->reg_count].data = data;
+ list->reg_count++;
+}
+
+void vsp1_dl_commit(struct vsp1_dl *dl)
+{
+ struct vsp1_device *vsp1 = dl->vsp1;
+ struct vsp1_dl_list *list;
+ unsigned long flags;
+ bool update;
+
+ list = dl->lists.write;
+ dl->lists.write = NULL;
+
+ spin_lock_irqsave(&dl->lock, flags);
+
+ /* Once the UPD bit has been set the hardware can start processing the
+ * display list at any time and we can't touch the address and size
+ * registers. In that case mark the update as pending, it will be
+ * queued up to the hardware by the frame end interrupt handler.
+ */
+ update = !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD);
+ if (update) {
+ vsp1_dl_free_list(dl->lists.pending);
+ dl->lists.pending = list;
+ goto done;
+ }
+
+ /* Program the hardware with the display list body address and size.
+ * The UPD bit will be cleared by the device when the display list is
+ * processed.
+ */
+ vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma);
+ vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
+ (list->reg_count * 8));
+
+ vsp1_dl_free_list(dl->lists.queued);
+ dl->lists.queued = list;
+
+done:
+ spin_unlock_irqrestore(&dl->lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt Handling
+ */
+
+void vsp1_dl_irq_display_start(struct vsp1_dl *dl)
+{
+ spin_lock(&dl->lock);
+
+ /* The display start interrupt signals the end of the display list
+ * processing by the device. The active display list, if any, won't be
+ * accessed anymore and can be reused.
+ */
+ if (dl->lists.active) {
+ vsp1_dl_free_list(dl->lists.active);
+ dl->lists.active = NULL;
+ }
+
+ spin_unlock(&dl->lock);
+}
+
+void vsp1_dl_irq_frame_end(struct vsp1_dl *dl)
+{
+ struct vsp1_device *vsp1 = dl->vsp1;
+
+ spin_lock(&dl->lock);
+
+ /* The UPD bit set indicates that the commit operation raced with the
+ * interrupt and occurred after the frame end event and UPD clear but
+ * before interrupt processing. The hardware hasn't taken the update
+ * into account yet, we'll thus skip one frame and retry.
+ */
+ if (vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD)
+ goto done;
+
+ /* The device starts processing the queued display list right after the
+ * frame end interrupt. The display list thus becomes active.
+ */
+ if (dl->lists.queued) {
+ WARN_ON(dl->lists.active);
+ dl->lists.active = dl->lists.queued;
+ dl->lists.queued = NULL;
+ }
+
+ /* Now that the UPD bit has been cleared we can queue the next display
+ * list to the hardware if one has been prepared.
+ */
+ if (dl->lists.pending) {
+ struct vsp1_dl_list *list = dl->lists.pending;
+
+ vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma);
+ vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
+ (list->reg_count * 8));
+
+ dl->lists.queued = list;
+ dl->lists.pending = NULL;
+ }
+
+done:
+ spin_unlock(&dl->lock);
+}
+
+/* -----------------------------------------------------------------------------
+ * Hardware Setup
+ */
+
+void vsp1_dl_setup(struct vsp1_device *vsp1)
+{
+ u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT)
+ | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
+ | VI6_DL_CTRL_DLE;
+
+ /* The DRM pipeline operates with header-less display lists in
+ * Continuous Frame Mode.
+ */
+ if (vsp1->drm)
+ ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
+
+ vsp1_write(vsp1, VI6_DL_CTRL, ctrl);
+ vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS);
+}
+
+/* -----------------------------------------------------------------------------
+ * Initialization and Cleanup
+ */
+
+struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1)
+{
+ struct vsp1_dl *dl;
+ unsigned int i;
+
+ dl = kzalloc(sizeof(*dl), GFP_KERNEL);
+ if (!dl)
+ return NULL;
+
+ spin_lock_init(&dl->lock);
+
+ dl->vsp1 = vsp1;
+ dl->size = VSP1_DL_BODY_SIZE * ARRAY_SIZE(dl->lists.all);
+
+ dl->mem = dma_alloc_writecombine(vsp1->dev, dl->size, &dl->dma,
+ GFP_KERNEL);
+ if (!dl->mem) {
+ kfree(dl);
+ return NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) {
+ struct vsp1_dl_list *list = &dl->lists.all[i];
+
+ list->size = VSP1_DL_BODY_SIZE;
+ list->reg_count = 0;
+ list->in_use = false;
+ list->dma = dl->dma + VSP1_DL_BODY_SIZE * i;
+ list->body = dl->mem + VSP1_DL_BODY_SIZE * i;
+ }
+
+ return dl;
+}
+
+void vsp1_dl_destroy(struct vsp1_dl *dl)
+{
+ dma_free_writecombine(dl->vsp1->dev, dl->size, dl->mem, dl->dma);
+ kfree(dl);
+}
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
new file mode 100644
index 000000000000..448c4250e54c
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -0,0 +1,42 @@
+/*
+ * vsp1_dl.h -- R-Car VSP1 Display List
+ *
+ * Copyright (C) 2015 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ */
+#ifndef __VSP1_DL_H__
+#define __VSP1_DL_H__
+
+#include "vsp1_entity.h"
+
+struct vsp1_device;
+struct vsp1_dl;
+
+struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1);
+void vsp1_dl_destroy(struct vsp1_dl *dl);
+
+void vsp1_dl_setup(struct vsp1_device *vsp1);
+
+void vsp1_dl_reset(struct vsp1_dl *dl);
+void vsp1_dl_begin(struct vsp1_dl *dl);
+void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data);
+void vsp1_dl_commit(struct vsp1_dl *dl);
+
+void vsp1_dl_irq_display_start(struct vsp1_dl *dl);
+void vsp1_dl_irq_frame_end(struct vsp1_dl *dl);
+
+static inline void vsp1_dl_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
+{
+ if (e->vsp1->use_dl)
+ vsp1_dl_add(e, reg, data);
+ else
+ vsp1_write(e->vsp1, reg, data);
+}
+
+#endif /* __VSP1_DL_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
new file mode 100644
index 000000000000..021fe5778cd1
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -0,0 +1,597 @@
+/*
+ * vsp1_drm.c -- R-Car VSP1 DRM API
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ */
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/vsp1.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+
+#include "vsp1.h"
+#include "vsp1_bru.h"
+#include "vsp1_dl.h"
+#include "vsp1_drm.h"
+#include "vsp1_lif.h"
+#include "vsp1_pipe.h"
+#include "vsp1_rwpf.h"
+
+/* -----------------------------------------------------------------------------
+ * Runtime Handling
+ */
+
+static void vsp1_drm_pipeline_frame_end(struct vsp1_pipeline *pipe)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pipe->irqlock, flags);
+ if (pipe->num_inputs)
+ vsp1_pipeline_run(pipe);
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * DU Driver API
+ */
+
+int vsp1_du_init(struct device *dev)
+{
+ struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+
+ if (!vsp1)
+ return -EPROBE_DEFER;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vsp1_du_init);
+
+/**
+ * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
+ * @dev: the VSP device
+ * @width: output frame width in pixels
+ * @height: output frame height in pixels
+ *
+ * Configure the output part of VSP DRM pipeline for the given frame @width and
+ * @height. This sets up formats on the BRU source pad, the WPF0 sink and source
+ * pads, and the LIF sink pad.
+ *
+ * As the media bus code on the BRU source pad is conditioned by the
+ * configuration of the BRU sink 0 pad, we also set up the formats on all BRU
+ * sinks, even if the configuration will be overwritten later by
+ * vsp1_du_setup_rpf(). This ensures that the BRU configuration is set to a well
+ * defined state.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+int vsp1_du_setup_lif(struct device *dev, unsigned int width,
+ unsigned int height)
+{
+ struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+ struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
+ struct vsp1_bru *bru = vsp1->bru;
+ struct v4l2_subdev_format format;
+ unsigned int i;
+ int ret;
+
+ dev_dbg(vsp1->dev, "%s: configuring LIF with format %ux%u\n",
+ __func__, width, height);
+
+ if (width == 0 || height == 0) {
+ /* Zero width or height means the CRTC is being disabled, stop
+ * the pipeline and turn the light off.
+ */
+ ret = vsp1_pipeline_stop(pipe);
+ if (ret == -ETIMEDOUT)
+ dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
+
+ media_entity_pipeline_stop(&pipe->output->entity.subdev.entity);
+
+ for (i = 0; i < bru->entity.source_pad; ++i) {
+ bru->inputs[i].rpf = NULL;
+ pipe->inputs[i] = NULL;
+ }
+
+ pipe->num_inputs = 0;
+
+ vsp1_device_put(vsp1);
+
+ dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
+
+ return 0;
+ }
+
+ vsp1_dl_reset(vsp1->drm->dl);
+
+ /* Configure the format at the BRU sinks and propagate it through the
+ * pipeline.
+ */
+ memset(&format, 0, sizeof(format));
+ format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+
+ for (i = 0; i < bru->entity.source_pad; ++i) {
+ format.pad = i;
+
+ format.format.width = width;
+ format.format.height = height;
+ format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
+ format.format.field = V4L2_FIELD_NONE;
+
+ ret = v4l2_subdev_call(&bru->entity.subdev, pad,
+ set_fmt, NULL, &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code, i);
+ }
+
+ format.pad = bru->entity.source_pad;
+ format.format.width = width;
+ format.format.height = height;
+ format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
+ format.format.field = V4L2_FIELD_NONE;
+
+ ret = v4l2_subdev_call(&bru->entity.subdev, pad, set_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code, i);
+
+ format.pad = RWPF_PAD_SINK;
+ ret = v4l2_subdev_call(&vsp1->wpf[0]->entity.subdev, pad, set_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on WPF0 sink\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code);
+
+ format.pad = RWPF_PAD_SOURCE;
+ ret = v4l2_subdev_call(&vsp1->wpf[0]->entity.subdev, pad, get_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev, "%s: got format %ux%u (%x) on WPF0 source\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code);
+
+ format.pad = LIF_PAD_SINK;
+ ret = v4l2_subdev_call(&vsp1->lif->entity.subdev, pad, set_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on LIF sink\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code);
+
+ /* Verify that the format at the output of the pipeline matches the
+ * requested frame size and media bus code.
+ */
+ if (format.format.width != width || format.format.height != height ||
+ format.format.code != MEDIA_BUS_FMT_ARGB8888_1X32) {
+ dev_dbg(vsp1->dev, "%s: format mismatch\n", __func__);
+ return -EPIPE;
+ }
+
+ /* Mark the pipeline as streaming and enable the VSP1. This will store
+ * the pipeline pointer in all entities, which the s_stream handlers
+ * will need. We don't start the entities themselves right at this point
+ * as there's no plane configured yet, so we can't start processing
+ * buffers.
+ */
+ ret = vsp1_device_get(vsp1);
+ if (ret < 0)
+ return ret;
+
+ ret = media_entity_pipeline_start(&pipe->output->entity.subdev.entity,
+ &pipe->pipe);
+ if (ret < 0) {
+ dev_dbg(vsp1->dev, "%s: pipeline start failed\n", __func__);
+ vsp1_device_put(vsp1);
+ return ret;
+ }
+
+ dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vsp1_du_setup_lif);
+
+/**
+ * vsp1_du_atomic_begin - Prepare for an atomic update
+ * @dev: the VSP device
+ */
+void vsp1_du_atomic_begin(struct device *dev)
+{
+ struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+ struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pipe->irqlock, flags);
+
+ vsp1->drm->num_inputs = pipe->num_inputs;
+
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+
+ /* Prepare the display list. */
+ vsp1_dl_begin(vsp1->drm->dl);
+}
+EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
+
+/**
+ * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline
+ * @dev: the VSP device
+ * @rpf_index: index of the RPF to setup (0-based)
+ * @pixelformat: V4L2 pixel format for the RPF memory input
+ * @pitch: number of bytes per line in the image stored in memory
+ * @mem: DMA addresses of the memory buffers (one per plane)
+ * @src: the source crop rectangle for the RPF
+ * @dst: the destination compose rectangle for the BRU input
+ *
+ * Configure the VSP to perform composition of the image referenced by @mem
+ * through RPF @rpf_index, using the @src crop rectangle and the @dst
+ * composition rectangle. The Z-order is fixed with RPF 0 at the bottom.
+ *
+ * Image format as stored in memory is expressed as a V4L2 @pixelformat value.
+ * As a special case, setting the pixel format to 0 will disable the RPF. The
+ * @pitch, @mem, @src and @dst parameters are ignored in that case. Calling the
+ * function on a disabled RPF is allowed.
+ *
+ * The memory pitch is configurable to allow for padding at end of lines, or
+ * simple for images that extend beyond the crop rectangle boundaries. The
+ * @pitch value is expressed in bytes and applies to all planes for multiplanar
+ * formats.
+ *
+ * The source memory buffer is referenced by the DMA address of its planes in
+ * the @mem array. Up to two planes are supported. The second plane DMA address
+ * is ignored for formats using a single plane.
+ *
+ * This function isn't reentrant, the caller needs to serialize calls.
+ *
+ * TODO: Implement Z-order control by decoupling the RPF index from the BRU
+ * input index.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
+ u32 pixelformat, unsigned int pitch,
+ dma_addr_t mem[2], const struct v4l2_rect *src,
+ const struct v4l2_rect *dst)
+{
+ struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+ struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
+ const struct vsp1_format_info *fmtinfo;
+ struct v4l2_subdev_selection sel;
+ struct v4l2_subdev_format format;
+ struct vsp1_rwpf_memory memory;
+ struct vsp1_rwpf *rpf;
+ unsigned long flags;
+ int ret;
+
+ if (rpf_index >= vsp1->info->rpf_count)
+ return -EINVAL;
+
+ rpf = vsp1->rpf[rpf_index];
+
+ if (pixelformat == 0) {
+ dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
+ rpf_index);
+
+ spin_lock_irqsave(&pipe->irqlock, flags);
+
+ if (pipe->inputs[rpf_index]) {
+ /* Remove the RPF from the pipeline if it was previously
+ * enabled.
+ */
+ vsp1->bru->inputs[rpf_index].rpf = NULL;
+ pipe->inputs[rpf_index] = NULL;
+
+ pipe->num_inputs--;
+ }
+
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+
+ return 0;
+ }
+
+ dev_dbg(vsp1->dev,
+ "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad }\n",
+ __func__, rpf_index,
+ src->left, src->top, src->width, src->height,
+ dst->left, dst->top, dst->width, dst->height,
+ pixelformat, pitch, &mem[0], &mem[1]);
+
+ /* Set the stride at the RPF input. */
+ fmtinfo = vsp1_get_format_info(pixelformat);
+ if (!fmtinfo) {
+ dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n",
+ pixelformat);
+ return -EINVAL;
+ }
+
+ rpf->fmtinfo = fmtinfo;
+ rpf->format.num_planes = fmtinfo->planes;
+ rpf->format.plane_fmt[0].bytesperline = pitch;
+ rpf->format.plane_fmt[1].bytesperline = pitch;
+
+ /* Configure the format on the RPF sink pad and propagate it up to the
+ * BRU sink pad.
+ */
+ memset(&format, 0, sizeof(format));
+ format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.pad = RWPF_PAD_SINK;
+ format.format.width = src->width + src->left;
+ format.format.height = src->height + src->top;
+ format.format.code = fmtinfo->mbus;
+ format.format.field = V4L2_FIELD_NONE;
+
+ ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev,
+ "%s: set format %ux%u (%x) on RPF%u sink\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code, rpf->entity.index);
+
+ memset(&sel, 0, sizeof(sel));
+ sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ sel.pad = RWPF_PAD_SINK;
+ sel.target = V4L2_SEL_TGT_CROP;
+ sel.r = *src;
+
+ ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL,
+ &sel);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev,
+ "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
+ __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
+ rpf->entity.index);
+
+ /* RPF source, hardcode the format to ARGB8888 to turn on format
+ * conversion if needed.
+ */
+ format.pad = RWPF_PAD_SOURCE;
+
+ ret = v4l2_subdev_call(&rpf->entity.subdev, pad, get_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev,
+ "%s: got format %ux%u (%x) on RPF%u source\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code, rpf->entity.index);
+
+ format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
+
+ ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ /* BRU sink, propagate the format from the RPF source. */
+ format.pad = rpf->entity.index;
+
+ ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code, format.pad);
+
+ sel.pad = rpf->entity.index;
+ sel.target = V4L2_SEL_TGT_COMPOSE;
+ sel.r = *dst;
+
+ ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_selection,
+ NULL, &sel);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev,
+ "%s: set selection (%u,%u)/%ux%u on BRU pad %u\n",
+ __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
+ sel.pad);
+
+ /* Store the compose rectangle coordinates in the RPF. */
+ rpf->location.left = dst->left;
+ rpf->location.top = dst->top;
+
+ /* Set the memory buffer address. */
+ memory.num_planes = fmtinfo->planes;
+ memory.addr[0] = mem[0];
+ memory.addr[1] = mem[1];
+
+ rpf->ops->set_memory(rpf, &memory);
+
+ spin_lock_irqsave(&pipe->irqlock, flags);
+
+ /* If the RPF was previously stopped set the BRU input to the RPF and
+ * store the RPF in the pipeline inputs array.
+ */
+ if (!pipe->inputs[rpf->entity.index]) {
+ vsp1->bru->inputs[rpf_index].rpf = rpf;
+ pipe->inputs[rpf->entity.index] = rpf;
+ pipe->num_inputs++;
+ }
+
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
+
+/**
+ * vsp1_du_atomic_flush - Commit an atomic update
+ * @dev: the VSP device
+ */
+void vsp1_du_atomic_flush(struct device *dev)
+{
+ struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+ struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
+ struct vsp1_entity *entity;
+ unsigned long flags;
+ bool stop = false;
+ int ret;
+
+ list_for_each_entry(entity, &pipe->entities, list_pipe) {
+ /* Disconnect unused RPFs from the pipeline. */
+ if (entity->type == VSP1_ENTITY_RPF) {
+ struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
+
+ if (!pipe->inputs[rpf->entity.index]) {
+ vsp1_mod_write(entity, entity->route->reg,
+ VI6_DPR_NODE_UNUSED);
+ continue;
+ }
+ }
+
+ vsp1_entity_route_setup(entity);
+
+ ret = v4l2_subdev_call(&entity->subdev, video,
+ s_stream, 1);
+ if (ret < 0) {
+ dev_err(vsp1->dev,
+ "DRM pipeline start failure on entity %s\n",
+ entity->subdev.name);
+ return;
+ }
+ }
+
+ vsp1_dl_commit(vsp1->drm->dl);
+
+ spin_lock_irqsave(&pipe->irqlock, flags);
+
+ /* Start or stop the pipeline if needed. */
+ if (!vsp1->drm->num_inputs && pipe->num_inputs) {
+ vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
+ vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE);
+ vsp1_pipeline_run(pipe);
+ } else if (vsp1->drm->num_inputs && !pipe->num_inputs) {
+ stop = true;
+ }
+
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+
+ if (stop) {
+ vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0);
+ vsp1_pipeline_stop(pipe);
+ }
+}
+EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+int vsp1_drm_create_links(struct vsp1_device *vsp1)
+{
+ const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
+ unsigned int i;
+ int ret;
+
+ /* VSPD instances require a BRU to perform composition and a LIF to
+ * output to the DU.
+ */
+ if (!vsp1->bru || !vsp1->lif)
+ return -ENXIO;
+
+ for (i = 0; i < vsp1->info->rpf_count; ++i) {
+ struct vsp1_rwpf *rpf = vsp1->rpf[i];
+
+ ret = media_create_pad_link(&rpf->entity.subdev.entity,
+ RWPF_PAD_SOURCE,
+ &vsp1->bru->entity.subdev.entity,
+ i, flags);
+ if (ret < 0)
+ return ret;
+
+ rpf->entity.sink = &vsp1->bru->entity.subdev.entity;
+ rpf->entity.sink_pad = i;
+ }
+
+ ret = media_create_pad_link(&vsp1->bru->entity.subdev.entity,
+ vsp1->bru->entity.source_pad,
+ &vsp1->wpf[0]->entity.subdev.entity,
+ RWPF_PAD_SINK, flags);
+ if (ret < 0)
+ return ret;
+
+ vsp1->bru->entity.sink = &vsp1->wpf[0]->entity.subdev.entity;
+ vsp1->bru->entity.sink_pad = RWPF_PAD_SINK;
+
+ ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity,
+ RWPF_PAD_SOURCE,
+ &vsp1->lif->entity.subdev.entity,
+ LIF_PAD_SINK, flags);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int vsp1_drm_init(struct vsp1_device *vsp1)
+{
+ struct vsp1_pipeline *pipe;
+ unsigned int i;
+
+ vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
+ if (!vsp1->drm)
+ return -ENOMEM;
+
+ vsp1->drm->dl = vsp1_dl_create(vsp1);
+ if (!vsp1->drm->dl)
+ return -ENOMEM;
+
+ pipe = &vsp1->drm->pipe;
+
+ vsp1_pipeline_init(pipe);
+ pipe->frame_end = vsp1_drm_pipeline_frame_end;
+
+ /* The DRM pipeline is static, add entities manually. */
+ for (i = 0; i < vsp1->info->rpf_count; ++i) {
+ struct vsp1_rwpf *input = vsp1->rpf[i];
+
+ list_add_tail(&input->entity.list_pipe, &pipe->entities);
+ }
+
+ list_add_tail(&vsp1->bru->entity.list_pipe, &pipe->entities);
+ list_add_tail(&vsp1->wpf[0]->entity.list_pipe, &pipe->entities);
+ list_add_tail(&vsp1->lif->entity.list_pipe, &pipe->entities);
+
+ pipe->bru = &vsp1->bru->entity;
+ pipe->lif = &vsp1->lif->entity;
+ pipe->output = vsp1->wpf[0];
+
+ pipe->dl = vsp1->drm->dl;
+
+ return 0;
+}
+
+void vsp1_drm_cleanup(struct vsp1_device *vsp1)
+{
+ vsp1_dl_destroy(vsp1->drm->dl);
+}
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h
new file mode 100644
index 000000000000..f68056838319
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -0,0 +1,49 @@
+/*
+ * vsp1_drm.h -- R-Car VSP1 DRM/KMS Interface
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ */
+#ifndef __VSP1_DRM_H__
+#define __VSP1_DRM_H__
+
+#include "vsp1_pipe.h"
+
+struct vsp1_dl;
+
+/**
+ * vsp1_drm - State for the API exposed to the DRM driver
+ * @dl: display list for DRM pipeline operation
+ * @pipe: the VSP1 pipeline used for display
+ * @num_inputs: number of active pipeline inputs at the beginning of an update
+ * @update: the pipeline configuration has been updated
+ */
+struct vsp1_drm {
+ struct vsp1_dl *dl;
+ struct vsp1_pipeline pipe;
+ unsigned int num_inputs;
+ bool update;
+};
+
+int vsp1_drm_init(struct vsp1_device *vsp1);
+void vsp1_drm_cleanup(struct vsp1_device *vsp1);
+int vsp1_drm_create_links(struct vsp1_device *vsp1);
+
+int vsp1_du_init(struct device *dev);
+int vsp1_du_setup_lif(struct device *dev, unsigned int width,
+ unsigned int height);
+void vsp1_du_atomic_begin(struct device *dev);
+int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
+ u32 pixelformat, unsigned int pitch,
+ dma_addr_t mem[2], const struct v4l2_rect *src,
+ const struct v4l2_rect *dst);
+void vsp1_du_atomic_flush(struct device *dev);
+
+
+#endif /* __VSP1_DRM_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 533bc796391e..25750a0e4631 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -17,17 +17,23 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+
#include "vsp1.h"
#include "vsp1_bru.h"
+#include "vsp1_dl.h"
+#include "vsp1_drm.h"
#include "vsp1_hsit.h"
#include "vsp1_lif.h"
#include "vsp1_lut.h"
#include "vsp1_rwpf.h"
#include "vsp1_sru.h"
#include "vsp1_uds.h"
+#include "vsp1_video.h"
/* -----------------------------------------------------------------------------
* Interrupt Handling
@@ -39,11 +45,11 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
struct vsp1_device *vsp1 = data;
irqreturn_t ret = IRQ_NONE;
unsigned int i;
+ u32 status;
- for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
+ for (i = 0; i < vsp1->info->wpf_count; ++i) {
struct vsp1_rwpf *wpf = vsp1->wpf[i];
struct vsp1_pipeline *pipe;
- u32 status;
if (wpf == NULL)
continue;
@@ -58,6 +64,21 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
}
}
+ status = vsp1_read(vsp1, VI6_DISP_IRQ_STA);
+ vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST);
+
+ if (status & VI6_DISP_IRQ_STA_DST) {
+ struct vsp1_rwpf *wpf = vsp1->wpf[0];
+ struct vsp1_pipeline *pipe;
+
+ if (wpf) {
+ pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
+ vsp1_pipeline_display_start(pipe);
+ }
+
+ ret = IRQ_HANDLED;
+ }
+
return ret;
}
@@ -66,7 +87,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
*/
/*
- * vsp1_create_links - Create links from all sources to the given sink
+ * vsp1_create_sink_links - Create links from all sources to the given sink
*
* This function creates media links from all valid sources to the given sink
* pad. Links that would be invalid according to the VSP1 hardware capabilities
@@ -75,7 +96,8 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
* - from a UDS to a UDS (UDS entities can't be chained)
* - from an entity to itself (no loops are allowed)
*/
-static int vsp1_create_links(struct vsp1_device *vsp1, struct vsp1_entity *sink)
+static int vsp1_create_sink_links(struct vsp1_device *vsp1,
+ struct vsp1_entity *sink)
{
struct media_entity *entity = &sink->subdev.entity;
struct vsp1_entity *source;
@@ -115,19 +137,86 @@ static int vsp1_create_links(struct vsp1_device *vsp1, struct vsp1_entity *sink)
return 0;
}
-static void vsp1_destroy_entities(struct vsp1_device *vsp1)
+static int vsp1_uapi_create_links(struct vsp1_device *vsp1)
{
struct vsp1_entity *entity;
- struct vsp1_entity *next;
+ unsigned int i;
+ int ret;
+
+ list_for_each_entry(entity, &vsp1->entities, list_dev) {
+ if (entity->type == VSP1_ENTITY_LIF ||
+ entity->type == VSP1_ENTITY_RPF)
+ continue;
+
+ ret = vsp1_create_sink_links(vsp1, entity);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (vsp1->info->features & VSP1_HAS_LIF) {
+ ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity,
+ RWPF_PAD_SOURCE,
+ &vsp1->lif->entity.subdev.entity,
+ LIF_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < vsp1->info->rpf_count; ++i) {
+ struct vsp1_rwpf *rpf = vsp1->rpf[i];
- list_for_each_entry_safe(entity, next, &vsp1->entities, list_dev) {
+ ret = media_create_pad_link(&rpf->video->video.entity, 0,
+ &rpf->entity.subdev.entity,
+ RWPF_PAD_SINK,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < vsp1->info->wpf_count; ++i) {
+ /* Connect the video device to the WPF. All connections are
+ * immutable except for the WPF0 source link if a LIF is
+ * present.
+ */
+ struct vsp1_rwpf *wpf = vsp1->wpf[i];
+ unsigned int flags = MEDIA_LNK_FL_ENABLED;
+
+ if (!(vsp1->info->features & VSP1_HAS_LIF) || i != 0)
+ flags |= MEDIA_LNK_FL_IMMUTABLE;
+
+ ret = media_create_pad_link(&wpf->entity.subdev.entity,
+ RWPF_PAD_SOURCE,
+ &wpf->video->video.entity, 0,
+ flags);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void vsp1_destroy_entities(struct vsp1_device *vsp1)
+{
+ struct vsp1_entity *entity, *_entity;
+ struct vsp1_video *video, *_video;
+
+ list_for_each_entry_safe(entity, _entity, &vsp1->entities, list_dev) {
list_del(&entity->list_dev);
vsp1_entity_destroy(entity);
}
+ list_for_each_entry_safe(video, _video, &vsp1->videos, list) {
+ list_del(&video->list);
+ vsp1_video_cleanup(video);
+ }
+
v4l2_device_unregister(&vsp1->v4l2_dev);
media_device_unregister(&vsp1->media_dev);
media_device_cleanup(&vsp1->media_dev);
+
+ if (!vsp1->info->uapi)
+ vsp1_drm_cleanup(vsp1);
}
static int vsp1_create_entities(struct vsp1_device *vsp1)
@@ -144,6 +233,14 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
dev_name(mdev->dev));
media_device_init(mdev);
+ vsp1->media_ops.link_setup = vsp1_entity_link_setup;
+ /* Don't perform link validation when the userspace API is disabled as
+ * the pipeline is configured internally by the driver in that case, and
+ * its configuration can thus be trusted.
+ */
+ if (vsp1->info->uapi)
+ vsp1->media_ops.link_validate = v4l2_subdev_link_validate;
+
vdev->mdev = mdev;
ret = v4l2_device_register(vsp1->dev, vdev);
if (ret < 0) {
@@ -153,13 +250,15 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
}
/* Instantiate all the entities. */
- vsp1->bru = vsp1_bru_create(vsp1);
- if (IS_ERR(vsp1->bru)) {
- ret = PTR_ERR(vsp1->bru);
- goto done;
- }
+ if (vsp1->info->features & VSP1_HAS_BRU) {
+ vsp1->bru = vsp1_bru_create(vsp1);
+ if (IS_ERR(vsp1->bru)) {
+ ret = PTR_ERR(vsp1->bru);
+ goto done;
+ }
- list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
+ list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
+ }
vsp1->hsi = vsp1_hsit_create(vsp1, true);
if (IS_ERR(vsp1->hsi)) {
@@ -177,7 +276,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
- if (vsp1->pdata.features & VSP1_HAS_LIF) {
+ if (vsp1->info->features & VSP1_HAS_LIF) {
vsp1->lif = vsp1_lif_create(vsp1);
if (IS_ERR(vsp1->lif)) {
ret = PTR_ERR(vsp1->lif);
@@ -187,7 +286,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities);
}
- if (vsp1->pdata.features & VSP1_HAS_LUT) {
+ if (vsp1->info->features & VSP1_HAS_LUT) {
vsp1->lut = vsp1_lut_create(vsp1);
if (IS_ERR(vsp1->lut)) {
ret = PTR_ERR(vsp1->lut);
@@ -197,7 +296,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
}
- for (i = 0; i < vsp1->pdata.rpf_count; ++i) {
+ for (i = 0; i < vsp1->info->rpf_count; ++i) {
struct vsp1_rwpf *rpf;
rpf = vsp1_rpf_create(vsp1, i);
@@ -208,9 +307,20 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
vsp1->rpf[i] = rpf;
list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
+
+ if (vsp1->info->uapi) {
+ struct vsp1_video *video = vsp1_video_create(vsp1, rpf);
+
+ if (IS_ERR(video)) {
+ ret = PTR_ERR(video);
+ goto done;
+ }
+
+ list_add_tail(&video->list, &vsp1->videos);
+ }
}
- if (vsp1->pdata.features & VSP1_HAS_SRU) {
+ if (vsp1->info->features & VSP1_HAS_SRU) {
vsp1->sru = vsp1_sru_create(vsp1);
if (IS_ERR(vsp1->sru)) {
ret = PTR_ERR(vsp1->sru);
@@ -220,7 +330,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities);
}
- for (i = 0; i < vsp1->pdata.uds_count; ++i) {
+ for (i = 0; i < vsp1->info->uds_count; ++i) {
struct vsp1_uds *uds;
uds = vsp1_uds_create(vsp1, i);
@@ -233,7 +343,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&uds->entity.list_dev, &vsp1->entities);
}
- for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
+ for (i = 0; i < vsp1->info->wpf_count; ++i) {
struct vsp1_rwpf *wpf;
wpf = vsp1_wpf_create(vsp1, i);
@@ -244,6 +354,18 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
vsp1->wpf[i] = wpf;
list_add_tail(&wpf->entity.list_dev, &vsp1->entities);
+
+ if (vsp1->info->uapi) {
+ struct vsp1_video *video = vsp1_video_create(vsp1, wpf);
+
+ if (IS_ERR(video)) {
+ ret = PTR_ERR(video);
+ goto done;
+ }
+
+ list_add_tail(&video->list, &vsp1->videos);
+ wpf->entity.sink = &video->video.entity;
+ }
}
/* Register all subdevs. */
@@ -255,34 +377,23 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
}
/* Create links. */
- list_for_each_entry(entity, &vsp1->entities, list_dev) {
- if (entity->type == VSP1_ENTITY_WPF) {
- ret = vsp1_wpf_create_links(vsp1, entity);
- if (ret < 0)
- goto done;
- } else if (entity->type == VSP1_ENTITY_RPF) {
- ret = vsp1_rpf_create_links(vsp1, entity);
- if (ret < 0)
- goto done;
- }
-
- if (entity->type != VSP1_ENTITY_LIF &&
- entity->type != VSP1_ENTITY_RPF) {
- ret = vsp1_create_links(vsp1, entity);
- if (ret < 0)
- goto done;
- }
- }
+ if (vsp1->info->uapi)
+ ret = vsp1_uapi_create_links(vsp1);
+ else
+ ret = vsp1_drm_create_links(vsp1);
+ if (ret < 0)
+ goto done;
- if (vsp1->pdata.features & VSP1_HAS_LIF) {
- ret = media_create_pad_link(
- &vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE,
- &vsp1->lif->entity.subdev.entity, LIF_PAD_SINK, 0);
- if (ret < 0)
- return ret;
+ /* Register subdev nodes if the userspace API is enabled or initialize
+ * the DRM pipeline otherwise.
+ */
+ if (vsp1->info->uapi) {
+ vsp1->use_dl = false;
+ ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
+ } else {
+ vsp1->use_dl = true;
+ ret = vsp1_drm_init(vsp1);
}
-
- ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
if (ret < 0)
goto done;
@@ -295,42 +406,51 @@ done:
return ret;
}
-static int vsp1_device_init(struct vsp1_device *vsp1)
+int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
{
- unsigned int i;
+ unsigned int timeout;
u32 status;
- /* Reset any channel that might be running. */
status = vsp1_read(vsp1, VI6_STATUS);
+ if (!(status & VI6_STATUS_SYS_ACT(index)))
+ return 0;
- for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
- unsigned int timeout;
+ vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
+ for (timeout = 10; timeout > 0; --timeout) {
+ status = vsp1_read(vsp1, VI6_STATUS);
+ if (!(status & VI6_STATUS_SYS_ACT(index)))
+ break;
- if (!(status & VI6_STATUS_SYS_ACT(i)))
- continue;
+ usleep_range(1000, 2000);
+ }
- vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(i));
- for (timeout = 10; timeout > 0; --timeout) {
- status = vsp1_read(vsp1, VI6_STATUS);
- if (!(status & VI6_STATUS_SYS_ACT(i)))
- break;
+ if (!timeout) {
+ dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
+ return -ETIMEDOUT;
+ }
- usleep_range(1000, 2000);
- }
+ return 0;
+}
- if (!timeout) {
- dev_err(vsp1->dev, "failed to reset wpf.%u\n", i);
- return -ETIMEDOUT;
- }
+static int vsp1_device_init(struct vsp1_device *vsp1)
+{
+ unsigned int i;
+ int ret;
+
+ /* Reset any channel that might be running. */
+ for (i = 0; i < vsp1->info->wpf_count; ++i) {
+ ret = vsp1_reset_wpf(vsp1, i);
+ if (ret < 0)
+ return ret;
}
vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
(8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
- for (i = 0; i < vsp1->pdata.rpf_count; ++i)
+ for (i = 0; i < vsp1->info->rpf_count; ++i)
vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED);
- for (i = 0; i < vsp1->pdata.uds_count; ++i)
+ for (i = 0; i < vsp1->info->uds_count; ++i)
vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED);
vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED);
@@ -345,6 +465,9 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
(VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
+ if (vsp1->use_dl)
+ vsp1_dl_setup(vsp1);
+
return 0;
}
@@ -444,48 +567,76 @@ static const struct dev_pm_ops vsp1_pm_ops = {
* Platform Driver
*/
-static int vsp1_parse_dt(struct vsp1_device *vsp1)
-{
- struct device_node *np = vsp1->dev->of_node;
- struct vsp1_platform_data *pdata = &vsp1->pdata;
-
- if (of_property_read_bool(np, "renesas,has-lif"))
- pdata->features |= VSP1_HAS_LIF;
- if (of_property_read_bool(np, "renesas,has-lut"))
- pdata->features |= VSP1_HAS_LUT;
- if (of_property_read_bool(np, "renesas,has-sru"))
- pdata->features |= VSP1_HAS_SRU;
-
- of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count);
- of_property_read_u32(np, "renesas,#uds", &pdata->uds_count);
- of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count);
-
- if (pdata->rpf_count <= 0 || pdata->rpf_count > VSP1_MAX_RPF) {
- dev_err(vsp1->dev, "invalid number of RPF (%u)\n",
- pdata->rpf_count);
- return -EINVAL;
- }
-
- if (pdata->uds_count <= 0 || pdata->uds_count > VSP1_MAX_UDS) {
- dev_err(vsp1->dev, "invalid number of UDS (%u)\n",
- pdata->uds_count);
- return -EINVAL;
- }
-
- if (pdata->wpf_count <= 0 || pdata->wpf_count > VSP1_MAX_WPF) {
- dev_err(vsp1->dev, "invalid number of WPF (%u)\n",
- pdata->wpf_count);
- return -EINVAL;
- }
-
- return 0;
-}
+static const struct vsp1_device_info vsp1_device_infos[] = {
+ {
+ .version = VI6_IP_VERSION_MODEL_VSPS_H2,
+ .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
+ .rpf_count = 5,
+ .uds_count = 3,
+ .wpf_count = 4,
+ .num_bru_inputs = 4,
+ .uapi = true,
+ }, {
+ .version = VI6_IP_VERSION_MODEL_VSPR_H2,
+ .features = VSP1_HAS_BRU | VSP1_HAS_SRU,
+ .rpf_count = 5,
+ .uds_count = 1,
+ .wpf_count = 4,
+ .num_bru_inputs = 4,
+ .uapi = true,
+ }, {
+ .version = VI6_IP_VERSION_MODEL_VSPD_GEN2,
+ .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT,
+ .rpf_count = 4,
+ .uds_count = 1,
+ .wpf_count = 4,
+ .num_bru_inputs = 4,
+ .uapi = true,
+ }, {
+ .version = VI6_IP_VERSION_MODEL_VSPS_M2,
+ .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
+ .rpf_count = 5,
+ .uds_count = 3,
+ .wpf_count = 4,
+ .num_bru_inputs = 4,
+ .uapi = true,
+ }, {
+ .version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
+ .features = VSP1_HAS_LUT | VSP1_HAS_SRU,
+ .rpf_count = 1,
+ .uds_count = 1,
+ .wpf_count = 1,
+ .uapi = true,
+ }, {
+ .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
+ .features = VSP1_HAS_BRU,
+ .rpf_count = 5,
+ .wpf_count = 1,
+ .num_bru_inputs = 5,
+ .uapi = true,
+ }, {
+ .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
+ .features = VSP1_HAS_BRU | VSP1_HAS_LUT,
+ .rpf_count = 5,
+ .wpf_count = 1,
+ .num_bru_inputs = 5,
+ .uapi = true,
+ }, {
+ .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
+ .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT,
+ .rpf_count = 5,
+ .wpf_count = 2,
+ .num_bru_inputs = 5,
+ },
+};
static int vsp1_probe(struct platform_device *pdev)
{
struct vsp1_device *vsp1;
struct resource *irq;
struct resource *io;
+ unsigned int i;
+ u32 version;
int ret;
vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
@@ -495,10 +646,7 @@ static int vsp1_probe(struct platform_device *pdev)
vsp1->dev = &pdev->dev;
mutex_init(&vsp1->lock);
INIT_LIST_HEAD(&vsp1->entities);
-
- ret = vsp1_parse_dt(vsp1);
- if (ret < 0)
- return ret;
+ INIT_LIST_HEAD(&vsp1->videos);
/* I/O, IRQ and clock resources */
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -525,6 +673,29 @@ static int vsp1_probe(struct platform_device *pdev)
return ret;
}
+ /* Configure device parameters based on the version register. */
+ ret = clk_prepare_enable(vsp1->clock);
+ if (ret < 0)
+ return ret;
+
+ version = vsp1_read(vsp1, VI6_IP_VERSION);
+ clk_disable_unprepare(vsp1->clock);
+
+ for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
+ if ((version & VI6_IP_VERSION_MODEL_MASK) ==
+ vsp1_device_infos[i].version) {
+ vsp1->info = &vsp1_device_infos[i];
+ break;
+ }
+ }
+
+ if (!vsp1->info) {
+ dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version);
+ return -ENXIO;
+ }
+
+ dev_dbg(&pdev->dev, "IP version 0x%08x\n", version);
+
/* Instanciate entities */
ret = vsp1_create_entities(vsp1);
if (ret < 0) {
@@ -548,6 +719,7 @@ static int vsp1_remove(struct platform_device *pdev)
static const struct of_device_id vsp1_of_match[] = {
{ .compatible = "renesas,vsp1" },
+ { .compatible = "renesas,vsp2" },
{ },
};
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index d7308530952f..20a78fbd3691 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -20,7 +20,6 @@
#include "vsp1.h"
#include "vsp1_entity.h"
-#include "vsp1_video.h"
bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
{
@@ -46,7 +45,7 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
if (!streaming)
return 0;
- if (!entity->subdev.ctrl_handler)
+ if (!entity->vsp1->info->uapi || !entity->subdev.ctrl_handler)
return 0;
ret = v4l2_ctrl_handler_setup(entity->subdev.ctrl_handler);
@@ -59,6 +58,18 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
return ret;
}
+void vsp1_entity_route_setup(struct vsp1_entity *source)
+{
+ struct vsp1_entity *sink;
+
+ if (source->route->reg == 0)
+ return;
+
+ sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
+ vsp1_mod_write(source, source->route->reg,
+ sink->route->inputs[source->sink_pad]);
+}
+
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations
*/
@@ -120,9 +131,9 @@ const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops = {
* Media Operations
*/
-static int vsp1_entity_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
+int vsp1_entity_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
{
struct vsp1_entity *source;
@@ -147,11 +158,6 @@ static int vsp1_entity_link_setup(struct media_entity *entity,
return 0;
}
-const struct media_entity_operations vsp1_media_ops = {
- .link_setup = vsp1_entity_link_setup,
- .link_validate = v4l2_subdev_link_validate,
-};
-
/* -----------------------------------------------------------------------------
* Initialization
*/
@@ -159,7 +165,8 @@ const struct media_entity_operations vsp1_media_ops = {
static const struct vsp1_route vsp1_routes[] = {
{ VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE,
{ VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1),
- VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), } },
+ VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3),
+ VI6_DPR_NODE_BRU_IN(4) } },
{ VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } },
{ VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } },
{ VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } },
@@ -225,8 +232,6 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
void vsp1_entity_destroy(struct vsp1_entity *entity)
{
- if (entity->video)
- vsp1_video_cleanup(entity->video);
if (entity->subdev.ctrl_handler)
v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
media_entity_cleanup(&entity->subdev.entity);
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 8867a5787c28..83570dfde8ec 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -19,7 +19,6 @@
#include <media/v4l2-subdev.h>
struct vsp1_device;
-struct vsp1_video;
enum vsp1_entity_type {
VSP1_ENTITY_BRU,
@@ -33,6 +32,8 @@ enum vsp1_entity_type {
VSP1_ENTITY_WPF,
};
+#define VSP1_ENTITY_MAX_INPUTS 5 /* For the BRU */
+
/*
* struct vsp1_route - Entity routing configuration
* @type: Entity type this routing entry is associated with
@@ -49,7 +50,7 @@ struct vsp1_route {
enum vsp1_entity_type type;
unsigned int index;
unsigned int reg;
- unsigned int inputs[4];
+ unsigned int inputs[VSP1_ENTITY_MAX_INPUTS];
};
struct vsp1_entity {
@@ -71,8 +72,6 @@ struct vsp1_entity {
struct v4l2_subdev subdev;
struct v4l2_mbus_framefmt *formats;
- struct vsp1_video *video;
-
spinlock_t lock; /* Protects the streaming field */
bool streaming;
};
@@ -87,7 +86,10 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
void vsp1_entity_destroy(struct vsp1_entity *entity);
extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops;
-extern const struct media_entity_operations vsp1_media_ops;
+
+int vsp1_entity_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags);
struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
@@ -99,4 +101,6 @@ void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
bool vsp1_entity_is_streaming(struct vsp1_entity *entity);
int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
+void vsp1_entity_route_setup(struct vsp1_entity *source);
+
#endif /* __VSP1_ENTITY_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 8ffb817ae525..c1087cff31a0 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -203,7 +203,7 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
subdev = &hsit->entity.subdev;
v4l2_subdev_init(subdev, &hsit_ops);
- subdev->entity.ops = &vsp1_media_ops;
+ subdev->entity.ops = &vsp1->media_ops;
subdev->internal_ops = &vsp1_subdev_internal_ops;
snprintf(subdev->name, sizeof(subdev->name), "%s %s",
dev_name(vsp1->dev), inverse ? "hsi" : "hst");
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 39fa5ef20fbb..433853ce8dbf 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -26,14 +26,9 @@
* Device Access
*/
-static inline u32 vsp1_lif_read(struct vsp1_lif *lif, u32 reg)
-{
- return vsp1_read(lif->entity.vsp1, reg);
-}
-
static inline void vsp1_lif_write(struct vsp1_lif *lif, u32 reg, u32 data)
{
- vsp1_write(lif->entity.vsp1, reg, data);
+ vsp1_mod_write(&lif->entity, reg, data);
}
/* -----------------------------------------------------------------------------
@@ -49,7 +44,7 @@ static int lif_s_stream(struct v4l2_subdev *subdev, int enable)
unsigned int lbth = 200;
if (!enable) {
- vsp1_lif_write(lif, VI6_LIF_CTRL, 0);
+ vsp1_write(lif->entity.vsp1, VI6_LIF_CTRL, 0);
return 0;
}
@@ -228,7 +223,7 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
subdev = &lif->entity.subdev;
v4l2_subdev_init(subdev, &lif_ops);
- subdev->entity.ops = &vsp1_media_ops;
+ subdev->entity.ops = &vsp1->media_ops;
subdev->internal_ops = &vsp1_subdev_internal_ops;
snprintf(subdev->name, sizeof(subdev->name), "%s lif",
dev_name(vsp1->dev));
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 656ec272a414..4b89095e7b5f 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -27,11 +27,6 @@
* Device Access
*/
-static inline u32 vsp1_lut_read(struct vsp1_lut *lut, u32 reg)
-{
- return vsp1_read(lut->entity.vsp1, reg);
-}
-
static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
{
vsp1_write(lut->entity.vsp1, reg, data);
@@ -242,7 +237,7 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
subdev = &lut->entity.subdev;
v4l2_subdev_init(subdev, &lut_ops);
- subdev->entity.ops = &vsp1_media_ops;
+ subdev->entity.ops = &vsp1->media_ops;
subdev->internal_ops = &vsp1_subdev_internal_ops;
snprintf(subdev->name, sizeof(subdev->name), "%s lut",
dev_name(vsp1->dev));
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
new file mode 100644
index 000000000000..6659f06b1643
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -0,0 +1,426 @@
+/*
+ * vsp1_pipe.c -- R-Car VSP1 Pipeline
+ *
+ * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ */
+
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+
+#include "vsp1.h"
+#include "vsp1_bru.h"
+#include "vsp1_dl.h"
+#include "vsp1_entity.h"
+#include "vsp1_pipe.h"
+#include "vsp1_rwpf.h"
+#include "vsp1_uds.h"
+
+/* -----------------------------------------------------------------------------
+ * Helper Functions
+ */
+
+static const struct vsp1_format_info vsp1_video_formats[] = {
+ { V4L2_PIX_FMT_RGB332, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGB_332, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 8, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_ARGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XRGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_BGR24, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_BGR_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 24, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_RGB24, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 24, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_ABGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XRGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 16, 0, 0 }, false, false, 2, 1, false },
+ { V4L2_PIX_FMT_VYUY, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 16, 0, 0 }, false, true, 2, 1, false },
+ { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 16, 0, 0 }, true, false, 2, 1, false },
+ { V4L2_PIX_FMT_YVYU, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 16, 0, 0 }, true, true, 2, 1, false },
+ { V4L2_PIX_FMT_NV12M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 2, { 8, 16, 0 }, false, false, 2, 2, false },
+ { V4L2_PIX_FMT_NV21M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 2, { 8, 16, 0 }, false, true, 2, 2, false },
+ { V4L2_PIX_FMT_NV16M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 2, { 8, 16, 0 }, false, false, 2, 1, false },
+ { V4L2_PIX_FMT_NV61M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 2, { 8, 16, 0 }, false, true, 2, 1, false },
+ { V4L2_PIX_FMT_YUV420M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 3, { 8, 8, 8 }, false, false, 2, 2, false },
+ { V4L2_PIX_FMT_YVU420M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 3, { 8, 8, 8 }, false, true, 2, 2, false },
+ { V4L2_PIX_FMT_YUV422M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 3, { 8, 8, 8 }, false, false, 2, 1, false },
+ { V4L2_PIX_FMT_YVU422M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 3, { 8, 8, 8 }, false, true, 2, 1, false },
+ { V4L2_PIX_FMT_YUV444M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 3, { 8, 8, 8 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_YVU444M, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 3, { 8, 8, 8 }, false, true, 1, 1, false },
+};
+
+/*
+ * vsp1_get_format_info - Retrieve format information for a 4CC
+ * @fourcc: the format 4CC
+ *
+ * Return a pointer to the format information structure corresponding to the
+ * given V4L2 format 4CC, or NULL if no corresponding format can be found.
+ */
+const struct vsp1_format_info *vsp1_get_format_info(u32 fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) {
+ const struct vsp1_format_info *info = &vsp1_video_formats[i];
+
+ if (info->fourcc == fourcc)
+ return info;
+ }
+
+ return NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline Management
+ */
+
+void vsp1_pipeline_reset(struct vsp1_pipeline *pipe)
+{
+ unsigned int i;
+
+ if (pipe->bru) {
+ struct vsp1_bru *bru = to_bru(&pipe->bru->subdev);
+
+ for (i = 0; i < ARRAY_SIZE(bru->inputs); ++i)
+ bru->inputs[i].rpf = NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i)
+ pipe->inputs[i] = NULL;
+
+ INIT_LIST_HEAD(&pipe->entities);
+ pipe->state = VSP1_PIPELINE_STOPPED;
+ pipe->buffers_ready = 0;
+ pipe->num_inputs = 0;
+ pipe->output = NULL;
+ pipe->bru = NULL;
+ pipe->lif = NULL;
+ pipe->uds = NULL;
+}
+
+void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
+{
+ mutex_init(&pipe->lock);
+ spin_lock_init(&pipe->irqlock);
+ init_waitqueue_head(&pipe->wq);
+
+ INIT_LIST_HEAD(&pipe->entities);
+ pipe->state = VSP1_PIPELINE_STOPPED;
+}
+
+void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
+{
+ struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+
+ if (pipe->state == VSP1_PIPELINE_STOPPED) {
+ vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index),
+ VI6_CMD_STRCMD);
+ pipe->state = VSP1_PIPELINE_RUNNING;
+ }
+
+ pipe->buffers_ready = 0;
+}
+
+bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe)
+{
+ unsigned long flags;
+ bool stopped;
+
+ spin_lock_irqsave(&pipe->irqlock, flags);
+ stopped = pipe->state == VSP1_PIPELINE_STOPPED;
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+
+ return stopped;
+}
+
+int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
+{
+ struct vsp1_entity *entity;
+ unsigned long flags;
+ int ret;
+
+ if (pipe->dl) {
+ /* When using display lists in continuous frame mode the only
+ * way to stop the pipeline is to reset the hardware.
+ */
+ ret = vsp1_reset_wpf(pipe->output->entity.vsp1,
+ pipe->output->entity.index);
+ if (ret == 0) {
+ spin_lock_irqsave(&pipe->irqlock, flags);
+ pipe->state = VSP1_PIPELINE_STOPPED;
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+ }
+ } else {
+ /* Otherwise just request a stop and wait. */
+ spin_lock_irqsave(&pipe->irqlock, flags);
+ if (pipe->state == VSP1_PIPELINE_RUNNING)
+ pipe->state = VSP1_PIPELINE_STOPPING;
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+
+ ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe),
+ msecs_to_jiffies(500));
+ ret = ret == 0 ? -ETIMEDOUT : 0;
+ }
+
+ list_for_each_entry(entity, &pipe->entities, list_pipe) {
+ if (entity->route && entity->route->reg)
+ vsp1_write(entity->vsp1, entity->route->reg,
+ VI6_DPR_NODE_UNUSED);
+
+ v4l2_subdev_call(&entity->subdev, video, s_stream, 0);
+ }
+
+ return ret;
+}
+
+bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
+{
+ unsigned int mask;
+
+ mask = ((1 << pipe->num_inputs) - 1) << 1;
+ if (!pipe->lif)
+ mask |= 1 << 0;
+
+ return pipe->buffers_ready == mask;
+}
+
+void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe)
+{
+ if (pipe->dl)
+ vsp1_dl_irq_display_start(pipe->dl);
+}
+
+void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
+{
+ enum vsp1_pipeline_state state;
+ unsigned long flags;
+
+ if (pipe == NULL)
+ return;
+
+ if (pipe->dl)
+ vsp1_dl_irq_frame_end(pipe->dl);
+
+ /* Signal frame end to the pipeline handler. */
+ pipe->frame_end(pipe);
+
+ spin_lock_irqsave(&pipe->irqlock, flags);
+
+ state = pipe->state;
+
+ /* When using display lists in continuous frame mode the pipeline is
+ * automatically restarted by the hardware.
+ */
+ if (!pipe->dl)
+ pipe->state = VSP1_PIPELINE_STOPPED;
+
+ /* If a stop has been requested, mark the pipeline as stopped and
+ * return.
+ */
+ if (state == VSP1_PIPELINE_STOPPING) {
+ wake_up(&pipe->wq);
+ goto done;
+ }
+
+ /* Restart the pipeline if ready. */
+ if (vsp1_pipeline_ready(pipe))
+ vsp1_pipeline_run(pipe);
+
+done:
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+}
+
+/*
+ * Propagate the alpha value through the pipeline.
+ *
+ * As the UDS has restricted scaling capabilities when the alpha component needs
+ * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha
+ * value. The UDS then outputs a fixed alpha value which needs to be programmed
+ * from the input RPF alpha.
+ */
+void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
+ struct vsp1_entity *input,
+ unsigned int alpha)
+{
+ struct vsp1_entity *entity;
+ struct media_pad *pad;
+
+ pad = media_entity_remote_pad(&input->pads[RWPF_PAD_SOURCE]);
+
+ while (pad) {
+ if (!is_media_entity_v4l2_subdev(pad->entity))
+ break;
+
+ entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
+
+ /* The BRU background color has a fixed alpha value set to 255,
+ * the output alpha value is thus always equal to 255.
+ */
+ if (entity->type == VSP1_ENTITY_BRU)
+ alpha = 255;
+
+ if (entity->type == VSP1_ENTITY_UDS) {
+ struct vsp1_uds *uds = to_uds(&entity->subdev);
+
+ vsp1_uds_set_alpha(uds, alpha);
+ break;
+ }
+
+ pad = &entity->pads[entity->source_pad];
+ pad = media_entity_remote_pad(pad);
+ }
+}
+
+void vsp1_pipelines_suspend(struct vsp1_device *vsp1)
+{
+ unsigned long flags;
+ unsigned int i;
+ int ret;
+
+ /* To avoid increasing the system suspend time needlessly, loop over the
+ * pipelines twice, first to set them all to the stopping state, and
+ * then to wait for the stop to complete.
+ */
+ for (i = 0; i < vsp1->info->wpf_count; ++i) {
+ struct vsp1_rwpf *wpf = vsp1->wpf[i];
+ struct vsp1_pipeline *pipe;
+
+ if (wpf == NULL)
+ continue;
+
+ pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
+ if (pipe == NULL)
+ continue;
+
+ spin_lock_irqsave(&pipe->irqlock, flags);
+ if (pipe->state == VSP1_PIPELINE_RUNNING)
+ pipe->state = VSP1_PIPELINE_STOPPING;
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
+ }
+
+ for (i = 0; i < vsp1->info->wpf_count; ++i) {
+ struct vsp1_rwpf *wpf = vsp1->wpf[i];
+ struct vsp1_pipeline *pipe;
+
+ if (wpf == NULL)
+ continue;
+
+ pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
+ if (pipe == NULL)
+ continue;
+
+ ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe),
+ msecs_to_jiffies(500));
+ if (ret == 0)
+ dev_warn(vsp1->dev, "pipeline %u stop timeout\n",
+ wpf->entity.index);
+ }
+}
+
+void vsp1_pipelines_resume(struct vsp1_device *vsp1)
+{
+ unsigned int i;
+
+ /* Resume pipeline all running pipelines. */
+ for (i = 0; i < vsp1->info->wpf_count; ++i) {
+ struct vsp1_rwpf *wpf = vsp1->wpf[i];
+ struct vsp1_pipeline *pipe;
+
+ if (wpf == NULL)
+ continue;
+
+ pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
+ if (pipe == NULL)
+ continue;
+
+ if (vsp1_pipeline_ready(pipe))
+ vsp1_pipeline_run(pipe);
+ }
+}
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
new file mode 100644
index 000000000000..b2f3a8a896c9
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -0,0 +1,134 @@
+/*
+ * vsp1_pipe.h -- R-Car VSP1 Pipeline
+ *
+ * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ */
+#ifndef __VSP1_PIPE_H__
+#define __VSP1_PIPE_H__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#include <media/media-entity.h>
+
+struct vsp1_dl;
+struct vsp1_rwpf;
+
+/*
+ * struct vsp1_format_info - VSP1 video format description
+ * @mbus: media bus format code
+ * @fourcc: V4L2 pixel format FCC identifier
+ * @planes: number of planes
+ * @bpp: bits per pixel
+ * @hwfmt: VSP1 hardware format
+ * @swap_yc: the Y and C components are swapped (Y comes before C)
+ * @swap_uv: the U and V components are swapped (V comes before U)
+ * @hsub: horizontal subsampling factor
+ * @vsub: vertical subsampling factor
+ * @alpha: has an alpha channel
+ */
+struct vsp1_format_info {
+ u32 fourcc;
+ unsigned int mbus;
+ unsigned int hwfmt;
+ unsigned int swap;
+ unsigned int planes;
+ unsigned int bpp[3];
+ bool swap_yc;
+ bool swap_uv;
+ unsigned int hsub;
+ unsigned int vsub;
+ bool alpha;
+};
+
+enum vsp1_pipeline_state {
+ VSP1_PIPELINE_STOPPED,
+ VSP1_PIPELINE_RUNNING,
+ VSP1_PIPELINE_STOPPING,
+};
+
+/*
+ * struct vsp1_pipeline - A VSP1 hardware pipeline
+ * @pipe: the media pipeline
+ * @irqlock: protects the pipeline state
+ * @state: current state
+ * @wq: work queue to wait for state change completion
+ * @frame_end: frame end interrupt handler
+ * @lock: protects the pipeline use count and stream count
+ * @use_count: number of video nodes using the pipeline
+ * @stream_count: number of streaming video nodes
+ * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available
+ * @num_inputs: number of RPFs
+ * @inputs: array of RPFs in the pipeline (indexed by RPF index)
+ * @output: WPF at the output of the pipeline
+ * @bru: BRU entity, if present
+ * @lif: LIF entity, if present
+ * @uds: UDS entity, if present
+ * @uds_input: entity at the input of the UDS, if the UDS is present
+ * @entities: list of entities in the pipeline
+ * @dl: display list associated with the pipeline
+ */
+struct vsp1_pipeline {
+ struct media_pipeline pipe;
+
+ spinlock_t irqlock;
+ enum vsp1_pipeline_state state;
+ wait_queue_head_t wq;
+
+ void (*frame_end)(struct vsp1_pipeline *pipe);
+
+ struct mutex lock;
+ unsigned int use_count;
+ unsigned int stream_count;
+ unsigned int buffers_ready;
+
+ unsigned int num_inputs;
+ struct vsp1_rwpf *inputs[VSP1_MAX_RPF];
+ struct vsp1_rwpf *output;
+ struct vsp1_entity *bru;
+ struct vsp1_entity *lif;
+ struct vsp1_entity *uds;
+ struct vsp1_entity *uds_input;
+
+ struct list_head entities;
+
+ struct vsp1_dl *dl;
+};
+
+static inline struct vsp1_pipeline *to_vsp1_pipeline(struct media_entity *e)
+{
+ if (likely(e->pipe))
+ return container_of(e->pipe, struct vsp1_pipeline, pipe);
+ else
+ return NULL;
+}
+
+void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
+void vsp1_pipeline_init(struct vsp1_pipeline *pipe);
+
+void vsp1_pipeline_run(struct vsp1_pipeline *pipe);
+bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
+int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
+bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe);
+
+void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe);
+void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
+
+void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
+ struct vsp1_entity *input,
+ unsigned int alpha);
+
+void vsp1_pipelines_suspend(struct vsp1_device *vsp1);
+void vsp1_pipelines_resume(struct vsp1_device *vsp1);
+
+const struct vsp1_format_info *vsp1_get_format_info(u32 fourcc);
+
+#endif /* __VSP1_PIPE_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 25b48738b147..069216f0eb44 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -46,7 +46,7 @@
#define VI6_DISP_IRQ_ENB_LNEE(n) (1 << (n))
#define VI6_DISP_IRQ_STA 0x007c
-#define VI6_DISP_IRQ_STA_DSE (1 << 8)
+#define VI6_DISP_IRQ_STA_DST (1 << 8)
#define VI6_DISP_IRQ_STA_MAE (1 << 5)
#define VI6_DISP_IRQ_STA_LNE(n) (1 << (n))
@@ -322,7 +322,7 @@
#define VI6_DPR_NODE_SRU 16
#define VI6_DPR_NODE_UDS(n) (17 + (n))
#define VI6_DPR_NODE_LUT 22
-#define VI6_DPR_NODE_BRU_IN(n) (23 + (n))
+#define VI6_DPR_NODE_BRU_IN(n) (((n) <= 3) ? 23 + (n) : 49)
#define VI6_DPR_NODE_BRU_OUT 27
#define VI6_DPR_NODE_CLU 29
#define VI6_DPR_NODE_HST 30
@@ -504,12 +504,12 @@
#define VI6_BRU_VIRRPF_COL_BCB_MASK (0xff << 0)
#define VI6_BRU_VIRRPF_COL_BCB_SHIFT 0
-#define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8)
+#define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8 + ((n) <= 3 ? 0 : 4))
#define VI6_BRU_CTRL_RBC (1 << 31)
-#define VI6_BRU_CTRL_DSTSEL_BRUIN(n) ((n) << 20)
+#define VI6_BRU_CTRL_DSTSEL_BRUIN(n) (((n) <= 3 ? (n) : (n)+1) << 20)
#define VI6_BRU_CTRL_DSTSEL_VRPF (4 << 20)
#define VI6_BRU_CTRL_DSTSEL_MASK (7 << 20)
-#define VI6_BRU_CTRL_SRCSEL_BRUIN(n) ((n) << 16)
+#define VI6_BRU_CTRL_SRCSEL_BRUIN(n) (((n) <= 3 ? (n) : (n)+1) << 16)
#define VI6_BRU_CTRL_SRCSEL_VRPF (4 << 16)
#define VI6_BRU_CTRL_SRCSEL_MASK (7 << 16)
#define VI6_BRU_CTRL_CROP(rop) ((rop) << 4)
@@ -517,7 +517,7 @@
#define VI6_BRU_CTRL_AROP(rop) ((rop) << 0)
#define VI6_BRU_CTRL_AROP_MASK (0xf << 0)
-#define VI6_BRU_BLD(n) (0x2c14 + (n) * 8)
+#define VI6_BRU_BLD(n) (0x2c14 + (n) * 8 + ((n) <= 3 ? 0 : 4))
#define VI6_BRU_BLD_CBES (1 << 31)
#define VI6_BRU_BLD_CCMDX_DST_A (0 << 28)
#define VI6_BRU_BLD_CCMDX_255_DST_A (1 << 28)
@@ -551,7 +551,7 @@
#define VI6_BRU_BLD_COEFY_SHIFT 0
#define VI6_BRU_ROP 0x2c30
-#define VI6_BRU_ROP_DSTSEL_BRUIN(n) ((n) << 20)
+#define VI6_BRU_ROP_DSTSEL_BRUIN(n) (((n) <= 3 ? (n) : (n)+1) << 20)
#define VI6_BRU_ROP_DSTSEL_VRPF (4 << 20)
#define VI6_BRU_ROP_DSTSEL_MASK (7 << 20)
#define VI6_BRU_ROP_CROP(rop) ((rop) << 4)
@@ -625,6 +625,24 @@
#define VI6_SECURITY_CTRL1 0x3d04
/* -----------------------------------------------------------------------------
+ * IP Version Registers
+ */
+
+#define VI6_IP_VERSION 0x3f00
+#define VI6_IP_VERSION_MODEL_MASK (0xff << 8)
+#define VI6_IP_VERSION_MODEL_VSPS_H2 (0x09 << 8)
+#define VI6_IP_VERSION_MODEL_VSPR_H2 (0x0a << 8)
+#define VI6_IP_VERSION_MODEL_VSPD_GEN2 (0x0b << 8)
+#define VI6_IP_VERSION_MODEL_VSPS_M2 (0x0c << 8)
+#define VI6_IP_VERSION_MODEL_VSPI_GEN3 (0x14 << 8)
+#define VI6_IP_VERSION_MODEL_VSPBD_GEN3 (0x15 << 8)
+#define VI6_IP_VERSION_MODEL_VSPBC_GEN3 (0x16 << 8)
+#define VI6_IP_VERSION_MODEL_VSPD_GEN3 (0x17 << 8)
+#define VI6_IP_VERSION_SOC_MASK (0xff << 0)
+#define VI6_IP_VERSION_SOC_H (0x01 << 0)
+#define VI6_IP_VERSION_SOC_M (0x02 << 0)
+
+/* -----------------------------------------------------------------------------
* RPF CLUT Registers
*/
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 924538223d3e..5bc1d1574a43 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -26,16 +26,10 @@
* Device Access
*/
-static inline u32 vsp1_rpf_read(struct vsp1_rwpf *rpf, u32 reg)
-{
- return vsp1_read(rpf->entity.vsp1,
- reg + rpf->entity.index * VI6_RPF_OFFSET);
-}
-
static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
{
- vsp1_write(rpf->entity.vsp1,
- reg + rpf->entity.index * VI6_RPF_OFFSET, data);
+ vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET,
+ data);
}
/* -----------------------------------------------------------------------------
@@ -74,9 +68,11 @@ static const struct v4l2_ctrl_ops rpf_ctrl_ops = {
static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
{
+ struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
struct vsp1_rwpf *rpf = to_rwpf(subdev);
- const struct vsp1_format_info *fmtinfo = rpf->video.fmtinfo;
- const struct v4l2_pix_format_mplane *format = &rpf->video.format;
+ struct vsp1_device *vsp1 = rpf->entity.vsp1;
+ const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
+ const struct v4l2_pix_format_mplane *format = &rpf->format;
const struct v4l2_rect *crop = &rpf->crop;
u32 pstride;
u32 infmt;
@@ -154,6 +150,15 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
(fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
: VI6_RPF_ALPH_SEL_ASEL_FIXED));
+
+ if (vsp1->info->uapi)
+ mutex_lock(rpf->ctrls.lock);
+ vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
+ rpf->alpha->cur.val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
+ vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha->cur.val);
+ if (vsp1->info->uapi)
+ mutex_unlock(rpf->ctrls.lock);
+
vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
@@ -186,30 +191,28 @@ static struct v4l2_subdev_ops rpf_ops = {
* Video Device Operations
*/
-static void rpf_vdev_queue(struct vsp1_video *video,
- struct vsp1_video_buffer *buf)
+static void rpf_set_memory(struct vsp1_rwpf *rpf, struct vsp1_rwpf_memory *mem)
{
- struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video);
unsigned int i;
for (i = 0; i < 3; ++i)
- rpf->buf_addr[i] = buf->addr[i];
+ rpf->buf_addr[i] = mem->addr[i];
if (!vsp1_entity_is_streaming(&rpf->entity))
return;
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
- buf->addr[0] + rpf->offsets[0]);
- if (buf->buf.vb2_buf.num_planes > 1)
+ mem->addr[0] + rpf->offsets[0]);
+ if (mem->num_planes > 1)
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
- buf->addr[1] + rpf->offsets[1]);
- if (buf->buf.vb2_buf.num_planes > 2)
+ mem->addr[1] + rpf->offsets[1]);
+ if (mem->num_planes > 2)
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
- buf->addr[2] + rpf->offsets[1]);
+ mem->addr[2] + rpf->offsets[1]);
}
-static const struct vsp1_video_operations rpf_vdev_ops = {
- .queue = rpf_vdev_queue,
+static const struct vsp1_rwpf_operations rpf_vdev_ops = {
+ .set_memory = rpf_set_memory,
};
/* -----------------------------------------------------------------------------
@@ -219,7 +222,6 @@ static const struct vsp1_video_operations rpf_vdev_ops = {
struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
{
struct v4l2_subdev *subdev;
- struct vsp1_video *video;
struct vsp1_rwpf *rpf;
int ret;
@@ -227,6 +229,8 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
if (rpf == NULL)
return ERR_PTR(-ENOMEM);
+ rpf->ops = &rpf_vdev_ops;
+
rpf->max_width = RPF_MAX_WIDTH;
rpf->max_height = RPF_MAX_HEIGHT;
@@ -241,7 +245,7 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
subdev = &rpf->entity.subdev;
v4l2_subdev_init(subdev, &rpf_ops);
- subdev->entity.ops = &vsp1_media_ops;
+ subdev->entity.ops = &vsp1->media_ops;
subdev->internal_ops = &vsp1_subdev_internal_ops;
snprintf(subdev->name, sizeof(subdev->name), "%s rpf.%u",
dev_name(vsp1->dev), index);
@@ -252,8 +256,9 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
/* Initialize the control handler. */
v4l2_ctrl_handler_init(&rpf->ctrls, 1);
- v4l2_ctrl_new_std(&rpf->ctrls, &rpf_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
- 0, 255, 1, 255);
+ rpf->alpha = v4l2_ctrl_new_std(&rpf->ctrls, &rpf_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT,
+ 0, 255, 1, 255);
rpf->entity.subdev.ctrl_handler = &rpf->ctrls;
@@ -264,42 +269,9 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
goto error;
}
- /* Initialize the video device. */
- video = &rpf->video;
-
- video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- video->vsp1 = vsp1;
- video->ops = &rpf_vdev_ops;
-
- ret = vsp1_video_init(video, &rpf->entity);
- if (ret < 0)
- goto error;
-
- rpf->entity.video = video;
-
return rpf;
error:
vsp1_entity_destroy(&rpf->entity);
return ERR_PTR(ret);
}
-
-/*
- * vsp1_rpf_create_links() - RPF pads links creation
- * @vsp1: Pointer to VSP1 device
- * @entity: Pointer to VSP1 entity
- *
- * return negative error code or zero on success
- */
-int vsp1_rpf_create_links(struct vsp1_device *vsp1,
- struct vsp1_entity *entity)
-{
- struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
-
- /* Connect the video device to the RPF. */
- return media_create_pad_link(&rpf->video.video.entity, 0,
- &rpf->entity.subdev.entity,
- RWPF_PAD_SINK,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
-}
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 731d36e5258d..8e8235682ada 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -19,19 +19,39 @@
#include "vsp1.h"
#include "vsp1_entity.h"
-#include "vsp1_video.h"
#define RWPF_PAD_SINK 0
#define RWPF_PAD_SOURCE 1
+struct v4l2_ctrl;
+struct vsp1_rwpf;
+struct vsp1_video;
+
+struct vsp1_rwpf_memory {
+ unsigned int num_planes;
+ dma_addr_t addr[3];
+ unsigned int length[3];
+};
+
+struct vsp1_rwpf_operations {
+ void (*set_memory)(struct vsp1_rwpf *rwpf,
+ struct vsp1_rwpf_memory *mem);
+};
+
struct vsp1_rwpf {
struct vsp1_entity entity;
- struct vsp1_video video;
struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *alpha;
+
+ struct vsp1_video *video;
+
+ const struct vsp1_rwpf_operations *ops;
unsigned int max_width;
unsigned int max_height;
+ struct v4l2_pix_format_mplane format;
+ const struct vsp1_format_info *fmtinfo;
struct {
unsigned int left;
unsigned int top;
@@ -50,11 +70,6 @@ static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
-int vsp1_rpf_create_links(struct vsp1_device *vsp1,
- struct vsp1_entity *entity);
-int vsp1_wpf_create_links(struct vsp1_device *vsp1,
- struct vsp1_entity *entity);
-
int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code);
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 6310acab60e7..cc09efbfb24f 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -151,10 +151,13 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
/* Take the control handler lock to ensure that the CTRL0 value won't be
* changed behind our back by a set control operation.
*/
- mutex_lock(sru->ctrls.lock);
+ if (sru->entity.vsp1->info->uapi)
+ mutex_lock(sru->ctrls.lock);
ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0)
& (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK);
- mutex_unlock(sru->ctrls.lock);
+ vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
+ if (sru->entity.vsp1->info->uapi)
+ mutex_unlock(sru->ctrls.lock);
vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
@@ -360,7 +363,7 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
subdev = &sru->entity.subdev;
v4l2_subdev_init(subdev, &sru_ops);
- subdev->entity.ops = &vsp1_media_ops;
+ subdev->entity.ops = &vsp1->media_ops;
subdev->internal_ops = &vsp1_subdev_internal_ops;
snprintf(subdev->name, sizeof(subdev->name), "%s sru",
dev_name(vsp1->dev));
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index ccc8243e3493..bba67770cf95 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -29,12 +29,6 @@
* Device Access
*/
-static inline u32 vsp1_uds_read(struct vsp1_uds *uds, u32 reg)
-{
- return vsp1_read(uds->entity.vsp1,
- reg + uds->entity.index * VI6_UDS_OFFSET);
-}
-
static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data)
{
vsp1_write(uds->entity.vsp1,
@@ -344,7 +338,7 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
subdev = &uds->entity.subdev;
v4l2_subdev_init(subdev, &uds_ops);
- subdev->entity.ops = &vsp1_media_ops;
+ subdev->entity.ops = &vsp1->media_ops;
subdev->internal_ops = &vsp1_subdev_internal_ops;
snprintf(subdev->name, sizeof(subdev->name), "%s uds.%u",
dev_name(vsp1->dev), index);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index b4dca57d1ae3..72cc7d3729f8 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -14,10 +14,10 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
+#include <linux/wait.h>
#include <media/media-entity.h>
#include <media/v4l2-dev.h>
@@ -30,6 +30,7 @@
#include "vsp1.h"
#include "vsp1_bru.h"
#include "vsp1_entity.h"
+#include "vsp1_pipe.h"
#include "vsp1_rwpf.h"
#include "vsp1_uds.h"
#include "vsp1_video.h"
@@ -47,113 +48,6 @@
* Helper functions
*/
-static const struct vsp1_format_info vsp1_video_formats[] = {
- { V4L2_PIX_FMT_RGB332, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_RGB_332, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 8, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_ARGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_ARGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS,
- 1, { 16, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS,
- 1, { 16, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS,
- 1, { 16, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_XRGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS,
- 1, { 16, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS,
- 1, { 16, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_BGR24, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_BGR_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 24, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_RGB24, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 24, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_ABGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
- 1, { 32, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
- 1, { 32, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 32, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_XRGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
- VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 32, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32,
- VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 16, 0, 0 }, false, false, 2, 1, false },
- { V4L2_PIX_FMT_VYUY, MEDIA_BUS_FMT_AYUV8_1X32,
- VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 16, 0, 0 }, false, true, 2, 1, false },
- { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_AYUV8_1X32,
- VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 16, 0, 0 }, true, false, 2, 1, false },
- { V4L2_PIX_FMT_YVYU, MEDIA_BUS_FMT_AYUV8_1X32,
- VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 16, 0, 0 }, true, true, 2, 1, false },
- { V4L2_PIX_FMT_NV12M, MEDIA_BUS_FMT_AYUV8_1X32,
- VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 2, { 8, 16, 0 }, false, false, 2, 2, false },
- { V4L2_PIX_FMT_NV21M, MEDIA_BUS_FMT_AYUV8_1X32,
- VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 2, { 8, 16, 0 }, false, true, 2, 2, false },
- { V4L2_PIX_FMT_NV16M, MEDIA_BUS_FMT_AYUV8_1X32,
- VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 2, { 8, 16, 0 }, false, false, 2, 1, false },
- { V4L2_PIX_FMT_NV61M, MEDIA_BUS_FMT_AYUV8_1X32,
- VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 2, { 8, 16, 0 }, false, true, 2, 1, false },
- { V4L2_PIX_FMT_YUV420M, MEDIA_BUS_FMT_AYUV8_1X32,
- VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
- VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 3, { 8, 8, 8 }, false, false, 2, 2, false },
-};
-
-/*
- * vsp1_get_format_info - Retrieve format information for a 4CC
- * @fourcc: the format 4CC
- *
- * Return a pointer to the format information structure corresponding to the
- * given V4L2 format 4CC, or NULL if no corresponding format can be found.
- */
-static const struct vsp1_format_info *vsp1_get_format_info(u32 fourcc)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) {
- const struct vsp1_format_info *info = &vsp1_video_formats[i];
-
- if (info->fourcc == fourcc)
- return info;
- }
-
- return NULL;
-}
-
-
static struct v4l2_subdev *
vsp1_video_remote_subdev(struct media_pad *local, u32 *pad)
{
@@ -184,9 +78,9 @@ static int vsp1_video_verify_format(struct vsp1_video *video)
if (ret < 0)
return ret == -ENOIOCTLCMD ? -EINVAL : ret;
- if (video->fmtinfo->mbus != fmt.format.code ||
- video->format.height != fmt.format.height ||
- video->format.width != fmt.format.width)
+ if (video->rwpf->fmtinfo->mbus != fmt.format.code ||
+ video->rwpf->format.height != fmt.format.height ||
+ video->rwpf->format.width != fmt.format.width)
return -EINVAL;
return 0;
@@ -277,9 +171,9 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
* Pipeline Management
*/
-static int vsp1_pipeline_validate_branch(struct vsp1_pipeline *pipe,
- struct vsp1_rwpf *input,
- struct vsp1_rwpf *output)
+static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe,
+ struct vsp1_rwpf *input,
+ struct vsp1_rwpf *output)
{
struct vsp1_entity *entity;
struct media_entity_enum ent_enum;
@@ -370,29 +264,8 @@ out:
return rval;
}
-static void __vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe)
-{
- if (pipe->bru) {
- struct vsp1_bru *bru = to_bru(&pipe->bru->subdev);
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(bru->inputs); ++i)
- bru->inputs[i].rpf = NULL;
- }
-
- INIT_LIST_HEAD(&pipe->entities);
- pipe->state = VSP1_PIPELINE_STOPPED;
- pipe->buffers_ready = 0;
- pipe->num_video = 0;
- pipe->num_inputs = 0;
- pipe->output = NULL;
- pipe->bru = NULL;
- pipe->lif = NULL;
- pipe->uds = NULL;
-}
-
-static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
- struct vsp1_video *video)
+static int vsp1_video_pipeline_validate(struct vsp1_pipeline *pipe,
+ struct vsp1_video *video)
{
struct media_entity_graph graph;
struct media_entity *entity = &video->video.entity;
@@ -416,10 +289,8 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
struct vsp1_rwpf *rwpf;
struct vsp1_entity *e;
- if (is_media_entity_v4l2_io(entity)) {
- pipe->num_video++;
+ if (!is_media_entity_v4l2_subdev(entity))
continue;
- }
subdev = media_entity_to_v4l2_subdev(entity);
e = to_vsp1_entity(subdev);
@@ -427,12 +298,12 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
if (e->type == VSP1_ENTITY_RPF) {
rwpf = to_rwpf(subdev);
- pipe->inputs[pipe->num_inputs++] = rwpf;
- rwpf->video.pipe_index = pipe->num_inputs;
+ pipe->inputs[rwpf->entity.index] = rwpf;
+ rwpf->video->pipe_index = ++pipe->num_inputs;
} else if (e->type == VSP1_ENTITY_WPF) {
rwpf = to_rwpf(subdev);
- pipe->output = to_rwpf(subdev);
- rwpf->video.pipe_index = 0;
+ pipe->output = rwpf;
+ rwpf->video->pipe_index = 0;
} else if (e->type == VSP1_ENTITY_LIF) {
pipe->lif = e;
} else if (e->type == VSP1_ENTITY_BRU) {
@@ -453,9 +324,12 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
/* Follow links downstream for each input and make sure the graph
* contains no loop and that all branches end at the output WPF.
*/
- for (i = 0; i < pipe->num_inputs; ++i) {
- ret = vsp1_pipeline_validate_branch(pipe, pipe->inputs[i],
- pipe->output);
+ for (i = 0; i < video->vsp1->info->rpf_count; ++i) {
+ if (!pipe->inputs[i])
+ continue;
+
+ ret = vsp1_video_pipeline_validate_branch(pipe, pipe->inputs[i],
+ pipe->output);
if (ret < 0)
goto error;
}
@@ -463,12 +337,12 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
return 0;
error:
- __vsp1_pipeline_cleanup(pipe);
+ vsp1_pipeline_reset(pipe);
return ret;
}
-static int vsp1_pipeline_init(struct vsp1_pipeline *pipe,
- struct vsp1_video *video)
+static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe,
+ struct vsp1_video *video)
{
int ret;
@@ -476,7 +350,7 @@ static int vsp1_pipeline_init(struct vsp1_pipeline *pipe,
/* If we're the first user validate and initialize the pipeline. */
if (pipe->use_count == 0) {
- ret = vsp1_pipeline_validate(pipe, video);
+ ret = vsp1_video_pipeline_validate(pipe, video);
if (ret < 0)
goto done;
}
@@ -489,75 +363,17 @@ done:
return ret;
}
-static void vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe)
+static void vsp1_video_pipeline_cleanup(struct vsp1_pipeline *pipe)
{
mutex_lock(&pipe->lock);
/* If we're the last user clean up the pipeline. */
if (--pipe->use_count == 0)
- __vsp1_pipeline_cleanup(pipe);
+ vsp1_pipeline_reset(pipe);
mutex_unlock(&pipe->lock);
}
-static void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
-{
- struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
-
- vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index), VI6_CMD_STRCMD);
- pipe->state = VSP1_PIPELINE_RUNNING;
- pipe->buffers_ready = 0;
-}
-
-static bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe)
-{
- unsigned long flags;
- bool stopped;
-
- spin_lock_irqsave(&pipe->irqlock, flags);
- stopped = pipe->state == VSP1_PIPELINE_STOPPED;
- spin_unlock_irqrestore(&pipe->irqlock, flags);
-
- return stopped;
-}
-
-static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
-{
- struct vsp1_entity *entity;
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&pipe->irqlock, flags);
- if (pipe->state == VSP1_PIPELINE_RUNNING)
- pipe->state = VSP1_PIPELINE_STOPPING;
- spin_unlock_irqrestore(&pipe->irqlock, flags);
-
- ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe),
- msecs_to_jiffies(500));
- ret = ret == 0 ? -ETIMEDOUT : 0;
-
- list_for_each_entry(entity, &pipe->entities, list_pipe) {
- if (entity->route && entity->route->reg)
- vsp1_write(entity->vsp1, entity->route->reg,
- VI6_DPR_NODE_UNUSED);
-
- v4l2_subdev_call(&entity->subdev, video, s_stream, 0);
- }
-
- return ret;
-}
-
-static bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
-{
- unsigned int mask;
-
- mask = ((1 << pipe->num_inputs) - 1) << 1;
- if (!pipe->lif)
- mask |= 1 << 0;
-
- return pipe->buffers_ready == mask;
-}
-
/*
* vsp1_video_complete_buffer - Complete the current buffer
* @video: the video node
@@ -572,12 +388,12 @@ static bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
*
* Return the next queued buffer or NULL if the queue is empty.
*/
-static struct vsp1_video_buffer *
+static struct vsp1_vb2_buffer *
vsp1_video_complete_buffer(struct vsp1_video *video)
{
struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
- struct vsp1_video_buffer *next = NULL;
- struct vsp1_video_buffer *done;
+ struct vsp1_vb2_buffer *next = NULL;
+ struct vsp1_vb2_buffer *done;
unsigned long flags;
unsigned int i;
@@ -589,7 +405,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
}
done = list_first_entry(&video->irqqueue,
- struct vsp1_video_buffer, queue);
+ struct vsp1_vb2_buffer, queue);
/* In DU output mode reuse the buffer if the list is singular. */
if (pipe->lif && list_is_singular(&video->irqqueue)) {
@@ -601,23 +417,25 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
if (!list_empty(&video->irqqueue))
next = list_first_entry(&video->irqqueue,
- struct vsp1_video_buffer, queue);
+ struct vsp1_vb2_buffer, queue);
spin_unlock_irqrestore(&video->irqlock, flags);
done->buf.sequence = video->sequence++;
done->buf.vb2_buf.timestamp = ktime_get_ns();
for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
- vb2_set_plane_payload(&done->buf.vb2_buf, i, done->length[i]);
+ vb2_set_plane_payload(&done->buf.vb2_buf, i,
+ done->mem.length[i]);
vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE);
return next;
}
static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
- struct vsp1_video *video)
+ struct vsp1_rwpf *rwpf)
{
- struct vsp1_video_buffer *buf;
+ struct vsp1_video *video = rwpf->video;
+ struct vsp1_vb2_buffer *buf;
unsigned long flags;
buf = vsp1_video_complete_buffer(video);
@@ -626,155 +444,27 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
spin_lock_irqsave(&pipe->irqlock, flags);
- video->ops->queue(video, buf);
+ video->rwpf->ops->set_memory(video->rwpf, &buf->mem);
pipe->buffers_ready |= 1 << video->pipe_index;
spin_unlock_irqrestore(&pipe->irqlock, flags);
}
-void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
+static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
{
- enum vsp1_pipeline_state state;
- unsigned long flags;
+ struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
unsigned int i;
- if (pipe == NULL)
- return;
-
/* Complete buffers on all video nodes. */
- for (i = 0; i < pipe->num_inputs; ++i)
- vsp1_video_frame_end(pipe, &pipe->inputs[i]->video);
-
- if (!pipe->lif)
- vsp1_video_frame_end(pipe, &pipe->output->video);
-
- spin_lock_irqsave(&pipe->irqlock, flags);
-
- state = pipe->state;
- pipe->state = VSP1_PIPELINE_STOPPED;
-
- /* If a stop has been requested, mark the pipeline as stopped and
- * return.
- */
- if (state == VSP1_PIPELINE_STOPPING) {
- wake_up(&pipe->wq);
- goto done;
- }
-
- /* Restart the pipeline if ready. */
- if (vsp1_pipeline_ready(pipe))
- vsp1_pipeline_run(pipe);
-
-done:
- spin_unlock_irqrestore(&pipe->irqlock, flags);
-}
-
-/*
- * Propagate the alpha value through the pipeline.
- *
- * As the UDS has restricted scaling capabilities when the alpha component needs
- * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha
- * value. The UDS then outputs a fixed alpha value which needs to be programmed
- * from the input RPF alpha.
- */
-void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
- struct vsp1_entity *input,
- unsigned int alpha)
-{
- struct vsp1_entity *entity;
- struct media_pad *pad;
-
- pad = media_entity_remote_pad(&input->pads[RWPF_PAD_SOURCE]);
-
- while (pad) {
- if (!is_media_entity_v4l2_subdev(pad->entity))
- break;
-
- entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
-
- /* The BRU background color has a fixed alpha value set to 255,
- * the output alpha value is thus always equal to 255.
- */
- if (entity->type == VSP1_ENTITY_BRU)
- alpha = 255;
-
- if (entity->type == VSP1_ENTITY_UDS) {
- struct vsp1_uds *uds = to_uds(&entity->subdev);
-
- vsp1_uds_set_alpha(uds, alpha);
- break;
- }
-
- pad = &entity->pads[entity->source_pad];
- pad = media_entity_remote_pad(pad);
- }
-}
-
-void vsp1_pipelines_suspend(struct vsp1_device *vsp1)
-{
- unsigned long flags;
- unsigned int i;
- int ret;
-
- /* To avoid increasing the system suspend time needlessly, loop over the
- * pipelines twice, first to set them all to the stopping state, and then
- * to wait for the stop to complete.
- */
- for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
- struct vsp1_rwpf *wpf = vsp1->wpf[i];
- struct vsp1_pipeline *pipe;
-
- if (wpf == NULL)
- continue;
-
- pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
- if (pipe == NULL)
- continue;
-
- spin_lock_irqsave(&pipe->irqlock, flags);
- if (pipe->state == VSP1_PIPELINE_RUNNING)
- pipe->state = VSP1_PIPELINE_STOPPING;
- spin_unlock_irqrestore(&pipe->irqlock, flags);
- }
-
- for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
- struct vsp1_rwpf *wpf = vsp1->wpf[i];
- struct vsp1_pipeline *pipe;
-
- if (wpf == NULL)
- continue;
-
- pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
- if (pipe == NULL)
+ for (i = 0; i < vsp1->info->rpf_count; ++i) {
+ if (!pipe->inputs[i])
continue;
- ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe),
- msecs_to_jiffies(500));
- if (ret == 0)
- dev_warn(vsp1->dev, "pipeline %u stop timeout\n",
- wpf->entity.index);
+ vsp1_video_frame_end(pipe, pipe->inputs[i]);
}
-}
-
-void vsp1_pipelines_resume(struct vsp1_device *vsp1)
-{
- unsigned int i;
-
- /* Resume pipeline all running pipelines. */
- for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
- struct vsp1_rwpf *wpf = vsp1->wpf[i];
- struct vsp1_pipeline *pipe;
- if (wpf == NULL)
- continue;
-
- pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
- if (pipe == NULL)
- continue;
-
- if (vsp1_pipeline_ready(pipe))
- vsp1_pipeline_run(pipe);
- }
+ if (!pipe->lif)
+ vsp1_video_frame_end(pipe, pipe->output);
}
/* -----------------------------------------------------------------------------
@@ -787,7 +477,7 @@ vsp1_video_queue_setup(struct vb2_queue *vq,
unsigned int sizes[], void *alloc_ctxs[])
{
struct vsp1_video *video = vb2_get_drv_priv(vq);
- const struct v4l2_pix_format_mplane *format = &video->format;
+ const struct v4l2_pix_format_mplane *format = &video->rwpf->format;
unsigned int i;
if (*nplanes) {
@@ -816,18 +506,20 @@ static int vsp1_video_buffer_prepare(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue);
- struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vbuf);
- const struct v4l2_pix_format_mplane *format = &video->format;
+ struct vsp1_vb2_buffer *buf = to_vsp1_vb2_buffer(vbuf);
+ const struct v4l2_pix_format_mplane *format = &video->rwpf->format;
unsigned int i;
if (vb->num_planes < format->num_planes)
return -EINVAL;
+ buf->mem.num_planes = vb->num_planes;
+
for (i = 0; i < vb->num_planes; ++i) {
- buf->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
- buf->length[i] = vb2_plane_size(vb, i);
+ buf->mem.addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
+ buf->mem.length[i] = vb2_plane_size(vb, i);
- if (buf->length[i] < format->plane_fmt[i].sizeimage)
+ if (buf->mem.length[i] < format->plane_fmt[i].sizeimage)
return -EINVAL;
}
@@ -839,7 +531,7 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue);
struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
- struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vbuf);
+ struct vsp1_vb2_buffer *buf = to_vsp1_vb2_buffer(vbuf);
unsigned long flags;
bool empty;
@@ -853,7 +545,7 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
spin_lock_irqsave(&pipe->irqlock, flags);
- video->ops->queue(video, buf);
+ video->rwpf->ops->set_memory(video->rwpf, &buf->mem);
pipe->buffers_ready |= 1 << video->pipe_index;
if (vb2_is_streaming(&video->queue) &&
@@ -863,18 +555,6 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&pipe->irqlock, flags);
}
-static void vsp1_entity_route_setup(struct vsp1_entity *source)
-{
- struct vsp1_entity *sink;
-
- if (source->route->reg == 0)
- return;
-
- sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
- vsp1_write(source->vsp1, source->route->reg,
- sink->route->inputs[source->sink_pad]);
-}
-
static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vsp1_video *video = vb2_get_drv_priv(vq);
@@ -884,7 +564,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
int ret;
mutex_lock(&pipe->lock);
- if (pipe->stream_count == pipe->num_video - 1) {
+ if (pipe->stream_count == pipe->num_inputs) {
if (pipe->uds) {
struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
@@ -900,7 +580,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
struct vsp1_rwpf *rpf =
to_rwpf(&pipe->uds_input->subdev);
- uds->scale_alpha = rpf->video.fmtinfo->alpha;
+ uds->scale_alpha = rpf->fmtinfo->alpha;
}
}
@@ -931,7 +611,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
{
struct vsp1_video *video = vb2_get_drv_priv(vq);
struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
- struct vsp1_video_buffer *buffer;
+ struct vsp1_vb2_buffer *buffer;
unsigned long flags;
int ret;
@@ -944,7 +624,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
}
mutex_unlock(&pipe->lock);
- vsp1_pipeline_cleanup(pipe);
+ vsp1_video_pipeline_cleanup(pipe);
media_entity_pipeline_stop(&video->video.entity);
/* Remove all buffers from the IRQ queue. */
@@ -1004,7 +684,7 @@ vsp1_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
return -EINVAL;
mutex_lock(&video->lock);
- format->fmt.pix_mp = video->format;
+ format->fmt.pix_mp = video->rwpf->format;
mutex_unlock(&video->lock);
return 0;
@@ -1044,8 +724,8 @@ vsp1_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
goto done;
}
- video->format = format->fmt.pix_mp;
- video->fmtinfo = info;
+ video->rwpf->format = format->fmt.pix_mp;
+ video->rwpf->fmtinfo = info;
done:
mutex_unlock(&video->lock);
@@ -1085,7 +765,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
if (ret < 0)
goto err_stop;
- ret = vsp1_pipeline_init(pipe, video);
+ ret = vsp1_video_pipeline_init(pipe, video);
if (ret < 0)
goto err_stop;
@@ -1097,7 +777,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
return 0;
err_cleanup:
- vsp1_pipeline_cleanup(pipe);
+ vsp1_video_pipeline_cleanup(pipe);
err_stop:
media_entity_pipeline_stop(&video->video.entity);
return ret;
@@ -1183,62 +863,64 @@ static struct v4l2_file_operations vsp1_video_fops = {
* Initialization and Cleanup
*/
-int vsp1_video_init(struct vsp1_video *video, struct vsp1_entity *rwpf)
+struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
+ struct vsp1_rwpf *rwpf)
{
+ struct vsp1_video *video;
const char *direction;
int ret;
- switch (video->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- direction = "output";
- video->pad.flags = MEDIA_PAD_FL_SINK;
- break;
+ video = devm_kzalloc(vsp1->dev, sizeof(*video), GFP_KERNEL);
+ if (!video)
+ return ERR_PTR(-ENOMEM);
+
+ rwpf->video = video;
+
+ video->vsp1 = vsp1;
+ video->rwpf = rwpf;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (rwpf->entity.type == VSP1_ENTITY_RPF) {
direction = "input";
+ video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
video->pad.flags = MEDIA_PAD_FL_SOURCE;
video->video.vfl_dir = VFL_DIR_TX;
- break;
-
- default:
- return -EINVAL;
+ } else {
+ direction = "output";
+ video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ video->pad.flags = MEDIA_PAD_FL_SINK;
+ video->video.vfl_dir = VFL_DIR_RX;
}
- video->rwpf = rwpf;
-
mutex_init(&video->lock);
spin_lock_init(&video->irqlock);
INIT_LIST_HEAD(&video->irqqueue);
- mutex_init(&video->pipe.lock);
- spin_lock_init(&video->pipe.irqlock);
- INIT_LIST_HEAD(&video->pipe.entities);
- init_waitqueue_head(&video->pipe.wq);
- video->pipe.state = VSP1_PIPELINE_STOPPED;
+ vsp1_pipeline_init(&video->pipe);
+ video->pipe.frame_end = vsp1_video_pipeline_frame_end;
/* Initialize the media entity... */
ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
if (ret < 0)
- return ret;
+ return ERR_PTR(ret);
/* ... and the format ... */
- video->fmtinfo = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT);
- video->format.pixelformat = video->fmtinfo->fourcc;
- video->format.colorspace = V4L2_COLORSPACE_SRGB;
- video->format.field = V4L2_FIELD_NONE;
- video->format.width = VSP1_VIDEO_DEF_WIDTH;
- video->format.height = VSP1_VIDEO_DEF_HEIGHT;
- video->format.num_planes = 1;
- video->format.plane_fmt[0].bytesperline =
- video->format.width * video->fmtinfo->bpp[0] / 8;
- video->format.plane_fmt[0].sizeimage =
- video->format.plane_fmt[0].bytesperline * video->format.height;
+ rwpf->fmtinfo = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT);
+ rwpf->format.pixelformat = rwpf->fmtinfo->fourcc;
+ rwpf->format.colorspace = V4L2_COLORSPACE_SRGB;
+ rwpf->format.field = V4L2_FIELD_NONE;
+ rwpf->format.width = VSP1_VIDEO_DEF_WIDTH;
+ rwpf->format.height = VSP1_VIDEO_DEF_HEIGHT;
+ rwpf->format.num_planes = 1;
+ rwpf->format.plane_fmt[0].bytesperline =
+ rwpf->format.width * rwpf->fmtinfo->bpp[0] / 8;
+ rwpf->format.plane_fmt[0].sizeimage =
+ rwpf->format.plane_fmt[0].bytesperline * rwpf->format.height;
/* ... and the video node... */
video->video.v4l2_dev = &video->vsp1->v4l2_dev;
video->video.fops = &vsp1_video_fops;
snprintf(video->video.name, sizeof(video->video.name), "%s %s",
- rwpf->subdev.name, direction);
+ rwpf->entity.subdev.name, direction);
video->video.vfl_type = VFL_TYPE_GRABBER;
video->video.release = video_device_release_empty;
video->video.ioctl_ops = &vsp1_video_ioctl_ops;
@@ -1256,7 +938,7 @@ int vsp1_video_init(struct vsp1_video *video, struct vsp1_entity *rwpf)
video->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
video->queue.lock = &video->lock;
video->queue.drv_priv = video;
- video->queue.buf_struct_size = sizeof(struct vsp1_video_buffer);
+ video->queue.buf_struct_size = sizeof(struct vsp1_vb2_buffer);
video->queue.ops = &vsp1_video_queue_qops;
video->queue.mem_ops = &vb2_dma_contig_memops;
video->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
@@ -1274,12 +956,12 @@ int vsp1_video_init(struct vsp1_video *video, struct vsp1_entity *rwpf)
goto error;
}
- return 0;
+ return video;
error:
vb2_dma_contig_cleanup_ctx(video->alloc_ctx);
vsp1_video_cleanup(video);
- return ret;
+ return ERR_PTR(ret);
}
void vsp1_video_cleanup(struct vsp1_video *video)
diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h
index a929aa81cdbf..64abd39ee1e7 100644
--- a/drivers/media/platform/vsp1/vsp1_video.h
+++ b/drivers/media/platform/vsp1/vsp1_video.h
@@ -15,115 +15,34 @@
#include <linux/list.h>
#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <media/media-entity.h>
#include <media/videobuf2-v4l2.h>
-struct vsp1_video;
+#include "vsp1_pipe.h"
+#include "vsp1_rwpf.h"
-/*
- * struct vsp1_format_info - VSP1 video format description
- * @mbus: media bus format code
- * @fourcc: V4L2 pixel format FCC identifier
- * @planes: number of planes
- * @bpp: bits per pixel
- * @hwfmt: VSP1 hardware format
- * @swap_yc: the Y and C components are swapped (Y comes before C)
- * @swap_uv: the U and V components are swapped (V comes before U)
- * @hsub: horizontal subsampling factor
- * @vsub: vertical subsampling factor
- * @alpha: has an alpha channel
- */
-struct vsp1_format_info {
- u32 fourcc;
- unsigned int mbus;
- unsigned int hwfmt;
- unsigned int swap;
- unsigned int planes;
- unsigned int bpp[3];
- bool swap_yc;
- bool swap_uv;
- unsigned int hsub;
- unsigned int vsub;
- bool alpha;
-};
-
-enum vsp1_pipeline_state {
- VSP1_PIPELINE_STOPPED,
- VSP1_PIPELINE_RUNNING,
- VSP1_PIPELINE_STOPPING,
-};
-
-/*
- * struct vsp1_pipeline - A VSP1 hardware pipeline
- * @media: the media pipeline
- * @irqlock: protects the pipeline state
- * @lock: protects the pipeline use count and stream count
- */
-struct vsp1_pipeline {
- struct media_pipeline pipe;
-
- spinlock_t irqlock;
- enum vsp1_pipeline_state state;
- wait_queue_head_t wq;
-
- struct mutex lock;
- unsigned int use_count;
- unsigned int stream_count;
- unsigned int buffers_ready;
-
- unsigned int num_video;
- unsigned int num_inputs;
- struct vsp1_rwpf *inputs[VSP1_MAX_RPF];
- struct vsp1_rwpf *output;
- struct vsp1_entity *bru;
- struct vsp1_entity *lif;
- struct vsp1_entity *uds;
- struct vsp1_entity *uds_input;
-
- struct list_head entities;
-};
-
-static inline struct vsp1_pipeline *to_vsp1_pipeline(struct media_entity *e)
-{
- if (likely(e->pipe))
- return container_of(e->pipe, struct vsp1_pipeline, pipe);
- else
- return NULL;
-}
-
-struct vsp1_video_buffer {
+struct vsp1_vb2_buffer {
struct vb2_v4l2_buffer buf;
struct list_head queue;
-
- dma_addr_t addr[3];
- unsigned int length[3];
+ struct vsp1_rwpf_memory mem;
};
-static inline struct vsp1_video_buffer *
-to_vsp1_video_buffer(struct vb2_v4l2_buffer *vbuf)
+static inline struct vsp1_vb2_buffer *
+to_vsp1_vb2_buffer(struct vb2_v4l2_buffer *vbuf)
{
- return container_of(vbuf, struct vsp1_video_buffer, buf);
+ return container_of(vbuf, struct vsp1_vb2_buffer, buf);
}
-struct vsp1_video_operations {
- void (*queue)(struct vsp1_video *video, struct vsp1_video_buffer *buf);
-};
-
struct vsp1_video {
+ struct list_head list;
struct vsp1_device *vsp1;
- struct vsp1_entity *rwpf;
-
- const struct vsp1_video_operations *ops;
+ struct vsp1_rwpf *rwpf;
struct video_device video;
enum v4l2_buf_type type;
struct media_pad pad;
struct mutex lock;
- struct v4l2_pix_format_mplane format;
- const struct vsp1_format_info *fmtinfo;
struct vsp1_pipeline pipe;
unsigned int pipe_index;
@@ -140,16 +59,8 @@ static inline struct vsp1_video *to_vsp1_video(struct video_device *vdev)
return container_of(vdev, struct vsp1_video, video);
}
-int vsp1_video_init(struct vsp1_video *video, struct vsp1_entity *rwpf);
+struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
+ struct vsp1_rwpf *rwpf);
void vsp1_video_cleanup(struct vsp1_video *video);
-void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
-
-void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
- struct vsp1_entity *input,
- unsigned int alpha);
-
-void vsp1_pipelines_suspend(struct vsp1_device *vsp1);
-void vsp1_pipelines_resume(struct vsp1_device *vsp1);
-
#endif /* __VSP1_VIDEO_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index cbf514a6582d..c78d4af50fcf 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -34,8 +34,8 @@ static inline u32 vsp1_wpf_read(struct vsp1_rwpf *wpf, u32 reg)
static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
{
- vsp1_write(wpf->entity.vsp1,
- reg + wpf->entity.index * VI6_WPF_OFFSET, data);
+ vsp1_mod_write(&wpf->entity,
+ reg + wpf->entity.index * VI6_WPF_OFFSET, data);
}
/* -----------------------------------------------------------------------------
@@ -88,7 +88,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
if (!enable) {
vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
- vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, 0);
+ vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
+ VI6_WPF_SRCRPF, 0);
return 0;
}
@@ -97,9 +98,12 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
* inputs as sub-layers and select the virtual RPF as the master
* layer.
*/
- for (i = 0; i < pipe->num_inputs; ++i) {
+ for (i = 0; i < vsp1->info->rpf_count; ++i) {
struct vsp1_rwpf *input = pipe->inputs[i];
+ if (!input)
+ continue;
+
srcrpf |= (!pipe->bru && pipe->num_inputs == 1)
? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
: VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
@@ -112,7 +116,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
/* Destination stride. */
if (!pipe->lif) {
- struct v4l2_pix_format_mplane *format = &wpf->video.format;
+ struct v4l2_pix_format_mplane *format = &wpf->format;
vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y,
format->plane_fmt[0].bytesperline);
@@ -130,7 +134,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
/* Format */
if (!pipe->lif) {
- const struct vsp1_format_info *fmtinfo = wpf->video.fmtinfo;
+ const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;
@@ -151,15 +155,17 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
/* Take the control handler lock to ensure that the PDV value won't be
* changed behind our back by a set control operation.
*/
- mutex_lock(wpf->ctrls.lock);
- outfmt |= vsp1_wpf_read(wpf, VI6_WPF_OUTFMT) & VI6_WPF_OUTFMT_PDV_MASK;
+ if (vsp1->info->uapi)
+ mutex_lock(wpf->ctrls.lock);
+ outfmt |= wpf->alpha->cur.val << VI6_WPF_OUTFMT_PDV_SHIFT;
vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, outfmt);
- mutex_unlock(wpf->ctrls.lock);
+ if (vsp1->info->uapi)
+ mutex_unlock(wpf->ctrls.lock);
- vsp1_write(vsp1, VI6_DPR_WPF_FPORCH(wpf->entity.index),
- VI6_DPR_WPF_FPORCH_FP_WPFN);
+ vsp1_mod_write(&wpf->entity, VI6_DPR_WPF_FPORCH(wpf->entity.index),
+ VI6_DPR_WPF_FPORCH_FP_WPFN);
- vsp1_write(vsp1, VI6_WPF_WRBCK_CTRL, 0);
+ vsp1_mod_write(&wpf->entity, VI6_WPF_WRBCK_CTRL, 0);
/* Enable interrupts */
vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
@@ -195,20 +201,17 @@ static struct v4l2_subdev_ops wpf_ops = {
* Video Device Operations
*/
-static void wpf_vdev_queue(struct vsp1_video *video,
- struct vsp1_video_buffer *buf)
+static void wpf_set_memory(struct vsp1_rwpf *wpf, struct vsp1_rwpf_memory *mem)
{
- struct vsp1_rwpf *wpf = container_of(video, struct vsp1_rwpf, video);
-
- vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, buf->addr[0]);
- if (buf->buf.vb2_buf.num_planes > 1)
- vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, buf->addr[1]);
- if (buf->buf.vb2_buf.num_planes > 2)
- vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, buf->addr[2]);
+ vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, mem->addr[0]);
+ if (mem->num_planes > 1)
+ vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, mem->addr[1]);
+ if (mem->num_planes > 2)
+ vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, mem->addr[2]);
}
-static const struct vsp1_video_operations wpf_vdev_ops = {
- .queue = wpf_vdev_queue,
+static const struct vsp1_rwpf_operations wpf_vdev_ops = {
+ .set_memory = wpf_set_memory,
};
/* -----------------------------------------------------------------------------
@@ -218,7 +221,6 @@ static const struct vsp1_video_operations wpf_vdev_ops = {
struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
{
struct v4l2_subdev *subdev;
- struct vsp1_video *video;
struct vsp1_rwpf *wpf;
int ret;
@@ -226,6 +228,8 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
if (wpf == NULL)
return ERR_PTR(-ENOMEM);
+ wpf->ops = &wpf_vdev_ops;
+
wpf->max_width = WPF_MAX_WIDTH;
wpf->max_height = WPF_MAX_HEIGHT;
@@ -240,7 +244,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
subdev = &wpf->entity.subdev;
v4l2_subdev_init(subdev, &wpf_ops);
- subdev->entity.ops = &vsp1_media_ops;
+ subdev->entity.ops = &vsp1->media_ops;
subdev->internal_ops = &vsp1_subdev_internal_ops;
snprintf(subdev->name, sizeof(subdev->name), "%s wpf.%u",
dev_name(vsp1->dev), index);
@@ -251,8 +255,9 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
/* Initialize the control handler. */
v4l2_ctrl_handler_init(&wpf->ctrls, 1);
- v4l2_ctrl_new_std(&wpf->ctrls, &wpf_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
- 0, 255, 1, 255);
+ wpf->alpha = v4l2_ctrl_new_std(&wpf->ctrls, &wpf_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT,
+ 0, 255, 1, 255);
wpf->entity.subdev.ctrl_handler = &wpf->ctrls;
@@ -263,48 +268,9 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
goto error;
}
- /* Initialize the video device. */
- video = &wpf->video;
-
- video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- video->vsp1 = vsp1;
- video->ops = &wpf_vdev_ops;
-
- ret = vsp1_video_init(video, &wpf->entity);
- if (ret < 0)
- goto error;
-
- wpf->entity.video = video;
- wpf->entity.sink = &wpf->video.video.entity;
-
return wpf;
error:
vsp1_entity_destroy(&wpf->entity);
return ERR_PTR(ret);
}
-
-/*
- * vsp1_wpf_create_links() - RPF pads links creation
- * @vsp1: Pointer to VSP1 device
- * @entity: Pointer to VSP1 entity
- *
- * return negative error code or zero on success
- */
-int vsp1_wpf_create_links(struct vsp1_device *vsp1,
- struct vsp1_entity *entity)
-{
- struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
- unsigned int flags;
-
- /* Connect the video device to the WPF. All connections are immutable
- * except for the WPF0 source link if a LIF is present.
- */
- flags = MEDIA_LNK_FL_ENABLED;
- if (!(vsp1->pdata.features & VSP1_HAS_LIF) || entity->index != 0)
- flags |= MEDIA_LNK_FL_IMMUTABLE;
-
- return media_create_pad_link(&wpf->entity.subdev.entity,
- RWPF_PAD_SOURCE,
- &wpf->video.video.entity, 0, flags);
-}
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index 859f0c08ee05..271f725b17e8 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -1530,11 +1530,11 @@ static int si476x_radio_probe(struct platform_device *pdev)
if (si476x_core_has_diversity(radio->core)) {
si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def =
si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode);
- si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE);
+ rval = si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE);
if (rval < 0)
goto exit;
- si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK);
+ rval = si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK);
if (rval < 0)
goto exit;
}
diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c
index 3e08475af579..4dc2067bce14 100644
--- a/drivers/media/radio/tea575x.c
+++ b/drivers/media/radio/tea575x.c
@@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/delay.h>
@@ -226,6 +222,7 @@ void snd_tea575x_set_freq(struct snd_tea575x *tea)
snd_tea575x_write(tea, tea->val);
tea->freq = snd_tea575x_val_to_freq(tea, tea->val);
}
+EXPORT_SYMBOL(snd_tea575x_set_freq);
/*
* Linux Video interface
@@ -582,25 +579,11 @@ int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
return 0;
}
+EXPORT_SYMBOL(snd_tea575x_init);
void snd_tea575x_exit(struct snd_tea575x *tea)
{
video_unregister_device(&tea->vd);
v4l2_ctrl_handler_free(tea->vd.ctrl_handler);
}
-
-static int __init alsa_tea575x_module_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_tea575x_module_exit(void)
-{
-}
-
-module_init(alsa_tea575x_module_init)
-module_exit(alsa_tea575x_module_exit)
-
-EXPORT_SYMBOL(snd_tea575x_init);
EXPORT_SYMBOL(snd_tea575x_exit);
-EXPORT_SYMBOL(snd_tea575x_set_freq);
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index ebc73b034249..3f9e6df7d837 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -68,7 +68,7 @@ MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan");
/* RDS buffer blocks */
static u32 default_rds_buf = 300;
module_param(default_rds_buf, uint, 0444);
-MODULE_PARM_DESC(rds_buf, "RDS buffer entries");
+MODULE_PARM_DESC(default_rds_buf, "RDS buffer entries");
/* Radio Nr */
static u32 radio_nr = -1;
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index a35631891cc0..3f61d77d4147 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -443,6 +443,21 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd,
return retval;
}
+struct accel_times {
+ const char value;
+ unsigned int msecs;
+};
+
+static const struct accel_times accel[] = {
+ { 1, 125 },
+ { 2, 250 },
+ { 4, 500 },
+ { 6, 1000 },
+ { 9, 1500 },
+ { 13, 2000 },
+ { 20, 0 },
+};
+
/*
* ati_remote_compute_accel
*
@@ -454,30 +469,22 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd,
*/
static int ati_remote_compute_accel(struct ati_remote *ati_remote)
{
- static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
- unsigned long now = jiffies;
- int acc;
+ unsigned long now = jiffies, reset_time;
+ int i;
+
+ reset_time = msecs_to_jiffies(250);
- if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
- acc = 1;
+ if (time_after(now, ati_remote->old_jiffies + reset_time)) {
ati_remote->acc_jiffies = now;
+ return 1;
}
- else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
- acc = accel[0];
- else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
- acc = accel[1];
- else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
- acc = accel[2];
- else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
- acc = accel[3];
- else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
- acc = accel[4];
- else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
- acc = accel[5];
- else
- acc = accel[6];
+ for (i = 0; i < ARRAY_SIZE(accel) - 1; i++) {
+ unsigned long timeout = msecs_to_jiffies(accel[i].msecs);
- return acc;
+ if (time_before(now, ati_remote->acc_jiffies + timeout))
+ return accel[i].value;
+ }
+ return accel[i].value;
}
/*
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c
index b36e51576f8e..e0c531fa01da 100644
--- a/drivers/media/rc/igorplugusb.c
+++ b/drivers/media/rc/igorplugusb.c
@@ -152,7 +152,7 @@ static int igorplugusb_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep;
struct igorplugusb *ir;
struct rc_dev *rc;
- int ret;
+ int ret = -ENOMEM;
udev = interface_to_usbdev(intf);
idesc = intf->cur_altsetting;
@@ -182,7 +182,7 @@ static int igorplugusb_probe(struct usb_interface *intf,
ir->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ir->urb)
- return -ENOMEM;
+ goto fail;
usb_fill_control_urb(ir->urb, udev,
usb_rcvctrlpipe(udev, 0), (uint8_t *)&ir->request,
@@ -191,6 +191,9 @@ static int igorplugusb_probe(struct usb_interface *intf,
usb_make_path(udev, ir->phys, sizeof(ir->phys));
rc = rc_allocate_device();
+ if (!rc)
+ goto fail;
+
rc->input_name = DRIVER_DESC;
rc->input_phys = ir->phys;
usb_to_input_id(udev, &rc->input_id);
@@ -214,9 +217,7 @@ static int igorplugusb_probe(struct usb_interface *intf,
ret = rc_register_device(rc);
if (ret) {
dev_err(&intf->dev, "failed to register rc device: %d", ret);
- rc_free_device(rc);
- usb_free_urb(ir->urb);
- return ret;
+ goto fail;
}
usb_set_intfdata(intf, ir);
@@ -224,6 +225,12 @@ static int igorplugusb_probe(struct usb_interface *intf,
igorplugusb_cmd(ir, SET_INFRABUFFER_EMPTY);
return 0;
+fail:
+ rc_free_device(ir->rc);
+ usb_free_urb(ir->urb);
+ del_timer(&ir->timer);
+
+ return ret;
}
static void igorplugusb_disconnect(struct usb_interface *intf)
diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
index 8344bcc595be..2583400ca1b4 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
@@ -23,35 +23,35 @@
/* Initial keytable is from Jose Alberto Reguero <jareguero@telefonica.net>
and Felipe Morales Moreno <felipe.morales.moreno@gmail.com> */
-/* FIXME: mappings are not 100% correct? */
+/* Keytable fixed by Philippe Valembois <lephilousophe@users.sourceforge.net> */
static struct rc_map_table avermedia_rm_ks[] = {
- { 0x0501, KEY_POWER2 },
- { 0x0502, KEY_CHANNELUP },
- { 0x0503, KEY_CHANNELDOWN },
- { 0x0504, KEY_VOLUMEUP },
- { 0x0505, KEY_VOLUMEDOWN },
- { 0x0506, KEY_MUTE },
- { 0x0507, KEY_RIGHT },
- { 0x0508, KEY_RED },
- { 0x0509, KEY_1 },
- { 0x050a, KEY_2 },
- { 0x050b, KEY_3 },
- { 0x050c, KEY_4 },
- { 0x050d, KEY_5 },
- { 0x050e, KEY_6 },
- { 0x050f, KEY_7 },
- { 0x0510, KEY_8 },
- { 0x0511, KEY_9 },
- { 0x0512, KEY_0 },
- { 0x0513, KEY_AUDIO },
- { 0x0515, KEY_EPG },
- { 0x0516, KEY_PLAY },
- { 0x0517, KEY_RECORD },
- { 0x0518, KEY_STOP },
- { 0x051c, KEY_BACK },
- { 0x051d, KEY_FORWARD },
- { 0x054d, KEY_LEFT },
- { 0x0556, KEY_ZOOM },
+ { 0x0501, KEY_POWER2 }, /* Power (RED POWER BUTTON) */
+ { 0x0502, KEY_CHANNELUP }, /* Channel+ */
+ { 0x0503, KEY_CHANNELDOWN }, /* Channel- */
+ { 0x0504, KEY_VOLUMEUP }, /* Volume+ */
+ { 0x0505, KEY_VOLUMEDOWN }, /* Volume- */
+ { 0x0506, KEY_MUTE }, /* Mute */
+ { 0x0507, KEY_AGAIN }, /* Recall */
+ { 0x0508, KEY_VIDEO }, /* Source */
+ { 0x0509, KEY_1 }, /* 1 */
+ { 0x050a, KEY_2 }, /* 2 */
+ { 0x050b, KEY_3 }, /* 3 */
+ { 0x050c, KEY_4 }, /* 4 */
+ { 0x050d, KEY_5 }, /* 5 */
+ { 0x050e, KEY_6 }, /* 6 */
+ { 0x050f, KEY_7 }, /* 7 */
+ { 0x0510, KEY_8 }, /* 8 */
+ { 0x0511, KEY_9 }, /* 9 */
+ { 0x0512, KEY_0 }, /* 0 */
+ { 0x0513, KEY_AUDIO }, /* Audio */
+ { 0x0515, KEY_EPG }, /* EPG */
+ { 0x0516, KEY_PLAYPAUSE }, /* Play/Pause */
+ { 0x0517, KEY_RECORD }, /* Record */
+ { 0x0518, KEY_STOP }, /* Stop */
+ { 0x051c, KEY_BACK }, /* << */
+ { 0x051d, KEY_FORWARD }, /* >> */
+ { 0x054d, KEY_INFO }, /* Display information */
+ { 0x0556, KEY_ZOOM }, /* Fullscreen */
};
static struct rc_map_list avermedia_rm_ks_map = {
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 4de0e85af805..92ae1903c010 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -506,6 +506,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
{
struct irctl *ir = irctls[iminor(inode)];
struct cdev *cdev;
+ int ret;
if (!ir) {
printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
@@ -516,7 +517,8 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
- WARN_ON(mutex_lock_killable(&lirc_dev_lock));
+ ret = mutex_lock_killable(&lirc_dev_lock);
+ WARN_ON(ret);
rc_close(ir->d.rdev);
@@ -532,7 +534,8 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
kfree(ir);
}
- mutex_unlock(&lirc_dev_lock);
+ if (!ret)
+ mutex_unlock(&lirc_dev_lock);
return 0;
}
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 2cdb740cde48..35155ae500c7 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -587,9 +587,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
if (len == 2)
dev_dbg(dev, "Get hw/sw rev?");
else
- dev_dbg(dev, "hw/sw rev 0x%02x 0x%02x 0x%02x 0x%02x",
- data1, data2,
- buf[start + 4], buf[start + 5]);
+ dev_dbg(dev, "hw/sw rev %*ph",
+ 4, &buf[start + 2]);
break;
case MCE_CMD_RESUME:
dev_dbg(dev, "Device resume requested");
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 18adf580f502..99b303b702ac 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -39,6 +39,8 @@
#include "nuvoton-cir.h"
+static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt);
+
static const struct nvt_chip nvt_chips[] = {
{ "w83667hg", NVT_W83667HG },
{ "NCT6775F", NVT_6775F },
@@ -80,17 +82,24 @@ static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg)
}
/* enter extended function mode */
-static inline void nvt_efm_enable(struct nvt_dev *nvt)
+static inline int nvt_efm_enable(struct nvt_dev *nvt)
{
+ if (!request_muxed_region(nvt->cr_efir, 2, NVT_DRIVER_NAME))
+ return -EBUSY;
+
/* Enabling Extended Function Mode explicitly requires writing 2x */
outb(EFER_EFM_ENABLE, nvt->cr_efir);
outb(EFER_EFM_ENABLE, nvt->cr_efir);
+
+ return 0;
}
/* exit extended function mode */
static inline void nvt_efm_disable(struct nvt_dev *nvt)
{
outb(EFER_EFM_DISABLE, nvt->cr_efir);
+
+ release_region(nvt->cr_efir, 2);
}
/*
@@ -100,8 +109,25 @@ static inline void nvt_efm_disable(struct nvt_dev *nvt)
*/
static inline void nvt_select_logical_dev(struct nvt_dev *nvt, u8 ldev)
{
- outb(CR_LOGICAL_DEV_SEL, nvt->cr_efir);
- outb(ldev, nvt->cr_efdr);
+ nvt_cr_write(nvt, ldev, CR_LOGICAL_DEV_SEL);
+}
+
+/* select and enable logical device with setting EFM mode*/
+static inline void nvt_enable_logical_dev(struct nvt_dev *nvt, u8 ldev)
+{
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, ldev);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+ nvt_efm_disable(nvt);
+}
+
+/* select and disable logical device with setting EFM mode*/
+static inline void nvt_disable_logical_dev(struct nvt_dev *nvt, u8 ldev)
+{
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, ldev);
+ nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
+ nvt_efm_disable(nvt);
}
/* write val to cir config register */
@@ -137,6 +163,120 @@ static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset)
return val;
}
+/* don't override io address if one is set already */
+static void nvt_set_ioaddr(struct nvt_dev *nvt, unsigned long *ioaddr)
+{
+ unsigned long old_addr;
+
+ old_addr = nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8;
+ old_addr |= nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO);
+
+ if (old_addr)
+ *ioaddr = old_addr;
+ else {
+ nvt_cr_write(nvt, *ioaddr >> 8, CR_CIR_BASE_ADDR_HI);
+ nvt_cr_write(nvt, *ioaddr & 0xff, CR_CIR_BASE_ADDR_LO);
+ }
+}
+
+static ssize_t wakeup_data_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rc_dev *rc_dev = to_rc_dev(dev);
+ struct nvt_dev *nvt = rc_dev->priv;
+ int fifo_len, duration;
+ unsigned long flags;
+ ssize_t buf_len = 0;
+ int i;
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+ fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT);
+ fifo_len = min(fifo_len, WAKEUP_MAX_SIZE);
+
+ /* go to first element to be read */
+ while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX))
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY);
+
+ for (i = 0; i < fifo_len; i++) {
+ duration = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY);
+ duration = (duration & BUF_LEN_MASK) * SAMPLE_PERIOD;
+ buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len,
+ "%d ", duration);
+ }
+ buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n");
+
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ return buf_len;
+}
+
+static ssize_t wakeup_data_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct rc_dev *rc_dev = to_rc_dev(dev);
+ struct nvt_dev *nvt = rc_dev->priv;
+ unsigned long flags;
+ u8 tolerance, config, wake_buf[WAKEUP_MAX_SIZE];
+ char **argv;
+ int i, count;
+ unsigned int val;
+ ssize_t ret;
+
+ argv = argv_split(GFP_KERNEL, buf, &count);
+ if (!argv)
+ return -ENOMEM;
+ if (!count || count > WAKEUP_MAX_SIZE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ ret = kstrtouint(argv[i], 10, &val);
+ if (ret)
+ goto out;
+ val = DIV_ROUND_CLOSEST(val, SAMPLE_PERIOD);
+ if (!val || val > 0x7f) {
+ ret = -EINVAL;
+ goto out;
+ }
+ wake_buf[i] = val;
+ /* sequence must start with a pulse */
+ if (i % 2 == 0)
+ wake_buf[i] |= BUF_PULSE_BIT;
+ }
+
+ /* hardcode the tolerance to 10% */
+ tolerance = DIV_ROUND_UP(count, 10);
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+ nvt_clear_cir_wake_fifo(nvt);
+ nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP);
+ nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL);
+
+ config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
+
+ /* enable writes to wake fifo */
+ nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1,
+ CIR_WAKE_IRCON);
+
+ for (i = 0; i < count; i++)
+ nvt_cir_wake_reg_write(nvt, wake_buf[i], CIR_WAKE_WR_FIFO_DATA);
+
+ nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON);
+
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ ret = len;
+out:
+ argv_free(argv);
+ return ret;
+}
+static DEVICE_ATTR_RW(wakeup_data);
+
/* dump current cir register contents */
static void cir_dump_regs(struct nvt_dev *nvt)
{
@@ -251,7 +391,7 @@ static inline const char *nvt_find_chip(struct nvt_dev *nvt, int id)
/* detect hardware features */
-static void nvt_hw_detect(struct nvt_dev *nvt)
+static int nvt_hw_detect(struct nvt_dev *nvt)
{
const char *chip_name;
int chip_id;
@@ -266,10 +406,17 @@ static void nvt_hw_detect(struct nvt_dev *nvt)
nvt_efm_enable(nvt);
nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
}
-
nvt->chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
+ nvt_efm_disable(nvt);
+
chip_id = nvt->chip_major << 8 | nvt->chip_minor;
+ if (chip_id == NVT_INVALID) {
+ dev_err(&nvt->pdev->dev,
+ "No device found on either EFM port\n");
+ return -ENODEV;
+ }
+
chip_name = nvt_find_chip(nvt, chip_id);
/* warn, but still let the driver load, if we don't know this chip */
@@ -282,7 +429,7 @@ static void nvt_hw_detect(struct nvt_dev *nvt)
"found %s or compatible: chip id: 0x%02x 0x%02x",
chip_name, nvt->chip_major, nvt->chip_minor);
- nvt_efm_disable(nvt);
+ return 0;
}
static void nvt_cir_ldev_init(struct nvt_dev *nvt)
@@ -305,12 +452,10 @@ static void nvt_cir_ldev_init(struct nvt_dev *nvt)
val |= psval;
nvt_cr_write(nvt, val, psreg);
- /* Select CIR logical device and enable */
+ /* Select CIR logical device */
nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
- nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
- nvt_cr_write(nvt, nvt->cir_addr >> 8, CR_CIR_BASE_ADDR_HI);
- nvt_cr_write(nvt, nvt->cir_addr & 0xff, CR_CIR_BASE_ADDR_LO);
+ nvt_set_ioaddr(nvt, &nvt->cir_addr);
nvt_cr_write(nvt, nvt->cir_irq, CR_CIR_IRQ_RSRC);
@@ -320,7 +465,7 @@ static void nvt_cir_ldev_init(struct nvt_dev *nvt)
static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt)
{
- /* Select ACPI logical device, enable it and CIR Wake */
+ /* Select ACPI logical device and anable it */
nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
@@ -330,12 +475,10 @@ static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt)
/* enable pme interrupt of cir wakeup event */
nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
- /* Select CIR Wake logical device and enable */
+ /* Select CIR Wake logical device */
nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
- nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
- nvt_cr_write(nvt, nvt->cir_wake_addr >> 8, CR_CIR_BASE_ADDR_HI);
- nvt_cr_write(nvt, nvt->cir_wake_addr & 0xff, CR_CIR_BASE_ADDR_LO);
+ nvt_set_ioaddr(nvt, &nvt->cir_wake_addr);
nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC);
@@ -355,11 +498,19 @@ static void nvt_clear_cir_fifo(struct nvt_dev *nvt)
/* clear out the hardware's cir wake rx fifo */
static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt)
{
- u8 val;
+ u8 val, config;
+
+ config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
+
+ /* clearing wake fifo works in learning mode only */
+ nvt_cir_wake_reg_write(nvt, config & ~CIR_WAKE_IRCON_MODE0,
+ CIR_WAKE_IRCON);
val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON);
nvt_cir_wake_reg_write(nvt, val | CIR_WAKE_FIFOCON_RXFIFOCLR,
CIR_WAKE_FIFOCON);
+
+ nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON);
}
/* clear out the hardware's cir tx fifo */
@@ -408,6 +559,9 @@ static void nvt_cir_regs_init(struct nvt_dev *nvt)
/* and finally, enable interrupts */
nvt_set_cir_iren(nvt);
+
+ /* enable the CIR logical device */
+ nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR);
}
static void nvt_cir_wake_regs_init(struct nvt_dev *nvt)
@@ -442,10 +596,15 @@ static void nvt_cir_wake_regs_init(struct nvt_dev *nvt)
/* clear any and all stray interrupts */
nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
+
+ /* enable the CIR WAKE logical device */
+ nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
}
static void nvt_enable_wake(struct nvt_dev *nvt)
{
+ unsigned long flags;
+
nvt_efm_enable(nvt);
nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
@@ -457,12 +616,16 @@ static void nvt_enable_wake(struct nvt_dev *nvt)
nvt_efm_disable(nvt);
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
CIR_WAKE_IRCON);
nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
+
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
}
#if 0 /* Currently unused */
@@ -670,7 +833,6 @@ static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt)
/* copy data from hardware rx fifo into driver buffer */
static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
{
- unsigned long flags;
u8 fifocount, val;
unsigned int b_idx;
bool overrun = false;
@@ -689,8 +851,6 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount);
- spin_lock_irqsave(&nvt->nvt_lock, flags);
-
b_idx = nvt->pkts;
/* This should never happen, but lets check anyway... */
@@ -712,8 +872,6 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
if (overrun)
nvt_handle_rx_fifo_overrun(nvt);
-
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
}
static void nvt_cir_log_irqs(u8 status, u8 iren)
@@ -736,16 +894,13 @@ static void nvt_cir_log_irqs(u8 status, u8 iren)
static bool nvt_cir_tx_inactive(struct nvt_dev *nvt)
{
unsigned long flags;
- bool tx_inactive;
u8 tx_state;
spin_lock_irqsave(&nvt->tx.lock, flags);
tx_state = nvt->tx.tx_state;
spin_unlock_irqrestore(&nvt->tx.lock, flags);
- tx_inactive = (tx_state == ST_TX_NONE);
-
- return tx_inactive;
+ return tx_state == ST_TX_NONE;
}
/* interrupt service routine for incoming and outgoing CIR data */
@@ -757,9 +912,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
nvt_dbg_verbose("%s firing", __func__);
- nvt_efm_enable(nvt);
- nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
- nvt_efm_disable(nvt);
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
/*
* Get IR Status register contents. Write 1 to ack/clear
@@ -775,9 +928,14 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
* 0: CIR_IRSTS_GH - Min Length Detected
*/
status = nvt_cir_reg_read(nvt, CIR_IRSTS);
- if (!status) {
+ iren = nvt_cir_reg_read(nvt, CIR_IREN);
+
+ /* IRQ may be shared with CIR WAKE, therefore check for each
+ * status bit whether the related interrupt source is enabled
+ */
+ if (!(status & iren)) {
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__);
- nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
return IRQ_NONE;
}
@@ -785,13 +943,6 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
nvt_cir_reg_write(nvt, status, CIR_IRSTS);
nvt_cir_reg_write(nvt, 0, CIR_IRSTS);
- /* Interrupt may be shared with CIR Wake, bail if CIR not enabled */
- iren = nvt_cir_reg_read(nvt, CIR_IREN);
- if (!iren) {
- nvt_dbg_verbose("%s exiting, CIR not enabled", __func__);
- return IRQ_NONE;
- }
-
nvt_cir_log_irqs(status, iren);
if (status & CIR_IRSTS_RTR) {
@@ -805,16 +956,14 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
if (nvt_cir_tx_inactive(nvt))
nvt_get_rx_ir_data(nvt);
- spin_lock_irqsave(&nvt->nvt_lock, flags);
-
cur_state = nvt->study_state;
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
-
if (cur_state == ST_STUDY_NONE)
nvt_clear_cir_fifo(nvt);
}
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
if (status & CIR_IRSTS_TE)
nvt_clear_tx_fifo(nvt);
@@ -863,9 +1012,18 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
nvt_dbg_wake("%s firing", __func__);
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS);
- if (!status)
+ iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
+
+ /* IRQ may be shared with CIR, therefore check for each
+ * status bit whether the related interrupt source is enabled
+ */
+ if (!(status & iren)) {
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
return IRQ_NONE;
+ }
if (status & CIR_WAKE_IRSTS_IR_PENDING)
nvt_clear_cir_wake_fifo(nvt);
@@ -873,13 +1031,6 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS);
nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS);
- /* Interrupt may be shared with CIR, bail if Wake not enabled */
- iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
- if (!iren) {
- nvt_dbg_wake("%s exiting, wake not enabled", __func__);
- return IRQ_HANDLED;
- }
-
if ((status & CIR_WAKE_IRSTS_PE) &&
(nvt->wake_state == ST_WAKE_START)) {
while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) {
@@ -888,39 +1039,21 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
}
nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
- spin_lock_irqsave(&nvt->nvt_lock, flags);
nvt->wake_state = ST_WAKE_FINISH;
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
}
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
nvt_dbg_wake("%s done", __func__);
return IRQ_HANDLED;
}
-static void nvt_enable_cir(struct nvt_dev *nvt)
+static void nvt_disable_cir(struct nvt_dev *nvt)
{
- /* set function enable flags */
- nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN |
- CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
- CIR_IRCON);
-
- nvt_efm_enable(nvt);
-
- /* enable the CIR logical device */
- nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
- nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
-
- nvt_efm_disable(nvt);
-
- /* clear all pending interrupts */
- nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+ unsigned long flags;
- /* enable interrupts */
- nvt_set_cir_iren(nvt);
-}
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
-static void nvt_disable_cir(struct nvt_dev *nvt)
-{
/* disable CIR interrupts */
nvt_cir_reg_write(nvt, 0, CIR_IREN);
@@ -934,13 +1067,10 @@ static void nvt_disable_cir(struct nvt_dev *nvt)
nvt_clear_cir_fifo(nvt);
nvt_clear_tx_fifo(nvt);
- nvt_efm_enable(nvt);
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
/* disable the CIR logical device */
- nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
- nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
-
- nvt_efm_disable(nvt);
+ nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR);
}
static int nvt_open(struct rc_dev *dev)
@@ -949,20 +1079,31 @@ static int nvt_open(struct rc_dev *dev)
unsigned long flags;
spin_lock_irqsave(&nvt->nvt_lock, flags);
- nvt_enable_cir(nvt);
+
+ /* set function enable flags */
+ nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN |
+ CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
+ CIR_IRCON);
+
+ /* clear all pending interrupts */
+ nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+ /* enable interrupts */
+ nvt_set_cir_iren(nvt);
+
spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+ /* enable the CIR logical device */
+ nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR);
+
return 0;
}
static void nvt_close(struct rc_dev *dev)
{
struct nvt_dev *nvt = dev->priv;
- unsigned long flags;
- spin_lock_irqsave(&nvt->nvt_lock, flags);
nvt_disable_cir(nvt);
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
}
/* Allocate memory, probe hardware, and initialize everything */
@@ -1024,7 +1165,9 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
init_waitqueue_head(&nvt->tx.queue);
- nvt_hw_detect(nvt);
+ ret = nvt_hw_detect(nvt);
+ if (ret)
+ goto exit_free_dev_rdev;
/* Initialize CIR & CIR Wake Logical Devices */
nvt_efm_enable(nvt);
@@ -1032,7 +1175,10 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
nvt_cir_wake_ldev_init(nvt);
nvt_efm_disable(nvt);
- /* Initialize CIR & CIR Wake Config Registers */
+ /*
+ * Initialize CIR & CIR Wake Config Registers
+ * and enable logical devices
+ */
nvt_cir_regs_init(nvt);
nvt_cir_wake_regs_init(nvt);
@@ -1079,12 +1225,16 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
goto exit_unregister_device;
if (!devm_request_region(&pdev->dev, nvt->cir_wake_addr,
- CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
+ CIR_IOREG_LENGTH, NVT_DRIVER_NAME "-wake"))
goto exit_unregister_device;
if (devm_request_irq(&pdev->dev, nvt->cir_wake_irq,
nvt_cir_wake_isr, IRQF_SHARED,
- NVT_DRIVER_NAME, (void *)nvt))
+ NVT_DRIVER_NAME "-wake", (void *)nvt))
+ goto exit_unregister_device;
+
+ ret = device_create_file(&rdev->dev, &dev_attr_wakeup_data);
+ if (ret)
goto exit_unregister_device;
device_init_wakeup(&pdev->dev, true);
@@ -1109,15 +1259,13 @@ exit_free_dev_rdev:
static void nvt_remove(struct pnp_dev *pdev)
{
struct nvt_dev *nvt = pnp_get_drvdata(pdev);
- unsigned long flags;
- spin_lock_irqsave(&nvt->nvt_lock, flags);
- /* disable CIR */
- nvt_cir_reg_write(nvt, 0, CIR_IREN);
+ device_remove_file(&nvt->rdev->dev, &dev_attr_wakeup_data);
+
nvt_disable_cir(nvt);
+
/* enable CIR Wake (for IR power-on) */
nvt_enable_wake(nvt);
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
rc_unregister_device(nvt->rdev);
}
@@ -1129,26 +1277,23 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
nvt_dbg("%s called", __func__);
- /* zero out misc state tracking */
- spin_lock_irqsave(&nvt->nvt_lock, flags);
- nvt->study_state = ST_STUDY_NONE;
- nvt->wake_state = ST_WAKE_NONE;
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
-
spin_lock_irqsave(&nvt->tx.lock, flags);
nvt->tx.tx_state = ST_TX_NONE;
spin_unlock_irqrestore(&nvt->tx.lock, flags);
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+ /* zero out misc state tracking */
+ nvt->study_state = ST_STUDY_NONE;
+ nvt->wake_state = ST_WAKE_NONE;
+
/* disable all CIR interrupts */
nvt_cir_reg_write(nvt, 0, CIR_IREN);
- nvt_efm_enable(nvt);
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
/* disable cir logical dev */
- nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
- nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
-
- nvt_efm_disable(nvt);
+ nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR);
/* make sure wake is enabled */
nvt_enable_wake(nvt);
@@ -1162,16 +1307,6 @@ static int nvt_resume(struct pnp_dev *pdev)
nvt_dbg("%s called", __func__);
- /* open interrupt */
- nvt_set_cir_iren(nvt);
-
- /* Enable CIR logical device */
- nvt_efm_enable(nvt);
- nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
- nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
-
- nvt_efm_disable(nvt);
-
nvt_cir_regs_init(nvt);
nvt_cir_wake_regs_init(nvt);
@@ -1181,6 +1316,7 @@ static int nvt_resume(struct pnp_dev *pdev)
static void nvt_shutdown(struct pnp_dev *pdev)
{
struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+
nvt_enable_wake(nvt);
}
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 0ad15d34e9c9..c9c98ebb19ee 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -68,7 +68,8 @@ enum nvt_chip_ver {
NVT_W83667HG = 0xa510,
NVT_6775F = 0xb470,
NVT_6776F = 0xc330,
- NVT_6779D = 0xc560
+ NVT_6779D = 0xc560,
+ NVT_INVALID = 0xffff,
};
struct nvt_chip {
@@ -157,8 +158,8 @@ struct nvt_dev {
/* total length of CIR and CIR WAKE */
#define CIR_IOREG_LENGTH 0x0f
-/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL (0x7d0 = 2000) */
-#define CIR_RX_LIMIT_COUNT 0x7d0
+/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL */
+#define CIR_RX_LIMIT_COUNT (IR_DEFAULT_TIMEOUT / US_TO_NS(SAMPLE_PERIOD))
/* CIR Regs */
#define CIR_IRCON 0x00
@@ -292,10 +293,7 @@ struct nvt_dev {
#define CIR_WAKE_IREN_RTR 0x40
#define CIR_WAKE_IREN_PE 0x20
#define CIR_WAKE_IREN_RFO 0x10
-#define CIR_WAKE_IREN_TE 0x08
-#define CIR_WAKE_IREN_TTR 0x04
-#define CIR_WAKE_IREN_TFU 0x02
-#define CIR_WAKE_IREN_GH 0x01
+#define CIR_WAKE_IREN_GH 0x08
/* CIR WAKE FIFOCON settings */
#define CIR_WAKE_FIFOCON_RXFIFOCLR 0x08
@@ -419,3 +417,6 @@ struct nvt_dev {
/* as VISTA MCE definition, valid carrier value */
#define MAX_CARRIER 60000
#define MIN_CARRIER 30000
+
+/* max wakeup sequence length */
+#define WAKEUP_MAX_SIZE 65
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 7359f3d03b64..585d5e52118d 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -16,6 +16,9 @@
#ifndef _RC_CORE_PRIV
#define _RC_CORE_PRIV
+/* Define the max number of pulse/space transitions to buffer */
+#define MAX_IR_EVENT_SIZE 512
+
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <media/rc-core.h>
@@ -35,7 +38,8 @@ struct ir_raw_event_ctrl {
struct list_head list; /* to keep track of raw clients */
struct task_struct *thread;
spinlock_t lock;
- struct kfifo_rec_ptr_1 kfifo; /* fifo for the pulse/space durations */
+ /* fifo for the pulse/space durations */
+ DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE);
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
struct rc_dev *dev; /* pointer to the parent rc_dev */
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index c69807fe2fef..144304c94606 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -20,9 +20,6 @@
#include <linux/freezer.h>
#include "rc-core-priv.h"
-/* Define the max number of pulse/space transitions to buffer */
-#define MAX_IR_EVENT_SIZE 512
-
/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
static LIST_HEAD(ir_raw_client_list);
@@ -36,14 +33,12 @@ static int ir_raw_event_thread(void *data)
struct ir_raw_event ev;
struct ir_raw_handler *handler;
struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
- int retval;
while (!kthread_should_stop()) {
spin_lock_irq(&raw->lock);
- retval = kfifo_len(&raw->kfifo);
- if (retval < sizeof(ev)) {
+ if (!kfifo_len(&raw->kfifo)) {
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
@@ -54,7 +49,8 @@ static int ir_raw_event_thread(void *data)
continue;
}
- retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
+ if(!kfifo_out(&raw->kfifo, &ev, 1))
+ dev_err(&raw->dev->dev, "IR event FIFO is empty!\n");
spin_unlock_irq(&raw->lock);
mutex_lock(&ir_raw_handler_lock);
@@ -87,8 +83,10 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
IR_dprintk(2, "sample: (%05dus %s)\n",
TO_US(ev->duration), TO_STR(ev->pulse));
- if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
- return -ENOMEM;
+ if (!kfifo_put(&dev->raw->kfifo, *ev)) {
+ dev_err(&dev->dev, "IR event FIFO is full!\n");
+ return -ENOSPC;
+ }
return 0;
}
@@ -273,11 +271,7 @@ int ir_raw_event_register(struct rc_dev *dev)
dev->raw->dev = dev;
dev->change_protocol = change_protocol;
- rc = kfifo_alloc(&dev->raw->kfifo,
- sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
- GFP_KERNEL);
- if (rc < 0)
- goto out;
+ INIT_KFIFO(dev->raw->kfifo);
spin_lock_init(&dev->raw->lock);
dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
@@ -319,7 +313,6 @@ void ir_raw_event_unregister(struct rc_dev *dev)
handler->raw_unregister(dev);
mutex_unlock(&ir_raw_handler_lock);
- kfifo_free(&dev->raw->kfifo);
kfree(dev->raw);
dev->raw = NULL;
}
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 1042fa331a07..4e9bbe735ae9 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -13,6 +13,7 @@
*/
#include <media/rc-core.h>
+#include <linux/atomic.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/input.h>
@@ -723,6 +724,7 @@ int rc_open(struct rc_dev *rdev)
return -EINVAL;
mutex_lock(&rdev->lock);
+
if (!rdev->users++ && rdev->open != NULL)
rval = rdev->open(rdev);
@@ -873,6 +875,9 @@ static ssize_t show_protocols(struct device *device,
if (!dev)
return -EINVAL;
+ if (!atomic_read(&dev->initialized))
+ return -ERESTARTSYS;
+
mutex_lock(&dev->lock);
if (fattr->type == RC_FILTER_NORMAL) {
@@ -1054,6 +1059,9 @@ static ssize_t store_protocols(struct device *device,
if (!dev)
return -EINVAL;
+ if (!atomic_read(&dev->initialized))
+ return -ERESTARTSYS;
+
if (fattr->type == RC_FILTER_NORMAL) {
IR_dprintk(1, "Normal protocol change requested\n");
current_protocols = &dev->enabled_protocols;
@@ -1154,12 +1162,16 @@ static ssize_t show_filter(struct device *device,
if (!dev)
return -EINVAL;
+ if (!atomic_read(&dev->initialized))
+ return -ERESTARTSYS;
+
+ mutex_lock(&dev->lock);
+
if (fattr->type == RC_FILTER_NORMAL)
filter = &dev->scancode_filter;
else
filter = &dev->scancode_wakeup_filter;
- mutex_lock(&dev->lock);
if (fattr->mask)
val = filter->mask;
else
@@ -1204,6 +1216,9 @@ static ssize_t store_filter(struct device *device,
if (!dev)
return -EINVAL;
+ if (!atomic_read(&dev->initialized))
+ return -ERESTARTSYS;
+
ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
@@ -1408,6 +1423,7 @@ int rc_register_device(struct rc_dev *dev)
dev->minor = minor;
dev_set_name(&dev->dev, "rc%u", dev->minor);
dev_set_drvdata(&dev->dev, dev);
+ atomic_set(&dev->initialized, 0);
dev->dev.groups = dev->sysfs_groups;
dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
@@ -1419,14 +1435,6 @@ int rc_register_device(struct rc_dev *dev)
dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp;
dev->sysfs_groups[attr++] = NULL;
- /*
- * Take the lock here, as the device sysfs node will appear
- * when device_add() is called, which may trigger an ir-keytable udev
- * rule, which will in turn call show_protocols and access
- * dev->enabled_protocols before it has been initialized.
- */
- mutex_lock(&dev->lock);
-
rc = device_add(&dev->dev);
if (rc)
goto out_unlock;
@@ -1440,16 +1448,6 @@ int rc_register_device(struct rc_dev *dev)
dev->input_dev->phys = dev->input_phys;
dev->input_dev->name = dev->input_name;
- /* input_register_device can call ir_open, so unlock mutex here */
- mutex_unlock(&dev->lock);
-
- rc = input_register_device(dev->input_dev);
-
- mutex_lock(&dev->lock);
-
- if (rc)
- goto out_table;
-
/*
* Default delay of 250ms is too short for some protocols, especially
* since the timeout is currently set to 250ms. Increase it to 500ms,
@@ -1465,6 +1463,11 @@ int rc_register_device(struct rc_dev *dev)
*/
dev->input_dev->rep[REP_PERIOD] = 125;
+ /* rc_open will be called here */
+ rc = input_register_device(dev->input_dev);
+ if (rc)
+ goto out_table;
+
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
dev_info(&dev->dev, "%s as %s\n",
dev->input_name ?: "Unspecified device", path ?: "N/A");
@@ -1475,10 +1478,7 @@ int rc_register_device(struct rc_dev *dev)
request_module_nowait("ir-lirc-codec");
raw_init = true;
}
- /* calls ir_register_device so unlock mutex here*/
- mutex_unlock(&dev->lock);
rc = ir_raw_event_register(dev);
- mutex_lock(&dev->lock);
if (rc < 0)
goto out_input;
}
@@ -1491,6 +1491,9 @@ int rc_register_device(struct rc_dev *dev)
dev->enabled_protocols = rc_type;
}
+ /* Allow the RC sysfs nodes to be accessible */
+ mutex_lock(&dev->lock);
+ atomic_set(&dev->initialized, 1);
mutex_unlock(&dev->lock);
IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
@@ -1512,7 +1515,6 @@ out_table:
out_dev:
device_del(&dev->dev);
out_unlock:
- mutex_unlock(&dev->lock);
ida_simple_remove(&rc_ida, minor);
return rc;
}
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index 40f77685cc4a..eaadc081760a 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -326,6 +326,7 @@ static const struct of_device_id sunxi_ir_match[] = {
{ .compatible = "allwinner,sun5i-a13-ir", },
{},
};
+MODULE_DEVICE_TABLE(of, sunxi_ir_match);
static struct platform_driver sunxi_ir_driver = {
.probe = sunxi_ir_probe,
diff --git a/drivers/media/tuners/m88rs6000t.c b/drivers/media/tuners/m88rs6000t.c
index 504bfbc4027a..9f3e0fd4cad9 100644
--- a/drivers/media/tuners/m88rs6000t.c
+++ b/drivers/media/tuners/m88rs6000t.c
@@ -461,13 +461,12 @@ static int m88rs6000t_sleep(struct dvb_frontend *fe)
dev_dbg(&dev->client->dev, "%s:\n", __func__);
ret = regmap_write(dev->regmap, 0x07, 0x6d);
- if (ret)
- goto err;
- usleep_range(5000, 10000);
-err:
- if (ret)
+ if (ret) {
dev_dbg(&dev->client->dev, "failed=%d\n", ret);
- return ret;
+ return ret;
+ }
+ usleep_range(5000, 10000);
+ return 0;
}
static int m88rs6000t_get_frequency(struct dvb_frontend *fe, u32 *frequency)
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
index a7a8452e99d2..6ab35e315fe7 100644
--- a/drivers/media/tuners/r820t.c
+++ b/drivers/media/tuners/r820t.c
@@ -1295,7 +1295,7 @@ static int generic_set_freq(struct dvb_frontend *fe,
v4l2_std_id std, u32 delsys)
{
struct r820t_priv *priv = fe->tuner_priv;
- int rc = -EINVAL;
+ int rc;
u32 lo_freq;
tuner_dbg("should set frequency to %d kHz, bw %d MHz\n",
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index 0e1ca2b00e61..243ac3816028 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -364,8 +364,8 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
static const struct dvb_tuner_ops si2157_ops = {
.info = {
.name = "Silicon Labs Si2146/2147/2148/2157/2158",
- .frequency_min = 55000000,
- .frequency_max = 862000000,
+ .frequency_min = 42000000,
+ .frequency_max = 870000000,
},
.init = si2157_init,
@@ -403,7 +403,7 @@ err:
}
static int si2157_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct si2157_config *cfg = client->dev.platform_data;
struct dvb_frontend *fe = cfg->fe;
@@ -438,6 +438,31 @@ static int si2157_probe(struct i2c_client *client,
memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
fe->tuner_priv = client;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (cfg->mdev) {
+ dev->mdev = cfg->mdev;
+
+ dev->ent.name = KBUILD_MODNAME;
+ dev->ent.function = MEDIA_ENT_F_TUNER;
+
+ dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+ dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
+ &dev->pad[0]);
+
+ if (ret)
+ goto err_kfree;
+
+ ret = media_device_register_entity(cfg->mdev, &dev->ent);
+ if (ret) {
+ media_entity_cleanup(&dev->ent);
+ goto err_kfree;
+ }
+ }
+#endif
+
dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
"Si2146" : "Si2147/2148/2157/2158");
@@ -458,6 +483,14 @@ static int si2157_remove(struct i2c_client *client)
dev_dbg(&client->dev, "\n");
+ /* stop statistics polling */
+ cancel_delayed_work_sync(&dev->stat_work);
+
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (dev->mdev)
+ media_device_unregister_entity(&dev->ent);
+#endif
+
memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
fe->tuner_priv = NULL;
kfree(dev);
diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
index 4db97ab744d6..5f1a60bf7ced 100644
--- a/drivers/media/tuners/si2157.h
+++ b/drivers/media/tuners/si2157.h
@@ -18,6 +18,7 @@
#define SI2157_H
#include <linux/kconfig.h>
+#include <media/media-device.h>
#include "dvb_frontend.h"
/*
@@ -30,6 +31,10 @@ struct si2157_config {
*/
struct dvb_frontend *fe;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_device *mdev;
+#endif
+
/*
* Spectral Inversion
*/
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index ecc463db8f69..589d558d381c 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -18,6 +18,7 @@
#define SI2157_PRIV_H
#include <linux/firmware.h>
+#include <media/v4l2-mc.h>
#include "si2157.h"
/* state struct */
@@ -31,6 +32,13 @@ struct si2157_dev {
u8 if_port;
u32 if_frequency;
struct delayed_work stat_work;
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_device *mdev;
+ struct media_entity ent;
+ struct media_pad pad[TUNER_NUM_PADS];
+#endif
+
};
#define SI2157_CHIPTYPE_SI2157 0
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index 4e941f00b600..317ef63ee789 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -1403,11 +1403,14 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
* in order to avoid troubles during device release.
*/
kfree(priv->ctrl.fname);
+ priv->ctrl.fname = NULL;
memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
if (p->fname) {
priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
- if (priv->ctrl.fname == NULL)
+ if (priv->ctrl.fname == NULL) {
rc = -ENOMEM;
+ goto unlock;
+ }
}
/*
@@ -1439,6 +1442,7 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
} else
priv->state = XC2028_WAITING_FIRMWARE;
}
+unlock:
mutex_unlock(&priv->lock);
return rc;
diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c
index 219ebafae70f..d95c7e082ccf 100644
--- a/drivers/media/tuners/xc4000.c
+++ b/drivers/media/tuners/xc4000.c
@@ -1508,7 +1508,7 @@ static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength)
if (value >= 0x2000) {
value = 0;
} else {
- value = ~value << 3;
+ value = (~value << 3) & 0xffff;
}
goto ret;
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index 0d4ac5947f3a..87c12930416f 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -104,9 +104,8 @@ struct airspy_frame_buf {
};
struct airspy {
-#define POWER_ON (1 << 1)
-#define URB_BUF (1 << 2)
-#define USB_STATE_URB_BUF (1 << 3)
+#define POWER_ON 1
+#define USB_STATE_URB_BUF 2
unsigned long flags;
struct device *dev;
@@ -359,7 +358,7 @@ static int airspy_submit_urbs(struct airspy *s)
static int airspy_free_stream_bufs(struct airspy *s)
{
- if (s->flags & USB_STATE_URB_BUF) {
+ if (test_bit(USB_STATE_URB_BUF, &s->flags)) {
while (s->buf_num) {
s->buf_num--;
dev_dbg(s->dev, "free buf=%d\n", s->buf_num);
@@ -368,7 +367,7 @@ static int airspy_free_stream_bufs(struct airspy *s)
s->dma_addr[s->buf_num]);
}
}
- s->flags &= ~USB_STATE_URB_BUF;
+ clear_bit(USB_STATE_URB_BUF, &s->flags);
return 0;
}
@@ -394,7 +393,7 @@ static int airspy_alloc_stream_bufs(struct airspy *s)
dev_dbg(s->dev, "alloc buf=%d %p (dma %llu)\n", s->buf_num,
s->buf_list[s->buf_num],
(long long)s->dma_addr[s->buf_num]);
- s->flags |= USB_STATE_URB_BUF;
+ set_bit(USB_STATE_URB_BUF, &s->flags);
}
return 0;
diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h
index aee2d76e8dfc..8def19d9ab92 100644
--- a/drivers/media/usb/as102/as102_drv.h
+++ b/drivers/media/usb/as102/as102_drv.h
@@ -52,7 +52,7 @@ struct as10x_bus_adapter_t {
struct as10x_cmd_t *cmd, *rsp;
/* bus adapter private ops callback */
- struct as102_priv_ops_t *ops;
+ const struct as102_priv_ops_t *ops;
};
struct as102_dev_t {
diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c
index 3f669066ccf6..0e8030c071b8 100644
--- a/drivers/media/usb/as102/as102_usb_drv.c
+++ b/drivers/media/usb/as102/as102_usb_drv.c
@@ -189,7 +189,7 @@ static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap,
return actual_len;
}
-static struct as102_priv_ops_t as102_priv_ops = {
+static const struct as102_priv_ops_t as102_priv_ops = {
.upload_fw_pkt = as102_send_ep1,
.xfer_cmd = as102_usb_xfer_cmd,
.as102_read_ep2 = as102_read_ep2,
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 9e29e70a78d7..5dc82e8c8670 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -20,6 +20,7 @@
*/
#include "au0828.h"
+#include "au8522.h"
#include <linux/module.h>
#include <linux/slab.h>
@@ -134,16 +135,16 @@ static void au0828_unregister_media_device(struct au0828_dev *dev)
{
#ifdef CONFIG_MEDIA_CONTROLLER
- if (dev->media_dev) {
+ if (dev->media_dev &&
+ media_devnode_is_registered(&dev->media_dev->devnode)) {
media_device_unregister(dev->media_dev);
media_device_cleanup(dev->media_dev);
- kfree(dev->media_dev);
dev->media_dev = NULL;
}
#endif
}
-static void au0828_usb_release(struct au0828_dev *dev)
+void au0828_usb_release(struct au0828_dev *dev)
{
au0828_unregister_media_device(dev);
@@ -153,33 +154,6 @@ static void au0828_usb_release(struct au0828_dev *dev)
kfree(dev);
}
-#ifdef CONFIG_VIDEO_AU0828_V4L2
-
-static void au0828_usb_v4l2_media_release(struct au0828_dev *dev)
-{
-#ifdef CONFIG_MEDIA_CONTROLLER
- int i;
-
- for (i = 0; i < AU0828_MAX_INPUT; i++) {
- if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED)
- return;
- media_device_unregister_entity(&dev->input_ent[i]);
- }
-#endif
-}
-
-static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
-{
- struct au0828_dev *dev =
- container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
-
- v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
- v4l2_device_unregister(&dev->v4l2_dev);
- au0828_usb_v4l2_media_release(dev);
- au0828_usb_release(dev);
-}
-#endif
-
static void au0828_usb_disconnect(struct usb_interface *interface)
{
struct au0828_dev *dev = usb_get_intfdata(interface);
@@ -202,18 +176,13 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
mutex_lock(&dev->mutex);
dev->usbdev = NULL;
mutex_unlock(&dev->mutex);
-#ifdef CONFIG_VIDEO_AU0828_V4L2
- if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
- au0828_analog_unregister(dev);
- v4l2_device_disconnect(&dev->v4l2_dev);
- v4l2_device_put(&dev->v4l2_dev);
+ if (au0828_analog_unregister(dev)) {
/*
* No need to call au0828_usb_release() if V4L2 is enabled,
* as this is already called via au0828_usb_v4l2_release()
*/
return;
}
-#endif
au0828_usb_release(dev);
}
@@ -223,103 +192,334 @@ static int au0828_media_device_init(struct au0828_dev *dev,
#ifdef CONFIG_MEDIA_CONTROLLER
struct media_device *mdev;
- mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+ mdev = media_device_get_devres(&udev->dev);
if (!mdev)
return -ENOMEM;
- mdev->dev = &udev->dev;
-
- if (!dev->board.name)
- strlcpy(mdev->model, "unknown au0828", sizeof(mdev->model));
- else
- strlcpy(mdev->model, dev->board.name, sizeof(mdev->model));
- if (udev->serial)
- strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
- strcpy(mdev->bus_info, udev->devpath);
- mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
- mdev->driver_version = LINUX_VERSION_CODE;
-
- media_device_init(mdev);
+ /* check if media device is already initialized */
+ if (!mdev->dev)
+ media_device_usb_init(mdev, udev, udev->product);
dev->media_dev = mdev;
#endif
return 0;
}
+#ifdef CONFIG_MEDIA_CONTROLLER
+static void au0828_media_graph_notify(struct media_entity *new,
+ void *notify_data)
+{
+ struct au0828_dev *dev = (struct au0828_dev *) notify_data;
+ int ret;
+ struct media_entity *entity, *mixer = NULL, *decoder = NULL;
+
+ if (!new) {
+ /*
+ * Called during au0828 probe time to connect
+ * entites that were created prior to registering
+ * the notify handler. Find mixer and decoder.
+ */
+ media_device_for_each_entity(entity, dev->media_dev) {
+ if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
+ mixer = entity;
+ else if (entity->function == MEDIA_ENT_F_ATV_DECODER)
+ decoder = entity;
+ }
+ goto create_link;
+ }
+
+ switch (new->function) {
+ case MEDIA_ENT_F_AUDIO_MIXER:
+ mixer = new;
+ if (dev->decoder)
+ decoder = dev->decoder;
+ break;
+ case MEDIA_ENT_F_ATV_DECODER:
+ /* In case, Mixer is added first, find mixer and create link */
+ media_device_for_each_entity(entity, dev->media_dev) {
+ if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
+ mixer = entity;
+ }
+ decoder = new;
+ break;
+ default:
+ break;
+ }
+
+create_link:
+ if (decoder && mixer) {
+ ret = media_create_pad_link(decoder,
+ DEMOD_PAD_AUDIO_OUT,
+ mixer, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ dev_err(&dev->usbdev->dev,
+ "Mixer Pad Link Create Error: %d\n", ret);
+ }
+}
-static int au0828_create_media_graph(struct au0828_dev *dev)
+static int au0828_enable_source(struct media_entity *entity,
+ struct media_pipeline *pipe)
{
-#ifdef CONFIG_MEDIA_CONTROLLER
- struct media_device *mdev = dev->media_dev;
- struct media_entity *entity;
- struct media_entity *tuner = NULL, *decoder = NULL;
- int i, ret;
+ struct media_entity *source, *find_source;
+ struct media_entity *sink;
+ struct media_link *link, *found_link = NULL;
+ int ret = 0;
+ struct media_device *mdev = entity->graph_obj.mdev;
+ struct au0828_dev *dev;
if (!mdev)
- return 0;
+ return -ENODEV;
- media_device_for_each_entity(entity, mdev) {
- switch (entity->function) {
- case MEDIA_ENT_F_TUNER:
- tuner = entity;
- break;
- case MEDIA_ENT_F_ATV_DECODER:
- decoder = entity;
+ mutex_lock(&mdev->graph_mutex);
+
+ dev = mdev->source_priv;
+
+ /*
+ * For Audio and V4L2 entity, find the link to which decoder
+ * is the sink. Look for an active link between decoder and
+ * source (tuner/s-video/Composite), if one exists, nothing
+ * to do. If not, look for any active links between source
+ * and any other entity. If one exists, source is busy. If
+ * source is free, setup link and start pipeline from source.
+ * For DVB FE entity, the source for the link is the tuner.
+ * Check if tuner is available and setup link and start
+ * pipeline.
+ */
+ if (entity->function == MEDIA_ENT_F_DTV_DEMOD) {
+ sink = entity;
+ find_source = dev->tuner;
+ } else {
+ /* Analog isn't configured or register failed */
+ if (!dev->decoder) {
+ ret = -ENODEV;
+ goto end;
+ }
+
+ sink = dev->decoder;
+
+ /*
+ * Default input is tuner and default input_type
+ * is AU0828_VMUX_TELEVISION.
+ * FIXME:
+ * There is a problem when s_input is called to
+ * change the default input. s_input will try to
+ * enable_source before attempting to change the
+ * input on the device, and will end up enabling
+ * default source which is tuner.
+ *
+ * Additional logic is necessary in au0828
+ * to detect that the input has changed and
+ * enable the right source.
+ */
+
+ if (dev->input_type == AU0828_VMUX_TELEVISION)
+ find_source = dev->tuner;
+ else if (dev->input_type == AU0828_VMUX_SVIDEO ||
+ dev->input_type == AU0828_VMUX_COMPOSITE)
+ find_source = &dev->input_ent[dev->input_type];
+ else {
+ /* unknown input - let user select input */
+ ret = 0;
+ goto end;
+ }
+ }
+
+ /* Is an active link between sink and source */
+ if (dev->active_link) {
+ /*
+ * If DVB is using the tuner and calling entity is
+ * audio/video, the following check will be false,
+ * since sink is different. Result is Busy.
+ */
+ if (dev->active_link->sink->entity == sink &&
+ dev->active_link->source->entity == find_source) {
+ /*
+ * Either ALSA or Video own tuner. sink is
+ * the same for both. Prevent Video stepping
+ * on ALSA when ALSA owns the source.
+ */
+ if (dev->active_link_owner != entity &&
+ dev->active_link_owner->function ==
+ MEDIA_ENT_F_AUDIO_CAPTURE) {
+ pr_debug("ALSA has the tuner\n");
+ ret = -EBUSY;
+ goto end;
+ }
+ ret = 0;
+ goto end;
+ } else {
+ ret = -EBUSY;
+ goto end;
+ }
+ }
+
+ list_for_each_entry(link, &sink->links, list) {
+ /* Check sink, and source */
+ if (link->sink->entity == sink &&
+ link->source->entity == find_source) {
+ found_link = link;
break;
}
}
- /* Analog setup, using tuner as a link */
+ if (!found_link) {
+ ret = -ENODEV;
+ goto end;
+ }
- /* Something bad happened! */
- if (!decoder)
- return -EINVAL;
+ /* activate link between source and sink and start pipeline */
+ source = found_link->source->entity;
+ ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ pr_err("Activate tuner link %s->%s. Error %d\n",
+ source->name, sink->name, ret);
+ goto end;
+ }
- if (tuner) {
- ret = media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT,
- decoder, 0,
- MEDIA_LNK_FL_ENABLED);
+ ret = __media_entity_pipeline_start(entity, pipe);
+ if (ret) {
+ pr_err("Start Pipeline: %s->%s Error %d\n",
+ source->name, entity->name, ret);
+ ret = __media_entity_setup_link(found_link, 0);
+ pr_err("Deactivate link Error %d\n", ret);
+ goto end;
+ }
+ /*
+ * save active link and active link owner to avoid audio
+ * deactivating video owned link from disable_source and
+ * vice versa
+ */
+ dev->active_link = found_link;
+ dev->active_link_owner = entity;
+ dev->active_source = source;
+ dev->active_sink = sink;
+
+ pr_debug("Enabled Source: %s->%s->%s Ret %d\n",
+ dev->active_source->name, dev->active_sink->name,
+ dev->active_link_owner->name, ret);
+end:
+ mutex_unlock(&mdev->graph_mutex);
+ pr_debug("au0828_enable_source() end %s %d %d\n",
+ entity->name, entity->function, ret);
+ return ret;
+}
+
+static void au0828_disable_source(struct media_entity *entity)
+{
+ int ret = 0;
+ struct media_device *mdev = entity->graph_obj.mdev;
+ struct au0828_dev *dev;
+
+ if (!mdev)
+ return;
+
+ mutex_lock(&mdev->graph_mutex);
+ dev = mdev->source_priv;
+
+ if (!dev->active_link) {
+ ret = -ENODEV;
+ goto end;
+ }
+
+ /* link is active - stop pipeline from source (tuner) */
+ if (dev->active_link->sink->entity == dev->active_sink &&
+ dev->active_link->source->entity == dev->active_source) {
+ /*
+ * prevent video from deactivating link when audio
+ * has active pipeline
+ */
+ if (dev->active_link_owner != entity)
+ goto end;
+ __media_entity_pipeline_stop(entity);
+ ret = __media_entity_setup_link(dev->active_link, 0);
if (ret)
- return ret;
+ pr_err("Deactivate link Error %d\n", ret);
+
+ pr_debug("Disabled Source: %s->%s->%s Ret %d\n",
+ dev->active_source->name, dev->active_sink->name,
+ dev->active_link_owner->name, ret);
+
+ dev->active_link = NULL;
+ dev->active_link_owner = NULL;
+ dev->active_source = NULL;
+ dev->active_sink = NULL;
}
- ret = media_create_pad_link(decoder, 1, &dev->vdev.entity, 0,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
- return ret;
- ret = media_create_pad_link(decoder, 2, &dev->vbi_dev.entity, 0,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
- return ret;
- for (i = 0; i < AU0828_MAX_INPUT; i++) {
- struct media_entity *ent = &dev->input_ent[i];
+end:
+ mutex_unlock(&mdev->graph_mutex);
+}
+#endif
- if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED)
- break;
+static int au0828_media_device_register(struct au0828_dev *dev,
+ struct usb_device *udev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ int ret;
+ struct media_entity *entity, *demod = NULL, *tuner = NULL;
- switch (AUVI_INPUT(i).type) {
- case AU0828_VMUX_CABLE:
- case AU0828_VMUX_TELEVISION:
- case AU0828_VMUX_DVB:
- if (!tuner)
- break;
-
- ret = media_create_pad_link(ent, 0, tuner,
- TUNER_PAD_RF_INPUT,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
- return ret;
- break;
- case AU0828_VMUX_COMPOSITE:
- case AU0828_VMUX_SVIDEO:
- default: /* AU0828_VMUX_DEBUG */
- /* FIXME: fix the decoder PAD */
- ret = media_create_pad_link(ent, 0, decoder, 0, 0);
- if (ret)
- return ret;
- break;
+ if (!dev->media_dev)
+ return 0;
+
+ if (!media_devnode_is_registered(&dev->media_dev->devnode)) {
+
+ /* register media device */
+ ret = media_device_register(dev->media_dev);
+ if (ret) {
+ dev_err(&udev->dev,
+ "Media Device Register Error: %d\n", ret);
+ return ret;
+ }
+ } else {
+ /*
+ * Call au0828_media_graph_notify() to connect
+ * audio graph to our graph. In this case, audio
+ * driver registered the device and there is no
+ * entity_notify to be called when new entities
+ * are added. Invoke it now.
+ */
+ au0828_media_graph_notify(NULL, (void *) dev);
+ }
+
+ /*
+ * Find tuner and demod to disable the link between
+ * the two to avoid disable step when tuner is requested
+ * by video or audio. Note that this step can't be done
+ * until dvb graph is created during dvb register.
+ */
+ media_device_for_each_entity(entity, dev->media_dev) {
+ if (entity->function == MEDIA_ENT_F_DTV_DEMOD)
+ demod = entity;
+ else if (entity->function == MEDIA_ENT_F_TUNER)
+ tuner = entity;
+ }
+ /* Disable link between tuner and demod */
+ if (tuner && demod) {
+ struct media_link *link;
+
+ list_for_each_entry(link, &demod->links, list) {
+ if (link->sink->entity == demod &&
+ link->source->entity == tuner) {
+ media_entity_setup_link(link, 0);
+ }
}
}
+
+ /* register entity_notify callback */
+ dev->entity_notify.notify_data = (void *) dev;
+ dev->entity_notify.notify = (void *) au0828_media_graph_notify;
+ ret = media_device_register_entity_notify(dev->media_dev,
+ &dev->entity_notify);
+ if (ret) {
+ dev_err(&udev->dev,
+ "Media Device register entity_notify Error: %d\n",
+ ret);
+ return ret;
+ }
+ /* set enable_source */
+ dev->media_dev->source_priv = (void *) dev;
+ dev->media_dev->enable_source = au0828_enable_source;
+ dev->media_dev->disable_source = au0828_disable_source;
#endif
return 0;
}
@@ -378,32 +578,13 @@ static int au0828_usb_probe(struct usb_interface *interface,
return retval;
}
-#ifdef CONFIG_VIDEO_AU0828_V4L2
- dev->v4l2_dev.release = au0828_usb_v4l2_release;
-
- /* Create the v4l2_device */
-#ifdef CONFIG_MEDIA_CONTROLLER
- dev->v4l2_dev.mdev = dev->media_dev;
-#endif
- retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
+ retval = au0828_v4l2_device_register(interface, dev);
if (retval) {
- pr_err("%s() v4l2_device_register failed\n",
- __func__);
+ au0828_usb_v4l2_media_release(dev);
mutex_unlock(&dev->lock);
kfree(dev);
return retval;
}
- /* This control handler will inherit the controls from au8522 */
- retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4);
- if (retval) {
- pr_err("%s() v4l2_ctrl_handler_init failed\n",
- __func__);
- mutex_unlock(&dev->lock);
- kfree(dev);
- return retval;
- }
- dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
-#endif
/* Power Up the bridge */
au0828_write(dev, REG_600, 1 << 4);
@@ -417,11 +598,13 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Setup */
au0828_card_setup(dev);
-#ifdef CONFIG_VIDEO_AU0828_V4L2
/* Analog TV */
- if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
- au0828_analog_register(dev, interface);
-#endif
+ retval = au0828_analog_register(dev, interface);
+ if (retval) {
+ pr_err("%s() au0282_dev_register failed to register on V4L2\n",
+ __func__);
+ goto done;
+ }
/* Digital TV */
retval = au0828_dvb_register(dev);
@@ -443,16 +626,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
mutex_unlock(&dev->lock);
- retval = au0828_create_media_graph(dev);
- if (retval) {
- pr_err("%s() au0282_dev_register failed to create graph\n",
- __func__);
- goto done;
- }
-
-#ifdef CONFIG_MEDIA_CONTROLLER
- retval = media_device_register(dev->media_dev);
-#endif
+ retval = au0828_media_device_register(dev, usbdev);
done:
if (retval < 0)
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index 94363a3ba400..0e174e860614 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -181,7 +181,7 @@ static int stop_urb_transfer(struct au0828_dev *dev)
static int start_urb_transfer(struct au0828_dev *dev)
{
struct urb *purb;
- int i, ret = -ENOMEM;
+ int i, ret;
dprintk(2, "%s()\n", __func__);
@@ -194,7 +194,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urbs[i])
- goto err;
+ return -ENOMEM;
purb = dev->urbs[i];
@@ -207,9 +207,10 @@ static int start_urb_transfer(struct au0828_dev *dev)
if (!purb->transfer_buffer) {
usb_free_urb(purb);
dev->urbs[i] = NULL;
+ ret = -ENOMEM;
pr_err("%s: failed big buffer allocation, err = %d\n",
__func__, ret);
- goto err;
+ return ret;
}
purb->status = -EINPROGRESS;
@@ -235,10 +236,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
}
dev->urb_streaming = true;
- ret = 0;
-
-err:
- return ret;
+ return 0;
}
static void au0828_start_transport(struct au0828_dev *dev)
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 8c54fd21022e..13f6dab9ccc2 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -28,12 +28,14 @@
*/
#include "au0828.h"
+#include "au8522.h"
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/device.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-mc.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include <media/tuner.h>
@@ -638,61 +640,64 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
return rc;
}
-static int au0828_enable_analog_tuner(struct au0828_dev *dev)
+void au0828_usb_v4l2_media_release(struct au0828_dev *dev)
{
#ifdef CONFIG_MEDIA_CONTROLLER
- struct media_device *mdev = dev->media_dev;
- struct media_entity *source;
- struct media_link *link, *found_link = NULL;
- int ret, active_links = 0;
-
- if (!mdev || !dev->decoder)
- return 0;
+ int i;
- /*
- * This will find the tuner that is connected into the decoder.
- * Technically, this is not 100% correct, as the device may be
- * using an analog input instead of the tuner. However, as we can't
- * do DVB streaming while the DMA engine is being used for V4L2,
- * this should be enough for the actual needs.
- */
- list_for_each_entry(link, &dev->decoder->links, list) {
- if (link->sink->entity == dev->decoder) {
- found_link = link;
- if (link->flags & MEDIA_LNK_FL_ENABLED)
- active_links++;
- break;
- }
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED)
+ return;
+ media_device_unregister_entity(&dev->input_ent[i]);
}
+#endif
+}
- if (active_links == 1 || !found_link)
- return 0;
+static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
+{
+ struct au0828_dev *dev =
+ container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
+
+ v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ au0828_usb_v4l2_media_release(dev);
+ au0828_usb_release(dev);
+}
- source = found_link->source->entity;
- list_for_each_entry(link, &source->links, list) {
- struct media_entity *sink;
- int flags = 0;
+int au0828_v4l2_device_register(struct usb_interface *interface,
+ struct au0828_dev *dev)
+{
+ int retval;
- sink = link->sink->entity;
+ if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
+ return 0;
- if (sink == dev->decoder)
- flags = MEDIA_LNK_FL_ENABLED;
+ /* Create the v4l2_device */
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->v4l2_dev.mdev = dev->media_dev;
+#endif
+ retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
+ if (retval) {
+ pr_err("%s() v4l2_device_register failed\n",
+ __func__);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return retval;
+ }
- ret = media_entity_setup_link(link, flags);
- if (ret) {
- pr_err(
- "Couldn't change link %s->%s to %s. Error %d\n",
- source->name, sink->name,
- flags ? "enabled" : "disabled",
- ret);
- return ret;
- } else
- au0828_isocdbg(
- "link %s->%s was %s\n",
- source->name, sink->name,
- flags ? "ENABLED" : "disabled");
+ dev->v4l2_dev.release = au0828_usb_v4l2_release;
+
+ /* This control handler will inherit the controls from au8522 */
+ retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4);
+ if (retval) {
+ pr_err("%s() v4l2_ctrl_handler_init failed\n",
+ __func__);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return retval;
}
-#endif
+ dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
+
return 0;
}
@@ -707,9 +712,6 @@ static int queue_setup(struct vb2_queue *vq,
return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
sizes[0] = size;
-
- au0828_enable_analog_tuner(dev);
-
return 0;
}
@@ -949,13 +951,23 @@ static struct vb2_ops au0828_video_qops = {
* au0828_analog_unregister
* unregister v4l2 devices
*/
-void au0828_analog_unregister(struct au0828_dev *dev)
+int au0828_analog_unregister(struct au0828_dev *dev)
{
dprintk(1, "au0828_analog_unregister called\n");
+
+ /* No analog TV */
+ if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
+ return 0;
+
mutex_lock(&au0828_sysfs_lock);
video_unregister_device(&dev->vdev);
video_unregister_device(&dev->vbi_dev);
mutex_unlock(&au0828_sysfs_lock);
+
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ v4l2_device_put(&dev->v4l2_dev);
+
+ return 1;
}
/* This function ensures that video frames continue to be delivered even if
@@ -1067,8 +1079,39 @@ static int au0828_v4l2_close(struct file *filp)
goto end;
if (dev->users == 1) {
- /* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+ /*
+ * Avoid putting tuner in sleep if DVB or ALSA are
+ * streaming.
+ *
+ * On most USB devices like au0828 the tuner can
+ * be safely put in sleep stare here if ALSA isn't
+ * streaming. Exceptions are some very old USB tuner
+ * models such as em28xx-based WinTV USB2 which have
+ * a separate audio output jack. The devices that have
+ * a separate audio output jack have analog tuners,
+ * like Philips FM1236. Those devices are always on,
+ * so the s_power callback are silently ignored.
+ * So, the current logic here does the following:
+ * Disable (put tuner to sleep) when
+ * - ALSA and DVB aren't not streaming;
+ * - the last V4L2 file handler is closed.
+ *
+ * FIXME:
+ *
+ * Additionally, this logic could be improved to
+ * disable the media source if the above conditions
+ * are met and if the device:
+ * - doesn't have a separate audio out plug (or
+ * - doesn't use a silicon tuner like xc2028/3028/4000/5000).
+ *
+ * Once this additional logic is in place, a callback
+ * is needed to enable the media source and power on
+ * the tuner, for radio to work.
+ */
+ ret = v4l_enable_media_source(vdev);
+ if (ret == 0)
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core,
+ s_power, 0);
dev->std_set_in_tuner_core = 0;
/* When close the device, set the usb intf0 into alt0 to free
@@ -1312,7 +1355,6 @@ static int vidioc_enum_input(struct file *file, void *priv,
[AU0828_VMUX_CABLE] = "Cable TV",
[AU0828_VMUX_TELEVISION] = "Television",
[AU0828_VMUX_DVB] = "DVB",
- [AU0828_VMUX_DEBUG] = "tv debug"
};
dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
@@ -1375,9 +1417,11 @@ static void au0828_s_input(struct au0828_dev *dev, int index)
default:
dprintk(1, "unknown input type set [%d]\n",
AUVI_INPUT(index).type);
- break;
+ return;
}
+ dev->ctrl_input = index;
+
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
AUVI_INPUT(index).vmux, 0, 0);
@@ -1409,6 +1453,7 @@ static void au0828_s_input(struct au0828_dev *dev, int index)
static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
{
struct au0828_dev *dev = video_drvdata(file);
+ struct video_device *vfd = video_devdata(file);
dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
index);
@@ -1416,9 +1461,19 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
return -EINVAL;
if (AUVI_INPUT(index).type == 0)
return -EINVAL;
- dev->ctrl_input = index;
+
+ if (dev->ctrl_input == index)
+ return 0;
+
au0828_s_input(dev, index);
- return 0;
+
+ /*
+ * Input has been changed. Disable the media source
+ * associated with the old input and enable source
+ * for the newly set input
+ */
+ v4l_disable_media_source(vfd);
+ return v4l_enable_media_source(vfd);
}
static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a)
@@ -1469,10 +1524,16 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
{
struct au0828_dev *dev = video_drvdata(file);
+ struct video_device *vfd = video_devdata(file);
+ int ret;
if (t->index != 0)
return -EINVAL;
+ ret = v4l_enable_media_source(vfd);
+ if (ret)
+ return ret;
+
dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);
@@ -1804,7 +1865,6 @@ static void au0828_analog_create_entities(struct au0828_dev *dev)
[AU0828_VMUX_CABLE] = "Cable TV",
[AU0828_VMUX_TELEVISION] = "Television",
[AU0828_VMUX_DVB] = "DVB",
- [AU0828_VMUX_DEBUG] = "tv debug"
};
int ret, i;
@@ -1840,11 +1900,9 @@ static void au0828_analog_create_entities(struct au0828_dev *dev)
case AU0828_VMUX_CABLE:
case AU0828_VMUX_TELEVISION:
case AU0828_VMUX_DVB:
+ default: /* Just to shut up a warning */
ent->function = MEDIA_ENT_F_CONN_RF;
break;
- default: /* AU0828_VMUX_DEBUG */
- ent->function = MEDIA_ENT_F_CONN_TEST;
- break;
}
ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
@@ -1871,6 +1929,10 @@ int au0828_analog_register(struct au0828_dev *dev,
dprintk(1, "au0828_analog_register called for intf#%d!\n",
interface->cur_altsetting->desc.bInterfaceNumber);
+ /* No analog TV */
+ if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
+ return 0;
+
/* set au0828 usb interface0 to as5 */
retval = usb_set_interface(dev->usbdev,
interface->cur_altsetting->desc.bInterfaceNumber, 5);
@@ -1925,6 +1987,7 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->ctrl_ainput = 0;
dev->ctrl_freq = 960;
dev->std = V4L2_STD_NTSC_M;
+ /* Default input is TV Tuner */
au0828_s_input(dev, 0);
mutex_init(&dev->vb_queue_lock);
@@ -1977,6 +2040,16 @@ int au0828_analog_register(struct au0828_dev *dev,
goto err_reg_vbi_dev;
}
+#ifdef CONFIG_MEDIA_CONTROLLER
+ retval = v4l2_mc_create_media_graph(dev->media_dev);
+ if (retval) {
+ pr_err("%s() au0282_dev_register failed to create graph\n",
+ __func__);
+ ret = -ENODEV;
+ goto err_reg_vbi_dev;
+ }
+#endif
+
dprintk(1, "%s completed!\n", __func__);
return 0;
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 8276072bc55a..ff7f8510fb77 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -76,7 +76,6 @@ enum au0828_itype {
AU0828_VMUX_CABLE,
AU0828_VMUX_TELEVISION,
AU0828_VMUX_DVB,
- AU0828_VMUX_DEBUG
};
struct au0828_input {
@@ -283,6 +282,12 @@ struct au0828_dev {
struct media_entity *decoder;
struct media_entity input_ent[AU0828_MAX_INPUT];
struct media_pad input_pad[AU0828_MAX_INPUT];
+ struct media_entity_notify entity_notify;
+ struct media_entity *tuner;
+ struct media_link *active_link;
+ struct media_entity *active_link_owner;
+ struct media_entity *active_source;
+ struct media_entity *active_sink;
#endif
};
@@ -301,6 +306,7 @@ struct au0828_dev {
/* au0828-core.c */
extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
+extern void au0828_usb_release(struct au0828_dev *dev);
extern int au0828_debug;
/* ----------------------------------------------------------- */
@@ -319,16 +325,29 @@ extern int au0828_i2c_unregister(struct au0828_dev *dev);
/* ----------------------------------------------------------- */
/* au0828-video.c */
-extern int au0828_analog_register(struct au0828_dev *dev,
- struct usb_interface *interface);
-extern void au0828_analog_unregister(struct au0828_dev *dev);
extern int au0828_start_analog_streaming(struct vb2_queue *vq,
unsigned int count);
extern void au0828_stop_vbi_streaming(struct vb2_queue *vq);
#ifdef CONFIG_VIDEO_AU0828_V4L2
+extern int au0828_v4l2_device_register(struct usb_interface *interface,
+ struct au0828_dev *dev);
+
+extern int au0828_analog_register(struct au0828_dev *dev,
+ struct usb_interface *interface);
+extern int au0828_analog_unregister(struct au0828_dev *dev);
+extern void au0828_usb_v4l2_media_release(struct au0828_dev *dev);
extern void au0828_v4l2_suspend(struct au0828_dev *dev);
extern void au0828_v4l2_resume(struct au0828_dev *dev);
#else
+static inline int au0828_v4l2_device_register(struct usb_interface *interface,
+ struct au0828_dev *dev)
+{ return 0; };
+static inline int au0828_analog_register(struct au0828_dev *dev,
+ struct usb_interface *interface)
+{ return 0; };
+static inline int au0828_analog_unregister(struct au0828_dev *dev)
+{ return 0; };
+static inline void au0828_usb_v4l2_media_release(struct au0828_dev *dev) { };
static inline void au0828_v4l2_suspend(struct au0828_dev *dev) { };
static inline void au0828_v4l2_resume(struct au0828_dev *dev) { };
#endif
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c
index 0bd969063392..d4bdba60b0f7 100644
--- a/drivers/media/usb/b2c2/flexcop-usb.c
+++ b/drivers/media/usb/b2c2/flexcop-usb.c
@@ -10,7 +10,7 @@
/* Version information */
#define DRIVER_VERSION "0.1"
#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
-#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@posteo.de>"
/* debug */
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
diff --git a/drivers/media/usb/cpia2/cpia2_core.c b/drivers/media/usb/cpia2/cpia2_core.c
index 187012ce444b..0310fd6ed103 100644
--- a/drivers/media/usb/cpia2/cpia2_core.c
+++ b/drivers/media/usb/cpia2/cpia2_core.c
@@ -923,7 +923,7 @@ static int apply_vp_patch(struct camera_data *cam)
/* ... followed by the data payload */
for (i = 2; i < fw->size; i += 64) {
cmd.start = 0x0C; /* Data */
- cmd.reg_count = min_t(int, 64, fw->size - i);
+ cmd.reg_count = min_t(uint, 64, fw->size - i);
memcpy(cmd.buffer.block_data, &fw->data[i], cmd.reg_count);
cpia2_send_command(cam, &cmd);
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 48643b94e694..c9320d6c6131 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1382,6 +1382,8 @@ static int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
buffer_size = urb->actual_length;
buffer = kmalloc(buffer_size, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
memcpy(buffer, dma_q->ps_head, 3);
memcpy(buffer+3, p_buffer, buffer_size-3);
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index de4ae5eb4830..a6a9508418f8 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -499,6 +499,11 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
}
dev->adev.users--;
+ if (substream->runtime->dma_area) {
+ dev_dbg(dev->dev, "freeing\n");
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ }
mutex_unlock(&dev->lock);
if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 620b83d03f75..c63248a18823 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -1216,66 +1216,13 @@ static int cx231xx_media_device_init(struct cx231xx *dev,
if (!mdev)
return -ENOMEM;
- mdev->dev = dev->dev;
- strlcpy(mdev->model, dev->board.name, sizeof(mdev->model));
- if (udev->serial)
- strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
- strcpy(mdev->bus_info, udev->devpath);
- mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
- mdev->driver_version = LINUX_VERSION_CODE;
-
- media_device_init(mdev);
+ media_device_usb_init(mdev, udev, dev->board.name);
dev->media_dev = mdev;
#endif
return 0;
}
-static int cx231xx_create_media_graph(struct cx231xx *dev)
-{
-#ifdef CONFIG_MEDIA_CONTROLLER
- struct media_device *mdev = dev->media_dev;
- struct media_entity *entity;
- struct media_entity *tuner = NULL, *decoder = NULL;
- int ret;
-
- if (!mdev)
- return 0;
-
- media_device_for_each_entity(entity, mdev) {
- switch (entity->function) {
- case MEDIA_ENT_F_TUNER:
- tuner = entity;
- break;
- case MEDIA_ENT_F_ATV_DECODER:
- decoder = entity;
- break;
- }
- }
-
- /* Analog setup, using tuner as a link */
-
- if (!decoder)
- return 0;
-
- if (tuner) {
- ret = media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT, decoder, 0,
- MEDIA_LNK_FL_ENABLED);
- if (ret < 0)
- return ret;
- }
- ret = media_create_pad_link(decoder, 1, &dev->vdev.entity, 0,
- MEDIA_LNK_FL_ENABLED);
- if (ret < 0)
- return ret;
- ret = media_create_pad_link(decoder, 2, &dev->vbi_dev.entity, 0,
- MEDIA_LNK_FL_ENABLED);
- if (ret < 0)
- return ret;
-#endif
- return 0;
-}
-
/*
* cx231xx_init_dev()
* allocates and inits the device structs, registers i2c bus and v4l device
@@ -1739,15 +1686,14 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* load other modules required */
request_modules(dev);
- retval = cx231xx_create_media_graph(dev);
- if (retval < 0)
- goto done;
-
#ifdef CONFIG_MEDIA_CONTROLLER
- retval = media_device_register(dev->media_dev);
-#endif
+ /* Init entities at the Media Controller */
+ cx231xx_v4l2_create_entities(dev);
-done:
+ retval = v4l2_mc_create_media_graph(dev->media_dev);
+ if (!retval)
+ retval = media_device_register(dev->media_dev);
+#endif
if (retval < 0)
cx231xx_release_resources(dev);
return retval;
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index b8d5b2be9293..ab2fb9fa0cd1 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -25,6 +25,7 @@
#include <media/v4l2-common.h>
#include <media/videobuf-vmalloc.h>
+#include <media/tuner.h>
#include "xc5000.h"
#include "s5h1432.h"
@@ -551,7 +552,8 @@ static int register_dvb(struct cx231xx_dvb *dvb,
/* register network adapter */
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
- result = dvb_create_media_graph(&dvb->adapter, false);
+ result = dvb_create_media_graph(&dvb->adapter,
+ dev->tuner_type == TUNER_ABSENT);
if (result < 0)
goto fail_create_graph;
@@ -801,6 +803,9 @@ static int dvb_init(struct cx231xx *dev)
/* attach tuner */
memset(&si2157_config, 0, sizeof(si2157_config));
si2157_config.fe = dev->dvb->frontend;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+#endif
si2157_config.if_port = 1;
si2157_config.inversion = true;
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
@@ -857,6 +862,9 @@ static int dvb_init(struct cx231xx *dev)
/* attach tuner */
memset(&si2157_config, 0, sizeof(si2157_config));
si2157_config.fe = dev->dvb->frontend;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+#endif
si2157_config.if_port = 1;
si2157_config.inversion = true;
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 9b88cd8127ac..6414188ffdfa 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -1103,9 +1103,54 @@ static const char *iname[] = {
[CX231XX_VMUX_TELEVISION] = "Television",
[CX231XX_VMUX_CABLE] = "Cable TV",
[CX231XX_VMUX_DVB] = "DVB",
- [CX231XX_VMUX_DEBUG] = "for debug only",
};
+void cx231xx_v4l2_create_entities(struct cx231xx *dev)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ int ret, i;
+
+ /* Create entities for each input connector */
+ for (i = 0; i < MAX_CX231XX_INPUT; i++) {
+ struct media_entity *ent = &dev->input_ent[i];
+
+ if (!INPUT(i)->type)
+ break;
+
+ ent->name = iname[INPUT(i)->type];
+ ent->flags = MEDIA_ENT_FL_CONNECTOR;
+ dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ switch (INPUT(i)->type) {
+ case CX231XX_VMUX_COMPOSITE1:
+ ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
+ break;
+ case CX231XX_VMUX_SVIDEO:
+ ent->function = MEDIA_ENT_F_CONN_SVIDEO;
+ break;
+ case CX231XX_VMUX_TELEVISION:
+ case CX231XX_VMUX_CABLE:
+ case CX231XX_VMUX_DVB:
+ /* The DVB core will handle it */
+ if (dev->tuner_type == TUNER_ABSENT)
+ continue;
+ /* fall though */
+ default: /* just to shut up a gcc warning */
+ ent->function = MEDIA_ENT_F_CONN_RF;
+ break;
+ }
+
+ ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
+ if (ret < 0)
+ pr_err("failed to initialize input pad[%d]!\n", i);
+
+ ret = media_device_register_entity(dev->media_dev, ent);
+ if (ret < 0)
+ pr_err("failed to register input entity %d!\n", i);
+ }
+#endif
+}
+
int cx231xx_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index ec6d3f5bc36d..69f6d20870f5 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -281,7 +281,6 @@ enum cx231xx_itype {
CX231XX_VMUX_CABLE,
CX231XX_RADIO,
CX231XX_VMUX_DVB,
- CX231XX_VMUX_DEBUG
};
enum cx231xx_v_input {
@@ -663,6 +662,8 @@ struct cx231xx {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_device *media_dev;
struct media_pad video_pad, vbi_pad;
+ struct media_entity input_ent[MAX_CX231XX_INPUT];
+ struct media_pad input_pad[MAX_CX231XX_INPUT];
#endif
unsigned char eedata[256];
@@ -943,6 +944,7 @@ int cx231xx_register_extension(struct cx231xx_ops *dev);
void cx231xx_unregister_extension(struct cx231xx_ops *dev);
void cx231xx_init_extension(struct cx231xx *dev);
void cx231xx_close_extension(struct cx231xx *dev);
+void cx231xx_v4l2_create_entities(struct cx231xx *dev);
int cx231xx_querycap(struct file *file, void *priv,
struct v4l2_capability *cap);
int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t);
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 6e02a15d39ce..2638e3251f2a 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -684,7 +684,7 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
if (ret < 0)
goto err;
- if (tmp == 1 || tmp == 3) {
+ if (tmp == 1 || tmp == 3 || tmp == 5) {
/* configure gpioh1, reset & power slave demod */
ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01);
if (ret < 0)
@@ -823,7 +823,7 @@ static int af9035_read_config(struct dvb_usb_device *d)
if (ret < 0)
goto err;
- if (tmp == 1 || tmp == 3)
+ if (tmp == 1 || tmp == 3 || tmp == 5)
state->dual_mode = true;
dev_dbg(&d->udev->dev, "%s: ts mode=%d dual mode=%d\n", __func__,
@@ -2053,6 +2053,8 @@ static const struct usb_device_id af9035_id_table[] = {
&af9035_props, "Avermedia A835B(3835)", RC_MAP_IT913X_V2) },
{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835,
&af9035_props, "Avermedia A835B(4835)", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD110,
+ &af9035_props, "Avermedia AverTV Volar HD 2 (TD110)", RC_MAP_AVERMEDIA_RM_KS) },
{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335,
&af9035_props, "Avermedia H335", RC_MAP_IT913X_V2) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09,
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
index 416a97f05ec8..df22001f9e41 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.h
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -112,9 +112,10 @@ static const u32 clock_lut_it9135[] = {
* 0 TS
* 1 DCA + PIP
* 3 PIP
+ * 5 DCA + PIP
* n DCA
*
- * Values 0 and 3 are seen to this day. 0 for single TS and 3 for dual TS.
+ * Values 0, 3 and 5 are seen to this day. 0 for single TS and 3/5 for dual TS.
*/
#define EEPROM_BASE_AF9035 0x42fd
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index 023d91f7e654..35f27e2e4e28 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -1,7 +1,7 @@
/*
* DVB USB framework
*
- * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@posteo.de>
* Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h b/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
index 45f07090d431..a1622bda2a5e 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
@@ -1,7 +1,7 @@
/*
* DVB USB framework
*
- * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@posteo.de>
* Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index f0565bf3673e..3fbb2cd19f5e 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -1,7 +1,7 @@
/*
* DVB USB framework
*
- * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@posteo.de>
* Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
*/
#include "dvb_usb_common.h"
+#include <media/media-device.h>
static int dvb_usbv2_disable_rc_polling;
module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644);
@@ -411,15 +412,7 @@ static int dvb_usbv2_media_device_init(struct dvb_usb_adapter *adap)
if (!mdev)
return -ENOMEM;
- mdev->dev = &udev->dev;
- strlcpy(mdev->model, d->name, sizeof(mdev->model));
- if (udev->serial)
- strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
- strcpy(mdev->bus_info, udev->devpath);
- mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
- mdev->driver_version = LINUX_VERSION_CODE;
-
- media_device_init(mdev);
+ media_device_usb_init(mdev, udev, d->name);
dvb_register_media_controller(&adap->dvb_adap, mdev);
@@ -1129,7 +1122,7 @@ int dvb_usbv2_reset_resume(struct usb_interface *intf)
EXPORT_SYMBOL(dvb_usbv2_reset_resume);
MODULE_VERSION("2.0");
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("DVB USB common");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
index 22bdce15ecf3..5bafeb6486be 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
@@ -1,7 +1,7 @@
/*
* DVB USB framework
*
- * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@posteo.de>
* Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c
index 1dd962535f97..02dbc6c45423 100644
--- a/drivers/media/usb/dvb-usb-v2/dvbsky.c
+++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c
@@ -847,10 +847,17 @@ static const struct usb_device_id dvbsky_id_table[] = {
USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI,
&dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI",
RC_MAP_TT_1500) },
+ { DVB_USB_DEVICE(USB_VID_TECHNOTREND,
+ USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI_2,
+ &dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI v1.1",
+ RC_MAP_TT_1500) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC,
USB_PID_TERRATEC_H7_3,
&dvbsky_t680c_props, "Terratec H7 Rev.4",
RC_MAP_TT_1500) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R4,
+ &dvbsky_s960_props, "Terratec Cinergy S2 Rev.4",
+ RC_MAP_DVBSKY) },
{ }
};
MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
index 84f6de6fa07d..047a32fe43ea 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
@@ -507,9 +507,9 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
return 0;
}
-static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe)
+static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mxl111sf_demod_state *state = fe->demodulator_priv;
mxl_dbg("()");
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
index 444579be0b77..7d16252dbb71 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
@@ -36,7 +36,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
struct mxl111sf_tuner_state {
struct mxl111sf_state *mxl_state;
- struct mxl111sf_tuner_config *cfg;
+ const struct mxl111sf_tuner_config *cfg;
enum mxl_if_freq if_freq;
@@ -489,8 +489,8 @@ static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
};
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
- struct mxl111sf_state *mxl_state,
- struct mxl111sf_tuner_config *cfg)
+ struct mxl111sf_state *mxl_state,
+ const struct mxl111sf_tuner_config *cfg)
{
struct mxl111sf_tuner_state *state = NULL;
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
index e6caab21a197..509b55071218 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
@@ -63,13 +63,13 @@ struct mxl111sf_tuner_config {
#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF)
extern
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
- struct mxl111sf_state *mxl_state,
- struct mxl111sf_tuner_config *cfg);
+ struct mxl111sf_state *mxl_state,
+ const struct mxl111sf_tuner_config *cfg);
#else
static inline
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
- struct mxl111sf_state *mxl_state,
- struct mxl111sf_tuner_config *cfg)
+ struct mxl111sf_state *mxl_state,
+ const struct mxl111sf_tuner_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index b669deccc34c..5d676b533a3a 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -856,7 +856,7 @@ static int mxl111sf_ant_hunt(struct dvb_frontend *fe)
return 0;
}
-static struct mxl111sf_tuner_config mxl_tuner_config = {
+static const struct mxl111sf_tuner_config mxl_tuner_config = {
.if_freq = MXL_IF_6_0, /* applies to external IF output, only */
.invert_spectrum = 0,
.read_reg = mxl111sf_read_reg,
@@ -888,7 +888,7 @@ static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
state->tuner.function = MEDIA_ENT_F_TUNER;
state->tuner.name = "mxl111sf tuner";
state->tuner_pads[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
- state->tuner_pads[TUNER_PAD_IF_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->tuner_pads[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&state->tuner,
TUNER_NUM_PADS, state->tuner_pads);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index eb5787a3191e..fa72642d41f3 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -259,6 +259,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
ret = -EOPNOTSUPP;
}
+ /* Retry failed I2C messages */
+ if (ret == -EPIPE)
+ ret = -EAGAIN;
+
err_mutex_unlock:
mutex_unlock(&d->i2c_mutex);
@@ -619,6 +623,10 @@ static int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name)
}
dev_dbg(&d->intf->dev, "chip_id=%u\n", dev->chip_id);
+ /* Retry failed I2C messages */
+ d->i2c_adap.retries = 1;
+ d->i2c_adap.timeout = msecs_to_jiffies(10);
+
return WARM;
err:
dev_dbg(&d->intf->dev, "failed=%d\n", ret);
@@ -1563,19 +1571,19 @@ static int rtl28xxu_frontend_ctrl(struct dvb_frontend *fe, int onoff)
if (dev->chip_id == CHIP_ID_RTL2831U)
return 0;
- /* control internal demod ADC */
- if (fe->id == 0 && onoff)
- val = 0x48; /* enable ADC */
- else
- val = 0x00; /* disable ADC */
-
- ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, val, 0x48);
- if (ret)
- goto err;
+ if (fe->id == 0) {
+ /* control internal demod ADC */
+ if (onoff)
+ val = 0x48; /* enable ADC */
+ else
+ val = 0x00; /* disable ADC */
- /* bypass slave demod TS through master demod */
- if (fe->id == 1 && onoff) {
- ret = pdata->enable_slave_ts(dev->i2c_client_demod);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, val, 0x48);
+ if (ret)
+ goto err;
+ } else if (fe->id == 1) {
+ /* bypass slave demod TS through master demod */
+ ret = pdata->slave_ts_ctrl(dev->i2c_client_demod, onoff);
if (ret)
goto err;
}
diff --git a/drivers/media/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c
index ca8f3c2b1082..55136cde38f5 100644
--- a/drivers/media/usb/dvb-usb-v2/usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c
@@ -1,6 +1,6 @@
/* usb-urb.c is part of the DVB USB library.
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* This file keeps functions for initializing and handling the
diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c
index 83684ed023cd..7ba975bea96a 100644
--- a/drivers/media/usb/dvb-usb/a800.c
+++ b/drivers/media/usb/dvb-usb/a800.c
@@ -1,7 +1,7 @@
/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T
* USB2.0 (A800) DVB-T receiver.
*
- * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* Thanks to
* - AVerMedia who kindly provided information and
@@ -185,7 +185,7 @@ static struct usb_driver a800_driver = {
module_usb_driver(a800_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/af9005-fe.c b/drivers/media/usb/dvb-usb/af9005-fe.c
index ac97075d75f7..09db3d02bd82 100644
--- a/drivers/media/usb/dvb-usb/af9005-fe.c
+++ b/drivers/media/usb/dvb-usb/af9005-fe.c
@@ -1227,9 +1227,9 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int af9005_fe_get_frontend(struct dvb_frontend *fe)
+static int af9005_fe_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *fep)
{
- struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct af9005_fe_state *state = fe->demodulator_priv;
int ret;
u8 temp;
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index ab7151181728..907ac01ae297 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -13,7 +13,7 @@
*
* TODO: Use the cx25840-driver for the analogue part
*
- * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de)
* Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
* Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au)
*
@@ -2314,7 +2314,7 @@ static struct usb_driver cxusb_driver = {
module_usb_driver(cxusb_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index 0d248ce02a9b..c16f999b9d7c 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -881,7 +881,7 @@ static struct usb_driver dib0700_driver = {
module_usb_driver(dib0700_driver);
MODULE_FIRMWARE("dvb-usb-dib0700-1.20.fw");
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 7ed49646a699..ea0391e32d23 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -1736,8 +1736,13 @@ static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
struct dib0700_adapter_state *st = adap->priv;
struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
- if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
- return -ENODEV;
+ if (adap->id == 0) {
+ if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+ return -ENODEV;
+ } else {
+ if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+ return -ENODEV;
+ }
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;
@@ -1773,6 +1778,20 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
+static int stk809x_frontend1_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
+ return -ENODEV;
+
+ state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x82, 0);
+
+ adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);
+
+ return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
@@ -3794,6 +3813,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
/* 80 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) },
{ USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E) },
{ USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E_SE) },
+ { USB_DEVICE(USB_VID_PCTV, USB_PID_DIBCOM_STK8096PVR) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -4959,6 +4979,59 @@ struct dvb_usb_device_properties dib0700_devices[] = {
RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk80xx_pid_filter,
+ .pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+ .frontend_attach = stk809x_frontend_attach,
+ .tuner_attach = dib809x_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+ } },
+ .size_of_priv =
+ sizeof(struct dib0700_adapter_state),
+ }, {
+ .num_frontends = 1,
+ .fe = { {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk80xx_pid_filter,
+ .pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+ .frontend_attach = stk809x_frontend1_attach,
+ .tuner_attach = dib809x_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+ } },
+ .size_of_priv =
+ sizeof(struct dib0700_adapter_state),
+ },
+ },
+ .num_device_descs = 1,
+ .devices = {
+ { "DiBcom STK8096-PVR reference design",
+ { &dib0700_usb_id_table[83], NULL },
+ { NULL },
+ },
+ },
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
},
};
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
index ef3a8f75f82e..35de6095926d 100644
--- a/drivers/media/usb/dvb-usb/dibusb-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -1,6 +1,6 @@
/* Common methods for dibusb-based-receivers.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* 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
diff --git a/drivers/media/usb/dvb-usb/dibusb-mb.c b/drivers/media/usb/dvb-usb/dibusb-mb.c
index a4ac37e0e98b..a0057641cc86 100644
--- a/drivers/media/usb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mb.c
@@ -1,10 +1,10 @@
/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
* reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B)
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* based on GPL code from DiBcom, which has
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ * Copyright (C) 2004 Amaury Demol for DiBcom
*
* 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
@@ -465,7 +465,7 @@ static struct usb_driver dibusb_driver = {
module_usb_driver(dibusb_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dibusb-mc.c b/drivers/media/usb/dvb-usb/dibusb-mc.c
index 9d1a59d09c52..08fb8a3f6e0c 100644
--- a/drivers/media/usb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mc.c
@@ -1,10 +1,10 @@
/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
* reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P)
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* based on GPL code from DiBcom, which has
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ * Copyright (C) 2004 Amaury Demol for DiBcom
*
* 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
@@ -143,7 +143,7 @@ static struct usb_driver dibusb_mc_driver = {
module_usb_driver(dibusb_mc_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dibusb.h b/drivers/media/usb/dvb-usb/dibusb.h
index 32ab1392313f..3f82163d8ab8 100644
--- a/drivers/media/usb/dvb-usb/dibusb.h
+++ b/drivers/media/usb/dvb-usb/dibusb.h
@@ -1,6 +1,6 @@
/* Header file for all dibusb-based-receivers.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* 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
diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c
index 772bde3c5020..63134335c994 100644
--- a/drivers/media/usb/dvb-usb/digitv.c
+++ b/drivers/media/usb/dvb-usb/digitv.c
@@ -1,7 +1,7 @@
/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
* receiver
*
- * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* partly based on the SDK published by Nebula Electronics
*
@@ -348,7 +348,7 @@ static struct usb_driver digitv_driver = {
module_usb_driver(digitv_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0");
MODULE_VERSION("1.0-alpha");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dtt200u-fe.c b/drivers/media/usb/dvb-usb/dtt200u-fe.c
index 8637ad1be6be..c09332bd99cb 100644
--- a/drivers/media/usb/dvb-usb/dtt200u-fe.c
+++ b/drivers/media/usb/dvb-usb/dtt200u-fe.c
@@ -1,7 +1,7 @@
/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
* Typhoon/ Yuan DVB-T USB2.0 receiver.
*
- * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
*
* 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
@@ -140,10 +140,11 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static int dtt200u_fe_get_frontend(struct dvb_frontend* fe)
+static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
+ struct dtv_frontend_properties *fep)
{
- struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dtt200u_fe_state *state = fe->demodulator_priv;
+
memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties));
return 0;
}
diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c
index c357fb3b0a88..ca3b69aa9688 100644
--- a/drivers/media/usb/dvb-usb/dtt200u.c
+++ b/drivers/media/usb/dvb-usb/dtt200u.c
@@ -1,7 +1,7 @@
/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
* Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* Thanks to Steve Chang from WideView for providing support for the WT-220U.
*
@@ -362,7 +362,7 @@ static struct usb_driver dtt200u_usb_driver = {
module_usb_driver(dtt200u_usb_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dtt200u.h b/drivers/media/usb/dvb-usb/dtt200u.h
index 005b0a7df358..efccc399b1cb 100644
--- a/drivers/media/usb/dvb-usb/dtt200u.h
+++ b/drivers/media/usb/dvb-usb/dtt200u.h
@@ -1,7 +1,7 @@
/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/
* Typhoon/ Yuan DVB-T USB2.0 receiver.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* 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
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-common.h b/drivers/media/usb/dvb-usb/dvb-usb-common.h
index 6b7b2a89242e..7e619d638809 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-common.h
+++ b/drivers/media/usb/dvb-usb/dvb-usb-common.h
@@ -1,6 +1,6 @@
/* dvb-usb-common.h is part of the DVB USB library.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* a header file containing prototypes and types for internal use of the dvb-usb-lib
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
index 9ddfcab268be..6477b04e95c7 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
@@ -1,12 +1,13 @@
/* dvb-usb-dvb.c is part of the DVB USB library.
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for initializing and handling the
* linux-dvb API.
*/
#include "dvb-usb-common.h"
+#include <media/media-device.h>
/* does the complete input transfer handling */
static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
@@ -106,15 +107,7 @@ static int dvb_usb_media_device_init(struct dvb_usb_adapter *adap)
if (!mdev)
return -ENOMEM;
- mdev->dev = &udev->dev;
- strlcpy(mdev->model, d->desc->name, sizeof(mdev->model));
- if (udev->serial)
- strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
- strcpy(mdev->bus_info, udev->devpath);
- mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
- mdev->driver_version = LINUX_VERSION_CODE;
-
- media_device_init(mdev);
+ media_device_usb_init(mdev, udev, d->desc->name);
dvb_register_media_controller(&adap->dvb_adap, mdev);
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
index 733a7ff7b207..dd048a7c461c 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
@@ -1,6 +1,6 @@
/* dvb-usb-firmware.c is part of the DVB USB library.
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
index 88e4a62abc44..4f0b0adce7f5 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
@@ -1,6 +1,6 @@
/* dvb-usb-i2c.c is part of the DVB USB library.
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for (de-)initializing an I2C adapter.
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c
index 1adf325012f7..3896ba9a4179 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -3,7 +3,7 @@
*
* dvb-usb-init.c
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* 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
@@ -299,6 +299,6 @@ void dvb_usb_device_exit(struct usb_interface *intf)
EXPORT_SYMBOL(dvb_usb_device_exit);
MODULE_VERSION("1.0");
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
index 7b5dae3077f6..c259f9e43542 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
@@ -1,6 +1,6 @@
/* dvb-usb-remote.c is part of the DVB USB library.
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for initializing the input-device and for handling remote-control-queries.
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-urb.c b/drivers/media/usb/dvb-usb/dvb-usb-urb.c
index 5c8f651344fc..95f9097498cb 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-urb.c
@@ -1,6 +1,6 @@
/* dvb-usb-urb.c is part of the DVB USB library.
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* This file keeps functions for initializing and handling the
diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h
index ce4c4e3b58bb..639c4678c65b 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb.h
+++ b/drivers/media/usb/dvb-usb/dvb-usb.h
@@ -1,6 +1,6 @@
/* dvb-usb.h is part of the DVB USB library.
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* the headerfile, all dvb-usb-drivers have to include.
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 14ef25dc6cd3..6d0dd859d684 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -1,9 +1,10 @@
/* DVB USB framework compliant Linux driver for the
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
- * TeVii S600, S630, S650, S660, S480, S421, S632
+ * TeVii S421, S480, S482, S600, S630, S632, S650, S660, S662,
* Prof 1100, 7500,
* Geniatech SU3000, T220,
- * TechnoTrend S2-4600 Cards
+ * TechnoTrend S2-4600,
+ * Terratec Cinergy S2 cards
* Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by)
*
* This program is free software; you can redistribute it and/or modify it
@@ -33,7 +34,6 @@
#include "tda18271.h"
#include "cxd2820r.h"
#include "m88ds3103.h"
-#include "ts2020.h"
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64
@@ -66,6 +66,10 @@
#define USB_PID_TEVII_S660 0xd660
#endif
+#ifndef USB_PID_TEVII_S662
+#define USB_PID_TEVII_S662 0xd662
+#endif
+
#ifndef USB_PID_TEVII_S480_1
#define USB_PID_TEVII_S480_1 0xd481
#endif
@@ -118,6 +122,7 @@
struct dw2102_state {
u8 initialized;
u8 last_lock;
+ struct i2c_client *i2c_client_demod;
struct i2c_client *i2c_client_tuner;
/* fe hook functions*/
@@ -1141,22 +1146,6 @@ static struct tda18271_config tda18271_config = {
.gate = TDA18271_GATE_DIGITAL,
};
-static const struct m88ds3103_config tt_s2_4600_m88ds3103_config = {
- .i2c_addr = 0x68,
- .clock = 27000000,
- .i2c_wr_max = 33,
- .ts_mode = M88DS3103_TS_CI,
- .ts_clk = 16000,
- .ts_clk_pol = 0,
- .spec_inv = 0,
- .agc_inv = 0,
- .clock_out = M88DS3103_CLOCK_OUT_ENABLED,
- .envelope_mode = 0,
- .agc = 0x99,
- .lnb_hv_pol = 1,
- .lnb_en_pol = 0,
-};
-
static u8 m88rs2000_inittab[] = {
DEMOD_WRITE, 0x9a, 0x30,
DEMOD_WRITE, 0x00, 0x01,
@@ -1509,7 +1498,8 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
u8 ibuf[] = { 0 };
struct i2c_adapter *i2c_adapter;
struct i2c_client *client;
- struct i2c_board_info info;
+ struct i2c_board_info board_info;
+ struct m88ds3103_platform_data m88ds3103_pdata = {};
struct ts2020_config ts2020_config = {};
if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
@@ -1542,22 +1532,44 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 1, 0) < 0)
err("command 0x51 transfer failed.");
- memset(&info, 0, sizeof(struct i2c_board_info));
-
- adap->fe_adap[0].fe = dvb_attach(m88ds3103_attach,
- &tt_s2_4600_m88ds3103_config,
- &d->i2c_adap,
- &i2c_adapter);
- if (adap->fe_adap[0].fe == NULL)
+ /* attach demod */
+ m88ds3103_pdata.clk = 27000000;
+ m88ds3103_pdata.i2c_wr_max = 33;
+ m88ds3103_pdata.ts_mode = M88DS3103_TS_CI;
+ m88ds3103_pdata.ts_clk = 16000;
+ m88ds3103_pdata.ts_clk_pol = 0;
+ m88ds3103_pdata.spec_inv = 0;
+ m88ds3103_pdata.agc = 0x99;
+ m88ds3103_pdata.agc_inv = 0;
+ m88ds3103_pdata.clk_out = M88DS3103_CLOCK_OUT_ENABLED;
+ m88ds3103_pdata.envelope_mode = 0;
+ m88ds3103_pdata.lnb_hv_pol = 1;
+ m88ds3103_pdata.lnb_en_pol = 0;
+ memset(&board_info, 0, sizeof(board_info));
+ strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
+ board_info.addr = 0x68;
+ board_info.platform_data = &m88ds3103_pdata;
+ request_module("m88ds3103");
+ client = i2c_new_device(&d->i2c_adap, &board_info);
+ if (client == NULL || client->dev.driver == NULL)
return -ENODEV;
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ return -ENODEV;
+ }
+ adap->fe_adap[0].fe = m88ds3103_pdata.get_dvb_frontend(client);
+ i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client);
+
+ state->i2c_client_demod = client;
/* attach tuner */
ts2020_config.fe = adap->fe_adap[0].fe;
- strlcpy(info.type, "ts2022", I2C_NAME_SIZE);
- info.addr = 0x60;
- info.platform_data = &ts2020_config;
+ memset(&board_info, 0, sizeof(board_info));
+ strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE);
+ board_info.addr = 0x60;
+ board_info.platform_data = &ts2020_config;
request_module("ts2020");
- client = i2c_new_device(i2c_adapter, &info);
+ client = i2c_new_device(i2c_adapter, &board_info);
if (client == NULL || client->dev.driver == NULL) {
dvb_frontend_detach(adap->fe_adap[0].fe);
@@ -1688,6 +1700,8 @@ enum dw2102_table_entry {
TECHNOTREND_S2_4600,
TEVII_S482_1,
TEVII_S482_2,
+ TERRATEC_CINERGY_S2_BOX,
+ TEVII_S662
};
static struct usb_device_id dw2102_table[] = {
@@ -1702,19 +1716,21 @@ static struct usb_device_id dw2102_table[] = {
[TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
[PROF_7500] = {USB_DEVICE(0x3034, 0x7500)},
[GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)},
- [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)},
+ [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R1)},
[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
[TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)},
[TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)},
- [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)},
+ [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R2)},
[GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)},
[GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)},
[TECHNOTREND_S2_4600] = {USB_DEVICE(USB_VID_TECHNOTREND,
USB_PID_TECHNOTREND_CONNECT_S2_4600)},
[TEVII_S482_1] = {USB_DEVICE(0x9022, 0xd483)},
[TEVII_S482_2] = {USB_DEVICE(0x9022, 0xd484)},
+ [TERRATEC_CINERGY_S2_BOX] = {USB_DEVICE(USB_VID_TERRATEC, 0x0105)},
+ [TEVII_S662] = {USB_DEVICE(0x9022, USB_PID_TEVII_S662)},
{ }
};
@@ -2232,7 +2248,7 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = {
} },
}
},
- .num_device_descs = 3,
+ .num_device_descs = 5,
.devices = {
{ "TechnoTrend TT-connect S2-4600",
{ &dw2102_table[TECHNOTREND_S2_4600], NULL },
@@ -2246,6 +2262,14 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = {
{ &dw2102_table[TEVII_S482_2], NULL },
{ NULL },
},
+ { "Terratec Cinergy S2 USB BOX",
+ { &dw2102_table[TERRATEC_CINERGY_S2_BOX], NULL },
+ { NULL },
+ },
+ { "TeVii S662",
+ { &dw2102_table[TEVII_S662], NULL },
+ { NULL },
+ },
}
};
@@ -2344,6 +2368,13 @@ static void dw2102_disconnect(struct usb_interface *intf)
i2c_unregister_device(client);
}
+ /* remove I2C client for demodulator */
+ client = st->i2c_client_demod;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
dvb_usb_device_exit(intf);
}
@@ -2359,10 +2390,10 @@ module_usb_driver(dw2102_driver);
MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
" DVB-C 3101 USB2.0,"
- " TeVii S600, S630, S650, S660, S480, S421, S632"
- " Prof 1100, 7500 USB2.0,"
+ " TeVii S421, S480, S482, S600, S630, S632, S650,"
+ " TeVii S660, S662, Prof 1100, 7500 USB2.0,"
" Geniatech SU3000, T220,"
- " TechnoTrend S2-4600 devices");
+ " TechnoTrend S2-4600, Terratec Cinergy S2 devices");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(DW2101_FIRMWARE);
diff --git a/drivers/media/usb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c
index 8ec92fbeabad..979f05b4b87c 100644
--- a/drivers/media/usb/dvb-usb/friio-fe.c
+++ b/drivers/media/usb/dvb-usb/friio-fe.c
@@ -283,20 +283,6 @@ static int jdvbt90502_set_property(struct dvb_frontend *fe,
return r;
}
-static int jdvbt90502_get_frontend(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- p->inversion = INVERSION_AUTO;
- p->bandwidth_hz = 6000000;
- p->code_rate_HP = FEC_AUTO;
- p->code_rate_LP = FEC_AUTO;
- p->modulation = QAM_64;
- p->transmission_mode = TRANSMISSION_MODE_AUTO;
- p->guard_interval = GUARD_INTERVAL_AUTO;
- p->hierarchy = HIERARCHY_AUTO;
- return 0;
-}
-
static int jdvbt90502_set_frontend(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -312,8 +298,16 @@ static int jdvbt90502_set_frontend(struct dvb_frontend *fe)
deb_fe("%s: Freq:%d\n", __func__, p->frequency);
- /* for recovery from DTV_CLEAN */
- fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+ /* This driver only works on auto mode */
+ p->inversion = INVERSION_AUTO;
+ p->bandwidth_hz = 6000000;
+ p->code_rate_HP = FEC_AUTO;
+ p->code_rate_LP = FEC_AUTO;
+ p->modulation = QAM_64;
+ p->transmission_mode = TRANSMISSION_MODE_AUTO;
+ p->guard_interval = GUARD_INTERVAL_AUTO;
+ p->hierarchy = HIERARCHY_AUTO;
+ p->delivery_system = SYS_ISDBT;
ret = jdvbt90502_pll_set_freq(state, p->frequency);
if (ret) {
@@ -466,7 +460,6 @@ static struct dvb_frontend_ops jdvbt90502_ops = {
.set_property = jdvbt90502_set_property,
.set_frontend = jdvbt90502_set_frontend,
- .get_frontend = jdvbt90502_get_frontend,
.read_status = jdvbt90502_read_status,
.read_signal_strength = jdvbt90502_read_signal_strength,
diff --git a/drivers/media/usb/dvb-usb/nova-t-usb2.c b/drivers/media/usb/dvb-usb/nova-t-usb2.c
index 6c55384e2fca..fc7569e2728d 100644
--- a/drivers/media/usb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/usb/dvb-usb/nova-t-usb2.c
@@ -1,7 +1,7 @@
/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2
* DVB-T receiver.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* 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
@@ -227,7 +227,7 @@ static struct usb_driver nova_t_driver = {
module_usb_driver(nova_t_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index 6c3c47722955..d9f3262bf071 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -60,6 +60,8 @@ struct technisat_usb2_state {
u8 power_state;
u16 last_scan_code;
+
+ u8 buf[64];
};
/* debug print helpers */
@@ -220,19 +222,19 @@ enum technisat_usb2_led_state {
TECH_LED_UNDEFINED
};
-static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state)
+static int technisat_usb2_set_led(struct dvb_usb_device *d, int red,
+ enum technisat_usb2_led_state st)
{
+ struct technisat_usb2_state *state = d->priv;
+ u8 *led = state->buf;
int ret;
- u8 led[8] = {
- red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
- 0
- };
+ led[0] = red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST;
- if (disable_led_control && state != TECH_LED_OFF)
+ if (disable_led_control && st != TECH_LED_OFF)
return 0;
- switch (state) {
+ switch (st) {
case TECH_LED_ON:
led[1] = 0x82;
break;
@@ -263,7 +265,7 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni
red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
USB_TYPE_VENDOR | USB_DIR_OUT,
0, 0,
- led, sizeof(led), 500);
+ led, 8, 500);
mutex_unlock(&d->i2c_mutex);
return ret;
@@ -271,8 +273,11 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni
static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green)
{
+ struct technisat_usb2_state *state = d->priv;
+ u8 *b = state->buf;
int ret;
- u8 b = 0;
+
+ b[0] = 0;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
@@ -281,7 +286,7 @@ static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 gre
SET_LED_TIMER_DIVIDER_VENDOR_REQUEST,
USB_TYPE_VENDOR | USB_DIR_OUT,
(red << 8) | green, 0,
- &b, 1, 500);
+ b, 1, 500);
mutex_unlock(&d->i2c_mutex);
@@ -328,7 +333,11 @@ static int technisat_usb2_identify_state(struct usb_device *udev,
struct dvb_usb_device_description **desc, int *cold)
{
int ret;
- u8 version[3];
+ u8 *version;
+
+ version = kmalloc(3, GFP_KERNEL);
+ if (!version)
+ return -ENOMEM;
/* first select the interface */
if (usb_set_interface(udev, 0, 1) != 0)
@@ -342,7 +351,7 @@ static int technisat_usb2_identify_state(struct usb_device *udev,
GET_VERSION_INFO_VENDOR_REQUEST,
USB_TYPE_VENDOR | USB_DIR_IN,
0, 0,
- version, sizeof(version), 500);
+ version, 3, 500);
if (ret < 0)
*cold = 1;
@@ -351,6 +360,8 @@ static int technisat_usb2_identify_state(struct usb_device *udev,
*cold = 0;
}
+ kfree(version);
+
return 0;
}
@@ -512,7 +523,7 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
&a->dev->i2c_adap, STV090x_DEMODULATOR_0);
if (a->fe_adap[0].fe) {
- struct stv6110x_devctl *ctl;
+ const struct stv6110x_devctl *ctl;
ctl = dvb_attach(stv6110x_attach,
a->fe_adap[0].fe,
@@ -594,7 +605,9 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
static int technisat_usb2_get_ir(struct dvb_usb_device *d)
{
- u8 buf[62], *b;
+ struct technisat_usb2_state *state = d->priv;
+ u8 *buf = state->buf;
+ u8 *b;
int ret;
struct ir_raw_event ev;
@@ -620,7 +633,7 @@ static int technisat_usb2_get_ir(struct dvb_usb_device *d)
GET_IR_DATA_VENDOR_REQUEST,
USB_TYPE_VENDOR | USB_DIR_IN,
0x8080, 0,
- buf, sizeof(buf), 500);
+ buf, 62, 500);
unlock:
mutex_unlock(&d->i2c_mutex);
diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c
index f10717311e05..ecc207fbaf3c 100644
--- a/drivers/media/usb/dvb-usb/ttusb2.c
+++ b/drivers/media/usb/dvb-usb/ttusb2.c
@@ -820,7 +820,7 @@ static struct usb_driver ttusb2_driver = {
module_usb_driver(ttusb2_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/umt-010.c b/drivers/media/usb/dvb-usb/umt-010.c
index 9b042292e788..58ad5b4f856c 100644
--- a/drivers/media/usb/dvb-usb/umt-010.c
+++ b/drivers/media/usb/dvb-usb/umt-010.c
@@ -1,7 +1,7 @@
/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0
* DVB-T receiver.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* 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
@@ -145,7 +145,7 @@ static struct usb_driver umt_driver = {
module_usb_driver(umt_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/usb-urb.c b/drivers/media/usb/dvb-usb/usb-urb.c
index d62ee0f5a165..89173603be67 100644
--- a/drivers/media/usb/dvb-usb/usb-urb.c
+++ b/drivers/media/usb/dvb-usb/usb-urb.c
@@ -1,6 +1,6 @@
/* usb-urb.c is part of the DVB USB library.
*
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
* see dvb-usb-init.c for copyright information.
*
* This file keeps functions for initializing and handling the
diff --git a/drivers/media/usb/dvb-usb/vp702x-fe.c b/drivers/media/usb/dvb-usb/vp702x-fe.c
index d361a72ca0fa..27398c08c69d 100644
--- a/drivers/media/usb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/usb/dvb-usb/vp702x-fe.c
@@ -4,7 +4,7 @@
* Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
* Metzler Brothers Systementwicklung GbR
*
- * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
*
* Thanks to Twinhan who kindly provided hardware and information.
*
diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c
index ee1e19e36445..40de33de90a7 100644
--- a/drivers/media/usb/dvb-usb/vp702x.c
+++ b/drivers/media/usb/dvb-usb/vp702x.c
@@ -4,7 +4,7 @@
* Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
* Metzler Brothers Systementwicklung GbR
*
- * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
*
* Thanks to Twinhan who kindly provided hardware and information.
*
@@ -439,7 +439,7 @@ static struct usb_driver vp702x_usb_driver = {
module_usb_driver(vp702x_usb_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/vp7045-fe.c b/drivers/media/usb/dvb-usb/vp7045-fe.c
index e708afc6a57f..7765602ea658 100644
--- a/drivers/media/usb/dvb-usb/vp7045-fe.c
+++ b/drivers/media/usb/dvb-usb/vp7045-fe.c
@@ -1,7 +1,7 @@
/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0
* DVB-T receiver.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* Thanks to Twinhan who kindly provided hardware and information.
*
diff --git a/drivers/media/usb/dvb-usb/vp7045.c b/drivers/media/usb/dvb-usb/vp7045.c
index d750724132ee..13340af0d39c 100644
--- a/drivers/media/usb/dvb-usb/vp7045.c
+++ b/drivers/media/usb/dvb-usb/vp7045.c
@@ -2,7 +2,7 @@
* - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver
* - DigitalNow TinyUSB2 DVB-t receiver
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* Thanks to Twinhan who kindly provided hardware and information.
*
@@ -296,7 +296,7 @@ static struct usb_driver vp7045_usb_driver = {
module_usb_driver(vp7045_usb_driver);
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/vp7045.h b/drivers/media/usb/dvb-usb/vp7045.h
index cf5ec46f8bb1..66499932ca76 100644
--- a/drivers/media/usb/dvb-usb/vp7045.h
+++ b/drivers/media/usb/dvb-usb/vp7045.h
@@ -1,7 +1,7 @@
/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII
* USB2.0 DVB-T receiver.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* Thanks to Twinhan who kindly provided hardware and information.
*
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index b58acd3fcd99..72f3f4d50253 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -64,6 +64,8 @@ static int em28xx_initialize_mt9m111(struct em28xx *dev)
i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
&regs[i][0], 3);
+ /* FIXME: This won't be creating a sensor at the media graph */
+
return 0;
}
@@ -91,6 +93,8 @@ static int em28xx_initialize_mt9m001(struct em28xx *dev)
i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
&regs[i][0], 3);
+ /* FIXME: This won't be creating a sensor at the media graph */
+
return 0;
}
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index a1b6ef5894a6..930e3e3fc948 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -32,11 +32,12 @@
#include <media/tuner.h>
#include <media/drv-intf/msp3400.h>
#include <media/i2c/saa7115.h>
-#include <media/i2c/tvp5150.h>
+#include <dt-bindings/media/tvp5150.h>
#include <media/i2c/tvaudio.h>
#include <media/i2c-addr.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
+#include <sound/ac97_codec.h>
#include "em28xx.h"
@@ -560,6 +561,16 @@ static struct em28xx_led pctv_80e_leds[] = {
{-1, 0, 0, 0},
};
+static struct em28xx_led terratec_grabby_leds[] = {
+ {
+ .role = EM28XX_LED_ANALOG_CAPTURING,
+ .gpio_reg = EM2820_R08_GPIO_CTRL,
+ .gpio_mask = EM_GPIO_3,
+ .inverted = 1,
+ },
+ {-1, 0, 0, 0},
+};
+
/*
* Board definitions
*/
@@ -570,7 +581,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.is_webcam = 1,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = 0,
.amux = EM28XX_AMUX_VIDEO,
.gpio = silvercrest_reg_seq,
@@ -583,7 +594,7 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA711X,
.tuner_type = TUNER_ABSENT,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -605,7 +616,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.is_webcam = 1,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = 0,
.amux = EM28XX_AMUX_VIDEO,
} },
@@ -616,7 +627,7 @@ struct em28xx_board em28xx_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_SAA711X,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -635,7 +646,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_LINE_IN,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -655,7 +666,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -675,7 +686,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -715,7 +726,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_LINE_IN,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -735,7 +746,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_LINE_IN,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -755,7 +766,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -775,7 +786,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -800,7 +811,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE4,
.amux = EM28XX_AMUX_AUX,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE5,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -819,7 +830,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.is_webcam = 1,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = 0,
.amux = EM28XX_AMUX_VIDEO,
} },
@@ -829,7 +840,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.is_webcam = 1,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = 0,
.amux = EM28XX_AMUX_VIDEO,
.gpio = silvercrest_reg_seq,
@@ -848,7 +859,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_LINE_IN,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
}, {
@@ -863,7 +874,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT, /* Capture only device */
.decoder = EM28XX_SAA711X,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -879,7 +890,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.is_webcam = 1,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = 0,
.amux = EM28XX_AMUX_VIDEO,
} },
@@ -889,7 +900,7 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA711X,
.tuner_type = TUNER_ABSENT, /* Capture only device */
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -909,7 +920,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -930,7 +941,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -952,7 +963,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -974,7 +985,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -992,7 +1003,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1006,7 +1017,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT, /* Capture only device */
.decoder = EM28XX_TVP5150,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1029,7 +1040,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
.gpio = pinnacle_hybrid_pro_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = pinnacle_hybrid_pro_analog,
@@ -1100,7 +1111,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = terratec_cinergy_USB_XS_FR_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = terratec_cinergy_USB_XS_FR_analog,
@@ -1186,7 +1197,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -1213,7 +1224,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -1239,7 +1250,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -1265,7 +1276,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -1291,7 +1302,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -1317,7 +1328,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -1343,7 +1354,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = default_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = default_analog,
@@ -1368,7 +1379,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -1392,7 +1403,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE4,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1413,7 +1424,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1428,7 +1439,7 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA711X,
.tuner_type = TUNER_ABSENT, /* capture only board */
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1443,7 +1454,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT, /* Capture-only board */
.decoder = EM28XX_SAA711X,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = vc211a_enable,
@@ -1465,7 +1476,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1485,7 +1496,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1500,7 +1511,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT, /* capture only board */
.decoder = EM28XX_SAA711X,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1520,7 +1531,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1541,7 +1552,7 @@ struct em28xx_board em28xx_boards[] = {
.aout = EM28XX_AOUT_MONO | /* I2S */
EM28XX_AOUT_MASTER, /* Line out pin */
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1555,6 +1566,7 @@ struct em28xx_board em28xx_boards[] = {
.buttons = std_snapshot_button,
.tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_YMEC_TVF_5533MF,
+ .tuner_addr = 0x60,
.decoder = EM28XX_SAA711X,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1563,7 +1575,7 @@ struct em28xx_board em28xx_boards[] = {
.aout = EM28XX_AOUT_MONO | /* I2S */
EM28XX_AOUT_MASTER, /* Line out pin */
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1581,7 +1593,7 @@ struct em28xx_board em28xx_boards[] = {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
} },
},
@@ -1610,7 +1622,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = em2880_msi_digivox_ad_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = em2880_msi_digivox_ad_analog,
@@ -1633,7 +1645,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = em2880_msi_digivox_ad_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = em2880_msi_digivox_ad_analog,
@@ -1654,7 +1666,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1677,7 +1689,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = default_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = default_analog,
@@ -1708,7 +1720,7 @@ struct em28xx_board em28xx_boards[] = {
.gpio = em2882_kworld_315u_analog,
.aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = em2882_kworld_315u_analog1,
@@ -1735,7 +1747,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = default_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = default_analog,
@@ -1758,7 +1770,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = default_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = default_analog,
@@ -1782,7 +1794,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = pinnacle_hybrid_pro_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = pinnacle_hybrid_pro_analog,
@@ -1808,7 +1820,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -1834,7 +1846,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1859,7 +1871,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = hauppauge_wintv_hvr_900_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = hauppauge_wintv_hvr_900_analog,
@@ -1904,7 +1916,7 @@ struct em28xx_board em28xx_boards[] = {
.gpio = kworld_330u_analog,
.aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = kworld_330u_analog,
@@ -1951,7 +1963,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1970,7 +1982,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.decoder = EM28XX_SAA711X,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -1990,7 +2002,7 @@ struct em28xx_board em28xx_boards[] = {
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
}, { /* Composite has not been tested yet */
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_VIDEO,
}, { /* S-video has not been tested yet */
@@ -2006,7 +2018,7 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA711X,
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -2014,6 +2026,8 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_SVIDEO3,
.amux = EM28XX_AMUX_LINE_IN,
} },
+ .buttons = std_snapshot_button,
+ .leds = terratec_grabby_leds,
},
[EM2860_BOARD_TERRATEC_AV350] = {
.name = "Terratec AV350",
@@ -2023,7 +2037,7 @@ struct em28xx_board em28xx_boards[] = {
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
.mute_gpio = terratec_av350_mute_gpio,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AUDIO_SRC_LINE,
.gpio = terratec_av350_unmute_gpio,
@@ -2041,7 +2055,7 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA711X,
.tuner_type = TUNER_ABSENT, /* Capture only device */
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -2067,7 +2081,7 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
.gpio = evga_indtube_analog,
}, {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
.gpio = evga_indtube_analog,
@@ -2125,7 +2139,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.decoder = EM28XX_SAA711X,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = SAA7115_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -2238,7 +2252,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.is_webcam = 1,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.amux = EM28XX_AMUX_VIDEO,
.gpio = speedlink_vad_laplace_reg_seq,
} },
@@ -2272,7 +2286,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT, /* Capture only device */
.decoder = EM28XX_TVP5150,
.input = { {
- .type = EM28XX_VMUX_COMPOSITE1,
+ .type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
}, {
@@ -2550,6 +2564,36 @@ static inline void em28xx_set_model(struct em28xx *dev)
dev->def_i2c_bus = dev->board.def_i2c_bus;
}
+/* Wait until AC97_RESET reports the expected value reliably before proceeding.
+ * We also check that two unrelated registers accesses don't return the same
+ * value to avoid premature return.
+ * This procedure helps ensuring AC97 register accesses are reliable.
+ */
+static int em28xx_wait_until_ac97_features_equals(struct em28xx *dev,
+ int expected_feat)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(2000);
+ int feat, powerdown;
+
+ while (time_is_after_jiffies(timeout)) {
+ feat = em28xx_read_ac97(dev, AC97_RESET);
+ if (feat < 0)
+ return feat;
+
+ powerdown = em28xx_read_ac97(dev, AC97_POWERDOWN);
+ if (powerdown < 0)
+ return powerdown;
+
+ if (feat == expected_feat && feat != powerdown)
+ return 0;
+
+ msleep(50);
+ }
+
+ em28xx_warn("AC97 registers access is not reliable !\n");
+ return -ETIMEDOUT;
+}
+
/* Since em28xx_pre_card_setup() requires a proper dev->model,
* this won't work for boards with generic PCI IDs
*/
@@ -2655,6 +2699,13 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
msleep(70);
break;
+
+ case EM2860_BOARD_TERRATEC_GRABBY:
+ /* HACK?: Ensure AC97 register reading is reliable before
+ * proceeding. In practice, this will wait about 1.6 seconds.
+ */
+ em28xx_wait_until_ac97_features_equals(dev, 0x6a90);
+ break;
}
em28xx_gpio_set(dev, dev->board.tuner_gpio);
@@ -3012,6 +3063,41 @@ static void flush_request_modules(struct em28xx *dev)
flush_work(&dev->request_module_wk);
}
+static int em28xx_media_device_init(struct em28xx *dev,
+ struct usb_device *udev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev;
+
+ mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return -ENOMEM;
+
+ if (udev->product)
+ media_device_usb_init(mdev, udev, udev->product);
+ else if (udev->manufacturer)
+ media_device_usb_init(mdev, udev, udev->manufacturer);
+ else
+ media_device_usb_init(mdev, udev, dev->name);
+
+ dev->media_dev = mdev;
+#endif
+ return 0;
+}
+
+static void em28xx_unregister_media_device(struct em28xx *dev)
+{
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (dev->media_dev) {
+ media_device_unregister(dev->media_dev);
+ media_device_cleanup(dev->media_dev);
+ kfree(dev->media_dev);
+ dev->media_dev = NULL;
+ }
+#endif
+}
+
/*
* em28xx_release_resources()
* unregisters the v4l2,i2c and usb devices
@@ -3023,6 +3109,8 @@ static void em28xx_release_resources(struct em28xx *dev)
mutex_lock(&dev->lock);
+ em28xx_unregister_media_device(dev);
+
if (dev->def_i2c_bus)
em28xx_i2c_unregister(dev, 1);
em28xx_i2c_unregister(dev, 0);
@@ -3167,6 +3255,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
*/
snprintf(dev->name, sizeof(dev->name), "%s #%d", chip_name, dev->devno);
+ em28xx_media_device_init(dev, udev);
+
if (dev->is_audio_only) {
retval = em28xx_audio_setup(dev);
if (retval)
@@ -3467,7 +3557,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
- /* allocate device struct */
+ /* allocate device struct and check if the device is a webcam */
mutex_init(&dev->lock);
retval = em28xx_init_dev(dev, udev, interface, nr);
if (retval) {
@@ -3483,6 +3573,15 @@ static int em28xx_usb_probe(struct usb_interface *interface,
try_bulk = usb_xfer_mode > 0;
}
+ /* Disable V4L2 if the device doesn't have a decoder */
+ if (has_video &&
+ dev->board.decoder == EM28XX_NODECODER && !dev->board.is_webcam) {
+ printk(DRIVER_NAME
+ ": Currently, V4L2 is not supported on this model\n");
+ has_video = false;
+ dev->has_video = false;
+ }
+
/* Select USB transfer types to use */
if (has_video) {
if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
@@ -3501,9 +3600,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
request_modules(dev);
- /* Should be the last thing to do, to avoid newer udev's to
- open the device before fully initializing it
+ /*
+ * Do it at the end, to reduce dynamic configuration changes during
+ * the device init. Yet, as request_modules() can be async, the
+ * topology will likely change after the load of the em28xx subdrivers.
*/
+#ifdef CONFIG_MEDIA_CONTROLLER
+ retval = media_device_register(dev->media_dev);
+#endif
return 0;
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index bf5c24467c65..5d209c7c54d5 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -905,6 +905,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
struct em28xx *dev, struct device *device)
{
int result;
+ bool create_rf_connector = false;
mutex_init(&dvb->lock);
@@ -916,6 +917,9 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
dev->name, result);
goto fail_adapter;
}
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ dvb->adapter.mdev = dev->media_dev;
+#endif
/* Ensure all frontends negotiate bus access */
dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
@@ -994,8 +998,19 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
/* register network adapter */
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+
+ /* If the analog part won't create RF connectors, DVB will do it */
+ if (!dev->has_video || (dev->tuner_type == TUNER_ABSENT))
+ create_rf_connector = true;
+
+ result = dvb_create_media_graph(&dvb->adapter, create_rf_connector);
+ if (result < 0)
+ goto fail_create_graph;
+
return 0;
+fail_create_graph:
+ dvb_net_release(&dvb->net);
fail_fe_conn:
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
fail_fe_mem:
@@ -1656,6 +1671,9 @@ static int em28xx_dvb_init(struct em28xx *dev)
memset(&si2157_config, 0, sizeof(si2157_config));
si2157_config.fe = dvb->fe[0];
si2157_config.if_port = 1;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+#endif
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
@@ -1717,6 +1735,9 @@ static int em28xx_dvb_init(struct em28xx *dev)
memset(&si2157_config, 0, sizeof(si2157_config));
si2157_config.fe = dvb->fe[0];
si2157_config.if_port = 0;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+#endif
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2146", I2C_NAME_SIZE);
info.addr = 0x60;
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 0e86ff423c49..44834b2eff55 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -196,7 +196,6 @@ static void em28xx_wake_i2c(struct em28xx *dev)
v4l2_device_call_all(v4l2_dev, 0, core, reset, 0);
v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
INPUT(dev->ctl_input)->vmux, 0, 0);
- v4l2_device_call_all(v4l2_dev, 0, video, s_stream, 0);
}
static int em28xx_colorlevels_set_default(struct em28xx *dev)
@@ -867,6 +866,147 @@ static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type)
em28xx_videodbg("res: put %d\n", res_type);
}
+static void em28xx_v4l2_media_release(struct em28xx *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ int i;
+
+ for (i = 0; i < MAX_EM28XX_INPUT; i++) {
+ if (!INPUT(i)->type)
+ return;
+ media_device_unregister_entity(&dev->input_ent[i]);
+ }
+#endif
+}
+
+/*
+ * Media Controller helper functions
+ */
+
+static int em28xx_enable_analog_tuner(struct em28xx *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev = dev->media_dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ struct media_entity *source;
+ struct media_link *link, *found_link = NULL;
+ int ret, active_links = 0;
+
+ if (!mdev || !v4l2->decoder)
+ return 0;
+
+ /*
+ * This will find the tuner that is connected into the decoder.
+ * Technically, this is not 100% correct, as the device may be
+ * using an analog input instead of the tuner. However, as we can't
+ * do DVB streaming while the DMA engine is being used for V4L2,
+ * this should be enough for the actual needs.
+ */
+ list_for_each_entry(link, &v4l2->decoder->links, list) {
+ if (link->sink->entity == v4l2->decoder) {
+ found_link = link;
+ if (link->flags & MEDIA_LNK_FL_ENABLED)
+ active_links++;
+ break;
+ }
+ }
+
+ if (active_links == 1 || !found_link)
+ return 0;
+
+ source = found_link->source->entity;
+ list_for_each_entry(link, &source->links, list) {
+ struct media_entity *sink;
+ int flags = 0;
+
+ sink = link->sink->entity;
+
+ if (sink == v4l2->decoder)
+ flags = MEDIA_LNK_FL_ENABLED;
+
+ ret = media_entity_setup_link(link, flags);
+ if (ret) {
+ pr_err("Couldn't change link %s->%s to %s. Error %d\n",
+ source->name, sink->name,
+ flags ? "enabled" : "disabled",
+ ret);
+ return ret;
+ } else
+ em28xx_videodbg("link %s->%s was %s\n",
+ source->name, sink->name,
+ flags ? "ENABLED" : "disabled");
+ }
+#endif
+ return 0;
+}
+
+static const char * const iname[] = {
+ [EM28XX_VMUX_COMPOSITE] = "Composite",
+ [EM28XX_VMUX_SVIDEO] = "S-Video",
+ [EM28XX_VMUX_TELEVISION] = "Television",
+ [EM28XX_RADIO] = "Radio",
+};
+
+static void em28xx_v4l2_create_entities(struct em28xx *dev)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ int ret, i;
+
+ /* Initialize Video, VBI and Radio pads */
+ v4l2->video_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&v4l2->vdev.entity, 1, &v4l2->video_pad);
+ if (ret < 0)
+ pr_err("failed to initialize video media entity!\n");
+
+ if (em28xx_vbi_supported(dev)) {
+ v4l2->vbi_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&v4l2->vbi_dev.entity, 1,
+ &v4l2->vbi_pad);
+ if (ret < 0)
+ pr_err("failed to initialize vbi media entity!\n");
+ }
+
+ /* Webcams don't have input connectors */
+ if (dev->board.is_webcam)
+ return;
+
+ /* Create entities for each input connector */
+ for (i = 0; i < MAX_EM28XX_INPUT; i++) {
+ struct media_entity *ent = &dev->input_ent[i];
+
+ if (!INPUT(i)->type)
+ break;
+
+ ent->name = iname[INPUT(i)->type];
+ ent->flags = MEDIA_ENT_FL_CONNECTOR;
+ dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ switch (INPUT(i)->type) {
+ case EM28XX_VMUX_COMPOSITE:
+ ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
+ break;
+ case EM28XX_VMUX_SVIDEO:
+ ent->function = MEDIA_ENT_F_CONN_SVIDEO;
+ break;
+ default: /* EM28XX_VMUX_TELEVISION or EM28XX_RADIO */
+ if (dev->tuner_type != TUNER_ABSENT)
+ ent->function = MEDIA_ENT_F_CONN_RF;
+ break;
+ }
+
+ ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
+ if (ret < 0)
+ pr_err("failed to initialize input pad[%d]!\n", i);
+
+ ret = media_device_register_entity(dev->media_dev, ent);
+ if (ret < 0)
+ pr_err("failed to register input entity %d!\n", i);
+ }
+#endif
+}
+
+
/* ------------------------------------------------------------------
Videobuf2 operations
------------------------------------------------------------------*/
@@ -884,6 +1024,9 @@ static int queue_setup(struct vb2_queue *vq,
return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
sizes[0] = size;
+
+ em28xx_enable_analog_tuner(dev);
+
return 0;
}
@@ -962,6 +1105,9 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
f.type = V4L2_TUNER_ANALOG_TV;
v4l2_device_call_all(&v4l2->v4l2_dev,
0, tuner, s_frequency, &f);
+
+ /* Enable video stream at TV decoder */
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_stream, 1);
}
v4l2->streaming_users++;
@@ -981,6 +1127,9 @@ static void em28xx_stop_streaming(struct vb2_queue *vq)
res_free(dev, vq->type);
if (v4l2->streaming_users-- == 1) {
+ /* Disable video stream at TV decoder */
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_stream, 0);
+
/* Last active user, so shutdown all the URBS */
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
}
@@ -1013,6 +1162,9 @@ void em28xx_stop_vbi_streaming(struct vb2_queue *vq)
res_free(dev, vq->type);
if (v4l2->streaming_users-- == 1) {
+ /* Disable video stream at TV decoder */
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_stream, 0);
+
/* Last active user, so shutdown all the URBS */
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
}
@@ -1224,6 +1376,12 @@ static void scale_to_size(struct em28xx *dev,
*width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
*height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+ /* Don't let width or height to be zero */
+ if (*width < 1)
+ *width = 1;
+ if (*height < 1)
+ *height = 1;
}
/* ------------------------------------------------------------------
@@ -1299,6 +1457,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
1, 0);
}
+ /* Avoid division by zero at size_to_scale */
+ if (width < 1)
+ width = 1;
+ if (height < 1)
+ height = 1;
size_to_scale(dev, width, height, &hscale, &vscale);
scale_to_size(dev, hscale, vscale, &width, &height);
@@ -1434,18 +1597,6 @@ static int vidioc_s_parm(struct file *file, void *priv,
0, video, s_parm, p);
}
-static const char *iname[] = {
- [EM28XX_VMUX_COMPOSITE1] = "Composite1",
- [EM28XX_VMUX_COMPOSITE2] = "Composite2",
- [EM28XX_VMUX_COMPOSITE3] = "Composite3",
- [EM28XX_VMUX_COMPOSITE4] = "Composite4",
- [EM28XX_VMUX_SVIDEO] = "S-Video",
- [EM28XX_VMUX_TELEVISION] = "Television",
- [EM28XX_VMUX_CABLE] = "Cable TV",
- [EM28XX_VMUX_DVB] = "DVB",
- [EM28XX_VMUX_DEBUG] = "for debug only",
-};
-
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
@@ -1463,8 +1614,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
strcpy(i->name, iname[INPUT(n)->type]);
- if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
- (EM28XX_VMUX_CABLE == INPUT(n)->type))
+ if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type))
i->type = V4L2_INPUT_TYPE_TUNER;
i->std = dev->v4l2->vdev.tvnorms;
@@ -1961,6 +2111,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
+ em28xx_v4l2_media_release(dev);
+
if (video_is_registered(&v4l2->radio_dev)) {
em28xx_info("V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->radio_dev));
@@ -2284,6 +2436,9 @@ static int em28xx_v4l2_init(struct em28xx *dev)
v4l2->dev = dev;
dev->v4l2 = v4l2;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ v4l2->v4l2_dev.mdev = dev->media_dev;
+#endif
ret = v4l2_device_register(&dev->udev->dev, &v4l2->v4l2_dev);
if (ret < 0) {
em28xx_errdev("Call to v4l2_device_register() failed!\n");
@@ -2556,6 +2711,18 @@ static int em28xx_v4l2_init(struct em28xx *dev)
video_device_node_name(&v4l2->radio_dev));
}
+ /* Init entities at the Media Controller */
+ em28xx_v4l2_create_entities(dev);
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ ret = v4l2_mc_create_media_graph(dev->media_dev);
+ if (ret) {
+ em28xx_errdev("failed to create media graph\n");
+ em28xx_v4l2_media_release(dev);
+ goto unregister_dev;
+ }
+#endif
+
em28xx_info("V4L2 video device registered as %s\n",
video_device_node_name(&v4l2->vdev));
@@ -2577,6 +2744,22 @@ static int em28xx_v4l2_init(struct em28xx *dev)
return 0;
unregister_dev:
+ if (video_is_registered(&v4l2->radio_dev)) {
+ em28xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(&v4l2->radio_dev));
+ video_unregister_device(&v4l2->radio_dev);
+ }
+ if (video_is_registered(&v4l2->vbi_dev)) {
+ em28xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(&v4l2->vbi_dev));
+ video_unregister_device(&v4l2->vbi_dev);
+ }
+ if (video_is_registered(&v4l2->vdev)) {
+ em28xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(&v4l2->vdev));
+ video_unregister_device(&v4l2->vdev);
+ }
+
v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
v4l2_device_unregister(&v4l2->v4l2_dev);
err:
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 8ff066c977d9..267444961775 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -26,7 +26,7 @@
#ifndef _EM28XX_H
#define _EM28XX_H
-#define EM28XX_VERSION "0.2.1"
+#define EM28XX_VERSION "0.2.2"
#define DRIVER_DESC "Empia em28xx device driver"
#include <linux/workqueue.h>
@@ -291,15 +291,9 @@ struct em28xx_dmaqueue {
#define MAX_EM28XX_INPUT 4
enum enum28xx_itype {
- EM28XX_VMUX_COMPOSITE1 = 1,
- EM28XX_VMUX_COMPOSITE2,
- EM28XX_VMUX_COMPOSITE3,
- EM28XX_VMUX_COMPOSITE4,
+ EM28XX_VMUX_COMPOSITE = 1,
EM28XX_VMUX_SVIDEO,
EM28XX_VMUX_TELEVISION,
- EM28XX_VMUX_CABLE,
- EM28XX_VMUX_DVB,
- EM28XX_VMUX_DEBUG,
EM28XX_RADIO,
};
@@ -558,6 +552,11 @@ struct em28xx_v4l2 {
bool top_field;
int vbi_read;
unsigned int field_count;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_pad video_pad, vbi_pad;
+ struct media_entity *decoder;
+#endif
};
struct em28xx_audio {
@@ -718,6 +717,12 @@ struct em28xx {
/* Snapshot button input device */
char snapshot_button_path[30]; /* path of the input dev */
struct input_dev *sbutton_input_dev;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *media_dev;
+ struct media_entity input_ent[MAX_EM28XX_INPUT];
+ struct media_pad input_pad[MAX_EM28XX_INPUT];
+#endif
};
#define kref_to_dev(d) container_of(d, struct em28xx, ref)
diff --git a/drivers/media/usb/go7007/go7007-priv.h b/drivers/media/usb/go7007/go7007-priv.h
index 745185eb060b..bebee8ca9981 100644
--- a/drivers/media/usb/go7007/go7007-priv.h
+++ b/drivers/media/usb/go7007/go7007-priv.h
@@ -250,7 +250,7 @@ struct go7007 {
struct i2c_adapter i2c_adapter;
/* HPI driver */
- struct go7007_hpi_ops *hpi_ops;
+ const struct go7007_hpi_ops *hpi_ops;
void *hpi_context;
int interrupt_available;
wait_queue_head_t interrupt_waitq;
diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c
index 3dbf14c85c5c..14d3f8c1ce4a 100644
--- a/drivers/media/usb/go7007/go7007-usb.c
+++ b/drivers/media/usb/go7007/go7007-usb.c
@@ -932,7 +932,7 @@ static void go7007_usb_release(struct go7007 *go)
kfree(go->hpi_context);
}
-static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
+static const struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
.interface_reset = go7007_usb_interface_reset,
.write_interrupt = go7007_usb_ezusb_write_interrupt,
.read_interrupt = go7007_usb_read_interrupt,
@@ -942,7 +942,7 @@ static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
.release = go7007_usb_release,
};
-static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
+static const struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
.interface_reset = go7007_usb_interface_reset,
.write_interrupt = go7007_usb_onboard_write_interrupt,
.read_interrupt = go7007_usb_read_interrupt,
diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c
index c95f32a0c02b..965372a5ff2f 100644
--- a/drivers/media/usb/gspca/ov519.c
+++ b/drivers/media/usb/gspca/ov519.c
@@ -360,40 +360,6 @@ static const struct v4l2_pix_format ov511_sif_mode[] = {
.priv = 0},
};
-static const struct v4l2_pix_format ovfx2_vga_mode[] = {
- {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 320,
- .sizeimage = 320 * 240,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1},
- {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 640,
- .sizeimage = 640 * 480,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
-};
-static const struct v4l2_pix_format ovfx2_cif_mode[] = {
- {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 160,
- .sizeimage = 160 * 120,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 3},
- {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 176,
- .sizeimage = 176 * 144,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1},
- {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 320,
- .sizeimage = 320 * 240,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2},
- {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 352,
- .sizeimage = 352 * 288,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
-};
static const struct v4l2_pix_format ovfx2_ov2610_mode[] = {
{800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 800,
@@ -2042,6 +2008,9 @@ static void reg_w(struct sd *sd, u16 index, u16 value)
if (sd->gspca_dev.usb_err < 0)
return;
+ /* Avoid things going to fast for the bridge with a xhci host */
+ udelay(150);
+
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
@@ -2103,6 +2072,8 @@ static int reg_r(struct sd *sd, u16 index)
req = 1;
}
+ /* Avoid things going to fast for the bridge with a xhci host */
+ udelay(150);
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
req,
@@ -2131,6 +2102,8 @@ static int reg_r8(struct sd *sd,
if (sd->gspca_dev.usb_err < 0)
return -1;
+ /* Avoid things going to fast for the bridge with a xhci host */
+ udelay(150);
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
1, /* REQ_IO */
@@ -2187,6 +2160,8 @@ static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
*((__le32 *) sd->gspca_dev.usb_buf) = __cpu_to_le32(value);
+ /* Avoid things going to fast for the bridge with a xhci host */
+ udelay(150);
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0),
1 /* REG_IO */,
diff --git a/drivers/media/usb/gspca/touptek.c b/drivers/media/usb/gspca/touptek.c
index 7bac6bc96063..b8af4370d27c 100644
--- a/drivers/media/usb/gspca/touptek.c
+++ b/drivers/media/usb/gspca/touptek.c
@@ -203,7 +203,7 @@ static int val_reply(struct gspca_dev *gspca_dev, const char *reply, int rc)
return -EIO;
}
if (reply[0] != 0x08) {
- PERR("Bad reply 0x%02X", reply[0]);
+ PERR("Bad reply 0x%02x", (int)reply[0]);
return -EIO;
}
return 0;
@@ -211,7 +211,7 @@ static int val_reply(struct gspca_dev *gspca_dev, const char *reply, int rc)
static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
{
- char buff[1];
+ char *buff = gspca_dev->usb_buf;
int rc;
PDEBUG(D_USBO,
@@ -219,7 +219,7 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
value, index);
rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0),
0x0B, 0xC0, value, index, buff, 1, 500);
- PDEBUG(D_USBO, "rc=%d, ret={0x%02X}", rc, buff[0]);
+ PDEBUG(D_USBO, "rc=%d, ret={0x%02x}", rc, (int)buff[0]);
if (rc < 0) {
PERR("Failed reg_w(0x0B, 0xC0, 0x%04X, 0x%04X) w/ rc %d\n",
value, index, rc);
@@ -438,7 +438,7 @@ static void configure_encrypted(struct gspca_dev *gspca_dev)
static int configure(struct gspca_dev *gspca_dev)
{
int rc;
- uint8_t buff[4];
+ char *buff = gspca_dev->usb_buf;
PDEBUG(D_STREAM, "configure()\n");
diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c
index fb9fe2ef3a6f..896f1b2b9179 100644
--- a/drivers/media/usb/gspca/w996Xcf.c
+++ b/drivers/media/usb/gspca/w996Xcf.c
@@ -79,6 +79,8 @@ static void w9968cf_write_fsb(struct sd *sd, u16* data)
value = *data++;
memcpy(sd->gspca_dev.usb_buf, data, 6);
+ /* Avoid things going to fast for the bridge with a xhci host */
+ udelay(150);
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
value, 0x06, sd->gspca_dev.usb_buf, 6, 500);
@@ -99,6 +101,9 @@ static void w9968cf_write_sb(struct sd *sd, u16 value)
if (sd->gspca_dev.usb_err < 0)
return;
+ /* Avoid things going to fast for the bridge with a xhci host */
+ udelay(150);
+
/* We don't use reg_w here, as that would cause all writes when
bitbanging i2c to be logged, making the logs impossible to read */
ret = usb_control_msg(sd->gspca_dev.dev,
@@ -126,6 +131,9 @@ static int w9968cf_read_sb(struct sd *sd)
if (sd->gspca_dev.usb_err < 0)
return -1;
+ /* Avoid things going to fast for the bridge with a xhci host */
+ udelay(150);
+
/* We don't use reg_r here, as the w9968cf is special and has 16
bit registers instead of 8 bit */
ret = usb_control_msg(sd->gspca_dev.dev,
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 3fc64197b4e6..08f0ca7aa012 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -273,7 +273,9 @@ static int hdpvr_probe(struct usb_interface *interface,
struct hdpvr_device *dev;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
+#if IS_ENABLED(CONFIG_I2C)
struct i2c_client *client;
+#endif
size_t buffer_size;
int i;
int retval = -ENOMEM;
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 7dee22deebf3..ba7f02270c83 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -462,10 +462,8 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
}
if (wait_event_interruptible(dev->wait_data,
- buf->status == BUFSTAT_READY)) {
- ret = -ERESTARTSYS;
- goto err;
- }
+ buf->status == BUFSTAT_READY))
+ return -ERESTARTSYS;
}
if (buf->status != BUFSTAT_READY)
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
index c104315fdc17..2d33033682af 100644
--- a/drivers/media/usb/msi2500/msi2500.c
+++ b/drivers/media/usb/msi2500/msi2500.c
@@ -839,8 +839,6 @@ static int msi2500_set_usb_adc(struct msi2500_dev *dev)
goto err;
ret = msi2500_ctrl_msg(dev, CMD_WREG, reg3);
- if (ret)
- goto err;
err:
return ret;
}
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c
index fd888a604462..c45f30715dcd 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c
@@ -196,7 +196,7 @@ int pvr2_context_global_init(void)
pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
NULL,
"pvrusb2-context");
- return (pvr2_context_thread_ptr ? 0 : -ENOMEM);
+ return IS_ERR(pvr2_context_thread_ptr) ? -ENOMEM : 0;
}
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index 0533ef20decf..1a093e5953fd 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -4903,6 +4903,9 @@ static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
}
ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf));
+ if (ccnt >= sizeof(buf))
+ ccnt = sizeof(buf);
+
ucnt = 0;
while (ucnt < ccnt) {
lcnt = 0;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c
index d860344de84e..e68ce24f27e3 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c
@@ -473,7 +473,7 @@ static void buffer_complete(struct urb *urb)
}
spin_unlock_irqrestore(&sp->list_lock,irq_flags);
pvr2_buffer_set_ready(bp);
- if (sp && sp->callback_func) {
+ if (sp->callback_func) {
sp->callback_func(sp->callback_data);
}
}
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index 086cf1c7bd7d..18aed5dd325e 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -91,6 +91,7 @@ static const struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x0471, 0x0312) },
{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
{ USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
+ { USB_DEVICE(0x0471, 0x032C) }, /* Philips SPC 880NC PC Camera */
{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
@@ -810,6 +811,11 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
name = "Philips SPC 900NC webcam";
type_id = 740;
break;
+ case 0x032C:
+ PWC_INFO("Philips SPC 880NC USB webcam detected.\n");
+ name = "Philips SPC 880NC webcam";
+ type_id = 740;
+ break;
default:
return -ENODEV;
break;
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index 8abbd3cc8eba..c2e25876e93b 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -27,6 +27,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <media/media-device.h>
#include "sms-cards.h"
#include "smsendian.h"
@@ -51,6 +52,9 @@ struct smsusb_urb_t {
struct smsusb_device_t *dev;
struct urb urb;
+
+ /* For the bottom half */
+ struct work_struct wq;
};
struct smsusb_device_t {
@@ -71,6 +75,18 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev,
struct smsusb_urb_t *surb);
/**
+ * Completing URB's callback handler - bottom half (proccess context)
+ * submits the URB prepared on smsusb_onresponse()
+ */
+static void do_submit_urb(struct work_struct *work)
+{
+ struct smsusb_urb_t *surb = container_of(work, struct smsusb_urb_t, wq);
+ struct smsusb_device_t *dev = surb->dev;
+
+ smsusb_submit_urb(dev, surb);
+}
+
+/**
* Completing URB's callback handler - top half (interrupt context)
* adds completing sms urb to the global surbs list and activtes the worker
* thread the surb
@@ -138,13 +154,15 @@ static void smsusb_onresponse(struct urb *urb)
exit_and_resubmit:
- smsusb_submit_urb(dev, surb);
+ INIT_WORK(&surb->wq, do_submit_urb);
+ schedule_work(&surb->wq);
}
static int smsusb_submit_urb(struct smsusb_device_t *dev,
struct smsusb_urb_t *surb)
{
if (!surb->cb) {
+ /* This function can sleep */
surb->cb = smscore_getbuffer(dev->coredev);
if (!surb->cb) {
pr_err("smscore_getbuffer(...) returned NULL\n");
@@ -353,15 +371,7 @@ static void *siano_media_device_register(struct smsusb_device_t *dev,
if (!mdev)
return NULL;
- mdev->dev = &udev->dev;
- strlcpy(mdev->model, board->name, sizeof(mdev->model));
- if (udev->serial)
- strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
- strcpy(mdev->bus_info, udev->devpath);
- mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
- mdev->driver_version = LINUX_VERSION_CODE;
-
- media_device_init(mdev);
+ media_device_usb_init(mdev, udev, board->name);
ret = media_device_register(mdev);
if (ret) {
diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c
index 46191d5262eb..6ecb0b48423f 100644
--- a/drivers/media/usb/stk1160/stk1160-video.c
+++ b/drivers/media/usb/stk1160/stk1160-video.c
@@ -98,7 +98,6 @@ void stk1160_buffer_done(struct stk1160 *dev)
buf->vb.sequence = dev->sequence++;
buf->vb.field = V4L2_FIELD_INTERLACED;
- buf->vb.vb2_buf.planes[0].bytesused = buf->bytesused;
buf->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->bytesused);
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index 4ebb33943f9a..f6cfad46547e 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -312,20 +312,24 @@ static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk)
usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd);
usbtv->chunks_done++;
- /* Last chunk in a frame, signalling an end */
- if (odd && chunk_no == usbtv->n_chunks-1) {
- int size = vb2_plane_size(&buf->vb.vb2_buf, 0);
- enum vb2_buffer_state state = usbtv->chunks_done ==
- usbtv->n_chunks ?
- VB2_BUF_STATE_DONE :
- VB2_BUF_STATE_ERROR;
-
- buf->vb.field = V4L2_FIELD_INTERLACED;
- buf->vb.sequence = usbtv->sequence++;
- buf->vb.vb2_buf.timestamp = ktime_get_ns();
- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
- vb2_buffer_done(&buf->vb.vb2_buf, state);
- list_del(&buf->list);
+ /* Last chunk in a field */
+ if (chunk_no == usbtv->n_chunks-1) {
+ /* Last chunk in a frame, signalling an end */
+ if (odd && !usbtv->last_odd) {
+ int size = vb2_plane_size(&buf->vb.vb2_buf, 0);
+ enum vb2_buffer_state state = usbtv->chunks_done ==
+ usbtv->n_chunks ?
+ VB2_BUF_STATE_DONE :
+ VB2_BUF_STATE_ERROR;
+
+ buf->vb.field = V4L2_FIELD_INTERLACED;
+ buf->vb.sequence = usbtv->sequence++;
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ list_del(&buf->list);
+ }
+ usbtv->last_odd = odd;
}
spin_unlock_irqrestore(&usbtv->buflock, flags);
@@ -389,6 +393,10 @@ static struct urb *usbtv_setup_iso_transfer(struct usbtv *usbtv)
ip->transfer_flags = URB_ISO_ASAP;
ip->transfer_buffer = kzalloc(size * USBTV_ISOC_PACKETS,
GFP_KERNEL);
+ if (!ip->transfer_buffer) {
+ usb_free_urb(ip);
+ return NULL;
+ }
ip->complete = usbtv_iso_cb;
ip->number_of_packets = USBTV_ISOC_PACKETS;
ip->transfer_buffer_length = size * USBTV_ISOC_PACKETS;
@@ -639,6 +647,7 @@ static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count)
if (usbtv->udev == NULL)
return -ENODEV;
+ usbtv->last_odd = 1;
usbtv->sequence = 0;
return usbtv_start(usbtv);
}
diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h
index 19cb8bf7c4e9..161b38d5cfa0 100644
--- a/drivers/media/usb/usbtv/usbtv.h
+++ b/drivers/media/usb/usbtv/usbtv.h
@@ -95,6 +95,7 @@ struct usbtv {
int width, height;
int n_chunks;
int iso_size;
+ int last_odd;
unsigned int sequence;
struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index de9ff3bb8edd..12f5ebbd0436 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -162,8 +162,7 @@ MODULE_ALIAS(DRIVER_ALIAS);
static inline struct usb_usbvision *cd_to_usbvision(struct device *cd)
{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
return video_get_drvdata(vdev);
}
@@ -177,8 +176,7 @@ static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
static ssize_t show_model(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%s\n",
usbvision_device_data[usbvision->dev_model].model_string);
@@ -188,8 +186,7 @@ static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
static ssize_t show_hue(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_HUE;
@@ -203,8 +200,7 @@ static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
static ssize_t show_contrast(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_CONTRAST;
@@ -218,8 +214,7 @@ static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
static ssize_t show_brightness(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_BRIGHTNESS;
@@ -233,8 +228,7 @@ static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
static ssize_t show_saturation(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_SATURATION;
@@ -248,8 +242,7 @@ static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
static ssize_t show_streaming(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%s\n",
YES_NO(usbvision->streaming == stream_on ? 1 : 0));
@@ -259,8 +252,7 @@ static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
static ssize_t show_compression(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%s\n",
YES_NO(usbvision->isoc_mode == ISOC_MODE_COMPRESS));
@@ -270,8 +262,7 @@ static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
static ssize_t show_device_bridge(struct device *cd,
struct device_attribute *attr, char *buf)
{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
+ struct video_device *vdev = to_video_device(cd);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%d\n", usbvision->bridge_type);
}
@@ -1156,6 +1147,7 @@ static int usbvision_radio_close(struct file *file)
usbvision_audio_off(usbvision);
usbvision->radio = 0;
usbvision->user--;
+ mutex_unlock(&usbvision->v4l2_lock);
if (usbvision->remove_pending) {
printk(KERN_INFO "%s: Final disconnect\n", __func__);
@@ -1164,7 +1156,6 @@ static int usbvision_radio_close(struct file *file)
return 0;
}
- mutex_unlock(&usbvision->v4l2_lock);
PDEBUG(DBG_IO, "success");
return v4l2_fh_release(file);
}
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 4e7148815a78..451e84e962e2 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -148,6 +148,26 @@ static struct uvc_format_desc uvc_fmts[] = {
.guid = UVC_GUID_FORMAT_H264,
.fcc = V4L2_PIX_FMT_H264,
},
+ {
+ .name = "Greyscale 8 L/R (Y8I)",
+ .guid = UVC_GUID_FORMAT_Y8I,
+ .fcc = V4L2_PIX_FMT_Y8I,
+ },
+ {
+ .name = "Greyscale 12 L/R (Y12I)",
+ .guid = UVC_GUID_FORMAT_Y12I,
+ .fcc = V4L2_PIX_FMT_Y12I,
+ },
+ {
+ .name = "Depth data 16-bit (Z16)",
+ .guid = UVC_GUID_FORMAT_Z16,
+ .fcc = V4L2_PIX_FMT_Z16,
+ },
+ {
+ .name = "Bayer 10-bit (SRGGB10P)",
+ .guid = UVC_GUID_FORMAT_RW10,
+ .fcc = V4L2_PIX_FMT_SRGGB10P,
+ },
};
/* ------------------------------------------------------------------------
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index f0f2391e1b43..7e4d3eea371b 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -119,6 +119,18 @@
#define UVC_GUID_FORMAT_H264 \
{ 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y8I \
+ { 'Y', '8', 'I', ' ', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y12I \
+ { 'Y', '1', '2', 'I', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Z16 \
+ { 'Z', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RW10 \
+ { 'R', 'W', '1', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
/* ------------------------------------------------------------------------
* Driver specific constants.
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index 9beece00869b..29b3436d0910 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -37,7 +37,6 @@ config VIDEO_PCI_SKELETON
# Used by drivers that need tuner.ko
config VIDEO_TUNER
tristate
- depends on MEDIA_TUNER
# Used by drivers that need v4l2-mem2mem.ko
config V4L2_MEM2MEM_DEV
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index 1dc8bba2b198..795a5352761d 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -16,6 +16,7 @@ endif
ifeq ($(CONFIG_TRACEPOINTS),y)
videodev-objs += vb2-trace.o v4l2-trace.o
endif
+videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o
obj-$(CONFIG_VIDEO_V4L2) += videodev.o
obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index 76496fd282aa..731487be5baa 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -696,16 +696,32 @@ static int tuner_probe(struct i2c_client *client,
/* Should be just before return */
register_client:
#if defined(CONFIG_MEDIA_CONTROLLER)
- t->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
- t->pad[TUNER_PAD_IF_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
- t->sd.entity.function = MEDIA_ENT_F_TUNER;
t->sd.entity.name = t->name;
+ /*
+ * Handle the special case where the tuner has actually
+ * two stages: the PLL to tune into a frequency and the
+ * IF-PLL demodulator (tda988x).
+ */
+ if (t->type == TUNER_TDA9887) {
+ t->pad[IF_VID_DEC_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ t->pad[IF_VID_DEC_PAD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&t->sd.entity,
+ IF_VID_DEC_PAD_NUM_PADS,
+ &t->pad[0]);
+ t->sd.entity.function = MEDIA_ENT_F_IF_VID_DECODER;
+ } else {
+ t->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ t->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+ t->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&t->sd.entity, TUNER_NUM_PADS,
+ &t->pad[0]);
+ t->sd.entity.function = MEDIA_ENT_F_TUNER;
+ }
- ret = media_entity_pads_init(&t->sd.entity, TUNER_NUM_PADS, &t->pad[0]);
if (ret < 0) {
tuner_err("failed to initialize media entity!\n");
kfree(t);
- return -ENODEV;
+ return ret;
}
#endif
/* Sets a default mode */
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 5bada202b2d3..a4b224d92572 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -119,6 +119,13 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
return ret;
}
+ ret = v4l2_subdev_call(sd, core, registered_async);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ if (notifier->unbind)
+ notifier->unbind(notifier, sd, asd);
+ return ret;
+ }
+
if (list_empty(&notifier->waiting) && notifier->complete)
return notifier->complete(notifier);
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 8fd84a67478a..019644ff627d 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -415,7 +415,8 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
get_user(kp->index, &up->index) ||
get_user(kp->type, &up->type) ||
get_user(kp->flags, &up->flags) ||
- get_user(kp->memory, &up->memory))
+ get_user(kp->memory, &up->memory) ||
+ get_user(kp->length, &up->length))
return -EFAULT;
if (V4L2_TYPE_IS_OUTPUT(kp->type))
@@ -427,9 +428,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
return -EFAULT;
if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
- if (get_user(kp->length, &up->length))
- return -EFAULT;
-
num_planes = kp->length;
if (num_planes == 0) {
kp->m.planes = NULL;
@@ -462,16 +460,14 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
} else {
switch (kp->memory) {
case V4L2_MEMORY_MMAP:
- if (get_user(kp->length, &up->length) ||
- get_user(kp->m.offset, &up->m.offset))
+ if (get_user(kp->m.offset, &up->m.offset))
return -EFAULT;
break;
case V4L2_MEMORY_USERPTR:
{
compat_long_t tmp;
- if (get_user(kp->length, &up->length) ||
- get_user(tmp, &up->m.userptr))
+ if (get_user(tmp, &up->m.userptr))
return -EFAULT;
kp->m.userptr = (unsigned long)compat_ptr(tmp);
@@ -513,7 +509,8 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
put_user(kp->sequence, &up->sequence) ||
put_user(kp->reserved2, &up->reserved2) ||
- put_user(kp->reserved, &up->reserved))
+ put_user(kp->reserved, &up->reserved) ||
+ put_user(kp->length, &up->length))
return -EFAULT;
if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
@@ -536,13 +533,11 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
} else {
switch (kp->memory) {
case V4L2_MEMORY_MMAP:
- if (put_user(kp->length, &up->length) ||
- put_user(kp->m.offset, &up->m.offset))
+ if (put_user(kp->m.offset, &up->m.offset))
return -EFAULT;
break;
case V4L2_MEMORY_USERPTR:
- if (put_user(kp->length, &up->length) ||
- put_user(kp->m.userptr, &up->m.userptr))
+ if (put_user(kp->m.userptr, &up->m.userptr))
return -EFAULT;
break;
case V4L2_MEMORY_OVERLAY:
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index c9d5537b6af7..8b321e0aae62 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -462,6 +462,14 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
"RGB full range (0-255)",
NULL,
};
+ static const char * const dv_it_content_type[] = {
+ "Graphics",
+ "Photo",
+ "Cinema",
+ "Game",
+ "No IT Content",
+ NULL,
+ };
static const char * const detect_md_mode[] = {
"Disabled",
"Global",
@@ -560,6 +568,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
case V4L2_CID_DV_TX_RGB_RANGE:
case V4L2_CID_DV_RX_RGB_RANGE:
return dv_rgb_range;
+ case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
+ case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
+ return dv_it_content_type;
case V4L2_CID_DETECT_MD_MODE:
return detect_md_mode;
@@ -747,6 +758,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: return "Horizontal MV Search Range";
case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: return "Vertical MV Search Range";
case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header";
+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame";
/* VPX controls */
case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions";
@@ -881,8 +893,10 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_DV_TX_EDID_PRESENT: return "EDID Present";
case V4L2_CID_DV_TX_MODE: return "Transmit Mode";
case V4L2_CID_DV_TX_RGB_RANGE: return "Tx RGB Quantization Range";
+ case V4L2_CID_DV_TX_IT_CONTENT_TYPE: return "Tx IT Content Type";
case V4L2_CID_DV_RX_POWER_PRESENT: return "Power Present";
case V4L2_CID_DV_RX_RGB_RANGE: return "Rx RGB Quantization Range";
+ case V4L2_CID_DV_RX_IT_CONTENT_TYPE: return "Rx IT Content Type";
case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls";
case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis";
@@ -985,6 +999,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
case V4L2_CID_PAN_RESET:
case V4L2_CID_TILT_RESET:
case V4L2_CID_FLASH_STROBE:
@@ -1038,7 +1053,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_SCENE_MODE:
case V4L2_CID_DV_TX_MODE:
case V4L2_CID_DV_TX_RGB_RANGE:
+ case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
case V4L2_CID_DV_RX_RGB_RANGE:
+ case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
case V4L2_CID_TEST_PATTERN:
case V4L2_CID_TUNE_DEEMPHASIS:
case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
@@ -1185,6 +1202,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_DV_TX_RXSENSE:
case V4L2_CID_DV_TX_EDID_PRESENT:
case V4L2_CID_DV_RX_POWER_PRESENT:
+ case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
case V4L2_CID_RDS_RX_PTY:
case V4L2_CID_RDS_RX_PS_NAME:
case V4L2_CID_RDS_RX_RADIO_TEXT:
@@ -2211,22 +2229,6 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
}
EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
-/* Add a control from another handler to this handler */
-struct v4l2_ctrl *v4l2_ctrl_add_ctrl(struct v4l2_ctrl_handler *hdl,
- struct v4l2_ctrl *ctrl)
-{
- if (hdl == NULL || hdl->error)
- return NULL;
- if (ctrl == NULL) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- if (ctrl->handler == hdl)
- return ctrl;
- return handler_new_ref(hdl, ctrl) ? NULL : ctrl;
-}
-EXPORT_SYMBOL(v4l2_ctrl_add_ctrl);
-
/* Add the controls from another handler to our own. */
int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl_handler *add,
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index ec258b73001a..889de0a32152 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -165,7 +165,8 @@ bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t,
bt->width > cap->max_width ||
bt->pixelclock < cap->min_pixelclock ||
bt->pixelclock > cap->max_pixelclock ||
- (cap->standards && bt->standards &&
+ (!(caps & V4L2_DV_BT_CAP_CUSTOM) &&
+ cap->standards && bt->standards &&
!(bt->standards & cap->standards)) ||
(bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) ||
(!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE)))
diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c
index c97067a25bd2..c183f0996fa1 100644
--- a/drivers/media/v4l2-core/v4l2-fh.c
+++ b/drivers/media/v4l2-core/v4l2-fh.c
@@ -29,6 +29,7 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
{
@@ -92,6 +93,7 @@ void v4l2_fh_exit(struct v4l2_fh *fh)
{
if (fh->vdev == NULL)
return;
+ v4l_disable_media_source(fh->vdev);
v4l2_event_unsubscribe_all(fh);
fh->vdev = NULL;
}
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 8a018c6dd16a..170dd68d27f4 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -27,6 +27,7 @@
#include <media/v4l2-event.h>
#include <media/v4l2-device.h>
#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-mc.h>
#include <trace/events/v4l2.h>
@@ -1041,6 +1042,12 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops,
static int v4l_s_input(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
+ struct video_device *vfd = video_devdata(file);
+ int ret;
+
+ ret = v4l_enable_media_source(vfd);
+ if (ret)
+ return ret;
return ops->vidioc_s_input(file, fh, *(unsigned int *)arg);
}
@@ -1165,7 +1172,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_YVYU: descr = "YVYU 4:2:2"; break;
case V4L2_PIX_FMT_UYVY: descr = "UYVY 4:2:2"; break;
case V4L2_PIX_FMT_VYUY: descr = "VYUY 4:2:2"; break;
- case V4L2_PIX_FMT_YUV422P: descr = "Planar YVU 4:2:2"; break;
+ case V4L2_PIX_FMT_YUV422P: descr = "Planar YUV 4:2:2"; break;
case V4L2_PIX_FMT_YUV411P: descr = "Planar YUV 4:1:1"; break;
case V4L2_PIX_FMT_Y41P: descr = "YUV 4:1:1 (Packed)"; break;
case V4L2_PIX_FMT_YUV444: descr = "16-bit A/XYUV 4-4-4-4"; break;
@@ -1191,6 +1198,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV12MT_16X16: descr = "Y/CbCr 4:2:0 (16x16 MB, N-C)"; break;
case V4L2_PIX_FMT_YUV420M: descr = "Planar YUV 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_YVU420M: descr = "Planar YVU 4:2:0 (N-C)"; break;
+ case V4L2_PIX_FMT_YUV422M: descr = "Planar YUV 4:2:2 (N-C)"; break;
+ case V4L2_PIX_FMT_YVU422M: descr = "Planar YVU 4:2:2 (N-C)"; break;
+ case V4L2_PIX_FMT_YUV444M: descr = "Planar YUV 4:4:4 (N-C)"; break;
+ case V4L2_PIX_FMT_YVU444M: descr = "Planar YVU 4:4:4 (N-C)"; break;
case V4L2_PIX_FMT_SBGGR8: descr = "8-bit Bayer BGBG/GRGR"; break;
case V4L2_PIX_FMT_SGBRG8: descr = "8-bit Bayer GBGB/RGRG"; break;
case V4L2_PIX_FMT_SGRBG8: descr = "8-bit Bayer GRGR/BGBG"; break;
@@ -1448,6 +1459,9 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
int ret;
+ ret = v4l_enable_media_source(vfd);
+ if (ret)
+ return ret;
v4l_sanitize_format(p);
switch (p->type) {
@@ -1637,7 +1651,11 @@ static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops,
{
struct video_device *vfd = video_devdata(file);
struct v4l2_tuner *p = arg;
+ int ret;
+ ret = v4l_enable_media_source(vfd);
+ if (ret)
+ return ret;
p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
return ops->vidioc_s_tuner(file, fh, p);
@@ -1691,7 +1709,11 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops,
struct video_device *vfd = video_devdata(file);
const struct v4l2_frequency *p = arg;
enum v4l2_tuner_type type;
+ int ret;
+ ret = v4l_enable_media_source(vfd);
+ if (ret)
+ return ret;
if (vfd->vfl_type == VFL_TYPE_SDR) {
if (p->type != V4L2_TUNER_SDR && p->type != V4L2_TUNER_RF)
return -EINVAL;
@@ -1746,7 +1768,11 @@ static int v4l_s_std(const struct v4l2_ioctl_ops *ops,
{
struct video_device *vfd = video_devdata(file);
v4l2_std_id id = *(v4l2_std_id *)arg, norm;
+ int ret;
+ ret = v4l_enable_media_source(vfd);
+ if (ret)
+ return ret;
norm = id & vfd->tvnorms;
if (vfd->tvnorms && !norm) /* Check if std is supported */
return -EINVAL;
@@ -1760,7 +1786,11 @@ static int v4l_querystd(const struct v4l2_ioctl_ops *ops,
{
struct video_device *vfd = video_devdata(file);
v4l2_std_id *p = arg;
+ int ret;
+ ret = v4l_enable_media_source(vfd);
+ if (ret)
+ return ret;
/*
* If no signal is detected, then the driver should return
* V4L2_STD_UNKNOWN. Otherwise it should return tvnorms with
@@ -1779,7 +1809,11 @@ static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops,
struct video_device *vfd = video_devdata(file);
struct v4l2_hw_freq_seek *p = arg;
enum v4l2_tuner_type type;
+ int ret;
+ ret = v4l_enable_media_source(vfd);
+ if (ret)
+ return ret;
/* s_hw_freq_seek is not supported for SDR for now */
if (vfd->vfl_type == VFL_TYPE_SDR)
return -EINVAL;
diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
new file mode 100644
index 000000000000..2a7b79bc90fd
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-mc.c
@@ -0,0 +1,403 @@
+/*
+ * Media Controller ancillary functions
+ *
+ * Copyright (c) 2016 Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+ * Copyright (C) 2016 Shuah Khan <shuahkh@osg.samsung.com>
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (c) 2016 Intel Corporation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/usb.h>
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+#include <media/media-device.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-core.h>
+
+int v4l2_mc_create_media_graph(struct media_device *mdev)
+
+{
+ struct media_entity *entity;
+ struct media_entity *if_vid = NULL, *if_aud = NULL;
+ struct media_entity *tuner = NULL, *decoder = NULL, *dtv_demod = NULL;
+ struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL;
+ bool is_webcam = false;
+ u32 flags;
+ int ret;
+
+ if (!mdev)
+ return 0;
+
+ media_device_for_each_entity(entity, mdev) {
+ switch (entity->function) {
+ case MEDIA_ENT_F_IF_VID_DECODER:
+ if_vid = entity;
+ break;
+ case MEDIA_ENT_F_IF_AUD_DECODER:
+ if_aud = entity;
+ break;
+ case MEDIA_ENT_F_TUNER:
+ tuner = entity;
+ break;
+ case MEDIA_ENT_F_ATV_DECODER:
+ decoder = entity;
+ break;
+ case MEDIA_ENT_F_IO_V4L:
+ io_v4l = entity;
+ break;
+ case MEDIA_ENT_F_IO_VBI:
+ io_vbi = entity;
+ break;
+ case MEDIA_ENT_F_IO_SWRADIO:
+ io_swradio = entity;
+ break;
+ case MEDIA_ENT_F_CAM_SENSOR:
+ is_webcam = true;
+ break;
+ }
+ }
+
+ /* It should have at least one I/O entity */
+ if (!io_v4l && !io_vbi && !io_swradio)
+ return -EINVAL;
+
+ /*
+ * Here, webcams are modelled on a very simple way: the sensor is
+ * connected directly to the I/O entity. All dirty details, like
+ * scaler and crop HW are hidden. While such mapping is not enough
+ * for mc-centric hardware, it is enough for v4l2 interface centric
+ * PC-consumer's hardware.
+ */
+ if (is_webcam) {
+ if (!io_v4l)
+ return -EINVAL;
+
+ media_device_for_each_entity(entity, mdev) {
+ if (entity->function != MEDIA_ENT_F_CAM_SENSOR)
+ continue;
+ ret = media_create_pad_link(entity, 0,
+ io_v4l, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ }
+ if (!decoder)
+ return 0;
+ }
+
+ /* The device isn't a webcam. So, it should have a decoder */
+ if (!decoder)
+ return -EINVAL;
+
+ /* Link the tuner and IF video output pads */
+ if (tuner) {
+ if (if_vid) {
+ ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
+ if_vid,
+ IF_VID_DEC_PAD_IF_INPUT,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ ret = media_create_pad_link(if_vid, IF_VID_DEC_PAD_OUT,
+ decoder, DEMOD_PAD_IF_INPUT,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ } else {
+ ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
+ decoder, DEMOD_PAD_IF_INPUT,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ }
+
+ if (if_aud) {
+ ret = media_create_pad_link(tuner, TUNER_PAD_AUD_OUT,
+ if_aud,
+ IF_AUD_DEC_PAD_IF_INPUT,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ } else {
+ if_aud = tuner;
+ }
+
+ }
+
+ /* Create demod to V4L, VBI and SDR radio links */
+ if (io_v4l) {
+ ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
+ io_v4l, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ }
+
+ if (io_swradio) {
+ ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
+ io_swradio, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ }
+
+ if (io_vbi) {
+ ret = media_create_pad_link(decoder, DEMOD_PAD_VBI_OUT,
+ io_vbi, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ }
+
+ /* Create links for the media connectors */
+ flags = MEDIA_LNK_FL_ENABLED;
+ media_device_for_each_entity(entity, mdev) {
+ switch (entity->function) {
+ case MEDIA_ENT_F_CONN_RF:
+ if (!tuner)
+ continue;
+
+ ret = media_create_pad_link(entity, 0, tuner,
+ TUNER_PAD_RF_INPUT,
+ flags);
+ break;
+ case MEDIA_ENT_F_CONN_SVIDEO:
+ case MEDIA_ENT_F_CONN_COMPOSITE:
+ ret = media_create_pad_link(entity, 0, decoder,
+ DEMOD_PAD_IF_INPUT,
+ flags);
+ break;
+ default:
+ continue;
+ }
+ if (ret)
+ return ret;
+
+ flags = 0;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph);
+
+int v4l_enable_media_source(struct video_device *vdev)
+{
+ struct media_device *mdev = vdev->entity.graph_obj.mdev;
+ int ret;
+
+ if (!mdev || !mdev->enable_source)
+ return 0;
+ ret = mdev->enable_source(&vdev->entity, &vdev->pipe);
+ if (ret)
+ return -EBUSY;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l_enable_media_source);
+
+void v4l_disable_media_source(struct video_device *vdev)
+{
+ struct media_device *mdev = vdev->entity.graph_obj.mdev;
+
+ if (mdev && mdev->disable_source)
+ mdev->disable_source(&vdev->entity);
+}
+EXPORT_SYMBOL_GPL(v4l_disable_media_source);
+
+int v4l_vb2q_enable_media_source(struct vb2_queue *q)
+{
+ struct v4l2_fh *fh = q->owner;
+
+ if (fh && fh->vdev)
+ return v4l_enable_media_source(fh->vdev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
+
+/* -----------------------------------------------------------------------------
+ * Pipeline power management
+ *
+ * Entities must be powered up when part of a pipeline that contains at least
+ * one open video device node.
+ *
+ * To achieve this use the entity use_count field to track the number of users.
+ * For entities corresponding to video device nodes the use_count field stores
+ * the users count of the node. For entities corresponding to subdevs the
+ * use_count field stores the total number of users of all video device nodes
+ * in the pipeline.
+ *
+ * The v4l2_pipeline_pm_use() function must be called in the open() and
+ * close() handlers of video device nodes. It increments or decrements the use
+ * count of all subdev entities in the pipeline.
+ *
+ * To react to link management on powered pipelines, the link setup notification
+ * callback updates the use count of all entities in the source and sink sides
+ * of the link.
+ */
+
+/*
+ * pipeline_pm_use_count - Count the number of users of a pipeline
+ * @entity: The entity
+ *
+ * Return the total number of users of all video device nodes in the pipeline.
+ */
+static int pipeline_pm_use_count(struct media_entity *entity,
+ struct media_entity_graph *graph)
+{
+ int use = 0;
+
+ media_entity_graph_walk_start(graph, entity);
+
+ while ((entity = media_entity_graph_walk_next(graph))) {
+ if (is_media_entity_v4l2_io(entity))
+ use += entity->use_count;
+ }
+
+ return use;
+}
+
+/*
+ * pipeline_pm_power_one - Apply power change to an entity
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Change the entity use count by @change. If the entity is a subdev update its
+ * power state by calling the core::s_power operation when the use count goes
+ * from 0 to != 0 or from != 0 to 0.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int pipeline_pm_power_one(struct media_entity *entity, int change)
+{
+ struct v4l2_subdev *subdev;
+ int ret;
+
+ subdev = is_media_entity_v4l2_subdev(entity)
+ ? media_entity_to_v4l2_subdev(entity) : NULL;
+
+ if (entity->use_count == 0 && change > 0 && subdev != NULL) {
+ ret = v4l2_subdev_call(subdev, core, s_power, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ }
+
+ entity->use_count += change;
+ WARN_ON(entity->use_count < 0);
+
+ if (entity->use_count == 0 && change < 0 && subdev != NULL)
+ v4l2_subdev_call(subdev, core, s_power, 0);
+
+ return 0;
+}
+
+/*
+ * pipeline_pm_power - Apply power change to all entities in a pipeline
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Walk the pipeline to update the use count and the power state of all non-node
+ * entities.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int pipeline_pm_power(struct media_entity *entity, int change,
+ struct media_entity_graph *graph)
+{
+ struct media_entity *first = entity;
+ int ret = 0;
+
+ if (!change)
+ return 0;
+
+ media_entity_graph_walk_start(graph, entity);
+
+ while (!ret && (entity = media_entity_graph_walk_next(graph)))
+ if (is_media_entity_v4l2_subdev(entity))
+ ret = pipeline_pm_power_one(entity, change);
+
+ if (!ret)
+ return ret;
+
+ media_entity_graph_walk_start(graph, first);
+
+ while ((first = media_entity_graph_walk_next(graph))
+ && first != entity)
+ if (is_media_entity_v4l2_subdev(first))
+ pipeline_pm_power_one(first, -change);
+
+ return ret;
+}
+
+int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
+{
+ struct media_device *mdev = entity->graph_obj.mdev;
+ int change = use ? 1 : -1;
+ int ret;
+
+ mutex_lock(&mdev->graph_mutex);
+
+ /* Apply use count to node. */
+ entity->use_count += change;
+ WARN_ON(entity->use_count < 0);
+
+ /* Apply power change to connected non-nodes. */
+ ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
+ if (ret < 0)
+ entity->use_count -= change;
+
+ mutex_unlock(&mdev->graph_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_use);
+
+int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
+ unsigned int notification)
+{
+ struct media_entity_graph *graph = &link->graph_obj.mdev->pm_count_walk;
+ struct media_entity *source = link->source->entity;
+ struct media_entity *sink = link->sink->entity;
+ int source_use;
+ int sink_use;
+ int ret = 0;
+
+ source_use = pipeline_pm_use_count(source, graph);
+ sink_use = pipeline_pm_use_count(sink, graph);
+
+ if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+ !(flags & MEDIA_LNK_FL_ENABLED)) {
+ /* Powering off entities is assumed to never fail. */
+ pipeline_pm_power(source, -sink_use, graph);
+ pipeline_pm_power(sink, -source_use, graph);
+ return 0;
+ }
+
+ if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
+ (flags & MEDIA_LNK_FL_ENABLED)) {
+
+ ret = pipeline_pm_power(source, sink_use, graph);
+ if (ret < 0)
+ return ret;
+
+ ret = pipeline_pm_power(sink, source_use, graph);
+ if (ret < 0)
+ pipeline_pm_power(source, -sink_use, graph);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify);
diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c
index b27cbb1f5afe..93b33681776c 100644
--- a/drivers/media/v4l2-core/v4l2-of.c
+++ b/drivers/media/v4l2-core/v4l2-of.c
@@ -146,7 +146,7 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node,
* variable without a low fixed limit. Please use
* v4l2_of_alloc_parse_endpoint() in new drivers instead.
*
- * Return: 0.
+ * Return: 0 on success or a negative error code on failure.
*/
int v4l2_of_parse_endpoint(const struct device_node *node,
struct v4l2_of_endpoint *endpoint)
diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c
index 6c02989ee33f..def84753c4c3 100644
--- a/drivers/media/v4l2-core/videobuf-core.c
+++ b/drivers/media/v4l2-core/videobuf-core.c
@@ -75,7 +75,8 @@ struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
}
EXPORT_SYMBOL_GPL(videobuf_alloc_vb);
-static int is_state_active_or_queued(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int state_neither_active_nor_queued(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
{
unsigned long flags;
bool rc;
@@ -95,7 +96,7 @@ int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb,
MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
if (non_blocking) {
- if (is_state_active_or_queued(q, vb))
+ if (state_neither_active_nor_queued(q, vb))
return 0;
return -EAGAIN;
}
@@ -107,9 +108,10 @@ int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (is_ext_locked)
mutex_unlock(q->ext_lock);
if (intr)
- ret = wait_event_interruptible(vb->done, is_state_active_or_queued(q, vb));
+ ret = wait_event_interruptible(vb->done,
+ state_neither_active_nor_queued(q, vb));
else
- wait_event(vb->done, is_state_active_or_queued(q, vb));
+ wait_event(vb->done, state_neither_active_nor_queued(q, vb));
/* Relock */
if (is_ext_locked)
mutex_lock(q->ext_lock);
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index ff8953ae52d1..5d016f496e0e 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -25,6 +25,7 @@
#include <linux/kthread.h>
#include <media/videobuf2-core.h>
+#include <media/v4l2-mc.h>
#include <trace/events/vb2.h>
@@ -1227,6 +1228,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb)
if (planes[plane].length < vb->planes[plane].min_length) {
dprintk(1, "invalid dmabuf length for plane %d\n",
plane);
+ dma_buf_put(dbuf);
ret = -EINVAL;
goto err;
}
@@ -1886,6 +1888,9 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
* are available.
*/
if (q->queued_count >= q->min_buffers_needed) {
+ ret = v4l_vb2q_enable_media_source(q);
+ if (ret)
+ return ret;
ret = vb2_start_streaming(q);
if (ret) {
__vb2_queue_cancel(q);
diff --git a/drivers/media/v4l2-core/videobuf2-dvb.c b/drivers/media/v4l2-core/videobuf2-dvb.c
index d09269846b7e..9f38b4218c0d 100644
--- a/drivers/media/v4l2-core/videobuf2-dvb.c
+++ b/drivers/media/v4l2-core/videobuf2-dvb.c
@@ -77,6 +77,7 @@ static int vb2_dvb_register_adapter(struct vb2_dvb_frontends *fe,
struct module *module,
void *adapter_priv,
struct device *device,
+ struct media_device *mdev,
char *adapter_name,
short *adapter_nr,
int mfe_shared)
@@ -94,7 +95,10 @@ static int vb2_dvb_register_adapter(struct vb2_dvb_frontends *fe,
}
fe->adapter.priv = adapter_priv;
fe->adapter.mfe_shared = mfe_shared;
-
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (mdev)
+ fe->adapter.mdev = mdev;
+#endif
return result;
}
@@ -193,6 +197,7 @@ int vb2_dvb_register_bus(struct vb2_dvb_frontends *f,
struct module *module,
void *adapter_priv,
struct device *device,
+ struct media_device *mdev,
short *adapter_nr,
int mfe_shared)
{
@@ -207,7 +212,7 @@ int vb2_dvb_register_bus(struct vb2_dvb_frontends *f,
}
/* Bring up the adapter */
- res = vb2_dvb_register_adapter(f, module, adapter_priv, device,
+ res = vb2_dvb_register_adapter(f, module, adapter_priv, device, mdev,
fe->dvb.name, adapter_nr, mfe_shared);
if (res < 0) {
pr_warn("vb2_dvb_register_adapter failed (errno = %d)\n", res);
@@ -224,7 +229,11 @@ int vb2_dvb_register_bus(struct vb2_dvb_frontends *f,
fe->dvb.name, res);
goto err;
}
+ res = dvb_create_media_graph(&f->adapter, false);
+ if (res < 0)
+ goto err;
}
+
mutex_unlock(&f->lock);
return 0;
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5dcc0313c38a..5537f8df8512 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1801,8 +1801,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->pcidev = pdev;
if (mpt_mapresources(ioc)) {
- kfree(ioc);
- return r;
+ goto out_free_ioc;
}
/*
@@ -1871,9 +1870,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
if (!ioc->reset_work_q) {
printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
ioc->name);
- pci_release_selected_regions(pdev, ioc->bars);
- kfree(ioc);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto out_unmap_resources;
}
dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
@@ -1995,16 +1993,27 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ioc->fw_event_lock);
snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
+ if (!ioc->fw_event_q) {
+ printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
+ ioc->name);
+ r = -ENOMEM;
+ goto out_remove_ioc;
+ }
if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
CAN_SLEEP)) != 0){
printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
ioc->name, r);
+ destroy_workqueue(ioc->fw_event_q);
+ ioc->fw_event_q = NULL;
+
list_del(&ioc->list);
if (ioc->alt_ioc)
ioc->alt_ioc->alt_ioc = NULL;
iounmap(ioc->memmap);
+ if (pci_is_enabled(pdev))
+ pci_disable_device(pdev);
if (r != -5)
pci_release_selected_regions(pdev, ioc->bars);
@@ -2012,7 +2021,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->reset_work_q = NULL;
kfree(ioc);
- pci_set_drvdata(pdev, NULL);
return r;
}
@@ -2040,6 +2048,24 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
msecs_to_jiffies(MPT_POLLING_INTERVAL));
return 0;
+
+out_remove_ioc:
+ list_del(&ioc->list);
+ if (ioc->alt_ioc)
+ ioc->alt_ioc->alt_ioc = NULL;
+
+ destroy_workqueue(ioc->reset_work_q);
+ ioc->reset_work_q = NULL;
+
+out_unmap_resources:
+ iounmap(ioc->memmap);
+ pci_disable_device(pdev);
+ pci_release_selected_regions(pdev, ioc->bars);
+
+out_free_ioc:
+ kfree(ioc);
+
+ return r;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -6229,7 +6255,7 @@ mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
- out:
+out:
if (pbuf)
pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
@@ -6848,6 +6874,7 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
*size = y;
}
+#ifdef CONFIG_PROC_FS
static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
{
char expVer[32];
@@ -6879,6 +6906,7 @@ static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int
seq_putc(m, '\n');
}
+#endif
/**
* mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
index d959ebbb2194..98ecd136a21b 100644
--- a/drivers/mfd/max77686.c
+++ b/drivers/mfd/max77686.c
@@ -35,8 +35,6 @@
#include <linux/err.h>
#include <linux/of.h>
-#define I2C_ADDR_RTC (0x0C >> 1)
-
static const struct mfd_cell max77686_devs[] = {
{ .name = "max77686-pmic", },
{ .name = "max77686-rtc", },
@@ -116,11 +114,6 @@ static const struct regmap_config max77686_regmap_config = {
.val_bits = 8,
};
-static const struct regmap_config max77686_rtc_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-};
-
static const struct regmap_config max77802_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -156,25 +149,6 @@ static const struct regmap_irq_chip max77686_irq_chip = {
.num_irqs = ARRAY_SIZE(max77686_irqs),
};
-static const struct regmap_irq max77686_rtc_irqs[] = {
- /* RTC interrupts */
- { .reg_offset = 0, .mask = MAX77686_RTCINT_RTC60S_MSK, },
- { .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA1_MSK, },
- { .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA2_MSK, },
- { .reg_offset = 0, .mask = MAX77686_RTCINT_SMPL_MSK, },
- { .reg_offset = 0, .mask = MAX77686_RTCINT_RTC1S_MSK, },
- { .reg_offset = 0, .mask = MAX77686_RTCINT_WTSR_MSK, },
-};
-
-static const struct regmap_irq_chip max77686_rtc_irq_chip = {
- .name = "max77686-rtc",
- .status_base = MAX77686_RTC_INT,
- .mask_base = MAX77686_RTC_INTM,
- .num_regs = 1,
- .irqs = max77686_rtc_irqs,
- .num_irqs = ARRAY_SIZE(max77686_rtc_irqs),
-};
-
static const struct regmap_irq_chip max77802_irq_chip = {
.name = "max77802-pmic",
.status_base = MAX77802_REG_INT1,
@@ -184,15 +158,6 @@ static const struct regmap_irq_chip max77802_irq_chip = {
.num_irqs = ARRAY_SIZE(max77686_irqs),
};
-static const struct regmap_irq_chip max77802_rtc_irq_chip = {
- .name = "max77802-rtc",
- .status_base = MAX77802_RTC_INT,
- .mask_base = MAX77802_RTC_INTM,
- .num_regs = 1,
- .irqs = max77686_rtc_irqs, /* same masks as 77686 */
- .num_irqs = ARRAY_SIZE(max77686_rtc_irqs),
-};
-
static const struct of_device_id max77686_pmic_dt_match[] = {
{
.compatible = "maxim,max77686",
@@ -214,8 +179,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
int ret = 0;
const struct regmap_config *config;
const struct regmap_irq_chip *irq_chip;
- const struct regmap_irq_chip *rtc_irq_chip;
- struct regmap **rtc_regmap;
const struct mfd_cell *cells;
int n_devs;
@@ -242,15 +205,11 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
if (max77686->type == TYPE_MAX77686) {
config = &max77686_regmap_config;
irq_chip = &max77686_irq_chip;
- rtc_irq_chip = &max77686_rtc_irq_chip;
- rtc_regmap = &max77686->rtc_regmap;
cells = max77686_devs;
n_devs = ARRAY_SIZE(max77686_devs);
} else {
config = &max77802_regmap_config;
irq_chip = &max77802_irq_chip;
- rtc_irq_chip = &max77802_rtc_irq_chip;
- rtc_regmap = &max77686->regmap;
cells = max77802_devs;
n_devs = ARRAY_SIZE(max77802_devs);
}
@@ -270,60 +229,25 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
return -ENODEV;
}
- if (max77686->type == TYPE_MAX77686) {
- max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
- if (!max77686->rtc) {
- dev_err(max77686->dev,
- "Failed to allocate I2C device for RTC\n");
- return -ENODEV;
- }
- i2c_set_clientdata(max77686->rtc, max77686);
-
- max77686->rtc_regmap =
- devm_regmap_init_i2c(max77686->rtc,
- &max77686_rtc_regmap_config);
- if (IS_ERR(max77686->rtc_regmap)) {
- ret = PTR_ERR(max77686->rtc_regmap);
- dev_err(max77686->dev,
- "failed to allocate RTC regmap: %d\n",
- ret);
- goto err_unregister_i2c;
- }
- }
-
ret = regmap_add_irq_chip(max77686->regmap, max77686->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
IRQF_SHARED, 0, irq_chip,
&max77686->irq_data);
- if (ret) {
+ if (ret < 0) {
dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret);
- goto err_unregister_i2c;
- }
-
- ret = regmap_add_irq_chip(*rtc_regmap, max77686->irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
- IRQF_SHARED, 0, rtc_irq_chip,
- &max77686->rtc_irq_data);
- if (ret) {
- dev_err(&i2c->dev, "failed to add RTC irq chip: %d\n", ret);
- goto err_del_irqc;
+ return ret;
}
ret = mfd_add_devices(max77686->dev, -1, cells, n_devs, NULL, 0, NULL);
if (ret < 0) {
dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
- goto err_del_rtc_irqc;
+ goto err_del_irqc;
}
return 0;
-err_del_rtc_irqc:
- regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data);
err_del_irqc:
regmap_del_irq_chip(max77686->irq, max77686->irq_data);
-err_unregister_i2c:
- if (max77686->type == TYPE_MAX77686)
- i2c_unregister_device(max77686->rtc);
return ret;
}
@@ -334,12 +258,8 @@ static int max77686_i2c_remove(struct i2c_client *i2c)
mfd_remove_devices(max77686->dev);
- regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data);
regmap_del_irq_chip(max77686->irq, max77686->irq_data);
- if (max77686->type == TYPE_MAX77686)
- i2c_unregister_device(max77686->rtc);
-
return 0;
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 054fc10cb3b6..15579514d120 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -440,7 +440,7 @@ config ARM_CHARLCD
still useful.
config BMP085
- bool
+ tristate
depends on SYSFS
config BMP085_I2C
@@ -470,7 +470,7 @@ config BMP085_SPI
config PCH_PHUB
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
select GENERIC_NET_UTILS
- depends on PCI && (X86_32 || COMPILE_TEST)
+ depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
help
This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of
Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index 15e88078ba1e..fe1672747bc1 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -216,7 +216,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
*/
value = swab16(value);
- if (dpot->uid == DPOT_UID(AD5271_ID))
+ if (dpot->uid == DPOT_UID(AD5274_ID))
value = value >> 2;
return value;
default:
@@ -452,7 +452,7 @@ static ssize_t sysfs_set_reg(struct device *dev,
int err;
if (reg & DPOT_ADDR_OTP_EN) {
- if (!strncmp(buf, "enabled", sizeof("enabled")))
+ if (sysfs_streq(buf, "enabled"))
set_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
else
clear_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c
index a3e789b85cc8..dfb72ecfa604 100644
--- a/drivers/misc/apds990x.c
+++ b/drivers/misc/apds990x.c
@@ -1215,7 +1215,7 @@ static int apds990x_remove(struct i2c_client *client)
#ifdef CONFIG_PM_SLEEP
static int apds990x_suspend(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct apds990x_chip *chip = i2c_get_clientdata(client);
apds990x_chip_off(chip);
@@ -1224,7 +1224,7 @@ static int apds990x_suspend(struct device *dev)
static int apds990x_resume(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct apds990x_chip *chip = i2c_get_clientdata(client);
/*
@@ -1240,7 +1240,7 @@ static int apds990x_resume(struct device *dev)
#ifdef CONFIG_PM
static int apds990x_runtime_suspend(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct apds990x_chip *chip = i2c_get_clientdata(client);
apds990x_chip_off(chip);
@@ -1249,7 +1249,7 @@ static int apds990x_runtime_suspend(struct device *dev)
static int apds990x_runtime_resume(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct apds990x_chip *chip = i2c_get_clientdata(client);
apds990x_chip_on(chip);
diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c
index c65b5ea5d5ef..b3176ee92b90 100644
--- a/drivers/misc/arm-charlcd.c
+++ b/drivers/misc/arm-charlcd.c
@@ -8,7 +8,6 @@
* Author: Linus Walleij <triad@df.lth.se>
*/
#include <linux/init.h>
-#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of.h>
@@ -328,20 +327,6 @@ out_no_resource:
return ret;
}
-static int __exit charlcd_remove(struct platform_device *pdev)
-{
- struct charlcd *lcd = platform_get_drvdata(pdev);
-
- if (lcd) {
- free_irq(lcd->irq, lcd);
- iounmap(lcd->virtbase);
- release_mem_region(lcd->phybase, lcd->physize);
- kfree(lcd);
- }
-
- return 0;
-}
-
static int charlcd_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -376,13 +361,8 @@ static struct platform_driver charlcd_driver = {
.driver = {
.name = DRIVERNAME,
.pm = &charlcd_pm_ops,
+ .suppress_bind_attrs = true,
.of_match_table = of_match_ptr(charlcd_match),
},
- .remove = __exit_p(charlcd_remove),
};
-
-module_platform_driver_probe(charlcd_driver, charlcd_probe);
-
-MODULE_AUTHOR("Linus Walleij <triad@df.lth.se>");
-MODULE_DESCRIPTION("ARM Character LCD Driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver_probe(charlcd_driver, charlcd_probe);
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c
index 753d7ecdadaa..845466e45b95 100644
--- a/drivers/misc/bh1770glc.c
+++ b/drivers/misc/bh1770glc.c
@@ -1323,7 +1323,7 @@ static int bh1770_remove(struct i2c_client *client)
#ifdef CONFIG_PM_SLEEP
static int bh1770_suspend(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct bh1770_chip *chip = i2c_get_clientdata(client);
bh1770_chip_off(chip);
@@ -1333,7 +1333,7 @@ static int bh1770_suspend(struct device *dev)
static int bh1770_resume(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct bh1770_chip *chip = i2c_get_clientdata(client);
int ret = 0;
@@ -1361,7 +1361,7 @@ static int bh1770_resume(struct device *dev)
#ifdef CONFIG_PM
static int bh1770_runtime_suspend(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct bh1770_chip *chip = i2c_get_clientdata(client);
bh1770_chip_off(chip);
@@ -1371,7 +1371,7 @@ static int bh1770_runtime_suspend(struct device *dev)
static int bh1770_runtime_resume(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct bh1770_chip *chip = i2c_get_clientdata(client);
bh1770_chip_on(chip);
diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c
index cc8645b5369d..1922cb8f6b88 100644
--- a/drivers/misc/c2port/core.c
+++ b/drivers/misc/c2port/core.c
@@ -721,9 +721,7 @@ static ssize_t c2port_read_flash_data(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buffer, loff_t offset, size_t count)
{
- struct c2port_device *c2dev =
- dev_get_drvdata(container_of(kobj,
- struct device, kobj));
+ struct c2port_device *c2dev = dev_get_drvdata(kobj_to_dev(kobj));
ssize_t ret;
/* Check the device and flash access status */
@@ -838,9 +836,7 @@ static ssize_t c2port_write_flash_data(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buffer, loff_t offset, size_t count)
{
- struct c2port_device *c2dev =
- dev_get_drvdata(container_of(kobj,
- struct device, kobj));
+ struct c2port_device *c2dev = dev_get_drvdata(kobj_to_dev(kobj));
int ret;
/* Check the device access status */
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index 4c1903f781fc..a89608334ed5 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -19,7 +19,6 @@
#include <linux/delay.h>
#include <asm/opal.h>
#include <asm/msi_bitmap.h>
-#include <asm/pci-bridge.h> /* for struct pci_controller */
#include <asm/pnv-pci.h>
#include <asm/io.h>
@@ -415,7 +414,7 @@ static int cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
delta = mftb() - psl_tb;
if (delta < 0)
delta = -delta;
- } while (cputime_to_usecs(delta) > 16);
+ } while (tb_to_ns(delta) > 16000);
return 0;
}
diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c
index 02006f7109a8..038af5d45145 100644
--- a/drivers/misc/cxl/sysfs.c
+++ b/drivers/misc/cxl/sysfs.c
@@ -386,8 +386,7 @@ static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
{
- struct cxl_afu *afu = to_cxl_afu(container_of(kobj,
- struct device, kobj));
+ struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj));
return cxl_afu_read_err_buffer(afu, buf, off, count);
}
@@ -467,7 +466,7 @@ static ssize_t afu_read_config(struct file *filp, struct kobject *kobj,
loff_t off, size_t count)
{
struct afu_config_record *cr = to_cr(kobj);
- struct cxl_afu *afu = to_cxl_afu(container_of(kobj->parent, struct device, kobj));
+ struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent));
u64 i, j, val;
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1fa9dd1..cfc493c2e30a 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -3,6 +3,8 @@ menu "EEPROM support"
config EEPROM_AT24
tristate "I2C EEPROMs / RAMs / ROMs from most vendors"
depends on I2C && SYSFS
+ select REGMAP
+ select NVMEM
help
Enable this driver to get read/write support to most I2C EEPROMs
and compatible devices like FRAMs, SRAMs, ROMs etc. After you
@@ -30,6 +32,8 @@ config EEPROM_AT24
config EEPROM_AT25
tristate "SPI EEPROMs from most vendors"
depends on SPI && SYSFS
+ select REGMAP
+ select NVMEM
help
Enable this driver to get read/write support to most SPI EEPROMs,
after you configure the board init code to know about each eeprom
@@ -74,6 +78,8 @@ config EEPROM_93CX6
config EEPROM_93XX46
tristate "Microwire EEPROM 93XX46 support"
depends on SPI && SYSFS
+ select REGMAP
+ select NVMEM
help
Driver for the microwire EEPROM chipsets 93xx46x. The driver
supports both read and write commands and also the command to
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 5d7c0900fa1b..089d6943f68a 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -15,7 +15,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
-#include <linux/sysfs.h>
#include <linux/mod_devicetable.h>
#include <linux/log2.h>
#include <linux/bitops.h>
@@ -23,6 +22,8 @@
#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
#include <linux/platform_data/at24.h>
/*
@@ -55,7 +56,6 @@
struct at24_data {
struct at24_platform_data chip;
- struct memory_accessor macc;
int use_smbus;
int use_smbus_write;
@@ -64,12 +64,15 @@ struct at24_data {
* but not from changes by other I2C masters.
*/
struct mutex lock;
- struct bin_attribute bin;
u8 *writebuf;
unsigned write_max;
unsigned num_addresses;
+ struct regmap_config regmap_config;
+ struct nvmem_config nvmem_config;
+ struct nvmem_device *nvmem;
+
/*
* Some chips tie up multiple I2C addresses; dummy devices reserve
* them for us, and we'll use them with SMBus calls.
@@ -283,17 +286,6 @@ static ssize_t at24_read(struct at24_data *at24,
return retval;
}
-static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t off, size_t count)
-{
- struct at24_data *at24;
-
- at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
- return at24_read(at24, buf, off, count);
-}
-
-
/*
* Note that if the hardware write-protect pin is pulled high, the whole
* chip is normally write protected. But there are plenty of product
@@ -414,40 +406,49 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
return retval;
}
-static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t off, size_t count)
-{
- struct at24_data *at24;
-
- at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
- return at24_write(at24, buf, off, count);
-}
-
/*-------------------------------------------------------------------------*/
/*
- * This lets other kernel code access the eeprom data. For example, it
- * might hold a board's Ethernet address, or board-specific calibration
- * data generated on the manufacturing floor.
- */
-
-static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf,
- off_t offset, size_t count)
+ * Provide a regmap interface, which is registered with the NVMEM
+ * framework
+*/
+static int at24_regmap_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
{
- struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+ struct at24_data *at24 = context;
+ off_t offset = *(u32 *)reg;
+ int err;
- return at24_read(at24, buf, offset, count);
+ err = at24_read(at24, val, offset, val_size);
+ if (err)
+ return err;
+ return 0;
}
-static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,
- off_t offset, size_t count)
+static int at24_regmap_write(void *context, const void *data, size_t count)
{
- struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+ struct at24_data *at24 = context;
+ const char *buf;
+ u32 offset;
+ size_t len;
+ int err;
- return at24_write(at24, buf, offset, count);
+ memcpy(&offset, data, sizeof(offset));
+ buf = (const char *)data + sizeof(offset);
+ len = count - sizeof(offset);
+
+ err = at24_write(at24, buf, offset, len);
+ if (err)
+ return err;
+ return 0;
}
+static const struct regmap_bus at24_regmap_bus = {
+ .read = at24_regmap_read,
+ .write = at24_regmap_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_OF
@@ -481,6 +482,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct at24_data *at24;
int err;
unsigned i, num_addresses;
+ struct regmap *regmap;
if (client->dev.platform_data) {
chip = *(struct at24_platform_data *)client->dev.platform_data;
@@ -573,29 +575,12 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
at24->chip = chip;
at24->num_addresses = num_addresses;
- /*
- * Export the EEPROM bytes through sysfs, since that's convenient.
- * By default, only root should see the data (maybe passwords etc)
- */
- sysfs_bin_attr_init(&at24->bin);
- at24->bin.attr.name = "eeprom";
- at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
- at24->bin.read = at24_bin_read;
- at24->bin.size = chip.byte_len;
-
- at24->macc.read = at24_macc_read;
-
writable = !(chip.flags & AT24_FLAG_READONLY);
if (writable) {
if (!use_smbus || use_smbus_write) {
unsigned write_max = chip.page_size;
- at24->macc.write = at24_macc_write;
-
- at24->bin.write = at24_bin_write;
- at24->bin.attr.mode |= S_IWUSR;
-
if (write_max > io_limit)
write_max = io_limit;
if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
@@ -627,14 +612,38 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
}
- err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);
- if (err)
+ at24->regmap_config.reg_bits = 32;
+ at24->regmap_config.val_bits = 8;
+ at24->regmap_config.reg_stride = 1;
+ at24->regmap_config.max_register = chip.byte_len - 1;
+
+ regmap = devm_regmap_init(&client->dev, &at24_regmap_bus, at24,
+ &at24->regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "regmap init failed\n");
+ err = PTR_ERR(regmap);
+ goto err_clients;
+ }
+
+ at24->nvmem_config.name = dev_name(&client->dev);
+ at24->nvmem_config.dev = &client->dev;
+ at24->nvmem_config.read_only = !writable;
+ at24->nvmem_config.root_only = true;
+ at24->nvmem_config.owner = THIS_MODULE;
+ at24->nvmem_config.compat = true;
+ at24->nvmem_config.base_dev = &client->dev;
+
+ at24->nvmem = nvmem_register(&at24->nvmem_config);
+
+ if (IS_ERR(at24->nvmem)) {
+ err = PTR_ERR(at24->nvmem);
goto err_clients;
+ }
i2c_set_clientdata(client, at24);
- dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",
- at24->bin.size, client->name,
+ dev_info(&client->dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
+ chip.byte_len, client->name,
writable ? "writable" : "read-only", at24->write_max);
if (use_smbus == I2C_SMBUS_WORD_DATA ||
use_smbus == I2C_SMBUS_BYTE_DATA) {
@@ -645,7 +654,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* export data to kernel code */
if (chip.setup)
- chip.setup(&at24->macc, chip.context);
+ chip.setup(at24->nvmem, chip.context);
return 0;
@@ -663,7 +672,8 @@ static int at24_remove(struct i2c_client *client)
int i;
at24 = i2c_get_clientdata(client);
- sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);
+
+ nvmem_unregister(at24->nvmem);
for (i = 1; i < at24->num_addresses; i++)
i2c_unregister_device(at24->client[i]);
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index f850ef556bcc..fa36a6e37084 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -16,6 +16,8 @@
#include <linux/device.h>
#include <linux/sched.h>
+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
#include <linux/property.h>
@@ -29,11 +31,12 @@
struct at25_data {
struct spi_device *spi;
- struct memory_accessor mem;
struct mutex lock;
struct spi_eeprom chip;
- struct bin_attribute bin;
unsigned addrlen;
+ struct regmap_config regmap_config;
+ struct nvmem_config nvmem_config;
+ struct nvmem_device *nvmem;
};
#define AT25_WREN 0x06 /* latch the write enable */
@@ -77,10 +80,10 @@ at25_ee_read(
struct spi_message m;
u8 instr;
- if (unlikely(offset >= at25->bin.size))
+ if (unlikely(offset >= at25->chip.byte_len))
return 0;
- if ((offset + count) > at25->bin.size)
- count = at25->bin.size - offset;
+ if ((offset + count) > at25->chip.byte_len)
+ count = at25->chip.byte_len - offset;
if (unlikely(!count))
return count;
@@ -131,21 +134,19 @@ at25_ee_read(
return status ? status : count;
}
-static ssize_t
-at25_bin_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static int at25_regmap_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
{
- struct device *dev;
- struct at25_data *at25;
+ struct at25_data *at25 = context;
+ off_t offset = *(u32 *)reg;
+ int err;
- dev = container_of(kobj, struct device, kobj);
- at25 = dev_get_drvdata(dev);
-
- return at25_ee_read(at25, buf, off, count);
+ err = at25_ee_read(at25, val, offset, val_size);
+ if (err)
+ return err;
+ return 0;
}
-
static ssize_t
at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
size_t count)
@@ -155,10 +156,10 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
unsigned buf_size;
u8 *bounce;
- if (unlikely(off >= at25->bin.size))
+ if (unlikely(off >= at25->chip.byte_len))
return -EFBIG;
- if ((off + count) > at25->bin.size)
- count = at25->bin.size - off;
+ if ((off + count) > at25->chip.byte_len)
+ count = at25->chip.byte_len - off;
if (unlikely(!count))
return count;
@@ -265,39 +266,29 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
return written ? written : status;
}
-static ssize_t
-at25_bin_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static int at25_regmap_write(void *context, const void *data, size_t count)
{
- struct device *dev;
- struct at25_data *at25;
-
- dev = container_of(kobj, struct device, kobj);
- at25 = dev_get_drvdata(dev);
-
- return at25_ee_write(at25, buf, off, count);
-}
+ struct at25_data *at25 = context;
+ const char *buf;
+ u32 offset;
+ size_t len;
+ int err;
-/*-------------------------------------------------------------------------*/
-
-/* Let in-kernel code access the eeprom data. */
-
-static ssize_t at25_mem_read(struct memory_accessor *mem, char *buf,
- off_t offset, size_t count)
-{
- struct at25_data *at25 = container_of(mem, struct at25_data, mem);
+ memcpy(&offset, data, sizeof(offset));
+ buf = (const char *)data + sizeof(offset);
+ len = count - sizeof(offset);
- return at25_ee_read(at25, buf, offset, count);
+ err = at25_ee_write(at25, buf, offset, len);
+ if (err)
+ return err;
+ return 0;
}
-static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
- off_t offset, size_t count)
-{
- struct at25_data *at25 = container_of(mem, struct at25_data, mem);
-
- return at25_ee_write(at25, buf, offset, count);
-}
+static const struct regmap_bus at25_regmap_bus = {
+ .read = at25_regmap_read,
+ .write = at25_regmap_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
/*-------------------------------------------------------------------------*/
@@ -358,6 +349,7 @@ static int at25_probe(struct spi_device *spi)
{
struct at25_data *at25 = NULL;
struct spi_eeprom chip;
+ struct regmap *regmap;
int err;
int sr;
int addrlen;
@@ -402,40 +394,35 @@ static int at25_probe(struct spi_device *spi)
spi_set_drvdata(spi, at25);
at25->addrlen = addrlen;
- /* Export the EEPROM bytes through sysfs, since that's convenient.
- * And maybe to other kernel code; it might hold a board's Ethernet
- * address, or board-specific calibration data generated on the
- * manufacturing floor.
- *
- * Default to root-only access to the data; EEPROMs often hold data
- * that's sensitive for read and/or write, like ethernet addresses,
- * security codes, board-specific manufacturing calibrations, etc.
- */
- sysfs_bin_attr_init(&at25->bin);
- at25->bin.attr.name = "eeprom";
- at25->bin.attr.mode = S_IRUSR;
- at25->bin.read = at25_bin_read;
- at25->mem.read = at25_mem_read;
-
- at25->bin.size = at25->chip.byte_len;
- if (!(chip.flags & EE_READONLY)) {
- at25->bin.write = at25_bin_write;
- at25->bin.attr.mode |= S_IWUSR;
- at25->mem.write = at25_mem_write;
- }
+ at25->regmap_config.reg_bits = 32;
+ at25->regmap_config.val_bits = 8;
+ at25->regmap_config.reg_stride = 1;
+ at25->regmap_config.max_register = chip.byte_len - 1;
- err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
- if (err)
- return err;
-
- if (chip.setup)
- chip.setup(&at25->mem, chip.context);
+ regmap = devm_regmap_init(&spi->dev, &at25_regmap_bus, at25,
+ &at25->regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "regmap init failed\n");
+ return PTR_ERR(regmap);
+ }
- dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
- (at25->bin.size < 1024)
- ? at25->bin.size
- : (at25->bin.size / 1024),
- (at25->bin.size < 1024) ? "Byte" : "KByte",
+ at25->nvmem_config.name = dev_name(&spi->dev);
+ at25->nvmem_config.dev = &spi->dev;
+ at25->nvmem_config.read_only = chip.flags & EE_READONLY;
+ at25->nvmem_config.root_only = true;
+ at25->nvmem_config.owner = THIS_MODULE;
+ at25->nvmem_config.compat = true;
+ at25->nvmem_config.base_dev = &spi->dev;
+
+ at25->nvmem = nvmem_register(&at25->nvmem_config);
+ if (IS_ERR(at25->nvmem))
+ return PTR_ERR(at25->nvmem);
+
+ dev_info(&spi->dev, "%d %s %s eeprom%s, pagesize %u\n",
+ (chip.byte_len < 1024)
+ ? chip.byte_len
+ : (chip.byte_len / 1024),
+ (chip.byte_len < 1024) ? "Byte" : "KByte",
at25->chip.name,
(chip.flags & EE_READONLY) ? " (readonly)" : "",
at25->chip.page_size);
@@ -447,7 +434,8 @@ static int at25_remove(struct spi_device *spi)
struct at25_data *at25;
at25 = spi_get_drvdata(spi);
- sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin);
+ nvmem_unregister(at25->nvmem);
+
return 0;
}
diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c
index 7342fd637031..3d1d55157e5f 100644
--- a/drivers/misc/eeprom/eeprom.c
+++ b/drivers/misc/eeprom/eeprom.c
@@ -84,7 +84,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
+ struct i2c_client *client = to_i2c_client(kobj_to_dev(kobj));
struct eeprom_data *data = i2c_get_clientdata(client);
u8 slice;
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index ff63f05edc76..426fe2fd5238 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -10,12 +10,17 @@
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/sysfs.h>
+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
#include <linux/eeprom_93xx46.h>
#define OP_START 0x4
@@ -25,73 +30,111 @@
#define ADDR_ERAL 0x20
#define ADDR_EWEN 0x30
+struct eeprom_93xx46_devtype_data {
+ unsigned int quirks;
+};
+
+static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = {
+ .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ |
+ EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH,
+};
+
struct eeprom_93xx46_dev {
struct spi_device *spi;
struct eeprom_93xx46_platform_data *pdata;
- struct bin_attribute bin;
struct mutex lock;
+ struct regmap_config regmap_config;
+ struct nvmem_config nvmem_config;
+ struct nvmem_device *nvmem;
int addrlen;
+ int size;
};
+static inline bool has_quirk_single_word_read(struct eeprom_93xx46_dev *edev)
+{
+ return edev->pdata->quirks & EEPROM_93XX46_QUIRK_SINGLE_WORD_READ;
+}
+
+static inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev)
+{
+ return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH;
+}
+
static ssize_t
-eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+eeprom_93xx46_read(struct eeprom_93xx46_dev *edev, char *buf,
+ unsigned off, size_t count)
{
- struct eeprom_93xx46_dev *edev;
- struct device *dev;
- struct spi_message m;
- struct spi_transfer t[2];
- int bits, ret;
- u16 cmd_addr;
+ ssize_t ret = 0;
- dev = container_of(kobj, struct device, kobj);
- edev = dev_get_drvdata(dev);
+ if (unlikely(off >= edev->size))
+ return 0;
+ if ((off + count) > edev->size)
+ count = edev->size - off;
+ if (unlikely(!count))
+ return count;
- cmd_addr = OP_READ << edev->addrlen;
+ mutex_lock(&edev->lock);
- if (edev->addrlen == 7) {
- cmd_addr |= off & 0x7f;
- bits = 10;
- } else {
- cmd_addr |= off & 0x3f;
- bits = 9;
- }
+ if (edev->pdata->prepare)
+ edev->pdata->prepare(edev);
- dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n",
- cmd_addr, edev->spi->max_speed_hz);
+ while (count) {
+ struct spi_message m;
+ struct spi_transfer t[2] = { { 0 } };
+ u16 cmd_addr = OP_READ << edev->addrlen;
+ size_t nbytes = count;
+ int bits;
+ int err;
+
+ if (edev->addrlen == 7) {
+ cmd_addr |= off & 0x7f;
+ bits = 10;
+ if (has_quirk_single_word_read(edev))
+ nbytes = 1;
+ } else {
+ cmd_addr |= (off >> 1) & 0x3f;
+ bits = 9;
+ if (has_quirk_single_word_read(edev))
+ nbytes = 2;
+ }
- spi_message_init(&m);
- memset(t, 0, sizeof(t));
+ dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n",
+ cmd_addr, edev->spi->max_speed_hz);
- t[0].tx_buf = (char *)&cmd_addr;
- t[0].len = 2;
- t[0].bits_per_word = bits;
- spi_message_add_tail(&t[0], &m);
+ spi_message_init(&m);
- t[1].rx_buf = buf;
- t[1].len = count;
- t[1].bits_per_word = 8;
- spi_message_add_tail(&t[1], &m);
+ t[0].tx_buf = (char *)&cmd_addr;
+ t[0].len = 2;
+ t[0].bits_per_word = bits;
+ spi_message_add_tail(&t[0], &m);
- mutex_lock(&edev->lock);
+ t[1].rx_buf = buf;
+ t[1].len = count;
+ t[1].bits_per_word = 8;
+ spi_message_add_tail(&t[1], &m);
- if (edev->pdata->prepare)
- edev->pdata->prepare(edev);
+ err = spi_sync(edev->spi, &m);
+ /* have to wait at least Tcsl ns */
+ ndelay(250);
- ret = spi_sync(edev->spi, &m);
- /* have to wait at least Tcsl ns */
- ndelay(250);
- if (ret) {
- dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n",
- count, (int)off, ret);
+ if (err) {
+ dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n",
+ nbytes, (int)off, err);
+ ret = err;
+ break;
+ }
+
+ buf += nbytes;
+ off += nbytes;
+ count -= nbytes;
+ ret += nbytes;
}
if (edev->pdata->finish)
edev->pdata->finish(edev);
mutex_unlock(&edev->lock);
- return ret ? : count;
+ return ret;
}
static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
@@ -110,7 +153,13 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
bits = 9;
}
- dev_dbg(&edev->spi->dev, "ew cmd 0x%04x\n", cmd_addr);
+ if (has_quirk_instruction_length(edev)) {
+ cmd_addr <<= 2;
+ bits += 2;
+ }
+
+ dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n",
+ is_on ? "en" : "ds", cmd_addr, bits);
spi_message_init(&m);
memset(&t, 0, sizeof(t));
@@ -155,7 +204,7 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
bits = 10;
data_len = 1;
} else {
- cmd_addr |= off & 0x3f;
+ cmd_addr |= (off >> 1) & 0x3f;
bits = 9;
data_len = 2;
}
@@ -182,16 +231,17 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
}
static ssize_t
-eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+eeprom_93xx46_write(struct eeprom_93xx46_dev *edev, const char *buf,
+ loff_t off, size_t count)
{
- struct eeprom_93xx46_dev *edev;
- struct device *dev;
int i, ret, step = 1;
- dev = container_of(kobj, struct device, kobj);
- edev = dev_get_drvdata(dev);
+ if (unlikely(off >= edev->size))
+ return -EFBIG;
+ if ((off + count) > edev->size)
+ count = edev->size - off;
+ if (unlikely(!count))
+ return count;
/* only write even number of bytes on 16-bit devices */
if (edev->addrlen == 6) {
@@ -228,6 +278,49 @@ eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj,
return ret ? : count;
}
+/*
+ * Provide a regmap interface, which is registered with the NVMEM
+ * framework
+*/
+static int eeprom_93xx46_regmap_read(void *context, const void *reg,
+ size_t reg_size, void *val,
+ size_t val_size)
+{
+ struct eeprom_93xx46_dev *eeprom_93xx46 = context;
+ off_t offset = *(u32 *)reg;
+ int err;
+
+ err = eeprom_93xx46_read(eeprom_93xx46, val, offset, val_size);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int eeprom_93xx46_regmap_write(void *context, const void *data,
+ size_t count)
+{
+ struct eeprom_93xx46_dev *eeprom_93xx46 = context;
+ const char *buf;
+ u32 offset;
+ size_t len;
+ int err;
+
+ memcpy(&offset, data, sizeof(offset));
+ buf = (const char *)data + sizeof(offset);
+ len = count - sizeof(offset);
+
+ err = eeprom_93xx46_write(eeprom_93xx46, buf, offset, len);
+ if (err)
+ return err;
+ return 0;
+}
+
+static const struct regmap_bus eeprom_93xx46_regmap_bus = {
+ .read = eeprom_93xx46_regmap_read,
+ .write = eeprom_93xx46_regmap_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
{
struct eeprom_93xx46_platform_data *pd = edev->pdata;
@@ -245,6 +338,13 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
bits = 9;
}
+ if (has_quirk_instruction_length(edev)) {
+ cmd_addr <<= 2;
+ bits += 2;
+ }
+
+ dev_dbg(&edev->spi->dev, "eral cmd 0x%04x, %d bits\n", cmd_addr, bits);
+
spi_message_init(&m);
memset(&t, 0, sizeof(t));
@@ -294,12 +394,101 @@ static ssize_t eeprom_93xx46_store_erase(struct device *dev,
}
static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase);
+static void select_assert(void *context)
+{
+ struct eeprom_93xx46_dev *edev = context;
+
+ gpiod_set_value_cansleep(edev->pdata->select, 1);
+}
+
+static void select_deassert(void *context)
+{
+ struct eeprom_93xx46_dev *edev = context;
+
+ gpiod_set_value_cansleep(edev->pdata->select, 0);
+}
+
+static const struct of_device_id eeprom_93xx46_of_table[] = {
+ { .compatible = "eeprom-93xx46", },
+ { .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, },
+ {}
+};
+MODULE_DEVICE_TABLE(of, eeprom_93xx46_of_table);
+
+static int eeprom_93xx46_probe_dt(struct spi_device *spi)
+{
+ const struct of_device_id *of_id =
+ of_match_device(eeprom_93xx46_of_table, &spi->dev);
+ struct device_node *np = spi->dev.of_node;
+ struct eeprom_93xx46_platform_data *pd;
+ u32 tmp;
+ int gpio;
+ enum of_gpio_flags of_flags;
+ int ret;
+
+ pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(np, "data-size", &tmp);
+ if (ret < 0) {
+ dev_err(&spi->dev, "data-size property not found\n");
+ return ret;
+ }
+
+ if (tmp == 8) {
+ pd->flags |= EE_ADDR8;
+ } else if (tmp == 16) {
+ pd->flags |= EE_ADDR16;
+ } else {
+ dev_err(&spi->dev, "invalid data-size (%d)\n", tmp);
+ return -EINVAL;
+ }
+
+ if (of_property_read_bool(np, "read-only"))
+ pd->flags |= EE_READONLY;
+
+ gpio = of_get_named_gpio_flags(np, "select-gpios", 0, &of_flags);
+ if (gpio_is_valid(gpio)) {
+ unsigned long flags =
+ of_flags == OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0;
+
+ ret = devm_gpio_request_one(&spi->dev, gpio, flags,
+ "eeprom_93xx46_select");
+ if (ret)
+ return ret;
+
+ pd->select = gpio_to_desc(gpio);
+ pd->prepare = select_assert;
+ pd->finish = select_deassert;
+
+ gpiod_direction_output(pd->select, 0);
+ }
+
+ if (of_id->data) {
+ const struct eeprom_93xx46_devtype_data *data = of_id->data;
+
+ pd->quirks = data->quirks;
+ }
+
+ spi->dev.platform_data = pd;
+
+ return 0;
+}
+
static int eeprom_93xx46_probe(struct spi_device *spi)
{
struct eeprom_93xx46_platform_data *pd;
struct eeprom_93xx46_dev *edev;
+ struct regmap *regmap;
int err;
+ if (spi->dev.of_node) {
+ err = eeprom_93xx46_probe_dt(spi);
+ if (err < 0)
+ return err;
+ }
+
pd = spi->dev.platform_data;
if (!pd) {
dev_err(&spi->dev, "missing platform data\n");
@@ -325,19 +514,34 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
edev->spi = spi_dev_get(spi);
edev->pdata = pd;
- sysfs_bin_attr_init(&edev->bin);
- edev->bin.attr.name = "eeprom";
- edev->bin.attr.mode = S_IRUSR;
- edev->bin.read = eeprom_93xx46_bin_read;
- edev->bin.size = 128;
- if (!(pd->flags & EE_READONLY)) {
- edev->bin.write = eeprom_93xx46_bin_write;
- edev->bin.attr.mode |= S_IWUSR;
+ edev->size = 128;
+
+ edev->regmap_config.reg_bits = 32;
+ edev->regmap_config.val_bits = 8;
+ edev->regmap_config.reg_stride = 1;
+ edev->regmap_config.max_register = edev->size - 1;
+
+ regmap = devm_regmap_init(&spi->dev, &eeprom_93xx46_regmap_bus, edev,
+ &edev->regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "regmap init failed\n");
+ err = PTR_ERR(regmap);
+ goto fail;
}
- err = sysfs_create_bin_file(&spi->dev.kobj, &edev->bin);
- if (err)
+ edev->nvmem_config.name = dev_name(&spi->dev);
+ edev->nvmem_config.dev = &spi->dev;
+ edev->nvmem_config.read_only = pd->flags & EE_READONLY;
+ edev->nvmem_config.root_only = true;
+ edev->nvmem_config.owner = THIS_MODULE;
+ edev->nvmem_config.compat = true;
+ edev->nvmem_config.base_dev = &spi->dev;
+
+ edev->nvmem = nvmem_register(&edev->nvmem_config);
+ if (IS_ERR(edev->nvmem)) {
+ err = PTR_ERR(edev->nvmem);
goto fail;
+ }
dev_info(&spi->dev, "%d-bit eeprom %s\n",
(pd->flags & EE_ADDR8) ? 8 : 16,
@@ -359,10 +563,11 @@ static int eeprom_93xx46_remove(struct spi_device *spi)
{
struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);
+ nvmem_unregister(edev->nvmem);
+
if (!(edev->pdata->flags & EE_READONLY))
device_remove_file(&spi->dev, &dev_attr_erase);
- sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin);
kfree(edev);
return 0;
}
@@ -370,6 +575,7 @@ static int eeprom_93xx46_remove(struct spi_device *spi)
static struct spi_driver eeprom_93xx46_driver = {
.driver = {
.name = "93xx46",
+ .of_match_table = of_match_ptr(eeprom_93xx46_of_table),
},
.probe = eeprom_93xx46_probe,
.remove = eeprom_93xx46_remove,
diff --git a/drivers/misc/genwqe/card_sysfs.c b/drivers/misc/genwqe/card_sysfs.c
index 6ab31eff0536..c24c9b7c1dd3 100644
--- a/drivers/misc/genwqe/card_sysfs.c
+++ b/drivers/misc/genwqe/card_sysfs.c
@@ -278,7 +278,7 @@ static umode_t genwqe_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
unsigned int j;
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct genwqe_dev *cd = dev_get_drvdata(dev);
umode_t mode = attr->mode;
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index 5bd127727d8e..9fea49d2e15b 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -34,6 +34,7 @@
#include <linux/kref.h>
#include <linux/device.h>
#include <linux/input.h>
+#include <linux/time64.h>
/* Driver identification */
#define DRIVER_NAME "ibmasm"
@@ -53,9 +54,11 @@ extern int ibmasm_debug;
static inline char *get_timestamp(char *buf)
{
- struct timeval now;
- do_gettimeofday(&now);
- sprintf(buf, "%lu.%lu", now.tv_sec, now.tv_usec);
+ struct timespec64 now;
+
+ ktime_get_real_ts64(&now);
+ sprintf(buf, "%llu.%.08lu", (long long)now.tv_sec,
+ now.tv_nsec / NSEC_PER_USEC);
return buf;
}
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index 0c3bb7e3ee80..14b7d539fed6 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -209,7 +209,7 @@ static int lis3lv02d_i2c_remove(struct i2c_client *client)
#ifdef CONFIG_PM_SLEEP
static int lis3lv02d_i2c_suspend(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
if (!lis3->pdata || !lis3->pdata->wakeup_flags)
@@ -219,7 +219,7 @@ static int lis3lv02d_i2c_suspend(struct device *dev)
static int lis3lv02d_i2c_resume(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
/*
@@ -238,7 +238,7 @@ static int lis3lv02d_i2c_resume(struct device *dev)
#ifdef CONFIG_PM
static int lis3_i2c_runtime_suspend(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
lis3lv02d_poweroff(lis3);
@@ -247,7 +247,7 @@ static int lis3_i2c_runtime_suspend(struct device *dev)
static int lis3_i2c_runtime_resume(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
lis3lv02d_poweron(lis3);
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 11fdadc68e53..5f1a36b8fbb0 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -92,6 +92,9 @@ enum ctype {
CT_UNALIGNED_LOAD_STORE_WRITE,
CT_OVERWRITE_ALLOCATION,
CT_WRITE_AFTER_FREE,
+ CT_READ_AFTER_FREE,
+ CT_WRITE_BUDDY_AFTER_FREE,
+ CT_READ_BUDDY_AFTER_FREE,
CT_SOFTLOCKUP,
CT_HARDLOCKUP,
CT_SPINLOCKUP,
@@ -103,7 +106,9 @@ enum ctype {
CT_EXEC_USERSPACE,
CT_ACCESS_USERSPACE,
CT_WRITE_RO,
+ CT_WRITE_RO_AFTER_INIT,
CT_WRITE_KERN,
+ CT_WRAP_ATOMIC
};
static char* cp_name[] = {
@@ -129,6 +134,9 @@ static char* cp_type[] = {
"UNALIGNED_LOAD_STORE_WRITE",
"OVERWRITE_ALLOCATION",
"WRITE_AFTER_FREE",
+ "READ_AFTER_FREE",
+ "WRITE_BUDDY_AFTER_FREE",
+ "READ_BUDDY_AFTER_FREE",
"SOFTLOCKUP",
"HARDLOCKUP",
"SPINLOCKUP",
@@ -140,7 +148,9 @@ static char* cp_type[] = {
"EXEC_USERSPACE",
"ACCESS_USERSPACE",
"WRITE_RO",
+ "WRITE_RO_AFTER_INIT",
"WRITE_KERN",
+ "WRAP_ATOMIC"
};
static struct jprobe lkdtm;
@@ -162,6 +172,7 @@ static DEFINE_SPINLOCK(lock_me_up);
static u8 data_area[EXEC_SIZE];
static const unsigned long rodata = 0xAA55AA55;
+static unsigned long ro_after_init __ro_after_init = 0x55AA5500;
module_param(recur_count, int, 0644);
MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test");
@@ -335,7 +346,7 @@ static noinline void corrupt_stack(void)
memset((void *)data, 0, 64);
}
-static void execute_location(void *dst)
+static void noinline execute_location(void *dst)
{
void (*func)(void) = dst;
@@ -409,12 +420,109 @@ static void lkdtm_do_action(enum ctype which)
break;
}
case CT_WRITE_AFTER_FREE: {
+ int *base, *again;
size_t len = 1024;
- u32 *data = kmalloc(len, GFP_KERNEL);
+ /*
+ * The slub allocator uses the first word to store the free
+ * pointer in some configurations. Use the middle of the
+ * allocation to avoid running into the freelist
+ */
+ size_t offset = (len / sizeof(*base)) / 2;
+
+ base = kmalloc(len, GFP_KERNEL);
+ pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]);
+ pr_info("Attempting bad write to freed memory at %p\n",
+ &base[offset]);
+ kfree(base);
+ base[offset] = 0x0abcdef0;
+ /* Attempt to notice the overwrite. */
+ again = kmalloc(len, GFP_KERNEL);
+ kfree(again);
+ if (again != base)
+ pr_info("Hmm, didn't get the same memory range.\n");
- kfree(data);
+ break;
+ }
+ case CT_READ_AFTER_FREE: {
+ int *base, *val, saw;
+ size_t len = 1024;
+ /*
+ * The slub allocator uses the first word to store the free
+ * pointer in some configurations. Use the middle of the
+ * allocation to avoid running into the freelist
+ */
+ size_t offset = (len / sizeof(*base)) / 2;
+
+ base = kmalloc(len, GFP_KERNEL);
+ if (!base)
+ break;
+
+ val = kmalloc(len, GFP_KERNEL);
+ if (!val)
+ break;
+
+ *val = 0x12345678;
+ base[offset] = *val;
+ pr_info("Value in memory before free: %x\n", base[offset]);
+
+ kfree(base);
+
+ pr_info("Attempting bad read from freed memory\n");
+ saw = base[offset];
+ if (saw != *val) {
+ /* Good! Poisoning happened, so declare a win. */
+ pr_info("Memory correctly poisoned (%x)\n", saw);
+ BUG();
+ }
+ pr_info("Memory was not poisoned\n");
+
+ kfree(val);
+ break;
+ }
+ case CT_WRITE_BUDDY_AFTER_FREE: {
+ unsigned long p = __get_free_page(GFP_KERNEL);
+ if (!p)
+ break;
+ pr_info("Writing to the buddy page before free\n");
+ memset((void *)p, 0x3, PAGE_SIZE);
+ free_page(p);
schedule();
- memset(data, 0x78, len);
+ pr_info("Attempting bad write to the buddy page after free\n");
+ memset((void *)p, 0x78, PAGE_SIZE);
+ /* Attempt to notice the overwrite. */
+ p = __get_free_page(GFP_KERNEL);
+ free_page(p);
+ schedule();
+
+ break;
+ }
+ case CT_READ_BUDDY_AFTER_FREE: {
+ unsigned long p = __get_free_page(GFP_KERNEL);
+ int saw, *val = kmalloc(1024, GFP_KERNEL);
+ int *base;
+
+ if (!p)
+ break;
+
+ if (!val)
+ break;
+
+ base = (int *)p;
+
+ *val = 0x12345678;
+ base[0] = *val;
+ pr_info("Value in memory before free: %x\n", base[0]);
+ free_page(p);
+ pr_info("Attempting to read from freed memory\n");
+ saw = base[0];
+ if (saw != *val) {
+ /* Good! Poisoning happened, so declare a win. */
+ pr_info("Memory correctly poisoned (%x)\n", saw);
+ BUG();
+ }
+ pr_info("Buddy page was not poisoned\n");
+
+ kfree(val);
break;
}
case CT_SOFTLOCKUP:
@@ -503,11 +611,28 @@ static void lkdtm_do_action(enum ctype which)
break;
}
case CT_WRITE_RO: {
- unsigned long *ptr;
+ /* Explicitly cast away "const" for the test. */
+ unsigned long *ptr = (unsigned long *)&rodata;
- ptr = (unsigned long *)&rodata;
+ pr_info("attempting bad rodata write at %p\n", ptr);
+ *ptr ^= 0xabcd1234;
- pr_info("attempting bad write at %p\n", ptr);
+ break;
+ }
+ case CT_WRITE_RO_AFTER_INIT: {
+ unsigned long *ptr = &ro_after_init;
+
+ /*
+ * Verify we were written to during init. Since an Oops
+ * is considered a "success", a failure is to just skip the
+ * real test.
+ */
+ if ((*ptr & 0xAA) != 0xAA) {
+ pr_info("%p was NOT written during init!?\n", ptr);
+ break;
+ }
+
+ pr_info("attempting bad ro_after_init write at %p\n", ptr);
*ptr ^= 0xabcd1234;
break;
@@ -528,6 +653,17 @@ static void lkdtm_do_action(enum ctype which)
do_overwritten();
break;
}
+ case CT_WRAP_ATOMIC: {
+ atomic_t under = ATOMIC_INIT(INT_MIN);
+ atomic_t over = ATOMIC_INIT(INT_MAX);
+
+ pr_info("attempting atomic underflow\n");
+ atomic_dec(&under);
+ pr_info("attempting atomic overflow\n");
+ atomic_inc(&over);
+
+ return;
+ }
case CT_NONE:
default:
break;
@@ -817,6 +953,9 @@ static int __init lkdtm_module_init(void)
int n_debugfs_entries = 1; /* Assume only the direct entry */
int i;
+ /* Make sure we can write to __ro_after_init values during __init */
+ ro_after_init |= 0xAA;
+
/* Register debugfs interface */
lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
if (!lkdtm_debugfs_root) {
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index d23384dde73b..c49e1d2269af 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -1,6 +1,6 @@
config INTEL_MEI
tristate "Intel Management Engine Interface"
- depends on X86 && PCI && WATCHDOG_CORE
+ depends on X86 && PCI
help
The Intel Management Engine (Intel ME) provides Manageability,
Security and Media services for system containing Intel chipsets.
@@ -12,7 +12,7 @@ config INTEL_MEI
config INTEL_MEI_ME
tristate "ME Enabled Intel Chipsets"
select INTEL_MEI
- depends on X86 && PCI && WATCHDOG_CORE
+ depends on X86 && PCI
help
MEI support for ME Enabled Intel chipsets.
@@ -37,7 +37,7 @@ config INTEL_MEI_ME
config INTEL_MEI_TXE
tristate "Intel Trusted Execution Environment with ME Interface"
select INTEL_MEI
- depends on X86 && PCI && WATCHDOG_CORE
+ depends on X86 && PCI
help
MEI Support for Trusted Execution Environment device on Intel SoCs
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 01447ca21c26..59e6b0aede34 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -9,7 +9,6 @@ mei-objs += interrupt.o
mei-objs += client.o
mei-objs += main.o
mei-objs += amthif.o
-mei-objs += wd.o
mei-objs += bus.o
mei-objs += bus-fixup.o
mei-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index cd0403f09267..194360a5f782 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -50,7 +50,6 @@ void mei_amthif_reset_params(struct mei_device *dev)
dev->iamthif_current_cb = NULL;
dev->iamthif_canceled = false;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
- dev->iamthif_timer = 0;
dev->iamthif_stall_timer = 0;
dev->iamthif_open_count = 0;
}
@@ -68,11 +67,14 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
struct mei_cl *cl = &dev->iamthif_cl;
int ret;
+ if (mei_cl_is_connected(cl))
+ return 0;
+
dev->iamthif_state = MEI_IAMTHIF_IDLE;
mei_cl_init(cl, dev);
- ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
+ ret = mei_cl_link(cl);
if (ret < 0) {
dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
return ret;
@@ -80,32 +82,10 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
ret = mei_cl_connect(cl, me_cl, NULL);
- dev->iamthif_state = MEI_IAMTHIF_IDLE;
-
return ret;
}
/**
- * mei_amthif_find_read_list_entry - finds a amthilist entry for current file
- *
- * @dev: the device structure
- * @file: pointer to file object
- *
- * Return: returned a list entry on success, NULL on failure.
- */
-struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
- struct file *file)
-{
- struct mei_cl_cb *cb;
-
- list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
- if (cb->file_object == file)
- return cb;
- return NULL;
-}
-
-
-/**
* mei_amthif_read - read data from AMTHIF client
*
* @dev: the device structure
@@ -126,18 +106,11 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
{
struct mei_cl *cl = file->private_data;
struct mei_cl_cb *cb;
- unsigned long timeout;
int rets;
int wait_ret;
- /* Only possible if we are in timeout */
- if (!cl) {
- dev_err(dev->dev, "bad file ext.\n");
- return -ETIME;
- }
-
dev_dbg(dev->dev, "checking amthif data\n");
- cb = mei_amthif_find_read_list_entry(dev, file);
+ cb = mei_cl_read_cb(cl, file);
/* Check for if we can block or not*/
if (cb == NULL && file->f_flags & O_NONBLOCK)
@@ -149,8 +122,9 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
/* unlock the Mutex */
mutex_unlock(&dev->device_lock);
- wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
- (cb = mei_amthif_find_read_list_entry(dev, file)));
+ wait_ret = wait_event_interruptible(cl->rx_wait,
+ !list_empty(&cl->rd_completed) ||
+ !mei_cl_is_connected(cl));
/* Locking again the Mutex */
mutex_lock(&dev->device_lock);
@@ -158,7 +132,12 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
if (wait_ret)
return -ERESTARTSYS;
- dev_dbg(dev->dev, "woke up from sleep\n");
+ if (!mei_cl_is_connected(cl)) {
+ rets = -EBUSY;
+ goto out;
+ }
+
+ cb = mei_cl_read_cb(cl, file);
}
if (cb->status) {
@@ -168,24 +147,10 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
}
dev_dbg(dev->dev, "Got amthif data\n");
- dev->iamthif_timer = 0;
-
- timeout = cb->read_time +
- mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
- dev_dbg(dev->dev, "amthif timeout = %lud\n",
- timeout);
-
- if (time_after(jiffies, timeout)) {
- dev_dbg(dev->dev, "amthif Time out\n");
- /* 15 sec for the message has expired */
- list_del_init(&cb->list);
- rets = -ETIME;
- goto free;
- }
/* if the whole message will fit remove it from the list */
if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
list_del_init(&cb->list);
- else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
+ else if (cb->buf_idx <= *offset) {
/* end of the message has been reached */
list_del_init(&cb->list);
rets = 0;
@@ -195,9 +160,8 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
* remove message from deletion list
*/
- dev_dbg(dev->dev, "amthif cb->buf size - %d\n",
- cb->buf.size);
- dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
+ dev_dbg(dev->dev, "amthif cb->buf.size - %zu cb->buf_idx - %zu\n",
+ cb->buf.size, cb->buf_idx);
/* length is being truncated to PAGE_SIZE, however,
* the buf_idx may point beyond */
@@ -229,7 +193,7 @@ out:
*
* Return: 0 on success, <0 on failure.
*/
-static int mei_amthif_read_start(struct mei_cl *cl, struct file *file)
+static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file)
{
struct mei_device *dev = cl->dev;
struct mei_cl_cb *cb;
@@ -248,7 +212,7 @@ static int mei_amthif_read_start(struct mei_cl *cl, struct file *file)
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
dev->iamthif_state = MEI_IAMTHIF_READING;
- dev->iamthif_file_object = cb->file_object;
+ dev->iamthif_fp = cb->fp;
dev->iamthif_current_cb = cb;
return 0;
@@ -277,7 +241,7 @@ static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
dev->iamthif_state = MEI_IAMTHIF_WRITING;
dev->iamthif_current_cb = cb;
- dev->iamthif_file_object = cb->file_object;
+ dev->iamthif_fp = cb->fp;
dev->iamthif_canceled = false;
ret = mei_cl_write(cl, cb, false);
@@ -285,7 +249,7 @@ static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
return ret;
if (cb->completed)
- cb->status = mei_amthif_read_start(cl, cb->file_object);
+ cb->status = mei_amthif_read_start(cl, cb->fp);
return 0;
}
@@ -304,8 +268,7 @@ int mei_amthif_run_next_cmd(struct mei_device *dev)
dev->iamthif_canceled = false;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
- dev->iamthif_timer = 0;
- dev->iamthif_file_object = NULL;
+ dev->iamthif_fp = NULL;
dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
@@ -329,17 +292,17 @@ int mei_amthif_run_next_cmd(struct mei_device *dev)
int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
{
- struct mei_device *dev;
-
- if (WARN_ON(!cl || !cl->dev))
- return -ENODEV;
+ struct mei_device *dev = cl->dev;
- if (WARN_ON(!cb))
- return -EINVAL;
+ list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
- dev = cl->dev;
+ /*
+ * The previous request is still in processing, queue this one.
+ */
+ if (dev->iamthif_state > MEI_IAMTHIF_IDLE &&
+ dev->iamthif_state < MEI_IAMTHIF_READ_COMPLETE)
+ return 0;
- list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
return mei_amthif_run_next_cmd(dev);
}
@@ -360,10 +323,10 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
{
unsigned int mask = 0;
- poll_wait(file, &dev->iamthif_cl.wait, wait);
+ poll_wait(file, &dev->iamthif_cl.rx_wait, wait);
if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
- dev->iamthif_file_object == file) {
+ dev->iamthif_fp == file) {
mask |= POLLIN | POLLRDNORM;
mei_amthif_run_next_cmd(dev);
@@ -393,7 +356,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
return ret;
if (cb->completed)
- cb->status = mei_amthif_read_start(cl, cb->file_object);
+ cb->status = mei_amthif_read_start(cl, cb->fp);
return 0;
}
@@ -437,11 +400,12 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl,
/**
* mei_amthif_complete - complete amthif callback.
*
- * @dev: the device structure.
+ * @cl: host client
* @cb: callback block.
*/
-void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
+void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
{
+ struct mei_device *dev = cl->dev;
if (cb->fop_type == MEI_FOP_WRITE) {
if (!cb->status) {
@@ -453,25 +417,22 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
* in case of error enqueue the write cb to complete read list
* so it can be propagated to the reader
*/
- list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
- wake_up_interruptible(&dev->iamthif_cl.wait);
+ list_add_tail(&cb->list, &cl->rd_completed);
+ wake_up_interruptible(&cl->rx_wait);
return;
}
if (!dev->iamthif_canceled) {
dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
dev->iamthif_stall_timer = 0;
- list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
+ list_add_tail(&cb->list, &cl->rd_completed);
dev_dbg(dev->dev, "amthif read completed\n");
- dev->iamthif_timer = jiffies;
- dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
- dev->iamthif_timer);
} else {
mei_amthif_run_next_cmd(dev);
}
dev_dbg(dev->dev, "completing amthif call back.\n");
- wake_up_interruptible(&dev->iamthif_cl.wait);
+ wake_up_interruptible(&cl->rx_wait);
}
/**
@@ -497,7 +458,7 @@ static bool mei_clear_list(struct mei_device *dev,
/* list all list member */
list_for_each_entry_safe(cb, next, mei_cb_list, list) {
/* check if list member associated with a file */
- if (file == cb->file_object) {
+ if (file == cb->fp) {
/* check if cb equal to current iamthif cb */
if (dev->iamthif_current_cb == cb) {
dev->iamthif_current_cb = NULL;
@@ -523,13 +484,14 @@ static bool mei_clear_list(struct mei_device *dev,
*
* Return: true if callback removed from the list, false otherwise
*/
-static bool mei_clear_lists(struct mei_device *dev, struct file *file)
+static bool mei_clear_lists(struct mei_device *dev, const struct file *file)
{
bool removed = false;
+ struct mei_cl *cl = &dev->iamthif_cl;
/* remove callbacks associated with a file */
mei_clear_list(dev, file, &dev->amthif_cmd_list.list);
- if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list))
+ if (mei_clear_list(dev, file, &cl->rd_completed))
removed = true;
mei_clear_list(dev, file, &dev->ctrl_rd_list.list);
@@ -546,7 +508,7 @@ static bool mei_clear_lists(struct mei_device *dev, struct file *file)
/* check if iamthif_current_cb not NULL */
if (dev->iamthif_current_cb && !removed) {
/* check file and iamthif current cb association */
- if (dev->iamthif_current_cb->file_object == file) {
+ if (dev->iamthif_current_cb->fp == file) {
/* remove cb */
mei_io_cb_free(dev->iamthif_current_cb);
dev->iamthif_current_cb = NULL;
@@ -569,7 +531,7 @@ int mei_amthif_release(struct mei_device *dev, struct file *file)
if (dev->iamthif_open_count > 0)
dev->iamthif_open_count--;
- if (dev->iamthif_file_object == file &&
+ if (dev->iamthif_fp == file &&
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c
index 020de5919c21..e9e6ea3ab73c 100644
--- a/drivers/misc/mei/bus-fixup.c
+++ b/drivers/misc/mei/bus-fixup.c
@@ -35,6 +35,9 @@ static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO;
#define MEI_UUID_NFC_HCI UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, \
0x94, 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
+#define MEI_UUID_WD UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, \
+ 0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB)
+
#define MEI_UUID_ANY NULL_UUID_LE
/**
@@ -48,8 +51,7 @@ static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO;
*/
static void number_of_connections(struct mei_cl_device *cldev)
{
- dev_dbg(&cldev->dev, "running hook %s on %pUl\n",
- __func__, mei_me_cl_uuid(cldev->me_cl));
+ dev_dbg(&cldev->dev, "running hook %s\n", __func__);
if (cldev->me_cl->props.max_number_of_connections > 1)
cldev->do_match = 0;
@@ -62,11 +64,36 @@ static void number_of_connections(struct mei_cl_device *cldev)
*/
static void blacklist(struct mei_cl_device *cldev)
{
- dev_dbg(&cldev->dev, "running hook %s on %pUl\n",
- __func__, mei_me_cl_uuid(cldev->me_cl));
+ dev_dbg(&cldev->dev, "running hook %s\n", __func__);
+
cldev->do_match = 0;
}
+/**
+ * mei_wd - wd client on the bus, change protocol version
+ * as the API has changed.
+ *
+ * @cldev: me clients device
+ */
+#if IS_ENABLED(CONFIG_INTEL_MEI_ME)
+#include <linux/pci.h>
+#include "hw-me-regs.h"
+static void mei_wd(struct mei_cl_device *cldev)
+{
+ struct pci_dev *pdev = to_pci_dev(cldev->dev.parent);
+
+ dev_dbg(&cldev->dev, "running hook %s\n", __func__);
+ if (pdev->device == MEI_DEV_ID_WPT_LP ||
+ pdev->device == MEI_DEV_ID_SPT ||
+ pdev->device == MEI_DEV_ID_SPT_H)
+ cldev->me_cl->props.protocol_version = 0x2;
+
+ cldev->do_match = 1;
+}
+#else
+static inline void mei_wd(struct mei_cl_device *cldev) {}
+#endif /* CONFIG_INTEL_MEI_ME */
+
struct mei_nfc_cmd {
u8 command;
u8 status;
@@ -208,12 +235,11 @@ static void mei_nfc(struct mei_cl_device *cldev)
bus = cldev->bus;
- dev_dbg(bus->dev, "running hook %s: %pUl match=%d\n",
- __func__, mei_me_cl_uuid(cldev->me_cl), cldev->do_match);
+ dev_dbg(&cldev->dev, "running hook %s\n", __func__);
mutex_lock(&bus->device_lock);
/* we need to connect to INFO GUID */
- cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY);
+ cl = mei_cl_alloc_linked(bus);
if (IS_ERR(cl)) {
ret = PTR_ERR(cl);
cl = NULL;
@@ -282,6 +308,7 @@ static struct mei_fixup {
MEI_FIXUP(MEI_UUID_ANY, number_of_connections),
MEI_FIXUP(MEI_UUID_NFC_INFO, blacklist),
MEI_FIXUP(MEI_UUID_NFC_HCI, mei_nfc),
+ MEI_FIXUP(MEI_UUID_WD, mei_wd),
};
/**
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 0b05aa938799..5d5996e39a67 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -44,7 +44,7 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
bool blocking)
{
struct mei_device *bus;
- struct mei_cl_cb *cb = NULL;
+ struct mei_cl_cb *cb;
ssize_t rets;
if (WARN_ON(!cl || !cl->dev))
@@ -53,6 +53,11 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
bus = cl->dev;
mutex_lock(&bus->device_lock);
+ if (bus->dev_state != MEI_DEV_ENABLED) {
+ rets = -ENODEV;
+ goto out;
+ }
+
if (!mei_cl_is_connected(cl)) {
rets = -ENODEV;
goto out;
@@ -81,8 +86,6 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
out:
mutex_unlock(&bus->device_lock);
- if (rets < 0)
- mei_io_cb_free(cb);
return rets;
}
@@ -109,6 +112,10 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
bus = cl->dev;
mutex_lock(&bus->device_lock);
+ if (bus->dev_state != MEI_DEV_ENABLED) {
+ rets = -ENODEV;
+ goto out;
+ }
cb = mei_cl_read_cb(cl, NULL);
if (cb)
@@ -230,45 +237,55 @@ static void mei_cl_bus_event_work(struct work_struct *work)
* mei_cl_bus_notify_event - schedule notify cb on bus client
*
* @cl: host client
+ *
+ * Return: true if event was scheduled
+ * false if the client is not waiting for event
*/
-void mei_cl_bus_notify_event(struct mei_cl *cl)
+bool mei_cl_bus_notify_event(struct mei_cl *cl)
{
struct mei_cl_device *cldev = cl->cldev;
if (!cldev || !cldev->event_cb)
- return;
+ return false;
if (!(cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)))
- return;
+ return false;
if (!cl->notify_ev)
- return;
+ return false;
set_bit(MEI_CL_EVENT_NOTIF, &cldev->events);
schedule_work(&cldev->event_work);
cl->notify_ev = false;
+
+ return true;
}
/**
- * mei_cl_bus_rx_event - schedule rx evenet
+ * mei_cl_bus_rx_event - schedule rx event
*
* @cl: host client
+ *
+ * Return: true if event was scheduled
+ * false if the client is not waiting for event
*/
-void mei_cl_bus_rx_event(struct mei_cl *cl)
+bool mei_cl_bus_rx_event(struct mei_cl *cl)
{
struct mei_cl_device *cldev = cl->cldev;
if (!cldev || !cldev->event_cb)
- return;
+ return false;
if (!(cldev->events_mask & BIT(MEI_CL_EVENT_RX)))
- return;
+ return false;
set_bit(MEI_CL_EVENT_RX, &cldev->events);
schedule_work(&cldev->event_work);
+
+ return true;
}
/**
@@ -398,7 +415,7 @@ int mei_cldev_enable(struct mei_cl_device *cldev)
if (!cl) {
mutex_lock(&bus->device_lock);
- cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY);
+ cl = mei_cl_alloc_linked(bus);
mutex_unlock(&bus->device_lock);
if (IS_ERR(cl))
return PTR_ERR(cl);
@@ -958,6 +975,22 @@ void mei_cl_bus_rescan(struct mei_device *bus)
dev_dbg(bus->dev, "rescan end");
}
+void mei_cl_bus_rescan_work(struct work_struct *work)
+{
+ struct mei_device *bus =
+ container_of(work, struct mei_device, bus_rescan_work);
+ struct mei_me_client *me_cl;
+
+ mutex_lock(&bus->device_lock);
+ me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid);
+ if (me_cl)
+ mei_amthif_host_init(bus, me_cl);
+ mei_me_cl_put(me_cl);
+ mutex_unlock(&bus->device_lock);
+
+ mei_cl_bus_rescan(bus);
+}
+
int __mei_cldev_driver_register(struct mei_cl_driver *cldrv,
struct module *owner)
{
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index a6c87c713193..bab17e4197b6 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -359,7 +359,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
* Return: mei_cl_cb pointer or NULL;
*/
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
- struct file *fp)
+ const struct file *fp)
{
struct mei_cl_cb *cb;
@@ -368,7 +368,7 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
return NULL;
INIT_LIST_HEAD(&cb->list);
- cb->file_object = fp;
+ cb->fp = fp;
cb->cl = cl;
cb->buf_idx = 0;
cb->fop_type = type;
@@ -455,7 +455,8 @@ int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
* Return: cb on success and NULL on failure
*/
struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
- enum mei_cb_file_ops type, struct file *fp)
+ enum mei_cb_file_ops type,
+ const struct file *fp)
{
struct mei_cl_cb *cb;
@@ -485,7 +486,7 @@ struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp)
struct mei_cl_cb *cb;
list_for_each_entry(cb, &cl->rd_completed, list)
- if (!fp || fp == cb->file_object)
+ if (!fp || fp == cb->fp)
return cb;
return NULL;
@@ -503,12 +504,12 @@ void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp)
struct mei_cl_cb *cb, *next;
list_for_each_entry_safe(cb, next, &cl->rd_completed, list)
- if (!fp || fp == cb->file_object)
+ if (!fp || fp == cb->fp)
mei_io_cb_free(cb);
list_for_each_entry_safe(cb, next, &cl->rd_pending, list)
- if (!fp || fp == cb->file_object)
+ if (!fp || fp == cb->fp)
mei_io_cb_free(cb);
}
@@ -535,7 +536,6 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
- mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
mei_cl_read_cb_flush(cl, fp);
@@ -587,27 +587,23 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
* mei_cl_link - allocate host id in the host map
*
* @cl: host client
- * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one
*
* Return: 0 on success
* -EINVAL on incorrect values
* -EMFILE if open count exceeded.
*/
-int mei_cl_link(struct mei_cl *cl, int id)
+int mei_cl_link(struct mei_cl *cl)
{
struct mei_device *dev;
long open_handle_count;
+ int id;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
dev = cl->dev;
- /* If Id is not assigned get one*/
- if (id == MEI_HOST_CLIENT_ID_ANY)
- id = find_first_zero_bit(dev->host_clients_map,
- MEI_CLIENTS_MAX);
-
+ id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
if (id >= MEI_CLIENTS_MAX) {
dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
return -EMFILE;
@@ -648,7 +644,7 @@ int mei_cl_unlink(struct mei_cl *cl)
if (!cl)
return 0;
- /* wd and amthif might not be initialized */
+ /* amthif might not be initialized */
if (!cl->dev)
return 0;
@@ -670,31 +666,12 @@ int mei_cl_unlink(struct mei_cl *cl)
return 0;
}
-
-void mei_host_client_init(struct work_struct *work)
+void mei_host_client_init(struct mei_device *dev)
{
- struct mei_device *dev =
- container_of(work, struct mei_device, init_work);
- struct mei_me_client *me_cl;
-
- mutex_lock(&dev->device_lock);
-
-
- me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
- if (me_cl)
- mei_amthif_host_init(dev, me_cl);
- mei_me_cl_put(me_cl);
-
- me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
- if (me_cl)
- mei_wd_host_init(dev, me_cl);
- mei_me_cl_put(me_cl);
-
dev->dev_state = MEI_DEV_ENABLED;
dev->reset_count = 0;
- mutex_unlock(&dev->device_lock);
- mei_cl_bus_rescan(dev);
+ schedule_work(&dev->bus_rescan_work);
pm_runtime_mark_last_busy(dev->dev);
dev_dbg(dev->dev, "rpm: autosuspend\n");
@@ -726,6 +703,33 @@ bool mei_hbuf_acquire(struct mei_device *dev)
}
/**
+ * mei_cl_wake_all - wake up readers, writers and event waiters so
+ * they can be interrupted
+ *
+ * @cl: host client
+ */
+static void mei_cl_wake_all(struct mei_cl *cl)
+{
+ struct mei_device *dev = cl->dev;
+
+ /* synchronized under device mutex */
+ if (waitqueue_active(&cl->rx_wait)) {
+ cl_dbg(dev, cl, "Waking up reading client!\n");
+ wake_up_interruptible(&cl->rx_wait);
+ }
+ /* synchronized under device mutex */
+ if (waitqueue_active(&cl->tx_wait)) {
+ cl_dbg(dev, cl, "Waking up writing client!\n");
+ wake_up_interruptible(&cl->tx_wait);
+ }
+ /* synchronized under device mutex */
+ if (waitqueue_active(&cl->ev_wait)) {
+ cl_dbg(dev, cl, "Waking up waiting for event clients!\n");
+ wake_up_interruptible(&cl->ev_wait);
+ }
+}
+
+/**
* mei_cl_set_disconnected - set disconnected state and clear
* associated states and resources
*
@@ -740,8 +744,11 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
return;
cl->state = MEI_FILE_DISCONNECTED;
+ mei_io_list_free(&dev->write_list, cl);
+ mei_io_list_free(&dev->write_waiting_list, cl);
mei_io_list_flush(&dev->ctrl_rd_list, cl);
mei_io_list_flush(&dev->ctrl_wr_list, cl);
+ mei_cl_wake_all(cl);
cl->mei_flow_ctrl_creds = 0;
cl->timer_count = 0;
@@ -1034,7 +1041,7 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
* Return: 0 on success, <0 on failure.
*/
int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
- struct file *file)
+ const struct file *file)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
@@ -1119,11 +1126,10 @@ nortpm:
* mei_cl_alloc_linked - allocate and link host client
*
* @dev: the device structure
- * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one
*
* Return: cl on success ERR_PTR on failure
*/
-struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id)
+struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev)
{
struct mei_cl *cl;
int ret;
@@ -1134,7 +1140,7 @@ struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id)
goto err;
}
- ret = mei_cl_link(cl, id);
+ ret = mei_cl_link(cl);
if (ret)
goto err;
@@ -1149,11 +1155,12 @@ err:
/**
* mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
*
- * @cl: private data of the file object
+ * @cl: host client
+ * @fp: the file pointer associated with the pointer
*
* Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
*/
-int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
+static int mei_cl_flow_ctrl_creds(struct mei_cl *cl, const struct file *fp)
{
int rets;
@@ -1164,7 +1171,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
return 1;
if (mei_cl_is_fixed_address(cl)) {
- rets = mei_cl_read_start(cl, mei_cl_mtu(cl), NULL);
+ rets = mei_cl_read_start(cl, mei_cl_mtu(cl), fp);
if (rets && rets != -EBUSY)
return rets;
return 1;
@@ -1186,7 +1193,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
* 0 on success
* -EINVAL when ctrl credits are <= 0
*/
-int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
+static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
{
if (WARN_ON(!cl || !cl->me_cl))
return -EINVAL;
@@ -1283,7 +1290,8 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
*
* Return: 0 on such and error otherwise.
*/
-int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request)
+int mei_cl_notify_request(struct mei_cl *cl,
+ const struct file *file, u8 request)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
@@ -1368,12 +1376,12 @@ void mei_cl_notify(struct mei_cl *cl)
cl_dbg(dev, cl, "notify event");
cl->notify_ev = true;
- wake_up_interruptible_all(&cl->ev_wait);
+ if (!mei_cl_bus_notify_event(cl))
+ wake_up_interruptible(&cl->ev_wait);
if (cl->ev_async)
kill_fasync(&cl->ev_async, SIGIO, POLL_PRI);
- mei_cl_bus_notify_event(cl);
}
/**
@@ -1422,6 +1430,25 @@ out:
}
/**
+ * mei_cl_is_read_fc_cb - check if read cb is waiting for flow control
+ * for given host client
+ *
+ * @cl: host client
+ *
+ * Return: true, if found at least one cb.
+ */
+static bool mei_cl_is_read_fc_cb(struct mei_cl *cl)
+{
+ struct mei_device *dev = cl->dev;
+ struct mei_cl_cb *cb;
+
+ list_for_each_entry(cb, &dev->ctrl_wr_list.list, list)
+ if (cb->fop_type == MEI_FOP_READ && cb->cl == cl)
+ return true;
+ return false;
+}
+
+/**
* mei_cl_read_start - the start read client message function.
*
* @cl: host client
@@ -1430,7 +1457,7 @@ out:
*
* Return: 0 on success, <0 on failure.
*/
-int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
+int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
@@ -1445,7 +1472,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
return -ENODEV;
/* HW currently supports only one pending read */
- if (!list_empty(&cl->rd_pending))
+ if (!list_empty(&cl->rd_pending) || mei_cl_is_read_fc_cb(cl))
return -EBUSY;
if (!mei_me_cl_is_active(cl->me_cl)) {
@@ -1524,7 +1551,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
first_chunk = cb->buf_idx == 0;
- rets = first_chunk ? mei_cl_flow_ctrl_creds(cl) : 1;
+ rets = first_chunk ? mei_cl_flow_ctrl_creds(cl, cb->fp) : 1;
if (rets < 0)
return rets;
@@ -1556,7 +1583,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
return 0;
}
- cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
+ cl_dbg(dev, cl, "buf: size = %zu idx = %zu\n",
cb->buf.size, cb->buf_idx);
rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
@@ -1618,7 +1645,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
- return rets;
+ goto free;
}
cb->buf_idx = 0;
@@ -1630,7 +1657,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
mei_hdr.msg_complete = 0;
mei_hdr.internal = cb->internal;
- rets = mei_cl_flow_ctrl_creds(cl);
+ rets = mei_cl_flow_ctrl_creds(cl, cb->fp);
if (rets < 0)
goto err;
@@ -1677,7 +1704,8 @@ out:
mutex_unlock(&dev->device_lock);
rets = wait_event_interruptible(cl->tx_wait,
- cl->writing_state == MEI_WRITE_COMPLETE);
+ cl->writing_state == MEI_WRITE_COMPLETE ||
+ (!mei_cl_is_connected(cl)));
mutex_lock(&dev->device_lock);
/* wait_event_interruptible returns -ERESTARTSYS */
if (rets) {
@@ -1685,6 +1713,10 @@ out:
rets = -EINTR;
goto err;
}
+ if (cl->writing_state != MEI_WRITE_COMPLETE) {
+ rets = -EFAULT;
+ goto err;
+ }
}
rets = size;
@@ -1692,6 +1724,8 @@ err:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
+free:
+ mei_io_cb_free(cb);
return rets;
}
@@ -1721,10 +1755,8 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
case MEI_FOP_READ:
list_add_tail(&cb->list, &cl->rd_completed);
- if (waitqueue_active(&cl->rx_wait))
- wake_up_interruptible_all(&cl->rx_wait);
- else
- mei_cl_bus_rx_event(cl);
+ if (!mei_cl_bus_rx_event(cl))
+ wake_up_interruptible(&cl->rx_wait);
break;
case MEI_FOP_CONNECT:
@@ -1753,44 +1785,3 @@ void mei_cl_all_disconnect(struct mei_device *dev)
list_for_each_entry(cl, &dev->file_list, link)
mei_cl_set_disconnected(cl);
}
-
-
-/**
- * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
- *
- * @dev: mei device
- */
-void mei_cl_all_wakeup(struct mei_device *dev)
-{
- struct mei_cl *cl;
-
- list_for_each_entry(cl, &dev->file_list, link) {
- if (waitqueue_active(&cl->rx_wait)) {
- cl_dbg(dev, cl, "Waking up reading client!\n");
- wake_up_interruptible(&cl->rx_wait);
- }
- if (waitqueue_active(&cl->tx_wait)) {
- cl_dbg(dev, cl, "Waking up writing client!\n");
- wake_up_interruptible(&cl->tx_wait);
- }
-
- /* synchronized under device mutex */
- if (waitqueue_active(&cl->ev_wait)) {
- cl_dbg(dev, cl, "Waking up waiting for event clients!\n");
- wake_up_interruptible(&cl->ev_wait);
- }
- }
-}
-
-/**
- * mei_cl_all_write_clear - clear all pending writes
- *
- * @dev: mei device
- */
-void mei_cl_all_write_clear(struct mei_device *dev)
-{
- mei_io_list_free(&dev->write_list, NULL);
- mei_io_list_free(&dev->write_waiting_list, NULL);
-}
-
-
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 04e1aa39243f..0d7a3a1fef78 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -18,7 +18,6 @@
#define _MEI_CLIENT_H_
#include <linux/types.h>
-#include <linux/watchdog.h>
#include <linux/poll.h>
#include <linux/mei.h>
@@ -84,7 +83,7 @@ static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl)
* MEI IO Functions
*/
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
- struct file *fp);
+ const struct file *fp);
void mei_io_cb_free(struct mei_cl_cb *priv_cb);
int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length);
@@ -108,21 +107,19 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev);
void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
-int mei_cl_link(struct mei_cl *cl, int id);
+int mei_cl_link(struct mei_cl *cl);
int mei_cl_unlink(struct mei_cl *cl);
-struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id);
+struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev);
struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl,
const struct file *fp);
void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp);
struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
- enum mei_cb_file_ops type, struct file *fp);
+ enum mei_cb_file_ops type,
+ const struct file *fp);
int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp);
-int mei_cl_flow_ctrl_creds(struct mei_cl *cl);
-
-int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
/*
* MEI input output function prototype
*/
@@ -217,10 +214,10 @@ void mei_cl_set_disconnected(struct mei_cl *cl);
int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list);
int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
- struct file *file);
+ const struct file *file);
int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list);
-int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp);
+int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp);
int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr,
struct mei_cl_cb *cmpl_list);
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
@@ -229,19 +226,18 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
-void mei_host_client_init(struct work_struct *work);
+void mei_host_client_init(struct mei_device *dev);
u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop);
enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request);
-int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request);
+int mei_cl_notify_request(struct mei_cl *cl,
+ const struct file *file, u8 request);
int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list);
int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev);
void mei_cl_notify(struct mei_cl *cl);
void mei_cl_all_disconnect(struct mei_device *dev);
-void mei_cl_all_wakeup(struct mei_device *dev);
-void mei_cl_all_write_clear(struct mei_device *dev);
#define MEI_CL_FMT "cl:host=%02d me=%02d "
#define MEI_CL_PRM(cl) (cl)->host_client_id, mei_cl_me_id(cl)
@@ -249,6 +245,9 @@ void mei_cl_all_write_clear(struct mei_device *dev);
#define cl_dbg(dev, cl, format, arg...) \
dev_dbg((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
+#define cl_warn(dev, cl, format, arg...) \
+ dev_warn((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
+
#define cl_err(dev, cl, format, arg...) \
dev_err((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index a138d8a27ab5..c6c051b52f55 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -50,6 +50,7 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
}
pos += scnprintf(buf + pos, bufsz - pos, HDR);
+#undef HDR
/* if the driver is not enabled the list won't be consistent */
if (dev->dev_state != MEI_DEV_ENABLED)
@@ -90,23 +91,37 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
{
struct mei_device *dev = fp->private_data;
struct mei_cl *cl;
- const size_t bufsz = 1024;
+ size_t bufsz = 1;
char *buf;
int i = 0;
int pos = 0;
int ret;
+#define HDR " |me|host|state|rd|wr|\n"
+
if (!dev)
return -ENODEV;
+ mutex_lock(&dev->device_lock);
+
+ /*
+ * if the driver is not enabled the list won't be consistent,
+ * we output empty table
+ */
+ if (dev->dev_state == MEI_DEV_ENABLED)
+ list_for_each_entry(cl, &dev->file_list, link)
+ bufsz++;
+
+ bufsz *= sizeof(HDR) + 1;
+
buf = kzalloc(bufsz, GFP_KERNEL);
- if (!buf)
+ if (!buf) {
+ mutex_unlock(&dev->device_lock);
return -ENOMEM;
+ }
- pos += scnprintf(buf + pos, bufsz - pos,
- " |me|host|state|rd|wr|\n");
-
- mutex_lock(&dev->device_lock);
+ pos += scnprintf(buf + pos, bufsz - pos, HDR);
+#undef HDR
/* if the driver is not enabled the list won't be consistent */
if (dev->dev_state != MEI_DEV_ENABLED)
@@ -115,7 +130,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
list_for_each_entry(cl, &dev->file_list, link) {
pos += scnprintf(buf + pos, bufsz - pos,
- "%2d|%2d|%4d|%5d|%2d|%2d|\n",
+ "%3d|%2d|%4d|%5d|%2d|%2d|\n",
i, mei_cl_me_id(cl), cl->host_client_id, cl->state,
!list_empty(&cl->rd_completed), cl->writing_state);
i++;
@@ -150,16 +165,21 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n",
mei_hbm_state_str(dev->hbm_state));
- if (dev->hbm_state == MEI_HBM_STARTED) {
+ if (dev->hbm_state >= MEI_HBM_ENUM_CLIENTS &&
+ dev->hbm_state <= MEI_HBM_STARTED) {
pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n");
pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n",
dev->hbm_f_pg_supported);
pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",
dev->hbm_f_dc_supported);
+ pos += scnprintf(buf + pos, bufsz - pos, "\tIE: %01d\n",
+ dev->hbm_f_ie_supported);
pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n",
dev->hbm_f_dot_supported);
pos += scnprintf(buf + pos, bufsz - pos, "\tEV: %01d\n",
dev->hbm_f_ev_supported);
+ pos += scnprintf(buf + pos, bufsz - pos, "\tFA: %01d\n",
+ dev->hbm_f_fa_supported);
}
pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n",
@@ -175,6 +195,30 @@ static const struct file_operations mei_dbgfs_fops_devstate = {
.llseek = generic_file_llseek,
};
+static ssize_t mei_dbgfs_write_allow_fa(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct mei_device *dev;
+ int ret;
+
+ dev = container_of(file->private_data,
+ struct mei_device, allow_fixed_address);
+
+ ret = debugfs_write_file_bool(file, user_buf, count, ppos);
+ if (ret < 0)
+ return ret;
+ dev->override_fixed_address = true;
+ return ret;
+}
+
+static const struct file_operations mei_dbgfs_fops_allow_fa = {
+ .open = simple_open,
+ .read = debugfs_read_file_bool,
+ .write = mei_dbgfs_write_allow_fa,
+ .llseek = generic_file_llseek,
+};
+
/**
* mei_dbgfs_deregister - Remove the debugfs files and directories
*
@@ -224,8 +268,9 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name)
dev_err(dev->dev, "devstate: registration failed\n");
goto err;
}
- f = debugfs_create_bool("allow_fixed_address", S_IRUSR | S_IWUSR, dir,
- &dev->allow_fixed_address);
+ f = debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir,
+ &dev->allow_fixed_address,
+ &mei_dbgfs_fops_allow_fa);
if (!f) {
dev_err(dev->dev, "allow_fixed_address: registration failed\n");
goto err;
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index e7b7aad0999b..5e305d2605f3 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -301,7 +301,10 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev)
enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
memset(enum_req, 0, len);
enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
- enum_req->allow_add = dev->hbm_f_dc_supported;
+ enum_req->flags |= dev->hbm_f_dc_supported ?
+ MEI_HBM_ENUM_F_ALLOW_ADD : 0;
+ enum_req->flags |= dev->hbm_f_ie_supported ?
+ MEI_HBM_ENUM_F_IMMEDIATE_ENUM : 0;
ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
if (ret) {
@@ -401,6 +404,9 @@ static int mei_hbm_fw_add_cl_req(struct mei_device *dev,
if (ret)
status = !MEI_HBMS_SUCCESS;
+ if (dev->dev_state == MEI_DEV_ENABLED)
+ schedule_work(&dev->bus_rescan_work);
+
return mei_hbm_add_cl_resp(dev, req->me_addr, status);
}
@@ -543,7 +549,7 @@ static int mei_hbm_prop_req(struct mei_device *dev)
/* We got all client properties */
if (next_client_index == MEI_CLIENTS_MAX) {
dev->hbm_state = MEI_HBM_STARTED;
- schedule_work(&dev->init_work);
+ mei_host_client_init(dev);
return 0;
}
@@ -789,8 +795,11 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl,
cl->state = MEI_FILE_CONNECTED;
else {
cl->state = MEI_FILE_DISCONNECT_REPLY;
- if (rs->status == MEI_CL_CONN_NOT_FOUND)
+ if (rs->status == MEI_CL_CONN_NOT_FOUND) {
mei_me_cl_del(dev, cl->me_cl);
+ if (dev->dev_state == MEI_DEV_ENABLED)
+ schedule_work(&dev->bus_rescan_work);
+ }
}
cl->status = mei_cl_conn_status_to_errno(rs->status);
}
@@ -866,7 +875,7 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
cl = mei_hbm_cl_find_by_cmd(dev, disconnect_req);
if (cl) {
- cl_dbg(dev, cl, "fw disconnect request received\n");
+ cl_warn(dev, cl, "fw disconnect request received\n");
cl->state = MEI_FILE_DISCONNECTING;
cl->timer_count = 0;
@@ -972,6 +981,9 @@ static void mei_hbm_config_features(struct mei_device *dev)
if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
dev->hbm_f_dc_supported = 1;
+ if (dev->version.major_version >= HBM_MAJOR_VERSION_IE)
+ dev->hbm_f_ie_supported = 1;
+
/* disconnect on connect timeout instead of link reset */
if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
dev->hbm_f_dot_supported = 1;
@@ -979,6 +991,10 @@ static void mei_hbm_config_features(struct mei_device *dev)
/* Notification Event Support */
if (dev->version.major_version >= HBM_MAJOR_VERSION_EV)
dev->hbm_f_ev_supported = 1;
+
+ /* Fixed Address Client Support */
+ if (dev->version.major_version >= HBM_MAJOR_VERSION_FA)
+ dev->hbm_f_fa_supported = 1;
}
/**
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
index a8a68acd3267..0dcb854b4bfc 100644
--- a/drivers/misc/mei/hw-me-regs.h
+++ b/drivers/misc/mei/hw-me-regs.h
@@ -121,6 +121,10 @@
#define MEI_DEV_ID_SPT_2 0x9D3B /* Sunrise Point 2 */
#define MEI_DEV_ID_SPT_H 0xA13A /* Sunrise Point H */
#define MEI_DEV_ID_SPT_H_2 0xA13B /* Sunrise Point H 2 */
+
+#define MEI_DEV_ID_BXT_M 0x1A9A /* Broxton M */
+#define MEI_DEV_ID_APL_I 0x5A9A /* Apollo Lake I */
+
/*
* MEI HW Section
*/
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 25b1997a62cb..e2fb44cc5c37 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -189,8 +189,11 @@ static int mei_me_fw_status(struct mei_device *dev,
fw_status->count = fw_src->count;
for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
- ret = pci_read_config_dword(pdev,
- fw_src->status[i], &fw_status->status[i]);
+ ret = pci_read_config_dword(pdev, fw_src->status[i],
+ &fw_status->status[i]);
+ trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HSF_X",
+ fw_src->status[i],
+ fw_status->status[i]);
if (ret)
return ret;
}
@@ -215,6 +218,7 @@ static void mei_me_hw_config(struct mei_device *dev)
reg = 0;
pci_read_config_dword(pdev, PCI_CFG_HFS_1, &reg);
+ trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HFS_1", PCI_CFG_HFS_1, reg);
hw->d0i3_supported =
((reg & PCI_CFG_HFS_1_D0I3_MSK) == PCI_CFG_HFS_1_D0I3_MSK);
@@ -1248,6 +1252,7 @@ static bool mei_me_fw_type_nm(struct pci_dev *pdev)
u32 reg;
pci_read_config_dword(pdev, PCI_CFG_HFS_2, &reg);
+ trace_mei_pci_cfg_read(&pdev->dev, "PCI_CFG_HFS_2", PCI_CFG_HFS_2, reg);
/* make sure that bit 9 (NM) is up and bit 10 (DM) is down */
return (reg & 0x600) == 0x200;
}
@@ -1260,6 +1265,7 @@ static bool mei_me_fw_type_sps(struct pci_dev *pdev)
u32 reg;
/* Read ME FW Status check for SPS Firmware */
pci_read_config_dword(pdev, PCI_CFG_HFS_1, &reg);
+ trace_mei_pci_cfg_read(&pdev->dev, "PCI_CFG_HFS_1", PCI_CFG_HFS_1, reg);
/* if bits [19:16] = 15, running SPS Firmware */
return (reg & 0xf0000) == 0xf0000;
}
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
index bae680c648ff..4a6c1b85f11e 100644
--- a/drivers/misc/mei/hw-txe.c
+++ b/drivers/misc/mei/hw-txe.c
@@ -28,6 +28,9 @@
#include "client.h"
#include "hbm.h"
+#include "mei-trace.h"
+
+
/**
* mei_txe_reg_read - Reads 32bit data from the txe device
*
@@ -640,8 +643,11 @@ static int mei_txe_fw_status(struct mei_device *dev,
fw_status->count = fw_src->count;
for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
- ret = pci_read_config_dword(pdev,
- fw_src->status[i], &fw_status->status[i]);
+ ret = pci_read_config_dword(pdev, fw_src->status[i],
+ &fw_status->status[i]);
+ trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HSF_X",
+ fw_src->status[i],
+ fw_status->status[i]);
if (ret)
return ret;
}
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index 4cebde85924f..9daf3f9aed25 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -29,7 +29,6 @@
#define MEI_CLIENTS_INIT_TIMEOUT 15 /* HPS: Clients Enumeration Timeout */
#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */
-#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */
#define MEI_PGI_TIMEOUT 1 /* PG Isolation time response 1 sec */
#define MEI_D0I3_TIMEOUT 5 /* D0i3 set/unset max response time */
@@ -54,6 +53,12 @@
#define HBM_MAJOR_VERSION_DC 2
/*
+ * MEI version with immediate reply to enum request support
+ */
+#define HBM_MINOR_VERSION_IE 0
+#define HBM_MAJOR_VERSION_IE 2
+
+/*
* MEI version with disconnect on connection timeout support
*/
#define HBM_MINOR_VERSION_DOT 0
@@ -65,6 +70,12 @@
#define HBM_MINOR_VERSION_EV 0
#define HBM_MAJOR_VERSION_EV 2
+/*
+ * MEI version with fixed address client support
+ */
+#define HBM_MINOR_VERSION_FA 0
+#define HBM_MAJOR_VERSION_FA 2
+
/* Host bus message command opcode */
#define MEI_HBM_CMD_OP_MSK 0x7f
/* Host bus message command RESPONSE */
@@ -241,15 +252,26 @@ struct hbm_me_stop_request {
} __packed;
/**
- * struct hbm_host_enum_request - enumeration request from host to fw
+ * enum hbm_host_enum_flags - enumeration request flags (HBM version >= 2.0)
*
- * @hbm_cmd: bus message command header
- * @allow_add: allow dynamic clients add HBM version >= 2.0
+ * @MEI_HBM_ENUM_F_ALLOW_ADD: allow dynamic clients add
+ * @MEI_HBM_ENUM_F_IMMEDIATE_ENUM: allow FW to send answer immediately
+ */
+enum hbm_host_enum_flags {
+ MEI_HBM_ENUM_F_ALLOW_ADD = BIT(0),
+ MEI_HBM_ENUM_F_IMMEDIATE_ENUM = BIT(1),
+};
+
+/**
+ * struct hbm_host_enum_request - enumeration request from host to fw
+ *
+ * @hbm_cmd : bus message command header
+ * @flags : request flags
* @reserved: reserved
*/
struct hbm_host_enum_request {
u8 hbm_cmd;
- u8 allow_add;
+ u8 flags;
u8 reserved[2];
} __packed;
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 3edafc8d3ad4..f7c8dfdb6a12 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -91,8 +91,8 @@ EXPORT_SYMBOL_GPL(mei_fw_status2str);
*/
void mei_cancel_work(struct mei_device *dev)
{
- cancel_work_sync(&dev->init_work);
cancel_work_sync(&dev->reset_work);
+ cancel_work_sync(&dev->bus_rescan_work);
cancel_delayed_work(&dev->timer_work);
}
@@ -148,16 +148,10 @@ int mei_reset(struct mei_device *dev)
state != MEI_DEV_POWER_UP) {
/* remove all waiting requests */
- mei_cl_all_write_clear(dev);
-
mei_cl_all_disconnect(dev);
- /* wake up all readers and writers so they can be interrupted */
- mei_cl_all_wakeup(dev);
-
/* remove entry if already in list */
- dev_dbg(dev->dev, "remove iamthif and wd from the file list.\n");
- mei_cl_unlink(&dev->wd_cl);
+ dev_dbg(dev->dev, "remove iamthif from the file list.\n");
mei_cl_unlink(&dev->iamthif_cl);
mei_amthif_reset_params(dev);
}
@@ -165,7 +159,6 @@ int mei_reset(struct mei_device *dev)
mei_hbm_reset(dev);
dev->rd_msg_hdr = 0;
- dev->wd_pending = false;
if (ret) {
dev_err(dev->dev, "hw_reset failed ret = %d\n", ret);
@@ -335,16 +328,12 @@ void mei_stop(struct mei_device *dev)
mutex_lock(&dev->device_lock);
- mei_wd_stop(dev);
-
dev->dev_state = MEI_DEV_POWER_DOWN;
mei_reset(dev);
/* move device to disabled state unconditionally */
dev->dev_state = MEI_DEV_DISABLED;
mutex_unlock(&dev->device_lock);
-
- mei_watchdog_unregister(dev);
}
EXPORT_SYMBOL_GPL(mei_stop);
@@ -394,7 +383,6 @@ void mei_device_init(struct mei_device *dev,
init_waitqueue_head(&dev->wait_hw_ready);
init_waitqueue_head(&dev->wait_pg);
init_waitqueue_head(&dev->wait_hbm_start);
- init_waitqueue_head(&dev->wait_stop_wd);
dev->dev_state = MEI_DEV_INITIALIZING;
dev->reset_count = 0;
@@ -404,13 +392,11 @@ void mei_device_init(struct mei_device *dev,
mei_io_list_init(&dev->ctrl_rd_list);
INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
- INIT_WORK(&dev->init_work, mei_host_client_init);
INIT_WORK(&dev->reset_work, mei_reset_work);
+ INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work);
- INIT_LIST_HEAD(&dev->wd_cl.link);
INIT_LIST_HEAD(&dev->iamthif_cl.link);
mei_io_list_init(&dev->amthif_cmd_list);
- mei_io_list_init(&dev->amthif_rd_complete_list);
bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
dev->open_handle_count = 0;
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 64b568a0268d..1e5cb1f704f8 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -48,7 +48,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
dev_dbg(dev->dev, "completing call back.\n");
if (cl == &dev->iamthif_cl)
- mei_amthif_complete(dev, cb);
+ mei_amthif_complete(cl, cb);
else
mei_cl_complete(cl, cb);
}
@@ -104,6 +104,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
struct mei_device *dev = cl->dev;
struct mei_cl_cb *cb;
unsigned char *buffer = NULL;
+ size_t buf_sz;
cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list);
if (!cb) {
@@ -124,11 +125,21 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
goto out;
}
- if (cb->buf.size < mei_hdr->length + cb->buf_idx) {
- cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n",
+ buf_sz = mei_hdr->length + cb->buf_idx;
+ /* catch for integer overflow */
+ if (buf_sz < cb->buf_idx) {
+ cl_err(dev, cl, "message is too big len %d idx %zu\n",
+ mei_hdr->length, cb->buf_idx);
+
+ list_move_tail(&cb->list, &complete_list->list);
+ cb->status = -EMSGSIZE;
+ goto out;
+ }
+
+ if (cb->buf.size < buf_sz) {
+ cl_dbg(dev, cl, "message overflow. size %zu len %d idx %zu\n",
cb->buf.size, mei_hdr->length, cb->buf_idx);
- buffer = krealloc(cb->buf.data, mei_hdr->length + cb->buf_idx,
- GFP_KERNEL);
+ buffer = krealloc(cb->buf.data, buf_sz, GFP_KERNEL);
if (!buffer) {
cb->status = -ENOMEM;
@@ -136,7 +147,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
goto out;
}
cb->buf.data = buffer;
- cb->buf.size = mei_hdr->length + cb->buf_idx;
+ cb->buf.size = buf_sz;
}
buffer = cb->buf.data + cb->buf_idx;
@@ -145,8 +156,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
cb->buf_idx += mei_hdr->length;
if (mei_hdr->msg_complete) {
- cb->read_time = jiffies;
- cl_dbg(dev, cl, "completed read length = %lu\n", cb->buf_idx);
+ cl_dbg(dev, cl, "completed read length = %zu\n", cb->buf_idx);
list_move_tail(&cb->list, &complete_list->list);
} else {
pm_runtime_mark_last_busy(dev->dev);
@@ -229,6 +239,16 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
return 0;
}
+static inline bool hdr_is_hbm(struct mei_msg_hdr *mei_hdr)
+{
+ return mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0;
+}
+
+static inline bool hdr_is_fixed(struct mei_msg_hdr *mei_hdr)
+{
+ return mei_hdr->host_addr == 0 && mei_hdr->me_addr != 0;
+}
+
/**
* mei_irq_read_handler - bottom half read routine after ISR to
* handle the read processing.
@@ -270,7 +290,7 @@ int mei_irq_read_handler(struct mei_device *dev,
}
/* HBM message */
- if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) {
+ if (hdr_is_hbm(mei_hdr)) {
ret = mei_hbm_dispatch(dev, mei_hdr);
if (ret) {
dev_dbg(dev->dev, "mei_hbm_dispatch failed ret = %d\n",
@@ -290,6 +310,14 @@ int mei_irq_read_handler(struct mei_device *dev,
/* if no recipient cl was found we assume corrupted header */
if (&cl->link == &dev->file_list) {
+ /* A message for not connected fixed address clients
+ * should be silently discarded
+ */
+ if (hdr_is_fixed(mei_hdr)) {
+ mei_irq_discard_msg(dev, mei_hdr);
+ ret = 0;
+ goto reset_slots;
+ }
dev_err(dev->dev, "no destination client found 0x%08X\n",
dev->rd_msg_hdr);
ret = -EBADMSG;
@@ -360,21 +388,6 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
list_move_tail(&cb->list, &cmpl_list->list);
}
- if (dev->wd_state == MEI_WD_STOPPING) {
- dev->wd_state = MEI_WD_IDLE;
- wake_up(&dev->wait_stop_wd);
- }
-
- if (mei_cl_is_connected(&dev->wd_cl)) {
- if (dev->wd_pending &&
- mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
- ret = mei_wd_send(dev);
- if (ret)
- return ret;
- dev->wd_pending = false;
- }
- }
-
/* complete control write list CB */
dev_dbg(dev->dev, "complete control write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list.list, list) {
@@ -462,7 +475,6 @@ static void mei_connect_timeout(struct mei_cl *cl)
*/
void mei_timer(struct work_struct *work)
{
- unsigned long timeout;
struct mei_cl *cl;
struct mei_device *dev = container_of(work,
@@ -508,45 +520,15 @@ void mei_timer(struct work_struct *work)
mei_reset(dev);
dev->iamthif_canceled = false;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
- dev->iamthif_timer = 0;
mei_io_cb_free(dev->iamthif_current_cb);
dev->iamthif_current_cb = NULL;
- dev->iamthif_file_object = NULL;
+ dev->iamthif_fp = NULL;
mei_amthif_run_next_cmd(dev);
}
}
- if (dev->iamthif_timer) {
-
- timeout = dev->iamthif_timer +
- mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
-
- dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
- dev->iamthif_timer);
- dev_dbg(dev->dev, "timeout = %ld\n", timeout);
- dev_dbg(dev->dev, "jiffies = %ld\n", jiffies);
- if (time_after(jiffies, timeout)) {
- /*
- * User didn't read the AMTHI data on time (15sec)
- * freeing AMTHI for other requests
- */
-
- dev_dbg(dev->dev, "freeing AMTHI for other requests\n");
-
- mei_io_list_flush(&dev->amthif_rd_complete_list,
- &dev->iamthif_cl);
- mei_io_cb_free(dev->iamthif_current_cb);
- dev->iamthif_current_cb = NULL;
-
- dev->iamthif_file_object->private_data = NULL;
- dev->iamthif_file_object = NULL;
- dev->iamthif_timer = 0;
- mei_amthif_run_next_cmd(dev);
-
- }
- }
out:
if (dev->dev_state != MEI_DEV_DISABLED)
schedule_delayed_work(&dev->timer_work, 2 * HZ);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 80f9afcb1382..52635b063873 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -65,7 +65,7 @@ static int mei_open(struct inode *inode, struct file *file)
goto err_unlock;
}
- cl = mei_cl_alloc_linked(dev, MEI_HOST_CLIENT_ID_ANY);
+ cl = mei_cl_alloc_linked(dev);
if (IS_ERR(cl)) {
err = PTR_ERR(cl);
goto err_unlock;
@@ -159,27 +159,22 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
goto out;
}
+ if (ubuf == NULL) {
+ rets = -EMSGSIZE;
+ goto out;
+ }
+
if (cl == &dev->iamthif_cl) {
rets = mei_amthif_read(dev, file, ubuf, length, offset);
goto out;
}
cb = mei_cl_read_cb(cl, file);
- if (cb) {
- /* read what left */
- if (cb->buf_idx > *offset)
- goto copy_buffer;
- /* offset is beyond buf_idx we have no more data return 0 */
- if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
- rets = 0;
- goto free;
- }
- /* Offset needs to be cleaned for contiguous reads*/
- if (cb->buf_idx == 0 && *offset > 0)
- *offset = 0;
- } else if (*offset > 0) {
+ if (cb)
+ goto copy_buffer;
+
+ if (*offset > 0)
*offset = 0;
- }
err = mei_cl_read_start(cl, length, file);
if (err && err != -EBUSY) {
@@ -214,11 +209,6 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
cb = mei_cl_read_cb(cl, file);
if (!cb) {
- if (mei_cl_is_fixed_address(cl) && dev->allow_fixed_address) {
- cb = mei_cl_read_cb(cl, NULL);
- if (cb)
- goto copy_buffer;
- }
rets = 0;
goto out;
}
@@ -231,10 +221,10 @@ copy_buffer:
goto free;
}
- cl_dbg(dev, cl, "buf.size = %d buf.idx = %ld\n",
- cb->buf.size, cb->buf_idx);
- if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) {
- rets = -EMSGSIZE;
+ cl_dbg(dev, cl, "buf.size = %zu buf.idx = %zu offset = %lld\n",
+ cb->buf.size, cb->buf_idx, *offset);
+ if (*offset >= cb->buf_idx) {
+ rets = 0;
goto free;
}
@@ -250,11 +240,13 @@ copy_buffer:
rets = length;
*offset += length;
- if ((unsigned long)*offset < cb->buf_idx)
+ /* not all data was read, keep the cb */
+ if (*offset < cb->buf_idx)
goto out;
free:
mei_io_cb_free(cb);
+ *offset = 0;
out:
cl_dbg(dev, cl, "end mei read rets = %d\n", rets);
@@ -275,9 +267,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
size_t length, loff_t *offset)
{
struct mei_cl *cl = file->private_data;
- struct mei_cl_cb *write_cb = NULL;
+ struct mei_cl_cb *cb;
struct mei_device *dev;
- unsigned long timeout = 0;
int rets;
if (WARN_ON(!cl || !cl->dev))
@@ -313,52 +304,31 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
goto out;
}
- if (cl == &dev->iamthif_cl) {
- write_cb = mei_amthif_find_read_list_entry(dev, file);
-
- if (write_cb) {
- timeout = write_cb->read_time +
- mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
-
- if (time_after(jiffies, timeout)) {
- *offset = 0;
- mei_io_cb_free(write_cb);
- write_cb = NULL;
- }
- }
- }
-
*offset = 0;
- write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
- if (!write_cb) {
+ cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
+ if (!cb) {
rets = -ENOMEM;
goto out;
}
- rets = copy_from_user(write_cb->buf.data, ubuf, length);
+ rets = copy_from_user(cb->buf.data, ubuf, length);
if (rets) {
dev_dbg(dev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
+ mei_io_cb_free(cb);
goto out;
}
if (cl == &dev->iamthif_cl) {
- rets = mei_amthif_write(cl, write_cb);
-
- if (rets) {
- dev_err(dev->dev,
- "amthif write failed with status = %d\n", rets);
- goto out;
- }
- mutex_unlock(&dev->device_lock);
- return length;
+ rets = mei_amthif_write(cl, cb);
+ if (!rets)
+ rets = length;
+ goto out;
}
- rets = mei_cl_write(cl, write_cb, false);
+ rets = mei_cl_write(cl, cb, false);
out:
mutex_unlock(&dev->device_lock);
- if (rets < 0)
- mei_io_cb_free(write_cb);
return rets;
}
@@ -393,12 +363,22 @@ static int mei_ioctl_connect_client(struct file *file,
/* find ME client we're trying to connect to */
me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
- if (!me_cl ||
- (me_cl->props.fixed_address && !dev->allow_fixed_address)) {
+ if (!me_cl) {
dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
&data->in_client_uuid);
- mei_me_cl_put(me_cl);
- return -ENOTTY;
+ rets = -ENOTTY;
+ goto end;
+ }
+
+ if (me_cl->props.fixed_address) {
+ bool forbidden = dev->override_fixed_address ?
+ !dev->allow_fixed_address : !dev->hbm_f_fa_supported;
+ if (forbidden) {
+ dev_dbg(dev->dev, "Connection forbidden to FW Client UUID = %pUl\n",
+ &data->in_client_uuid);
+ rets = -ENOTTY;
+ goto end;
+ }
}
dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
@@ -454,7 +434,7 @@ end:
*
* Return: 0 on success , <0 on error
*/
-static int mei_ioctl_client_notify_request(struct file *file, u32 request)
+static int mei_ioctl_client_notify_request(const struct file *file, u32 request)
{
struct mei_cl *cl = file->private_data;
@@ -473,7 +453,7 @@ static int mei_ioctl_client_notify_request(struct file *file, u32 request)
*
* Return: 0 on success , <0 on error
*/
-static int mei_ioctl_client_notify_get(struct file *file, u32 *notify_get)
+static int mei_ioctl_client_notify_get(const struct file *file, u32 *notify_get)
{
struct mei_cl *cl = file->private_data;
bool notify_ev;
diff --git a/drivers/misc/mei/mei-trace.c b/drivers/misc/mei/mei-trace.c
index 388efb519138..e19e6acb191b 100644
--- a/drivers/misc/mei/mei-trace.c
+++ b/drivers/misc/mei/mei-trace.c
@@ -22,4 +22,6 @@
EXPORT_TRACEPOINT_SYMBOL(mei_reg_read);
EXPORT_TRACEPOINT_SYMBOL(mei_reg_write);
+EXPORT_TRACEPOINT_SYMBOL(mei_pci_cfg_read);
+EXPORT_TRACEPOINT_SYMBOL(mei_pci_cfg_write);
#endif /* __CHECKER__ */
diff --git a/drivers/misc/mei/mei-trace.h b/drivers/misc/mei/mei-trace.h
index 47e1bc6551d4..7d2d5d4a1624 100644
--- a/drivers/misc/mei/mei-trace.h
+++ b/drivers/misc/mei/mei-trace.h
@@ -60,7 +60,45 @@ TRACE_EVENT(mei_reg_write,
__entry->offs = offs;
__entry->val = val;
),
- TP_printk("[%s] write %s[%#x] = %#x)",
+ TP_printk("[%s] write %s[%#x] = %#x",
+ __get_str(dev), __entry->reg, __entry->offs, __entry->val)
+);
+
+TRACE_EVENT(mei_pci_cfg_read,
+ TP_PROTO(const struct device *dev, const char *reg, u32 offs, u32 val),
+ TP_ARGS(dev, reg, offs, val),
+ TP_STRUCT__entry(
+ __string(dev, dev_name(dev))
+ __field(const char *, reg)
+ __field(u32, offs)
+ __field(u32, val)
+ ),
+ TP_fast_assign(
+ __assign_str(dev, dev_name(dev))
+ __entry->reg = reg;
+ __entry->offs = offs;
+ __entry->val = val;
+ ),
+ TP_printk("[%s] pci cfg read %s:[%#x] = %#x",
+ __get_str(dev), __entry->reg, __entry->offs, __entry->val)
+);
+
+TRACE_EVENT(mei_pci_cfg_write,
+ TP_PROTO(const struct device *dev, const char *reg, u32 offs, u32 val),
+ TP_ARGS(dev, reg, offs, val),
+ TP_STRUCT__entry(
+ __string(dev, dev_name(dev))
+ __field(const char *, reg)
+ __field(u32, offs)
+ __field(u32, val)
+ ),
+ TP_fast_assign(
+ __assign_str(dev, dev_name(dev))
+ __entry->reg = reg;
+ __entry->offs = offs;
+ __entry->val = val;
+ ),
+ TP_printk("[%s] pci cfg write %s[%#x] = %#x",
__get_str(dev), __entry->reg, __entry->offs, __entry->val)
);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 4250555d5e72..db78e6d99456 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -18,7 +18,7 @@
#define _MEI_DEV_H_
#include <linux/types.h>
-#include <linux/watchdog.h>
+#include <linux/cdev.h>
#include <linux/poll.h>
#include <linux/mei.h>
#include <linux/mei_cl_bus.h>
@@ -26,33 +26,13 @@
#include "hw.h"
#include "hbm.h"
-/*
- * watch dog definition
- */
-#define MEI_WD_HDR_SIZE 4
-#define MEI_WD_STOP_MSG_SIZE MEI_WD_HDR_SIZE
-#define MEI_WD_START_MSG_SIZE (MEI_WD_HDR_SIZE + 16)
-
-#define MEI_WD_DEFAULT_TIMEOUT 120 /* seconds */
-#define MEI_WD_MIN_TIMEOUT 120 /* seconds */
-#define MEI_WD_MAX_TIMEOUT 65535 /* seconds */
-
-#define MEI_WD_STOP_TIMEOUT 10 /* msecs */
-
-#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
-
-#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
-
/*
* AMTHI Client UUID
*/
extern const uuid_le mei_amthif_guid;
-/*
- * Watchdog Client UUID
- */
-extern const uuid_le mei_wd_guid;
+#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
/*
* Number of Maximum MEI Clients
@@ -73,15 +53,6 @@ extern const uuid_le mei_wd_guid;
*/
#define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1)
-/*
- * Internal Clients Number
- */
-#define MEI_HOST_CLIENT_ID_ANY (-1)
-#define MEI_HBM_HOST_CLIENT_ID 0 /* not used, just for documentation */
-#define MEI_WD_HOST_CLIENT_ID 1
-#define MEI_IAMTHIF_HOST_CLIENT_ID 2
-
-
/* File state */
enum file_state {
MEI_FILE_INITIALIZING = 0,
@@ -123,12 +94,6 @@ enum mei_file_transaction_states {
MEI_READ_COMPLETE
};
-enum mei_wd_states {
- MEI_WD_IDLE,
- MEI_WD_RUNNING,
- MEI_WD_STOPPING,
-};
-
/**
* enum mei_cb_file_ops - file operation associated with the callback
* @MEI_FOP_READ: read
@@ -153,7 +118,7 @@ enum mei_cb_file_ops {
* Intel MEI message data struct
*/
struct mei_msg_data {
- u32 size;
+ size_t size;
unsigned char *data;
};
@@ -206,8 +171,7 @@ struct mei_cl;
* @fop_type: file operation type
* @buf: buffer for data associated with the callback
* @buf_idx: last read index
- * @read_time: last read operation time stamp (iamthif)
- * @file_object: pointer to file structure
+ * @fp: pointer to file structure
* @status: io status of the cb
* @internal: communication between driver and FW flag
* @completed: the transfer or reception has completed
@@ -217,9 +181,8 @@ struct mei_cl_cb {
struct mei_cl *cl;
enum mei_cb_file_ops fop_type;
struct mei_msg_data buf;
- unsigned long buf_idx;
- unsigned long read_time;
- struct file *file_object;
+ size_t buf_idx;
+ const struct file *fp;
int status;
u32 internal:1;
u32 completed:1;
@@ -341,12 +304,13 @@ struct mei_hw_ops {
/* MEI bus API*/
void mei_cl_bus_rescan(struct mei_device *bus);
+void mei_cl_bus_rescan_work(struct work_struct *work);
void mei_cl_bus_dev_fixup(struct mei_cl_device *dev);
ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
bool blocking);
ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
-void mei_cl_bus_rx_event(struct mei_cl *cl);
-void mei_cl_bus_notify_event(struct mei_cl *cl);
+bool mei_cl_bus_rx_event(struct mei_cl *cl);
+bool mei_cl_bus_notify_event(struct mei_cl *cl);
void mei_cl_bus_remove_devices(struct mei_device *bus);
int mei_cl_bus_init(void);
void mei_cl_bus_exit(void);
@@ -404,7 +368,6 @@ const char *mei_pg_state_str(enum mei_pg_state state);
* @wait_hw_ready : wait queue for receive HW ready message form FW
* @wait_pg : wait queue for receive PG message from FW
* @wait_hbm_start : wait queue for receive HBM start message from FW
- * @wait_stop_wd : wait queue for receive WD stop message from FW
*
* @reset_count : number of consecutive resets
* @dev_state : device state
@@ -426,6 +389,8 @@ const char *mei_pg_state_str(enum mei_pg_state state);
* @hbm_f_dc_supported : hbm feature dynamic clients
* @hbm_f_dot_supported : hbm feature disconnect on timeout
* @hbm_f_ev_supported : hbm feature event notification
+ * @hbm_f_fa_supported : hbm feature fixed address client
+ * @hbm_f_ie_supported : hbm feature immediate reply to enum request
*
* @me_clients_rwsem: rw lock over me_clients list
* @me_clients : list of FW clients
@@ -434,26 +399,19 @@ const char *mei_pg_state_str(enum mei_pg_state state);
* @me_client_index : last FW client index in enumeration
*
* @allow_fixed_address: allow user space to connect a fixed client
- *
- * @wd_cl : watchdog client
- * @wd_state : watchdog client state
- * @wd_pending : watchdog command is pending
- * @wd_timeout : watchdog expiration timeout
- * @wd_data : watchdog message buffer
+ * @override_fixed_address: force allow fixed address behavior
*
* @amthif_cmd_list : amthif list for cmd waiting
- * @amthif_rd_complete_list : amthif list for reading completed cmd data
- * @iamthif_file_object : file for current amthif operation
+ * @iamthif_fp : file for current amthif operation
* @iamthif_cl : amthif host client
* @iamthif_current_cb : amthif current operation callback
* @iamthif_open_count : number of opened amthif connections
- * @iamthif_timer : time stamp of current amthif command completion
* @iamthif_stall_timer : timer to detect amthif hang
* @iamthif_state : amthif processor state
* @iamthif_canceled : current amthif command is canceled
*
- * @init_work : work item for the device init
* @reset_work : work item for the device reset
+ * @bus_rescan_work : work item for the bus rescan
*
* @device_list : mei client bus list
* @cl_bus_lock : client bus list lock
@@ -486,7 +444,6 @@ struct mei_device {
wait_queue_head_t wait_hw_ready;
wait_queue_head_t wait_pg;
wait_queue_head_t wait_hbm_start;
- wait_queue_head_t wait_stop_wd;
/*
* mei device states
@@ -522,6 +479,8 @@ struct mei_device {
unsigned int hbm_f_dc_supported:1;
unsigned int hbm_f_dot_supported:1;
unsigned int hbm_f_ev_supported:1;
+ unsigned int hbm_f_fa_supported:1;
+ unsigned int hbm_f_ie_supported:1;
struct rw_semaphore me_clients_rwsem;
struct list_head me_clients;
@@ -530,29 +489,21 @@ struct mei_device {
unsigned long me_client_index;
bool allow_fixed_address;
-
- struct mei_cl wd_cl;
- enum mei_wd_states wd_state;
- bool wd_pending;
- u16 wd_timeout;
- unsigned char wd_data[MEI_WD_START_MSG_SIZE];
-
+ bool override_fixed_address;
/* amthif list for cmd waiting */
struct mei_cl_cb amthif_cmd_list;
/* driver managed amthif list for reading completed amthif cmd data */
- struct mei_cl_cb amthif_rd_complete_list;
- struct file *iamthif_file_object;
+ const struct file *iamthif_fp;
struct mei_cl iamthif_cl;
struct mei_cl_cb *iamthif_current_cb;
long iamthif_open_count;
- unsigned long iamthif_timer;
u32 iamthif_stall_timer;
enum iamthif_states iamthif_state;
bool iamthif_canceled;
- struct work_struct init_work;
struct work_struct reset_work;
+ struct work_struct bus_rescan_work;
/* List of bus devices */
struct list_head device_list;
@@ -635,47 +586,18 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
int mei_amthif_release(struct mei_device *dev, struct file *file);
-struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
- struct file *file);
-
int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb);
int mei_amthif_run_next_cmd(struct mei_device *dev);
int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list);
-void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb);
+void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
int mei_amthif_irq_read_msg(struct mei_cl *cl,
struct mei_msg_hdr *mei_hdr,
struct mei_cl_cb *complete_list);
int mei_amthif_irq_read(struct mei_device *dev, s32 *slots);
/*
- * NFC functions
- */
-int mei_nfc_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
-void mei_nfc_host_exit(struct mei_device *dev);
-
-/*
- * NFC Client UUID
- */
-extern const uuid_le mei_nfc_guid;
-
-int mei_wd_send(struct mei_device *dev);
-int mei_wd_stop(struct mei_device *dev);
-int mei_wd_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
-/*
- * mei_watchdog_register - Registering watchdog interface
- * once we got connection to the WD Client
- * @dev: mei device
- */
-int mei_watchdog_register(struct mei_device *dev);
-/*
- * mei_watchdog_unregister - Unregistering watchdog interface
- * @dev: mei device
- */
-void mei_watchdog_unregister(struct mei_device *dev);
-
-/*
* Register Access Function
*/
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index 75fc9c688df8..64e64da6da44 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -88,6 +88,9 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, mei_me_pch8_cfg)},
{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, mei_me_pch8_cfg)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, mei_me_pch8_cfg)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, mei_me_pch8_cfg)},
+
/* required last entry */
{0, }
};
@@ -210,7 +213,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = mei_register(dev, &pdev->dev);
if (err)
- goto release_irq;
+ goto stop;
pci_set_drvdata(pdev, dev);
@@ -231,6 +234,8 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
+stop:
+ mei_stop(dev);
release_irq:
mei_cancel_work(dev);
mei_disable_interrupts(dev);
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index 71f8a7475717..30cc30683c07 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -154,7 +154,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = mei_register(dev, &pdev->dev);
if (err)
- goto release_irq;
+ goto stop;
pci_set_drvdata(pdev, dev);
@@ -170,6 +170,8 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
+stop:
+ mei_stop(dev);
release_irq:
mei_cancel_work(dev);
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
deleted file mode 100644
index b346638833b0..000000000000
--- a/drivers/misc/mei/wd.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/sched.h>
-#include <linux/watchdog.h>
-
-#include <linux/mei.h>
-
-#include "mei_dev.h"
-#include "hbm.h"
-#include "client.h"
-
-static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
-static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
-
-/*
- * AMT Watchdog Device
- */
-#define INTEL_AMT_WATCHDOG_ID "INTCAMT"
-
-/* UUIDs for AMT F/W clients */
-const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
- 0x9D, 0xA9, 0x15, 0x14, 0xCB,
- 0x32, 0xAB);
-
-static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
-{
- dev_dbg(dev->dev, "wd: set timeout=%d.\n", timeout);
- memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
- memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16));
-}
-
-/**
- * mei_wd_host_init - connect to the watchdog client
- *
- * @dev: the device structure
- * @me_cl: me client
- *
- * Return: -ENOTTY if wd client cannot be found
- * -EIO if write has failed
- * 0 on success
- */
-int mei_wd_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
-{
- struct mei_cl *cl = &dev->wd_cl;
- int ret;
-
- mei_cl_init(cl, dev);
-
- dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
- dev->wd_state = MEI_WD_IDLE;
-
- ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
- if (ret < 0) {
- dev_info(dev->dev, "wd: failed link client\n");
- return ret;
- }
-
- ret = mei_cl_connect(cl, me_cl, NULL);
- if (ret) {
- dev_err(dev->dev, "wd: failed to connect = %d\n", ret);
- mei_cl_unlink(cl);
- return ret;
- }
-
- ret = mei_watchdog_register(dev);
- if (ret) {
- mei_cl_disconnect(cl);
- mei_cl_unlink(cl);
- }
- return ret;
-}
-
-/**
- * mei_wd_send - sends watch dog message to fw.
- *
- * @dev: the device structure
- *
- * Return: 0 if success,
- * -EIO when message send fails
- * -EINVAL when invalid message is to be sent
- * -ENODEV on flow control failure
- */
-int mei_wd_send(struct mei_device *dev)
-{
- struct mei_cl *cl = &dev->wd_cl;
- struct mei_msg_hdr hdr;
- int ret;
-
- hdr.host_addr = cl->host_client_id;
- hdr.me_addr = mei_cl_me_id(cl);
- hdr.msg_complete = 1;
- hdr.reserved = 0;
- hdr.internal = 0;
-
- if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))
- hdr.length = MEI_WD_START_MSG_SIZE;
- else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
- hdr.length = MEI_WD_STOP_MSG_SIZE;
- else {
- dev_err(dev->dev, "wd: invalid message is to be sent, aborting\n");
- return -EINVAL;
- }
-
- ret = mei_write_message(dev, &hdr, dev->wd_data);
- if (ret) {
- dev_err(dev->dev, "wd: write message failed\n");
- return ret;
- }
-
- ret = mei_cl_flow_ctrl_reduce(cl);
- if (ret) {
- dev_err(dev->dev, "wd: flow_ctrl_reduce failed.\n");
- return ret;
- }
-
- return 0;
-}
-
-/**
- * mei_wd_stop - sends watchdog stop message to fw.
- *
- * @dev: the device structure
- *
- * Return: 0 if success
- * on error:
- * -EIO when message send fails
- * -EINVAL when invalid message is to be sent
- * -ETIME on message timeout
- */
-int mei_wd_stop(struct mei_device *dev)
-{
- struct mei_cl *cl = &dev->wd_cl;
- int ret;
-
- if (!mei_cl_is_connected(cl) ||
- dev->wd_state != MEI_WD_RUNNING)
- return 0;
-
- memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE);
-
- dev->wd_state = MEI_WD_STOPPING;
-
- ret = mei_cl_flow_ctrl_creds(cl);
- if (ret < 0)
- goto err;
-
- if (ret && mei_hbuf_acquire(dev)) {
- ret = mei_wd_send(dev);
- if (ret)
- goto err;
- dev->wd_pending = false;
- } else {
- dev->wd_pending = true;
- }
-
- mutex_unlock(&dev->device_lock);
-
- ret = wait_event_timeout(dev->wait_stop_wd,
- dev->wd_state == MEI_WD_IDLE,
- msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
- mutex_lock(&dev->device_lock);
- if (dev->wd_state != MEI_WD_IDLE) {
- /* timeout */
- ret = -ETIME;
- dev_warn(dev->dev, "wd: stop failed to complete ret=%d\n", ret);
- goto err;
- }
- dev_dbg(dev->dev, "wd: stop completed after %u msec\n",
- MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret));
- return 0;
-err:
- return ret;
-}
-
-/**
- * mei_wd_ops_start - wd start command from the watchdog core.
- *
- * @wd_dev: watchdog device struct
- *
- * Return: 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_start(struct watchdog_device *wd_dev)
-{
- struct mei_device *dev;
- struct mei_cl *cl;
- int err = -ENODEV;
-
- dev = watchdog_get_drvdata(wd_dev);
- if (!dev)
- return -ENODEV;
-
- cl = &dev->wd_cl;
-
- mutex_lock(&dev->device_lock);
-
- if (dev->dev_state != MEI_DEV_ENABLED) {
- dev_dbg(dev->dev, "wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n",
- mei_dev_state_str(dev->dev_state));
- goto end_unlock;
- }
-
- if (!mei_cl_is_connected(cl)) {
- cl_dbg(dev, cl, "MEI Driver is not connected to Watchdog Client\n");
- goto end_unlock;
- }
-
- mei_wd_set_start_timeout(dev, dev->wd_timeout);
-
- err = 0;
-end_unlock:
- mutex_unlock(&dev->device_lock);
- return err;
-}
-
-/**
- * mei_wd_ops_stop - wd stop command from the watchdog core.
- *
- * @wd_dev: watchdog device struct
- *
- * Return: 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
-{
- struct mei_device *dev;
-
- dev = watchdog_get_drvdata(wd_dev);
- if (!dev)
- return -ENODEV;
-
- mutex_lock(&dev->device_lock);
- mei_wd_stop(dev);
- mutex_unlock(&dev->device_lock);
-
- return 0;
-}
-
-/**
- * mei_wd_ops_ping - wd ping command from the watchdog core.
- *
- * @wd_dev: watchdog device struct
- *
- * Return: 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
-{
- struct mei_device *dev;
- struct mei_cl *cl;
- int ret;
-
- dev = watchdog_get_drvdata(wd_dev);
- if (!dev)
- return -ENODEV;
-
- cl = &dev->wd_cl;
-
- mutex_lock(&dev->device_lock);
-
- if (!mei_cl_is_connected(cl)) {
- cl_err(dev, cl, "wd: not connected.\n");
- ret = -ENODEV;
- goto end;
- }
-
- dev->wd_state = MEI_WD_RUNNING;
-
- ret = mei_cl_flow_ctrl_creds(cl);
- if (ret < 0)
- goto end;
-
- /* Check if we can send the ping to HW*/
- if (ret && mei_hbuf_acquire(dev)) {
- dev_dbg(dev->dev, "wd: sending ping\n");
-
- ret = mei_wd_send(dev);
- if (ret)
- goto end;
- dev->wd_pending = false;
- } else {
- dev->wd_pending = true;
- }
-
-end:
- mutex_unlock(&dev->device_lock);
- return ret;
-}
-
-/**
- * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core.
- *
- * @wd_dev: watchdog device struct
- * @timeout: timeout value to set
- *
- * Return: 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev,
- unsigned int timeout)
-{
- struct mei_device *dev;
-
- dev = watchdog_get_drvdata(wd_dev);
- if (!dev)
- return -ENODEV;
-
- /* Check Timeout value */
- if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT)
- return -EINVAL;
-
- mutex_lock(&dev->device_lock);
-
- dev->wd_timeout = timeout;
- wd_dev->timeout = timeout;
- mei_wd_set_start_timeout(dev, dev->wd_timeout);
-
- mutex_unlock(&dev->device_lock);
-
- return 0;
-}
-
-/*
- * Watchdog Device structs
- */
-static const struct watchdog_ops wd_ops = {
- .owner = THIS_MODULE,
- .start = mei_wd_ops_start,
- .stop = mei_wd_ops_stop,
- .ping = mei_wd_ops_ping,
- .set_timeout = mei_wd_ops_set_timeout,
-};
-static const struct watchdog_info wd_info = {
- .identity = INTEL_AMT_WATCHDOG_ID,
- .options = WDIOF_KEEPALIVEPING |
- WDIOF_SETTIMEOUT |
- WDIOF_ALARMONLY,
-};
-
-static struct watchdog_device amt_wd_dev = {
- .info = &wd_info,
- .ops = &wd_ops,
- .timeout = MEI_WD_DEFAULT_TIMEOUT,
- .min_timeout = MEI_WD_MIN_TIMEOUT,
- .max_timeout = MEI_WD_MAX_TIMEOUT,
-};
-
-
-int mei_watchdog_register(struct mei_device *dev)
-{
-
- int ret;
-
- amt_wd_dev.parent = dev->dev;
- /* unlock to perserve correct locking order */
- mutex_unlock(&dev->device_lock);
- ret = watchdog_register_device(&amt_wd_dev);
- mutex_lock(&dev->device_lock);
- if (ret) {
- dev_err(dev->dev, "wd: unable to register watchdog device = %d.\n",
- ret);
- return ret;
- }
-
- dev_dbg(dev->dev, "wd: successfully register watchdog interface.\n");
- watchdog_set_drvdata(&amt_wd_dev, dev);
- return 0;
-}
-
-void mei_watchdog_unregister(struct mei_device *dev)
-{
- if (watchdog_get_drvdata(&amt_wd_dev) == NULL)
- return;
-
- watchdog_set_drvdata(&amt_wd_dev, NULL);
- watchdog_unregister_device(&amt_wd_dev);
-}
-
diff --git a/drivers/misc/mic/Kconfig b/drivers/misc/mic/Kconfig
index 40677df7f996..2e4f3ba75c8e 100644
--- a/drivers/misc/mic/Kconfig
+++ b/drivers/misc/mic/Kconfig
@@ -32,12 +32,29 @@ config SCIF_BUS
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
+comment "VOP Bus Driver"
+
+config VOP_BUS
+ tristate "VOP Bus Driver"
+ depends on 64BIT && PCI && X86 && X86_DEV_DMA_OPS
+ help
+ This option is selected by any driver which registers a
+ device or driver on the VOP Bus, such as CONFIG_INTEL_MIC_HOST
+ and CONFIG_INTEL_MIC_CARD.
+
+ If you are building a host/card kernel with an Intel MIC device
+ then say M (recommended) or Y, else say N. If unsure say N.
+
+ More information about the Intel MIC family as well as the Linux
+ OS and tools for MIC to use with this driver are available from
+ <http://software.intel.com/en-us/mic-developer>.
+
comment "Intel MIC Host Driver"
config INTEL_MIC_HOST
tristate "Intel MIC Host Driver"
- depends on 64BIT && PCI && X86 && INTEL_MIC_BUS && SCIF_BUS && MIC_COSM
- select VHOST_RING
+ depends on 64BIT && PCI && X86
+ depends on INTEL_MIC_BUS && SCIF_BUS && MIC_COSM && VOP_BUS
help
This enables Host Driver support for the Intel Many Integrated
Core (MIC) family of PCIe form factor coprocessor devices that
@@ -56,7 +73,8 @@ comment "Intel MIC Card Driver"
config INTEL_MIC_CARD
tristate "Intel MIC Card Driver"
- depends on 64BIT && X86 && INTEL_MIC_BUS && SCIF_BUS && MIC_COSM
+ depends on 64BIT && X86
+ depends on INTEL_MIC_BUS && SCIF_BUS && MIC_COSM && VOP_BUS
select VIRTIO
help
This enables card driver support for the Intel Many Integrated
@@ -107,3 +125,23 @@ config MIC_COSM
More information about the Intel MIC family as well as the Linux
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
+
+comment "VOP Driver"
+
+config VOP
+ tristate "VOP Driver"
+ depends on 64BIT && PCI && X86 && VOP_BUS
+ select VHOST_RING
+ help
+ This enables VOP (Virtio over PCIe) Driver support for the Intel
+ Many Integrated Core (MIC) family of PCIe form factor coprocessor
+ devices. The VOP driver allows virtio drivers, e.g. net, console
+ and block drivers, on the card connect to user space virtio
+ devices on the host.
+
+ If you are building a host kernel with an Intel MIC device then
+ say M (recommended) or Y, else say N. If unsure say N.
+
+ More information about the Intel MIC family as well as the Linux
+ OS and tools for MIC to use with this driver are available from
+ <http://software.intel.com/en-us/mic-developer>.
diff --git a/drivers/misc/mic/Makefile b/drivers/misc/mic/Makefile
index e288a1106738..f2b1323ff96c 100644
--- a/drivers/misc/mic/Makefile
+++ b/drivers/misc/mic/Makefile
@@ -8,3 +8,4 @@ obj-y += bus/
obj-$(CONFIG_SCIF) += scif/
obj-$(CONFIG_MIC_COSM) += cosm/
obj-$(CONFIG_MIC_COSM) += cosm_client/
+obj-$(CONFIG_VOP) += vop/
diff --git a/drivers/misc/mic/bus/Makefile b/drivers/misc/mic/bus/Makefile
index 761842b0d0bb..8758a7daa52c 100644
--- a/drivers/misc/mic/bus/Makefile
+++ b/drivers/misc/mic/bus/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_INTEL_MIC_BUS) += mic_bus.o
obj-$(CONFIG_SCIF_BUS) += scif_bus.o
obj-$(CONFIG_MIC_COSM) += cosm_bus.o
+obj-$(CONFIG_VOP_BUS) += vop_bus.o
diff --git a/drivers/misc/mic/bus/cosm_bus.h b/drivers/misc/mic/bus/cosm_bus.h
index f7c57f266916..8b6341855dc3 100644
--- a/drivers/misc/mic/bus/cosm_bus.h
+++ b/drivers/misc/mic/bus/cosm_bus.h
@@ -30,6 +30,7 @@
* @attr_group: Pointer to list of sysfs attribute groups.
* @sdev: Device for sysfs entries.
* @state: MIC state.
+ * @prev_state: MIC state previous to MIC_RESETTING
* @shutdown_status: MIC status reported by card for shutdown/crashes.
* @shutdown_status_int: Internal shutdown status maintained by the driver
* @cosm_mutex: Mutex for synchronizing access to data structures.
@@ -55,6 +56,7 @@ struct cosm_device {
const struct attribute_group **attr_group;
struct device *sdev;
u8 state;
+ u8 prev_state;
u8 shutdown_status;
u8 shutdown_status_int;
struct mutex cosm_mutex;
diff --git a/drivers/misc/mic/bus/vop_bus.c b/drivers/misc/mic/bus/vop_bus.c
new file mode 100644
index 000000000000..303da222f5b6
--- /dev/null
+++ b/drivers/misc/mic/bus/vop_bus.c
@@ -0,0 +1,203 @@
+/*
+ * Intel MIC Platform Software Stack (MPSS)
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * 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
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Intel Virtio Over PCIe (VOP) Bus driver.
+ */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/dma-mapping.h>
+
+#include "vop_bus.h"
+
+static ssize_t device_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct vop_device *dev = dev_to_vop(d);
+
+ return sprintf(buf, "0x%04x\n", dev->id.device);
+}
+static DEVICE_ATTR_RO(device);
+
+static ssize_t vendor_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct vop_device *dev = dev_to_vop(d);
+
+ return sprintf(buf, "0x%04x\n", dev->id.vendor);
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t modalias_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct vop_device *dev = dev_to_vop(d);
+
+ return sprintf(buf, "vop:d%08Xv%08X\n",
+ dev->id.device, dev->id.vendor);
+}
+static DEVICE_ATTR_RO(modalias);
+
+static struct attribute *vop_dev_attrs[] = {
+ &dev_attr_device.attr,
+ &dev_attr_vendor.attr,
+ &dev_attr_modalias.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(vop_dev);
+
+static inline int vop_id_match(const struct vop_device *dev,
+ const struct vop_device_id *id)
+{
+ if (id->device != dev->id.device && id->device != VOP_DEV_ANY_ID)
+ return 0;
+
+ return id->vendor == VOP_DEV_ANY_ID || id->vendor == dev->id.vendor;
+}
+
+/*
+ * This looks through all the IDs a driver claims to support. If any of them
+ * match, we return 1 and the kernel will call vop_dev_probe().
+ */
+static int vop_dev_match(struct device *dv, struct device_driver *dr)
+{
+ unsigned int i;
+ struct vop_device *dev = dev_to_vop(dv);
+ const struct vop_device_id *ids;
+
+ ids = drv_to_vop(dr)->id_table;
+ for (i = 0; ids[i].device; i++)
+ if (vop_id_match(dev, &ids[i]))
+ return 1;
+ return 0;
+}
+
+static int vop_uevent(struct device *dv, struct kobj_uevent_env *env)
+{
+ struct vop_device *dev = dev_to_vop(dv);
+
+ return add_uevent_var(env, "MODALIAS=vop:d%08Xv%08X",
+ dev->id.device, dev->id.vendor);
+}
+
+static int vop_dev_probe(struct device *d)
+{
+ struct vop_device *dev = dev_to_vop(d);
+ struct vop_driver *drv = drv_to_vop(dev->dev.driver);
+
+ return drv->probe(dev);
+}
+
+static int vop_dev_remove(struct device *d)
+{
+ struct vop_device *dev = dev_to_vop(d);
+ struct vop_driver *drv = drv_to_vop(dev->dev.driver);
+
+ drv->remove(dev);
+ return 0;
+}
+
+static struct bus_type vop_bus = {
+ .name = "vop_bus",
+ .match = vop_dev_match,
+ .dev_groups = vop_dev_groups,
+ .uevent = vop_uevent,
+ .probe = vop_dev_probe,
+ .remove = vop_dev_remove,
+};
+
+int vop_register_driver(struct vop_driver *driver)
+{
+ driver->driver.bus = &vop_bus;
+ return driver_register(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(vop_register_driver);
+
+void vop_unregister_driver(struct vop_driver *driver)
+{
+ driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(vop_unregister_driver);
+
+static void vop_release_dev(struct device *d)
+{
+ put_device(d);
+}
+
+struct vop_device *
+vop_register_device(struct device *pdev, int id,
+ const struct dma_map_ops *dma_ops,
+ struct vop_hw_ops *hw_ops, u8 dnode, struct mic_mw *aper,
+ struct dma_chan *chan)
+{
+ int ret;
+ struct vop_device *vdev;
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev)
+ return ERR_PTR(-ENOMEM);
+
+ vdev->dev.parent = pdev;
+ vdev->id.device = id;
+ vdev->id.vendor = VOP_DEV_ANY_ID;
+ vdev->dev.archdata.dma_ops = (struct dma_map_ops *)dma_ops;
+ vdev->dev.dma_mask = &vdev->dev.coherent_dma_mask;
+ dma_set_mask(&vdev->dev, DMA_BIT_MASK(64));
+ vdev->dev.release = vop_release_dev;
+ vdev->hw_ops = hw_ops;
+ vdev->dev.bus = &vop_bus;
+ vdev->dnode = dnode;
+ vdev->aper = aper;
+ vdev->dma_ch = chan;
+ vdev->index = dnode - 1;
+ dev_set_name(&vdev->dev, "vop-dev%u", vdev->index);
+ /*
+ * device_register() causes the bus infrastructure to look for a
+ * matching driver.
+ */
+ ret = device_register(&vdev->dev);
+ if (ret)
+ goto free_vdev;
+ return vdev;
+free_vdev:
+ kfree(vdev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(vop_register_device);
+
+void vop_unregister_device(struct vop_device *dev)
+{
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(vop_unregister_device);
+
+static int __init vop_init(void)
+{
+ return bus_register(&vop_bus);
+}
+
+static void __exit vop_exit(void)
+{
+ bus_unregister(&vop_bus);
+}
+
+core_initcall(vop_init);
+module_exit(vop_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) VOP Bus driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mic/bus/vop_bus.h b/drivers/misc/mic/bus/vop_bus.h
new file mode 100644
index 000000000000..fff7a865d721
--- /dev/null
+++ b/drivers/misc/mic/bus/vop_bus.h
@@ -0,0 +1,140 @@
+/*
+ * Intel MIC Platform Software Stack (MPSS)
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * 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
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Intel Virtio over PCIe Bus driver.
+ */
+#ifndef _VOP_BUS_H_
+#define _VOP_BUS_H_
+/*
+ * Everything a vop driver needs to work with any particular vop
+ * implementation.
+ */
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+
+#include "../common/mic_dev.h"
+
+struct vop_device_id {
+ u32 device;
+ u32 vendor;
+};
+
+#define VOP_DEV_TRNSP 1
+#define VOP_DEV_ANY_ID 0xffffffff
+/*
+ * Size of the internal buffer used during DMA's as an intermediate buffer
+ * for copy to/from user. Must be an integral number of pages.
+ */
+#define VOP_INT_DMA_BUF_SIZE PAGE_ALIGN(64 * 1024ULL)
+
+/**
+ * vop_device - representation of a device using vop
+ * @hw_ops: the hardware ops supported by this device.
+ * @id: the device type identification (used to match it with a driver).
+ * @dev: underlying device.
+ * @dnode - The destination node which this device will communicate with.
+ * @aper: Aperture memory window
+ * @dma_ch - DMA channel
+ * @index: unique position on the vop bus
+ */
+struct vop_device {
+ struct vop_hw_ops *hw_ops;
+ struct vop_device_id id;
+ struct device dev;
+ u8 dnode;
+ struct mic_mw *aper;
+ struct dma_chan *dma_ch;
+ int index;
+};
+
+/**
+ * vop_driver - operations for a vop I/O driver
+ * @driver: underlying device driver (populate name and owner).
+ * @id_table: the ids serviced by this driver.
+ * @probe: the function to call when a device is found. Returns 0 or -errno.
+ * @remove: the function to call when a device is removed.
+ */
+struct vop_driver {
+ struct device_driver driver;
+ const struct vop_device_id *id_table;
+ int (*probe)(struct vop_device *dev);
+ void (*remove)(struct vop_device *dev);
+};
+
+/**
+ * vop_hw_ops - Hardware operations for accessing a VOP device on the VOP bus.
+ *
+ * @next_db: Obtain the next available doorbell.
+ * @request_irq: Request an interrupt on a particular doorbell.
+ * @free_irq: Free an interrupt requested previously.
+ * @ack_interrupt: acknowledge an interrupt in the ISR.
+ * @get_remote_dp: Get access to the virtio device page used by the remote
+ * node to add/remove/configure virtio devices.
+ * @get_dp: Get access to the virtio device page used by the self
+ * node to add/remove/configure virtio devices.
+ * @send_intr: Send an interrupt to the peer node on a specified doorbell.
+ * @ioremap: Map a buffer with the specified DMA address and length.
+ * @iounmap: Unmap a buffer previously mapped.
+ * @dma_filter: The DMA filter function to use for obtaining access to
+ * a DMA channel on the peer node.
+ */
+struct vop_hw_ops {
+ int (*next_db)(struct vop_device *vpdev);
+ struct mic_irq *(*request_irq)(struct vop_device *vpdev,
+ irqreturn_t (*func)(int irq, void *data),
+ const char *name, void *data,
+ int intr_src);
+ void (*free_irq)(struct vop_device *vpdev,
+ struct mic_irq *cookie, void *data);
+ void (*ack_interrupt)(struct vop_device *vpdev, int num);
+ void __iomem * (*get_remote_dp)(struct vop_device *vpdev);
+ void * (*get_dp)(struct vop_device *vpdev);
+ void (*send_intr)(struct vop_device *vpdev, int db);
+ void __iomem * (*ioremap)(struct vop_device *vpdev,
+ dma_addr_t pa, size_t len);
+ void (*iounmap)(struct vop_device *vpdev, void __iomem *va);
+};
+
+struct vop_device *
+vop_register_device(struct device *pdev, int id,
+ const struct dma_map_ops *dma_ops,
+ struct vop_hw_ops *hw_ops, u8 dnode, struct mic_mw *aper,
+ struct dma_chan *chan);
+void vop_unregister_device(struct vop_device *dev);
+int vop_register_driver(struct vop_driver *drv);
+void vop_unregister_driver(struct vop_driver *drv);
+
+/*
+ * module_vop_driver() - Helper macro for drivers that don't do
+ * anything special in module init/exit. This eliminates a lot of
+ * boilerplate. Each module may only use this macro once, and
+ * calling it replaces module_init() and module_exit()
+ */
+#define module_vop_driver(__vop_driver) \
+ module_driver(__vop_driver, vop_register_driver, \
+ vop_unregister_driver)
+
+static inline struct vop_device *dev_to_vop(struct device *dev)
+{
+ return container_of(dev, struct vop_device, dev);
+}
+
+static inline struct vop_driver *drv_to_vop(struct device_driver *drv)
+{
+ return container_of(drv, struct vop_driver, driver);
+}
+#endif /* _VOP_BUS_H */
diff --git a/drivers/misc/mic/card/Makefile b/drivers/misc/mic/card/Makefile
index 69d58bef92ce..6e9675e12a09 100644
--- a/drivers/misc/mic/card/Makefile
+++ b/drivers/misc/mic/card/Makefile
@@ -8,4 +8,3 @@ obj-$(CONFIG_INTEL_MIC_CARD) += mic_card.o
mic_card-y += mic_x100.o
mic_card-y += mic_device.o
mic_card-y += mic_debugfs.o
-mic_card-y += mic_virtio.o
diff --git a/drivers/misc/mic/card/mic_device.c b/drivers/misc/mic/card/mic_device.c
index d0edaf7e0cd5..e749af48f736 100644
--- a/drivers/misc/mic/card/mic_device.c
+++ b/drivers/misc/mic/card/mic_device.c
@@ -34,7 +34,6 @@
#include <linux/mic_common.h>
#include "../common/mic_dev.h"
#include "mic_device.h"
-#include "mic_virtio.h"
static struct mic_driver *g_drv;
@@ -250,12 +249,82 @@ static struct scif_hw_ops scif_hw_ops = {
.iounmap = ___mic_iounmap,
};
+static inline struct mic_driver *vpdev_to_mdrv(struct vop_device *vpdev)
+{
+ return dev_get_drvdata(vpdev->dev.parent);
+}
+
+static struct mic_irq *
+__mic_request_irq(struct vop_device *vpdev,
+ irqreturn_t (*func)(int irq, void *data),
+ const char *name, void *data, int intr_src)
+{
+ return mic_request_card_irq(func, NULL, name, data, intr_src);
+}
+
+static void __mic_free_irq(struct vop_device *vpdev,
+ struct mic_irq *cookie, void *data)
+{
+ return mic_free_card_irq(cookie, data);
+}
+
+static void __mic_ack_interrupt(struct vop_device *vpdev, int num)
+{
+ struct mic_driver *mdrv = vpdev_to_mdrv(vpdev);
+
+ mic_ack_interrupt(&mdrv->mdev);
+}
+
+static int __mic_next_db(struct vop_device *vpdev)
+{
+ return mic_next_card_db();
+}
+
+static void __iomem *__mic_get_remote_dp(struct vop_device *vpdev)
+{
+ struct mic_driver *mdrv = vpdev_to_mdrv(vpdev);
+
+ return mdrv->dp;
+}
+
+static void __mic_send_intr(struct vop_device *vpdev, int db)
+{
+ struct mic_driver *mdrv = vpdev_to_mdrv(vpdev);
+
+ mic_send_intr(&mdrv->mdev, db);
+}
+
+static void __iomem *__mic_ioremap(struct vop_device *vpdev,
+ dma_addr_t pa, size_t len)
+{
+ struct mic_driver *mdrv = vpdev_to_mdrv(vpdev);
+
+ return mic_card_map(&mdrv->mdev, pa, len);
+}
+
+static void __mic_iounmap(struct vop_device *vpdev, void __iomem *va)
+{
+ struct mic_driver *mdrv = vpdev_to_mdrv(vpdev);
+
+ mic_card_unmap(&mdrv->mdev, va);
+}
+
+static struct vop_hw_ops vop_hw_ops = {
+ .request_irq = __mic_request_irq,
+ .free_irq = __mic_free_irq,
+ .ack_interrupt = __mic_ack_interrupt,
+ .next_db = __mic_next_db,
+ .get_remote_dp = __mic_get_remote_dp,
+ .send_intr = __mic_send_intr,
+ .ioremap = __mic_ioremap,
+ .iounmap = __mic_iounmap,
+};
+
static int mic_request_dma_chans(struct mic_driver *mdrv)
{
dma_cap_mask_t mask;
struct dma_chan *chan;
- request_module("mic_x100_dma");
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
@@ -309,9 +378,13 @@ int __init mic_driver_init(struct mic_driver *mdrv)
rc = -ENODEV;
goto irq_uninit;
}
- rc = mic_devices_init(mdrv);
- if (rc)
+ mdrv->vpdev = vop_register_device(mdrv->dev, VOP_DEV_TRNSP,
+ NULL, &vop_hw_ops, 0,
+ NULL, mdrv->dma_ch[0]);
+ if (IS_ERR(mdrv->vpdev)) {
+ rc = PTR_ERR(mdrv->vpdev);
goto dma_free;
+ }
bootparam = mdrv->dp;
node_id = ioread8(&bootparam->node_id);
mdrv->scdev = scif_register_device(mdrv->dev, MIC_SCIF_DEV,
@@ -321,13 +394,13 @@ int __init mic_driver_init(struct mic_driver *mdrv)
mdrv->num_dma_ch, true);
if (IS_ERR(mdrv->scdev)) {
rc = PTR_ERR(mdrv->scdev);
- goto device_uninit;
+ goto vop_remove;
}
mic_create_card_debug_dir(mdrv);
done:
return rc;
-device_uninit:
- mic_devices_uninit(mdrv);
+vop_remove:
+ vop_unregister_device(mdrv->vpdev);
dma_free:
mic_free_dma_chans(mdrv);
irq_uninit:
@@ -348,7 +421,7 @@ void mic_driver_uninit(struct mic_driver *mdrv)
{
mic_delete_card_debug_dir(mdrv);
scif_unregister_device(mdrv->scdev);
- mic_devices_uninit(mdrv);
+ vop_unregister_device(mdrv->vpdev);
mic_free_dma_chans(mdrv);
mic_uninit_irq();
mic_dp_uninit();
diff --git a/drivers/misc/mic/card/mic_device.h b/drivers/misc/mic/card/mic_device.h
index 1dbf83c41289..333dbed972f6 100644
--- a/drivers/misc/mic/card/mic_device.h
+++ b/drivers/misc/mic/card/mic_device.h
@@ -32,6 +32,7 @@
#include <linux/interrupt.h>
#include <linux/mic_bus.h>
#include "../bus/scif_bus.h"
+#include "../bus/vop_bus.h"
/**
* struct mic_intr_info - Contains h/w specific interrupt sources info
@@ -76,6 +77,7 @@ struct mic_device {
* @dma_ch - Array of DMA channels
* @num_dma_ch - Number of DMA channels available
* @scdev: SCIF device on the SCIF virtual bus.
+ * @vpdev: Virtio over PCIe device on the VOP virtual bus.
*/
struct mic_driver {
char name[20];
@@ -90,6 +92,7 @@ struct mic_driver {
struct dma_chan *dma_ch[MIC_MAX_DMA_CHAN];
int num_dma_ch;
struct scif_hw_dev *scdev;
+ struct vop_device *vpdev;
};
/**
diff --git a/drivers/misc/mic/card/mic_virtio.c b/drivers/misc/mic/card/mic_virtio.c
deleted file mode 100644
index f6ed57d3125c..000000000000
--- a/drivers/misc/mic/card/mic_virtio.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Intel MIC Platform Software Stack (MPSS)
- *
- * Copyright(c) 2013 Intel Corporation.
- *
- * 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
- * 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Disclaimer: The codes contained in these modules may be specific to
- * the Intel Software Development Platform codenamed: Knights Ferry, and
- * the Intel product codenamed: Knights Corner, and are not backward
- * compatible with other Intel products. Additionally, Intel will NOT
- * support the codes or instruction set in future products.
- *
- * Adapted from:
- *
- * virtio for kvm on s390
- *
- * Copyright IBM Corp. 2008
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (version 2 only)
- * as published by the Free Software Foundation.
- *
- * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
- *
- * Intel MIC Card driver.
- *
- */
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/virtio_config.h>
-
-#include "../common/mic_dev.h"
-#include "mic_virtio.h"
-
-#define VIRTIO_SUBCODE_64 0x0D00
-
-#define MIC_MAX_VRINGS 4
-struct mic_vdev {
- struct virtio_device vdev;
- struct mic_device_desc __iomem *desc;
- struct mic_device_ctrl __iomem *dc;
- struct mic_device *mdev;
- void __iomem *vr[MIC_MAX_VRINGS];
- int used_size[MIC_MAX_VRINGS];
- struct completion reset_done;
- struct mic_irq *virtio_cookie;
- int c2h_vdev_db;
-};
-
-static struct mic_irq *virtio_config_cookie;
-#define to_micvdev(vd) container_of(vd, struct mic_vdev, vdev)
-
-/* Helper API to obtain the parent of the virtio device */
-static inline struct device *mic_dev(struct mic_vdev *mvdev)
-{
- return mvdev->vdev.dev.parent;
-}
-
-/* This gets the device's feature bits. */
-static u64 mic_get_features(struct virtio_device *vdev)
-{
- unsigned int i, bits;
- u32 features = 0;
- struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc;
- u8 __iomem *in_features = mic_vq_features(desc);
- int feature_len = ioread8(&desc->feature_len);
-
- bits = min_t(unsigned, feature_len, sizeof(features)) * 8;
- for (i = 0; i < bits; i++)
- if (ioread8(&in_features[i / 8]) & (BIT(i % 8)))
- features |= BIT(i);
-
- return features;
-}
-
-static int mic_finalize_features(struct virtio_device *vdev)
-{
- unsigned int i, bits;
- struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc;
- u8 feature_len = ioread8(&desc->feature_len);
- /* Second half of bitmap is features we accept. */
- u8 __iomem *out_features =
- mic_vq_features(desc) + feature_len;
-
- /* Give virtio_ring a chance to accept features. */
- vring_transport_features(vdev);
-
- /* Make sure we don't have any features > 32 bits! */
- BUG_ON((u32)vdev->features != vdev->features);
-
- memset_io(out_features, 0, feature_len);
- bits = min_t(unsigned, feature_len,
- sizeof(vdev->features)) * 8;
- for (i = 0; i < bits; i++) {
- if (__virtio_test_bit(vdev, i))
- iowrite8(ioread8(&out_features[i / 8]) | (1 << (i % 8)),
- &out_features[i / 8]);
- }
-
- return 0;
-}
-
-/*
- * Reading and writing elements in config space
- */
-static void mic_get(struct virtio_device *vdev, unsigned int offset,
- void *buf, unsigned len)
-{
- struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc;
-
- if (offset + len > ioread8(&desc->config_len))
- return;
- memcpy_fromio(buf, mic_vq_configspace(desc) + offset, len);
-}
-
-static void mic_set(struct virtio_device *vdev, unsigned int offset,
- const void *buf, unsigned len)
-{
- struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc;
-
- if (offset + len > ioread8(&desc->config_len))
- return;
- memcpy_toio(mic_vq_configspace(desc) + offset, buf, len);
-}
-
-/*
- * The operations to get and set the status word just access the status
- * field of the device descriptor. set_status also interrupts the host
- * to tell about status changes.
- */
-static u8 mic_get_status(struct virtio_device *vdev)
-{
- return ioread8(&to_micvdev(vdev)->desc->status);
-}
-
-static void mic_set_status(struct virtio_device *vdev, u8 status)
-{
- struct mic_vdev *mvdev = to_micvdev(vdev);
- if (!status)
- return;
- iowrite8(status, &mvdev->desc->status);
- mic_send_intr(mvdev->mdev, mvdev->c2h_vdev_db);
-}
-
-/* Inform host on a virtio device reset and wait for ack from host */
-static void mic_reset_inform_host(struct virtio_device *vdev)
-{
- struct mic_vdev *mvdev = to_micvdev(vdev);
- struct mic_device_ctrl __iomem *dc = mvdev->dc;
- int retry;
-
- iowrite8(0, &dc->host_ack);
- iowrite8(1, &dc->vdev_reset);
- mic_send_intr(mvdev->mdev, mvdev->c2h_vdev_db);
-
- /* Wait till host completes all card accesses and acks the reset */
- for (retry = 100; retry--;) {
- if (ioread8(&dc->host_ack))
- break;
- msleep(100);
- };
-
- dev_dbg(mic_dev(mvdev), "%s: retry: %d\n", __func__, retry);
-
- /* Reset status to 0 in case we timed out */
- iowrite8(0, &mvdev->desc->status);
-}
-
-static void mic_reset(struct virtio_device *vdev)
-{
- struct mic_vdev *mvdev = to_micvdev(vdev);
-
- dev_dbg(mic_dev(mvdev), "%s: virtio id %d\n",
- __func__, vdev->id.device);
-
- mic_reset_inform_host(vdev);
- complete_all(&mvdev->reset_done);
-}
-
-/*
- * The virtio_ring code calls this API when it wants to notify the Host.
- */
-static bool mic_notify(struct virtqueue *vq)
-{
- struct mic_vdev *mvdev = vq->priv;
-
- mic_send_intr(mvdev->mdev, mvdev->c2h_vdev_db);
- return true;
-}
-
-static void mic_del_vq(struct virtqueue *vq, int n)
-{
- struct mic_vdev *mvdev = to_micvdev(vq->vdev);
- struct vring *vr = (struct vring *)(vq + 1);
-
- free_pages((unsigned long) vr->used, get_order(mvdev->used_size[n]));
- vring_del_virtqueue(vq);
- mic_card_unmap(mvdev->mdev, mvdev->vr[n]);
- mvdev->vr[n] = NULL;
-}
-
-static void mic_del_vqs(struct virtio_device *vdev)
-{
- struct mic_vdev *mvdev = to_micvdev(vdev);
- struct virtqueue *vq, *n;
- int idx = 0;
-
- dev_dbg(mic_dev(mvdev), "%s\n", __func__);
-
- list_for_each_entry_safe(vq, n, &vdev->vqs, list)
- mic_del_vq(vq, idx++);
-}
-
-/*
- * This routine will assign vring's allocated in host/io memory. Code in
- * virtio_ring.c however continues to access this io memory as if it were local
- * memory without io accessors.
- */
-static struct virtqueue *mic_find_vq(struct virtio_device *vdev,
- unsigned index,
- void (*callback)(struct virtqueue *vq),
- const char *name)
-{
- struct mic_vdev *mvdev = to_micvdev(vdev);
- struct mic_vqconfig __iomem *vqconfig;
- struct mic_vqconfig config;
- struct virtqueue *vq;
- void __iomem *va;
- struct _mic_vring_info __iomem *info;
- void *used;
- int vr_size, _vr_size, err, magic;
- struct vring *vr;
- u8 type = ioread8(&mvdev->desc->type);
-
- if (index >= ioread8(&mvdev->desc->num_vq))
- return ERR_PTR(-ENOENT);
-
- if (!name)
- return ERR_PTR(-ENOENT);
-
- /* First assign the vring's allocated in host memory */
- vqconfig = mic_vq_config(mvdev->desc) + index;
- memcpy_fromio(&config, vqconfig, sizeof(config));
- _vr_size = vring_size(le16_to_cpu(config.num), MIC_VIRTIO_RING_ALIGN);
- vr_size = PAGE_ALIGN(_vr_size + sizeof(struct _mic_vring_info));
- va = mic_card_map(mvdev->mdev, le64_to_cpu(config.address), vr_size);
- if (!va)
- return ERR_PTR(-ENOMEM);
- mvdev->vr[index] = va;
- memset_io(va, 0x0, _vr_size);
- vq = vring_new_virtqueue(index, le16_to_cpu(config.num),
- MIC_VIRTIO_RING_ALIGN, vdev, false,
- (void __force *)va, mic_notify, callback,
- name);
- if (!vq) {
- err = -ENOMEM;
- goto unmap;
- }
- info = va + _vr_size;
- magic = ioread32(&info->magic);
-
- if (WARN(magic != MIC_MAGIC + type + index, "magic mismatch")) {
- err = -EIO;
- goto unmap;
- }
-
- /* Allocate and reassign used ring now */
- mvdev->used_size[index] = PAGE_ALIGN(sizeof(__u16) * 3 +
- sizeof(struct vring_used_elem) *
- le16_to_cpu(config.num));
- used = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
- get_order(mvdev->used_size[index]));
- if (!used) {
- err = -ENOMEM;
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, err);
- goto del_vq;
- }
- iowrite64(virt_to_phys(used), &vqconfig->used_address);
-
- /*
- * To reassign the used ring here we are directly accessing
- * struct vring_virtqueue which is a private data structure
- * in virtio_ring.c. At the minimum, a BUILD_BUG_ON() in
- * vring_new_virtqueue() would ensure that
- * (&vq->vring == (struct vring *) (&vq->vq + 1));
- */
- vr = (struct vring *)(vq + 1);
- vr->used = used;
-
- vq->priv = mvdev;
- return vq;
-del_vq:
- vring_del_virtqueue(vq);
-unmap:
- mic_card_unmap(mvdev->mdev, mvdev->vr[index]);
- return ERR_PTR(err);
-}
-
-static int mic_find_vqs(struct virtio_device *vdev, unsigned nvqs,
- struct virtqueue *vqs[],
- vq_callback_t *callbacks[],
- const char * const names[])
-{
- struct mic_vdev *mvdev = to_micvdev(vdev);
- struct mic_device_ctrl __iomem *dc = mvdev->dc;
- int i, err, retry;
-
- /* We must have this many virtqueues. */
- if (nvqs > ioread8(&mvdev->desc->num_vq))
- return -ENOENT;
-
- for (i = 0; i < nvqs; ++i) {
- dev_dbg(mic_dev(mvdev), "%s: %d: %s\n",
- __func__, i, names[i]);
- vqs[i] = mic_find_vq(vdev, i, callbacks[i], names[i]);
- if (IS_ERR(vqs[i])) {
- err = PTR_ERR(vqs[i]);
- goto error;
- }
- }
-
- iowrite8(1, &dc->used_address_updated);
- /*
- * Send an interrupt to the host to inform it that used
- * rings have been re-assigned.
- */
- mic_send_intr(mvdev->mdev, mvdev->c2h_vdev_db);
- for (retry = 100; retry--;) {
- if (!ioread8(&dc->used_address_updated))
- break;
- msleep(100);
- };
-
- dev_dbg(mic_dev(mvdev), "%s: retry: %d\n", __func__, retry);
- if (!retry) {
- err = -ENODEV;
- goto error;
- }
-
- return 0;
-error:
- mic_del_vqs(vdev);
- return err;
-}
-
-/*
- * The config ops structure as defined by virtio config
- */
-static struct virtio_config_ops mic_vq_config_ops = {
- .get_features = mic_get_features,
- .finalize_features = mic_finalize_features,
- .get = mic_get,
- .set = mic_set,
- .get_status = mic_get_status,
- .set_status = mic_set_status,
- .reset = mic_reset,
- .find_vqs = mic_find_vqs,
- .del_vqs = mic_del_vqs,
-};
-
-static irqreturn_t
-mic_virtio_intr_handler(int irq, void *data)
-{
- struct mic_vdev *mvdev = data;
- struct virtqueue *vq;
-
- mic_ack_interrupt(mvdev->mdev);
- list_for_each_entry(vq, &mvdev->vdev.vqs, list)
- vring_interrupt(0, vq);
-
- return IRQ_HANDLED;
-}
-
-static void mic_virtio_release_dev(struct device *_d)
-{
- /*
- * No need for a release method similar to virtio PCI.
- * Provide an empty one to avoid getting a warning from core.
- */
-}
-
-/*
- * adds a new device and register it with virtio
- * appropriate drivers are loaded by the device model
- */
-static int mic_add_device(struct mic_device_desc __iomem *d,
- unsigned int offset, struct mic_driver *mdrv)
-{
- struct mic_vdev *mvdev;
- int ret;
- int virtio_db;
- u8 type = ioread8(&d->type);
-
- mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL);
- if (!mvdev) {
- dev_err(mdrv->dev, "Cannot allocate mic dev %u type %u\n",
- offset, type);
- return -ENOMEM;
- }
-
- mvdev->mdev = &mdrv->mdev;
- mvdev->vdev.dev.parent = mdrv->dev;
- mvdev->vdev.dev.release = mic_virtio_release_dev;
- mvdev->vdev.id.device = type;
- mvdev->vdev.config = &mic_vq_config_ops;
- mvdev->desc = d;
- mvdev->dc = (void __iomem *)d + mic_aligned_desc_size(d);
- init_completion(&mvdev->reset_done);
-
- virtio_db = mic_next_card_db();
- mvdev->virtio_cookie = mic_request_card_irq(mic_virtio_intr_handler,
- NULL, "virtio intr", mvdev, virtio_db);
- if (IS_ERR(mvdev->virtio_cookie)) {
- ret = PTR_ERR(mvdev->virtio_cookie);
- goto kfree;
- }
- iowrite8((u8)virtio_db, &mvdev->dc->h2c_vdev_db);
- mvdev->c2h_vdev_db = ioread8(&mvdev->dc->c2h_vdev_db);
-
- ret = register_virtio_device(&mvdev->vdev);
- if (ret) {
- dev_err(mic_dev(mvdev),
- "Failed to register mic device %u type %u\n",
- offset, type);
- goto free_irq;
- }
- iowrite64((u64)mvdev, &mvdev->dc->vdev);
- dev_dbg(mic_dev(mvdev), "%s: registered mic device %u type %u mvdev %p\n",
- __func__, offset, type, mvdev);
-
- return 0;
-
-free_irq:
- mic_free_card_irq(mvdev->virtio_cookie, mvdev);
-kfree:
- kfree(mvdev);
- return ret;
-}
-
-/*
- * match for a mic device with a specific desc pointer
- */
-static int mic_match_desc(struct device *dev, void *data)
-{
- struct virtio_device *vdev = dev_to_virtio(dev);
- struct mic_vdev *mvdev = to_micvdev(vdev);
-
- return mvdev->desc == (void __iomem *)data;
-}
-
-static void mic_handle_config_change(struct mic_device_desc __iomem *d,
- unsigned int offset, struct mic_driver *mdrv)
-{
- struct mic_device_ctrl __iomem *dc
- = (void __iomem *)d + mic_aligned_desc_size(d);
- struct mic_vdev *mvdev = (struct mic_vdev *)ioread64(&dc->vdev);
-
- if (ioread8(&dc->config_change) != MIC_VIRTIO_PARAM_CONFIG_CHANGED)
- return;
-
- dev_dbg(mdrv->dev, "%s %d\n", __func__, __LINE__);
- virtio_config_changed(&mvdev->vdev);
- iowrite8(1, &dc->guest_ack);
-}
-
-/*
- * removes a virtio device if a hot remove event has been
- * requested by the host.
- */
-static int mic_remove_device(struct mic_device_desc __iomem *d,
- unsigned int offset, struct mic_driver *mdrv)
-{
- struct mic_device_ctrl __iomem *dc
- = (void __iomem *)d + mic_aligned_desc_size(d);
- struct mic_vdev *mvdev = (struct mic_vdev *)ioread64(&dc->vdev);
- u8 status;
- int ret = -1;
-
- if (ioread8(&dc->config_change) == MIC_VIRTIO_PARAM_DEV_REMOVE) {
- dev_dbg(mdrv->dev,
- "%s %d config_change %d type %d mvdev %p\n",
- __func__, __LINE__,
- ioread8(&dc->config_change), ioread8(&d->type), mvdev);
-
- status = ioread8(&d->status);
- reinit_completion(&mvdev->reset_done);
- unregister_virtio_device(&mvdev->vdev);
- mic_free_card_irq(mvdev->virtio_cookie, mvdev);
- if (status & VIRTIO_CONFIG_S_DRIVER_OK)
- wait_for_completion(&mvdev->reset_done);
- kfree(mvdev);
- iowrite8(1, &dc->guest_ack);
- dev_dbg(mdrv->dev, "%s %d guest_ack %d\n",
- __func__, __LINE__, ioread8(&dc->guest_ack));
- ret = 0;
- }
-
- return ret;
-}
-
-#define REMOVE_DEVICES true
-
-static void mic_scan_devices(struct mic_driver *mdrv, bool remove)
-{
- s8 type;
- unsigned int i;
- struct mic_device_desc __iomem *d;
- struct mic_device_ctrl __iomem *dc;
- struct device *dev;
- int ret;
-
- for (i = sizeof(struct mic_bootparam); i < MIC_DP_SIZE;
- i += mic_total_desc_size(d)) {
- d = mdrv->dp + i;
- dc = (void __iomem *)d + mic_aligned_desc_size(d);
- /*
- * This read barrier is paired with the corresponding write
- * barrier on the host which is inserted before adding or
- * removing a virtio device descriptor, by updating the type.
- */
- rmb();
- type = ioread8(&d->type);
-
- /* end of list */
- if (type == 0)
- break;
-
- if (type == -1)
- continue;
-
- /* device already exists */
- dev = device_find_child(mdrv->dev, (void __force *)d,
- mic_match_desc);
- if (dev) {
- if (remove)
- iowrite8(MIC_VIRTIO_PARAM_DEV_REMOVE,
- &dc->config_change);
- put_device(dev);
- mic_handle_config_change(d, i, mdrv);
- ret = mic_remove_device(d, i, mdrv);
- if (!ret && !remove)
- iowrite8(-1, &d->type);
- if (remove) {
- iowrite8(0, &dc->config_change);
- iowrite8(0, &dc->guest_ack);
- }
- continue;
- }
-
- /* new device */
- dev_dbg(mdrv->dev, "%s %d Adding new virtio device %p\n",
- __func__, __LINE__, d);
- if (!remove)
- mic_add_device(d, i, mdrv);
- }
-}
-
-/*
- * mic_hotplug_device tries to find changes in the device page.
- */
-static void mic_hotplug_devices(struct work_struct *work)
-{
- struct mic_driver *mdrv = container_of(work,
- struct mic_driver, hotplug_work);
-
- mic_scan_devices(mdrv, !REMOVE_DEVICES);
-}
-
-/*
- * Interrupt handler for hot plug/config changes etc.
- */
-static irqreturn_t
-mic_extint_handler(int irq, void *data)
-{
- struct mic_driver *mdrv = (struct mic_driver *)data;
-
- dev_dbg(mdrv->dev, "%s %d hotplug work\n",
- __func__, __LINE__);
- mic_ack_interrupt(&mdrv->mdev);
- schedule_work(&mdrv->hotplug_work);
- return IRQ_HANDLED;
-}
-
-/*
- * Init function for virtio
- */
-int mic_devices_init(struct mic_driver *mdrv)
-{
- int rc;
- struct mic_bootparam __iomem *bootparam;
- int config_db;
-
- INIT_WORK(&mdrv->hotplug_work, mic_hotplug_devices);
- mic_scan_devices(mdrv, !REMOVE_DEVICES);
-
- config_db = mic_next_card_db();
- virtio_config_cookie = mic_request_card_irq(mic_extint_handler, NULL,
- "virtio_config_intr", mdrv,
- config_db);
- if (IS_ERR(virtio_config_cookie)) {
- rc = PTR_ERR(virtio_config_cookie);
- goto exit;
- }
-
- bootparam = mdrv->dp;
- iowrite8(config_db, &bootparam->h2c_config_db);
- return 0;
-exit:
- return rc;
-}
-
-/*
- * Uninit function for virtio
- */
-void mic_devices_uninit(struct mic_driver *mdrv)
-{
- struct mic_bootparam __iomem *bootparam = mdrv->dp;
- iowrite8(-1, &bootparam->h2c_config_db);
- mic_free_card_irq(virtio_config_cookie, mdrv);
- flush_work(&mdrv->hotplug_work);
- mic_scan_devices(mdrv, REMOVE_DEVICES);
-}
diff --git a/drivers/misc/mic/card/mic_virtio.h b/drivers/misc/mic/card/mic_virtio.h
deleted file mode 100644
index d0407ba53bb7..000000000000
--- a/drivers/misc/mic/card/mic_virtio.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Intel MIC Platform Software Stack (MPSS)
- *
- * Copyright(c) 2013 Intel Corporation.
- *
- * 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
- * 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Disclaimer: The codes contained in these modules may be specific to
- * the Intel Software Development Platform codenamed: Knights Ferry, and
- * the Intel product codenamed: Knights Corner, and are not backward
- * compatible with other Intel products. Additionally, Intel will NOT
- * support the codes or instruction set in future products.
- *
- * Intel MIC Card driver.
- *
- */
-#ifndef __MIC_CARD_VIRTIO_H
-#define __MIC_CARD_VIRTIO_H
-
-#include <linux/mic_common.h>
-#include "mic_device.h"
-
-/*
- * 64 bit I/O access
- */
-#ifndef ioread64
-#define ioread64 readq
-#endif
-#ifndef iowrite64
-#define iowrite64 writeq
-#endif
-
-static inline unsigned mic_desc_size(struct mic_device_desc __iomem *desc)
-{
- return sizeof(*desc)
- + ioread8(&desc->num_vq) * sizeof(struct mic_vqconfig)
- + ioread8(&desc->feature_len) * 2
- + ioread8(&desc->config_len);
-}
-
-static inline struct mic_vqconfig __iomem *
-mic_vq_config(struct mic_device_desc __iomem *desc)
-{
- return (struct mic_vqconfig __iomem *)(desc + 1);
-}
-
-static inline __u8 __iomem *
-mic_vq_features(struct mic_device_desc __iomem *desc)
-{
- return (__u8 __iomem *)(mic_vq_config(desc) + ioread8(&desc->num_vq));
-}
-
-static inline __u8 __iomem *
-mic_vq_configspace(struct mic_device_desc __iomem *desc)
-{
- return mic_vq_features(desc) + ioread8(&desc->feature_len) * 2;
-}
-static inline unsigned mic_total_desc_size(struct mic_device_desc __iomem *desc)
-{
- return mic_aligned_desc_size(desc) + sizeof(struct mic_device_ctrl);
-}
-
-int mic_devices_init(struct mic_driver *mdrv);
-void mic_devices_uninit(struct mic_driver *mdrv);
-
-#endif
diff --git a/drivers/misc/mic/card/mic_x100.c b/drivers/misc/mic/card/mic_x100.c
index b2958ce2368c..b9f0710ffa6b 100644
--- a/drivers/misc/mic/card/mic_x100.c
+++ b/drivers/misc/mic/card/mic_x100.c
@@ -326,6 +326,7 @@ static int __init mic_init(void)
goto done;
}
+ request_module("mic_x100_dma");
mic_init_card_debugfs();
ret = platform_device_register(&mic_platform_dev);
if (ret) {
diff --git a/drivers/misc/mic/cosm/cosm_main.c b/drivers/misc/mic/cosm/cosm_main.c
index 4b4b356c797d..7005cb1e01d2 100644
--- a/drivers/misc/mic/cosm/cosm_main.c
+++ b/drivers/misc/mic/cosm/cosm_main.c
@@ -153,8 +153,10 @@ void cosm_stop(struct cosm_device *cdev, bool force)
* stop(..) calls device_unregister and will crash the system if
* called multiple times.
*/
- bool call_hw_ops = cdev->state != MIC_RESET_FAILED &&
- cdev->state != MIC_READY;
+ u8 state = cdev->state == MIC_RESETTING ?
+ cdev->prev_state : cdev->state;
+ bool call_hw_ops = state != MIC_RESET_FAILED &&
+ state != MIC_READY;
if (cdev->state != MIC_RESETTING)
cosm_set_state(cdev, MIC_RESETTING);
@@ -195,8 +197,11 @@ int cosm_reset(struct cosm_device *cdev)
mutex_lock(&cdev->cosm_mutex);
if (cdev->state != MIC_READY) {
- cosm_set_state(cdev, MIC_RESETTING);
- schedule_work(&cdev->reset_trigger_work);
+ if (cdev->state != MIC_RESETTING) {
+ cdev->prev_state = cdev->state;
+ cosm_set_state(cdev, MIC_RESETTING);
+ schedule_work(&cdev->reset_trigger_work);
+ }
} else {
dev_err(&cdev->dev, "%s %d MIC is READY\n", __func__, __LINE__);
rc = -EINVAL;
diff --git a/drivers/misc/mic/host/Makefile b/drivers/misc/mic/host/Makefile
index 004d3db0f990..f3b502333ded 100644
--- a/drivers/misc/mic/host/Makefile
+++ b/drivers/misc/mic/host/Makefile
@@ -9,5 +9,3 @@ mic_host-objs += mic_smpt.o
mic_host-objs += mic_intr.o
mic_host-objs += mic_boot.o
mic_host-objs += mic_debugfs.o
-mic_host-objs += mic_fops.o
-mic_host-objs += mic_virtio.o
diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c
index 7845564dff64..8c91c9950b54 100644
--- a/drivers/misc/mic/host/mic_boot.c
+++ b/drivers/misc/mic/host/mic_boot.c
@@ -25,10 +25,117 @@
#include <linux/mic_common.h>
#include <linux/mic_bus.h>
#include "../bus/scif_bus.h"
+#include "../bus/vop_bus.h"
#include "../common/mic_dev.h"
#include "mic_device.h"
#include "mic_smpt.h"
-#include "mic_virtio.h"
+
+static inline struct mic_device *vpdev_to_mdev(struct device *dev)
+{
+ return dev_get_drvdata(dev->parent);
+}
+
+static dma_addr_t
+_mic_dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ void *va = phys_to_virt(page_to_phys(page)) + offset;
+ struct mic_device *mdev = vpdev_to_mdev(dev);
+
+ return mic_map_single(mdev, va, size);
+}
+
+static void _mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct mic_device *mdev = vpdev_to_mdev(dev);
+
+ mic_unmap_single(mdev, dma_addr, size);
+}
+
+static const struct dma_map_ops _mic_dma_ops = {
+ .map_page = _mic_dma_map_page,
+ .unmap_page = _mic_dma_unmap_page,
+};
+
+static struct mic_irq *
+__mic_request_irq(struct vop_device *vpdev,
+ irqreturn_t (*func)(int irq, void *data),
+ const char *name, void *data, int intr_src)
+{
+ struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev);
+
+ return mic_request_threaded_irq(mdev, func, NULL, name, data,
+ intr_src, MIC_INTR_DB);
+}
+
+static void __mic_free_irq(struct vop_device *vpdev,
+ struct mic_irq *cookie, void *data)
+{
+ struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev);
+
+ return mic_free_irq(mdev, cookie, data);
+}
+
+static void __mic_ack_interrupt(struct vop_device *vpdev, int num)
+{
+ struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev);
+
+ mdev->ops->intr_workarounds(mdev);
+}
+
+static int __mic_next_db(struct vop_device *vpdev)
+{
+ struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev);
+
+ return mic_next_db(mdev);
+}
+
+static void *__mic_get_dp(struct vop_device *vpdev)
+{
+ struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev);
+
+ return mdev->dp;
+}
+
+static void __iomem *__mic_get_remote_dp(struct vop_device *vpdev)
+{
+ return NULL;
+}
+
+static void __mic_send_intr(struct vop_device *vpdev, int db)
+{
+ struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev);
+
+ mdev->ops->send_intr(mdev, db);
+}
+
+static void __iomem *__mic_ioremap(struct vop_device *vpdev,
+ dma_addr_t pa, size_t len)
+{
+ struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev);
+
+ return mdev->aper.va + pa;
+}
+
+static void __mic_iounmap(struct vop_device *vpdev, void __iomem *va)
+{
+ /* nothing to do */
+}
+
+static struct vop_hw_ops vop_hw_ops = {
+ .request_irq = __mic_request_irq,
+ .free_irq = __mic_free_irq,
+ .ack_interrupt = __mic_ack_interrupt,
+ .next_db = __mic_next_db,
+ .get_dp = __mic_get_dp,
+ .get_remote_dp = __mic_get_remote_dp,
+ .send_intr = __mic_send_intr,
+ .ioremap = __mic_ioremap,
+ .iounmap = __mic_iounmap,
+};
static inline struct mic_device *scdev_to_mdev(struct scif_hw_dev *scdev)
{
@@ -315,7 +422,6 @@ static int mic_request_dma_chans(struct mic_device *mdev)
dma_cap_mask_t mask;
struct dma_chan *chan;
- request_module("mic_x100_dma");
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
@@ -387,9 +493,18 @@ static int _mic_start(struct cosm_device *cdev, int id)
goto dma_free;
}
+ mdev->vpdev = vop_register_device(&mdev->pdev->dev,
+ VOP_DEV_TRNSP, &_mic_dma_ops,
+ &vop_hw_ops, id + 1, &mdev->aper,
+ mdev->dma_ch[0]);
+ if (IS_ERR(mdev->vpdev)) {
+ rc = PTR_ERR(mdev->vpdev);
+ goto scif_remove;
+ }
+
rc = mdev->ops->load_mic_fw(mdev, NULL);
if (rc)
- goto scif_remove;
+ goto vop_remove;
mic_smpt_restore(mdev);
mic_intr_restore(mdev);
mdev->intr_ops->enable_interrupts(mdev);
@@ -397,6 +512,8 @@ static int _mic_start(struct cosm_device *cdev, int id)
mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32);
mdev->ops->send_firmware_intr(mdev);
goto unlock_ret;
+vop_remove:
+ vop_unregister_device(mdev->vpdev);
scif_remove:
scif_unregister_device(mdev->scdev);
dma_free:
@@ -423,7 +540,7 @@ static void _mic_stop(struct cosm_device *cdev, bool force)
* will be the first to be registered and the last to be
* unregistered.
*/
- mic_virtio_reset_devices(mdev);
+ vop_unregister_device(mdev->vpdev);
scif_unregister_device(mdev->scdev);
mic_free_dma_chans(mdev);
mbus_unregister_device(mdev->dma_mbdev);
diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c
index 10581600777a..0a9daba8bb5d 100644
--- a/drivers/misc/mic/host/mic_debugfs.c
+++ b/drivers/misc/mic/host/mic_debugfs.c
@@ -26,7 +26,6 @@
#include "../common/mic_dev.h"
#include "mic_device.h"
#include "mic_smpt.h"
-#include "mic_virtio.h"
/* Debugfs parent dir */
static struct dentry *mic_dbg;
@@ -100,190 +99,6 @@ static const struct file_operations post_code_ops = {
.release = mic_post_code_debug_release
};
-static int mic_dp_show(struct seq_file *s, void *pos)
-{
- struct mic_device *mdev = s->private;
- struct mic_device_desc *d;
- struct mic_device_ctrl *dc;
- struct mic_vqconfig *vqconfig;
- __u32 *features;
- __u8 *config;
- struct mic_bootparam *bootparam = mdev->dp;
- int i, j;
-
- seq_printf(s, "Bootparam: magic 0x%x\n",
- bootparam->magic);
- seq_printf(s, "Bootparam: h2c_config_db %d\n",
- bootparam->h2c_config_db);
- seq_printf(s, "Bootparam: node_id %d\n",
- bootparam->node_id);
- seq_printf(s, "Bootparam: c2h_scif_db %d\n",
- bootparam->c2h_scif_db);
- seq_printf(s, "Bootparam: h2c_scif_db %d\n",
- bootparam->h2c_scif_db);
- seq_printf(s, "Bootparam: scif_host_dma_addr 0x%llx\n",
- bootparam->scif_host_dma_addr);
- seq_printf(s, "Bootparam: scif_card_dma_addr 0x%llx\n",
- bootparam->scif_card_dma_addr);
-
-
- for (i = sizeof(*bootparam); i < MIC_DP_SIZE;
- i += mic_total_desc_size(d)) {
- d = mdev->dp + i;
- dc = (void *)d + mic_aligned_desc_size(d);
-
- /* end of list */
- if (d->type == 0)
- break;
-
- if (d->type == -1)
- continue;
-
- seq_printf(s, "Type %d ", d->type);
- seq_printf(s, "Num VQ %d ", d->num_vq);
- seq_printf(s, "Feature Len %d\n", d->feature_len);
- seq_printf(s, "Config Len %d ", d->config_len);
- seq_printf(s, "Shutdown Status %d\n", d->status);
-
- for (j = 0; j < d->num_vq; j++) {
- vqconfig = mic_vq_config(d) + j;
- seq_printf(s, "vqconfig[%d]: ", j);
- seq_printf(s, "address 0x%llx ", vqconfig->address);
- seq_printf(s, "num %d ", vqconfig->num);
- seq_printf(s, "used address 0x%llx\n",
- vqconfig->used_address);
- }
-
- features = (__u32 *)mic_vq_features(d);
- seq_printf(s, "Features: Host 0x%x ", features[0]);
- seq_printf(s, "Guest 0x%x\n", features[1]);
-
- config = mic_vq_configspace(d);
- for (j = 0; j < d->config_len; j++)
- seq_printf(s, "config[%d]=%d\n", j, config[j]);
-
- seq_puts(s, "Device control:\n");
- seq_printf(s, "Config Change %d ", dc->config_change);
- seq_printf(s, "Vdev reset %d\n", dc->vdev_reset);
- seq_printf(s, "Guest Ack %d ", dc->guest_ack);
- seq_printf(s, "Host ack %d\n", dc->host_ack);
- seq_printf(s, "Used address updated %d ",
- dc->used_address_updated);
- seq_printf(s, "Vdev 0x%llx\n", dc->vdev);
- seq_printf(s, "c2h doorbell %d ", dc->c2h_vdev_db);
- seq_printf(s, "h2c doorbell %d\n", dc->h2c_vdev_db);
- }
-
- return 0;
-}
-
-static int mic_dp_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mic_dp_show, inode->i_private);
-}
-
-static int mic_dp_debug_release(struct inode *inode, struct file *file)
-{
- return single_release(inode, file);
-}
-
-static const struct file_operations dp_ops = {
- .owner = THIS_MODULE,
- .open = mic_dp_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = mic_dp_debug_release
-};
-
-static int mic_vdev_info_show(struct seq_file *s, void *unused)
-{
- struct mic_device *mdev = s->private;
- struct list_head *pos, *tmp;
- struct mic_vdev *mvdev;
- int i, j;
-
- mutex_lock(&mdev->mic_mutex);
- list_for_each_safe(pos, tmp, &mdev->vdev_list) {
- mvdev = list_entry(pos, struct mic_vdev, list);
- seq_printf(s, "VDEV type %d state %s in %ld out %ld\n",
- mvdev->virtio_id,
- mic_vdevup(mvdev) ? "UP" : "DOWN",
- mvdev->in_bytes,
- mvdev->out_bytes);
- for (i = 0; i < MIC_MAX_VRINGS; i++) {
- struct vring_desc *desc;
- struct vring_avail *avail;
- struct vring_used *used;
- struct mic_vringh *mvr = &mvdev->mvr[i];
- struct vringh *vrh = &mvr->vrh;
- int num = vrh->vring.num;
- if (!num)
- continue;
- desc = vrh->vring.desc;
- seq_printf(s, "vring i %d avail_idx %d",
- i, mvr->vring.info->avail_idx & (num - 1));
- seq_printf(s, " vring i %d avail_idx %d\n",
- i, mvr->vring.info->avail_idx);
- seq_printf(s, "vrh i %d weak_barriers %d",
- i, vrh->weak_barriers);
- seq_printf(s, " last_avail_idx %d last_used_idx %d",
- vrh->last_avail_idx, vrh->last_used_idx);
- seq_printf(s, " completed %d\n", vrh->completed);
- for (j = 0; j < num; j++) {
- seq_printf(s, "desc[%d] addr 0x%llx len %d",
- j, desc->addr, desc->len);
- seq_printf(s, " flags 0x%x next %d\n",
- desc->flags, desc->next);
- desc++;
- }
- avail = vrh->vring.avail;
- seq_printf(s, "avail flags 0x%x idx %d\n",
- vringh16_to_cpu(vrh, avail->flags),
- vringh16_to_cpu(vrh, avail->idx) & (num - 1));
- seq_printf(s, "avail flags 0x%x idx %d\n",
- vringh16_to_cpu(vrh, avail->flags),
- vringh16_to_cpu(vrh, avail->idx));
- for (j = 0; j < num; j++)
- seq_printf(s, "avail ring[%d] %d\n",
- j, avail->ring[j]);
- used = vrh->vring.used;
- seq_printf(s, "used flags 0x%x idx %d\n",
- vringh16_to_cpu(vrh, used->flags),
- vringh16_to_cpu(vrh, used->idx) & (num - 1));
- seq_printf(s, "used flags 0x%x idx %d\n",
- vringh16_to_cpu(vrh, used->flags),
- vringh16_to_cpu(vrh, used->idx));
- for (j = 0; j < num; j++)
- seq_printf(s, "used ring[%d] id %d len %d\n",
- j, vringh32_to_cpu(vrh,
- used->ring[j].id),
- vringh32_to_cpu(vrh,
- used->ring[j].len));
- }
- }
- mutex_unlock(&mdev->mic_mutex);
-
- return 0;
-}
-
-static int mic_vdev_info_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mic_vdev_info_show, inode->i_private);
-}
-
-static int mic_vdev_info_debug_release(struct inode *inode, struct file *file)
-{
- return single_release(inode, file);
-}
-
-static const struct file_operations vdev_info_ops = {
- .owner = THIS_MODULE,
- .open = mic_vdev_info_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = mic_vdev_info_debug_release
-};
-
static int mic_msi_irq_info_show(struct seq_file *s, void *pos)
{
struct mic_device *mdev = s->private;
@@ -367,11 +182,6 @@ void mic_create_debug_dir(struct mic_device *mdev)
debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev,
&post_code_ops);
- debugfs_create_file("dp", 0444, mdev->dbg_dir, mdev, &dp_ops);
-
- debugfs_create_file("vdev_info", 0444, mdev->dbg_dir, mdev,
- &vdev_info_ops);
-
debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, mdev,
&msi_irq_info_ops);
}
diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h
index 461184a12fbb..52b12b22f4ae 100644
--- a/drivers/misc/mic/host/mic_device.h
+++ b/drivers/misc/mic/host/mic_device.h
@@ -29,6 +29,7 @@
#include <linux/miscdevice.h>
#include <linux/mic_bus.h>
#include "../bus/scif_bus.h"
+#include "../bus/vop_bus.h"
#include "../bus/cosm_bus.h"
#include "mic_intr.h"
@@ -64,13 +65,11 @@ extern struct cosm_hw_ops cosm_hw_ops;
* @bootaddr: MIC boot address.
* @dp: virtio device page
* @dp_dma_addr: virtio device page DMA address.
- * @name: name for the misc char device
- * @miscdev: registered misc char device
- * @vdev_list: list of virtio devices.
* @dma_mbdev: MIC BUS DMA device.
* @dma_ch - Array of DMA channels
* @num_dma_ch - Number of DMA channels available
* @scdev: SCIF device on the SCIF virtual bus.
+ * @vpdev: Virtio over PCIe device on the VOP virtual bus.
* @cosm_dev: COSM device
*/
struct mic_device {
@@ -91,13 +90,11 @@ struct mic_device {
u32 bootaddr;
void *dp;
dma_addr_t dp_dma_addr;
- char name[16];
- struct miscdevice miscdev;
- struct list_head vdev_list;
struct mbus_device *dma_mbdev;
struct dma_chan *dma_ch[MIC_MAX_DMA_CHAN];
int num_dma_ch;
struct scif_hw_dev *scdev;
+ struct vop_device *vpdev;
struct cosm_device *cosm_dev;
};
diff --git a/drivers/misc/mic/host/mic_fops.c b/drivers/misc/mic/host/mic_fops.c
deleted file mode 100644
index 8cc1d90cd949..000000000000
--- a/drivers/misc/mic/host/mic_fops.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Intel MIC Platform Software Stack (MPSS)
- *
- * Copyright(c) 2013 Intel Corporation.
- *
- * 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
- * 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Intel MIC Host driver.
- *
- */
-#include <linux/poll.h>
-#include <linux/pci.h>
-
-#include <linux/mic_common.h>
-#include "../common/mic_dev.h"
-#include "mic_device.h"
-#include "mic_fops.h"
-#include "mic_virtio.h"
-
-int mic_open(struct inode *inode, struct file *f)
-{
- struct mic_vdev *mvdev;
- struct mic_device *mdev = container_of(f->private_data,
- struct mic_device, miscdev);
-
- mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL);
- if (!mvdev)
- return -ENOMEM;
-
- init_waitqueue_head(&mvdev->waitq);
- INIT_LIST_HEAD(&mvdev->list);
- mvdev->mdev = mdev;
- mvdev->virtio_id = -1;
-
- f->private_data = mvdev;
- return 0;
-}
-
-int mic_release(struct inode *inode, struct file *f)
-{
- struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
-
- if (-1 != mvdev->virtio_id)
- mic_virtio_del_device(mvdev);
- f->private_data = NULL;
- kfree(mvdev);
- return 0;
-}
-
-long mic_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
-{
- struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
- void __user *argp = (void __user *)arg;
- int ret;
-
- switch (cmd) {
- case MIC_VIRTIO_ADD_DEVICE:
- {
- ret = mic_virtio_add_device(mvdev, argp);
- if (ret < 0) {
- dev_err(mic_dev(mvdev),
- "%s %d errno ret %d\n",
- __func__, __LINE__, ret);
- return ret;
- }
- break;
- }
- case MIC_VIRTIO_COPY_DESC:
- {
- struct mic_copy_desc copy;
-
- ret = mic_vdev_inited(mvdev);
- if (ret)
- return ret;
-
- if (copy_from_user(&copy, argp, sizeof(copy)))
- return -EFAULT;
-
- dev_dbg(mic_dev(mvdev),
- "%s %d === iovcnt 0x%x vr_idx 0x%x update_used %d\n",
- __func__, __LINE__, copy.iovcnt, copy.vr_idx,
- copy.update_used);
-
- ret = mic_virtio_copy_desc(mvdev, &copy);
- if (ret < 0) {
- dev_err(mic_dev(mvdev),
- "%s %d errno ret %d\n",
- __func__, __LINE__, ret);
- return ret;
- }
- if (copy_to_user(
- &((struct mic_copy_desc __user *)argp)->out_len,
- &copy.out_len, sizeof(copy.out_len))) {
- dev_err(mic_dev(mvdev), "%s %d errno ret %d\n",
- __func__, __LINE__, -EFAULT);
- return -EFAULT;
- }
- break;
- }
- case MIC_VIRTIO_CONFIG_CHANGE:
- {
- ret = mic_vdev_inited(mvdev);
- if (ret)
- return ret;
-
- ret = mic_virtio_config_change(mvdev, argp);
- if (ret < 0) {
- dev_err(mic_dev(mvdev),
- "%s %d errno ret %d\n",
- __func__, __LINE__, ret);
- return ret;
- }
- break;
- }
- default:
- return -ENOIOCTLCMD;
- };
- return 0;
-}
-
-/*
- * We return POLLIN | POLLOUT from poll when new buffers are enqueued, and
- * not when previously enqueued buffers may be available. This means that
- * in the card->host (TX) path, when userspace is unblocked by poll it
- * must drain all available descriptors or it can stall.
- */
-unsigned int mic_poll(struct file *f, poll_table *wait)
-{
- struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
- int mask = 0;
-
- poll_wait(f, &mvdev->waitq, wait);
-
- if (mic_vdev_inited(mvdev)) {
- mask = POLLERR;
- } else if (mvdev->poll_wake) {
- mvdev->poll_wake = 0;
- mask = POLLIN | POLLOUT;
- }
-
- return mask;
-}
-
-static inline int
-mic_query_offset(struct mic_vdev *mvdev, unsigned long offset,
- unsigned long *size, unsigned long *pa)
-{
- struct mic_device *mdev = mvdev->mdev;
- unsigned long start = MIC_DP_SIZE;
- int i;
-
- /*
- * MMAP interface is as follows:
- * offset region
- * 0x0 virtio device_page
- * 0x1000 first vring
- * 0x1000 + size of 1st vring second vring
- * ....
- */
- if (!offset) {
- *pa = virt_to_phys(mdev->dp);
- *size = MIC_DP_SIZE;
- return 0;
- }
-
- for (i = 0; i < mvdev->dd->num_vq; i++) {
- struct mic_vringh *mvr = &mvdev->mvr[i];
- if (offset == start) {
- *pa = virt_to_phys(mvr->vring.va);
- *size = mvr->vring.len;
- return 0;
- }
- start += mvr->vring.len;
- }
- return -1;
-}
-
-/*
- * Maps the device page and virtio rings to user space for readonly access.
- */
-int
-mic_mmap(struct file *f, struct vm_area_struct *vma)
-{
- struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long pa, size = vma->vm_end - vma->vm_start, size_rem = size;
- int i, err;
-
- err = mic_vdev_inited(mvdev);
- if (err)
- return err;
-
- if (vma->vm_flags & VM_WRITE)
- return -EACCES;
-
- while (size_rem) {
- i = mic_query_offset(mvdev, offset, &size, &pa);
- if (i < 0)
- return -EINVAL;
- err = remap_pfn_range(vma, vma->vm_start + offset,
- pa >> PAGE_SHIFT, size, vma->vm_page_prot);
- if (err)
- return err;
- dev_dbg(mic_dev(mvdev),
- "%s %d type %d size 0x%lx off 0x%lx pa 0x%lx vma 0x%lx\n",
- __func__, __LINE__, mvdev->virtio_id, size, offset,
- pa, vma->vm_start + offset);
- size_rem -= size;
- offset += size;
- }
- return 0;
-}
diff --git a/drivers/misc/mic/host/mic_fops.h b/drivers/misc/mic/host/mic_fops.h
deleted file mode 100644
index dc3893dff667..000000000000
--- a/drivers/misc/mic/host/mic_fops.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Intel MIC Platform Software Stack (MPSS)
- *
- * Copyright(c) 2013 Intel Corporation.
- *
- * 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
- * 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Intel MIC Host driver.
- *
- */
-#ifndef _MIC_FOPS_H_
-#define _MIC_FOPS_H_
-
-int mic_open(struct inode *inode, struct file *filp);
-int mic_release(struct inode *inode, struct file *filp);
-ssize_t mic_read(struct file *filp, char __user *buf,
- size_t count, loff_t *pos);
-long mic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
-int mic_mmap(struct file *f, struct vm_area_struct *vma);
-unsigned int mic_poll(struct file *f, poll_table *wait);
-
-#endif
diff --git a/drivers/misc/mic/host/mic_main.c b/drivers/misc/mic/host/mic_main.c
index 153894e7ed5b..035be3e9ceba 100644
--- a/drivers/misc/mic/host/mic_main.c
+++ b/drivers/misc/mic/host/mic_main.c
@@ -27,8 +27,6 @@
#include "mic_device.h"
#include "mic_x100.h"
#include "mic_smpt.h"
-#include "mic_fops.h"
-#include "mic_virtio.h"
static const char mic_driver_name[] = "mic";
@@ -57,17 +55,6 @@ MODULE_DEVICE_TABLE(pci, mic_pci_tbl);
/* ID allocator for MIC devices */
static struct ida g_mic_ida;
-/* Base device node number for MIC devices */
-static dev_t g_mic_devno;
-
-static const struct file_operations mic_fops = {
- .open = mic_open,
- .release = mic_release,
- .unlocked_ioctl = mic_ioctl,
- .poll = mic_poll,
- .mmap = mic_mmap,
- .owner = THIS_MODULE,
-};
/* Initialize the device page */
static int mic_dp_init(struct mic_device *mdev)
@@ -169,7 +156,6 @@ mic_device_init(struct mic_device *mdev, struct pci_dev *pdev)
mic_ops_init(mdev);
mutex_init(&mdev->mic_mutex);
mdev->irq_info.next_avail_src = 0;
- INIT_LIST_HEAD(&mdev->vdev_list);
}
/**
@@ -259,30 +245,15 @@ static int mic_probe(struct pci_dev *pdev,
goto smpt_uninit;
}
mic_bootparam_init(mdev);
-
mic_create_debug_dir(mdev);
- mdev->miscdev.minor = MISC_DYNAMIC_MINOR;
- snprintf(mdev->name, sizeof(mdev->name), "mic%d", mdev->id);
- mdev->miscdev.name = mdev->name;
- mdev->miscdev.fops = &mic_fops;
- mdev->miscdev.parent = &mdev->pdev->dev;
- rc = misc_register(&mdev->miscdev);
- if (rc) {
- dev_err(&pdev->dev, "misc_register err id %d rc %d\n",
- mdev->id, rc);
- goto cleanup_debug_dir;
- }
-
mdev->cosm_dev = cosm_register_device(&mdev->pdev->dev, &cosm_hw_ops);
if (IS_ERR(mdev->cosm_dev)) {
rc = PTR_ERR(mdev->cosm_dev);
dev_err(&pdev->dev, "cosm_add_device failed rc %d\n", rc);
- goto misc_dereg;
+ goto cleanup_debug_dir;
}
return 0;
-misc_dereg:
- misc_deregister(&mdev->miscdev);
cleanup_debug_dir:
mic_delete_debug_dir(mdev);
mic_dp_uninit(mdev);
@@ -323,7 +294,6 @@ static void mic_remove(struct pci_dev *pdev)
return;
cosm_unregister_device(mdev->cosm_dev);
- misc_deregister(&mdev->miscdev);
mic_delete_debug_dir(mdev);
mic_dp_uninit(mdev);
mic_smpt_uninit(mdev);
@@ -347,26 +317,18 @@ static int __init mic_init(void)
{
int ret;
- ret = alloc_chrdev_region(&g_mic_devno, 0,
- MIC_MAX_NUM_DEVS, mic_driver_name);
- if (ret) {
- pr_err("alloc_chrdev_region failed ret %d\n", ret);
- goto error;
- }
-
+ request_module("mic_x100_dma");
mic_init_debugfs();
ida_init(&g_mic_ida);
ret = pci_register_driver(&mic_driver);
if (ret) {
pr_err("pci_register_driver failed ret %d\n", ret);
- goto cleanup_chrdev;
+ goto cleanup_debugfs;
}
- return ret;
-cleanup_chrdev:
+ return 0;
+cleanup_debugfs:
ida_destroy(&g_mic_ida);
mic_exit_debugfs();
- unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS);
-error:
return ret;
}
@@ -375,7 +337,6 @@ static void __exit mic_exit(void)
pci_unregister_driver(&mic_driver);
ida_destroy(&g_mic_ida);
mic_exit_debugfs();
- unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS);
}
module_init(mic_init);
diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c
deleted file mode 100644
index 58b107a24a8b..000000000000
--- a/drivers/misc/mic/host/mic_virtio.c
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * Intel MIC Platform Software Stack (MPSS)
- *
- * Copyright(c) 2013 Intel Corporation.
- *
- * 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
- * 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Intel MIC Host driver.
- *
- */
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/uaccess.h>
-#include <linux/dmaengine.h>
-#include <linux/mic_common.h>
-#include "../common/mic_dev.h"
-#include "mic_device.h"
-#include "mic_smpt.h"
-#include "mic_virtio.h"
-
-/*
- * Size of the internal buffer used during DMA's as an intermediate buffer
- * for copy to/from user.
- */
-#define MIC_INT_DMA_BUF_SIZE PAGE_ALIGN(64 * 1024ULL)
-
-static int mic_sync_dma(struct mic_device *mdev, dma_addr_t dst,
- dma_addr_t src, size_t len)
-{
- int err = 0;
- struct dma_async_tx_descriptor *tx;
- struct dma_chan *mic_ch = mdev->dma_ch[0];
-
- if (!mic_ch) {
- err = -EBUSY;
- goto error;
- }
-
- tx = mic_ch->device->device_prep_dma_memcpy(mic_ch, dst, src, len,
- DMA_PREP_FENCE);
- if (!tx) {
- err = -ENOMEM;
- goto error;
- } else {
- dma_cookie_t cookie = tx->tx_submit(tx);
-
- err = dma_submit_error(cookie);
- if (err)
- goto error;
- err = dma_sync_wait(mic_ch, cookie);
- }
-error:
- if (err)
- dev_err(&mdev->pdev->dev, "%s %d err %d\n",
- __func__, __LINE__, err);
- return err;
-}
-
-/*
- * Initiates the copies across the PCIe bus from card memory to a user
- * space buffer. When transfers are done using DMA, source/destination
- * addresses and transfer length must follow the alignment requirements of
- * the MIC DMA engine.
- */
-static int mic_virtio_copy_to_user(struct mic_vdev *mvdev, void __user *ubuf,
- size_t len, u64 daddr, size_t dlen,
- int vr_idx)
-{
- struct mic_device *mdev = mvdev->mdev;
- void __iomem *dbuf = mdev->aper.va + daddr;
- struct mic_vringh *mvr = &mvdev->mvr[vr_idx];
- size_t dma_alignment = 1 << mdev->dma_ch[0]->device->copy_align;
- size_t dma_offset;
- size_t partlen;
- int err;
-
- dma_offset = daddr - round_down(daddr, dma_alignment);
- daddr -= dma_offset;
- len += dma_offset;
-
- while (len) {
- partlen = min_t(size_t, len, MIC_INT_DMA_BUF_SIZE);
-
- err = mic_sync_dma(mdev, mvr->buf_da, daddr,
- ALIGN(partlen, dma_alignment));
- if (err)
- goto err;
-
- if (copy_to_user(ubuf, mvr->buf + dma_offset,
- partlen - dma_offset)) {
- err = -EFAULT;
- goto err;
- }
- daddr += partlen;
- ubuf += partlen;
- dbuf += partlen;
- mvdev->in_bytes_dma += partlen;
- mvdev->in_bytes += partlen;
- len -= partlen;
- dma_offset = 0;
- }
- return 0;
-err:
- dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err);
- return err;
-}
-
-/*
- * Initiates copies across the PCIe bus from a user space buffer to card
- * memory. When transfers are done using DMA, source/destination addresses
- * and transfer length must follow the alignment requirements of the MIC
- * DMA engine.
- */
-static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, void __user *ubuf,
- size_t len, u64 daddr, size_t dlen,
- int vr_idx)
-{
- struct mic_device *mdev = mvdev->mdev;
- void __iomem *dbuf = mdev->aper.va + daddr;
- struct mic_vringh *mvr = &mvdev->mvr[vr_idx];
- size_t dma_alignment = 1 << mdev->dma_ch[0]->device->copy_align;
- size_t partlen;
- int err;
-
- if (daddr & (dma_alignment - 1)) {
- mvdev->tx_dst_unaligned += len;
- goto memcpy;
- } else if (ALIGN(len, dma_alignment) > dlen) {
- mvdev->tx_len_unaligned += len;
- goto memcpy;
- }
-
- while (len) {
- partlen = min_t(size_t, len, MIC_INT_DMA_BUF_SIZE);
-
- if (copy_from_user(mvr->buf, ubuf, partlen)) {
- err = -EFAULT;
- goto err;
- }
- err = mic_sync_dma(mdev, daddr, mvr->buf_da,
- ALIGN(partlen, dma_alignment));
- if (err)
- goto err;
- daddr += partlen;
- ubuf += partlen;
- dbuf += partlen;
- mvdev->out_bytes_dma += partlen;
- mvdev->out_bytes += partlen;
- len -= partlen;
- }
-memcpy:
- /*
- * We are copying to IO below and should ideally use something
- * like copy_from_user_toio(..) if it existed.
- */
- if (copy_from_user((void __force *)dbuf, ubuf, len)) {
- err = -EFAULT;
- goto err;
- }
- mvdev->out_bytes += len;
- return 0;
-err:
- dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err);
- return err;
-}
-
-#define MIC_VRINGH_READ true
-
-/* The function to call to notify the card about added buffers */
-static void mic_notify(struct vringh *vrh)
-{
- struct mic_vringh *mvrh = container_of(vrh, struct mic_vringh, vrh);
- struct mic_vdev *mvdev = mvrh->mvdev;
- s8 db = mvdev->dc->h2c_vdev_db;
-
- if (db != -1)
- mvdev->mdev->ops->send_intr(mvdev->mdev, db);
-}
-
-/* Determine the total number of bytes consumed in a VRINGH KIOV */
-static inline u32 mic_vringh_iov_consumed(struct vringh_kiov *iov)
-{
- int i;
- u32 total = iov->consumed;
-
- for (i = 0; i < iov->i; i++)
- total += iov->iov[i].iov_len;
- return total;
-}
-
-/*
- * Traverse the VRINGH KIOV and issue the APIs to trigger the copies.
- * This API is heavily based on the vringh_iov_xfer(..) implementation
- * in vringh.c. The reason we cannot reuse vringh_iov_pull_kern(..)
- * and vringh_iov_push_kern(..) directly is because there is no
- * way to override the VRINGH xfer(..) routines as of v3.10.
- */
-static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov,
- void __user *ubuf, size_t len, bool read, int vr_idx,
- size_t *out_len)
-{
- int ret = 0;
- size_t partlen, tot_len = 0;
-
- while (len && iov->i < iov->used) {
- partlen = min(iov->iov[iov->i].iov_len, len);
- if (read)
- ret = mic_virtio_copy_to_user(mvdev, ubuf, partlen,
- (u64)iov->iov[iov->i].iov_base,
- iov->iov[iov->i].iov_len,
- vr_idx);
- else
- ret = mic_virtio_copy_from_user(mvdev, ubuf, partlen,
- (u64)iov->iov[iov->i].iov_base,
- iov->iov[iov->i].iov_len,
- vr_idx);
- if (ret) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- break;
- }
- len -= partlen;
- ubuf += partlen;
- tot_len += partlen;
- iov->consumed += partlen;
- iov->iov[iov->i].iov_len -= partlen;
- iov->iov[iov->i].iov_base += partlen;
- if (!iov->iov[iov->i].iov_len) {
- /* Fix up old iov element then increment. */
- iov->iov[iov->i].iov_len = iov->consumed;
- iov->iov[iov->i].iov_base -= iov->consumed;
-
- iov->consumed = 0;
- iov->i++;
- }
- }
- *out_len = tot_len;
- return ret;
-}
-
-/*
- * Use the standard VRINGH infrastructure in the kernel to fetch new
- * descriptors, initiate the copies and update the used ring.
- */
-static int _mic_virtio_copy(struct mic_vdev *mvdev,
- struct mic_copy_desc *copy)
-{
- int ret = 0;
- u32 iovcnt = copy->iovcnt;
- struct iovec iov;
- struct iovec __user *u_iov = copy->iov;
- void __user *ubuf = NULL;
- struct mic_vringh *mvr = &mvdev->mvr[copy->vr_idx];
- struct vringh_kiov *riov = &mvr->riov;
- struct vringh_kiov *wiov = &mvr->wiov;
- struct vringh *vrh = &mvr->vrh;
- u16 *head = &mvr->head;
- struct mic_vring *vr = &mvr->vring;
- size_t len = 0, out_len;
-
- copy->out_len = 0;
- /* Fetch a new IOVEC if all previous elements have been processed */
- if (riov->i == riov->used && wiov->i == wiov->used) {
- ret = vringh_getdesc_kern(vrh, riov, wiov,
- head, GFP_KERNEL);
- /* Check if there are available descriptors */
- if (ret <= 0)
- return ret;
- }
- while (iovcnt) {
- if (!len) {
- /* Copy over a new iovec from user space. */
- ret = copy_from_user(&iov, u_iov, sizeof(*u_iov));
- if (ret) {
- ret = -EINVAL;
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- break;
- }
- len = iov.iov_len;
- ubuf = iov.iov_base;
- }
- /* Issue all the read descriptors first */
- ret = mic_vringh_copy(mvdev, riov, ubuf, len, MIC_VRINGH_READ,
- copy->vr_idx, &out_len);
- if (ret) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- break;
- }
- len -= out_len;
- ubuf += out_len;
- copy->out_len += out_len;
- /* Issue the write descriptors next */
- ret = mic_vringh_copy(mvdev, wiov, ubuf, len, !MIC_VRINGH_READ,
- copy->vr_idx, &out_len);
- if (ret) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- break;
- }
- len -= out_len;
- ubuf += out_len;
- copy->out_len += out_len;
- if (!len) {
- /* One user space iovec is now completed */
- iovcnt--;
- u_iov++;
- }
- /* Exit loop if all elements in KIOVs have been processed. */
- if (riov->i == riov->used && wiov->i == wiov->used)
- break;
- }
- /*
- * Update the used ring if a descriptor was available and some data was
- * copied in/out and the user asked for a used ring update.
- */
- if (*head != USHRT_MAX && copy->out_len && copy->update_used) {
- u32 total = 0;
-
- /* Determine the total data consumed */
- total += mic_vringh_iov_consumed(riov);
- total += mic_vringh_iov_consumed(wiov);
- vringh_complete_kern(vrh, *head, total);
- *head = USHRT_MAX;
- if (vringh_need_notify_kern(vrh) > 0)
- vringh_notify(vrh);
- vringh_kiov_cleanup(riov);
- vringh_kiov_cleanup(wiov);
- /* Update avail idx for user space */
- vr->info->avail_idx = vrh->last_avail_idx;
- }
- return ret;
-}
-
-static inline int mic_verify_copy_args(struct mic_vdev *mvdev,
- struct mic_copy_desc *copy)
-{
- if (copy->vr_idx >= mvdev->dd->num_vq) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, -EINVAL);
- return -EINVAL;
- }
- return 0;
-}
-
-/* Copy a specified number of virtio descriptors in a chain */
-int mic_virtio_copy_desc(struct mic_vdev *mvdev,
- struct mic_copy_desc *copy)
-{
- int err;
- struct mic_vringh *mvr = &mvdev->mvr[copy->vr_idx];
-
- err = mic_verify_copy_args(mvdev, copy);
- if (err)
- return err;
-
- mutex_lock(&mvr->vr_mutex);
- if (!mic_vdevup(mvdev)) {
- err = -ENODEV;
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, err);
- goto err;
- }
- err = _mic_virtio_copy(mvdev, copy);
- if (err) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, err);
- }
-err:
- mutex_unlock(&mvr->vr_mutex);
- return err;
-}
-
-static void mic_virtio_init_post(struct mic_vdev *mvdev)
-{
- struct mic_vqconfig *vqconfig = mic_vq_config(mvdev->dd);
- int i;
-
- for (i = 0; i < mvdev->dd->num_vq; i++) {
- if (!le64_to_cpu(vqconfig[i].used_address)) {
- dev_warn(mic_dev(mvdev), "used_address zero??\n");
- continue;
- }
- mvdev->mvr[i].vrh.vring.used =
- (void __force *)mvdev->mdev->aper.va +
- le64_to_cpu(vqconfig[i].used_address);
- }
-
- mvdev->dc->used_address_updated = 0;
-
- dev_dbg(mic_dev(mvdev), "%s: device type %d LINKUP\n",
- __func__, mvdev->virtio_id);
-}
-
-static inline void mic_virtio_device_reset(struct mic_vdev *mvdev)
-{
- int i;
-
- dev_dbg(mic_dev(mvdev), "%s: status %d device type %d RESET\n",
- __func__, mvdev->dd->status, mvdev->virtio_id);
-
- for (i = 0; i < mvdev->dd->num_vq; i++)
- /*
- * Avoid lockdep false positive. The + 1 is for the mic
- * mutex which is held in the reset devices code path.
- */
- mutex_lock_nested(&mvdev->mvr[i].vr_mutex, i + 1);
-
- /* 0 status means "reset" */
- mvdev->dd->status = 0;
- mvdev->dc->vdev_reset = 0;
- mvdev->dc->host_ack = 1;
-
- for (i = 0; i < mvdev->dd->num_vq; i++) {
- struct vringh *vrh = &mvdev->mvr[i].vrh;
- mvdev->mvr[i].vring.info->avail_idx = 0;
- vrh->completed = 0;
- vrh->last_avail_idx = 0;
- vrh->last_used_idx = 0;
- }
-
- for (i = 0; i < mvdev->dd->num_vq; i++)
- mutex_unlock(&mvdev->mvr[i].vr_mutex);
-}
-
-void mic_virtio_reset_devices(struct mic_device *mdev)
-{
- struct list_head *pos, *tmp;
- struct mic_vdev *mvdev;
-
- dev_dbg(&mdev->pdev->dev, "%s\n", __func__);
-
- list_for_each_safe(pos, tmp, &mdev->vdev_list) {
- mvdev = list_entry(pos, struct mic_vdev, list);
- mic_virtio_device_reset(mvdev);
- mvdev->poll_wake = 1;
- wake_up(&mvdev->waitq);
- }
-}
-
-void mic_bh_handler(struct work_struct *work)
-{
- struct mic_vdev *mvdev = container_of(work, struct mic_vdev,
- virtio_bh_work);
-
- if (mvdev->dc->used_address_updated)
- mic_virtio_init_post(mvdev);
-
- if (mvdev->dc->vdev_reset)
- mic_virtio_device_reset(mvdev);
-
- mvdev->poll_wake = 1;
- wake_up(&mvdev->waitq);
-}
-
-static irqreturn_t mic_virtio_intr_handler(int irq, void *data)
-{
- struct mic_vdev *mvdev = data;
- struct mic_device *mdev = mvdev->mdev;
-
- mdev->ops->intr_workarounds(mdev);
- schedule_work(&mvdev->virtio_bh_work);
- return IRQ_HANDLED;
-}
-
-int mic_virtio_config_change(struct mic_vdev *mvdev,
- void __user *argp)
-{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
- int ret = 0, retry, i;
- struct mic_bootparam *bootparam = mvdev->mdev->dp;
- s8 db = bootparam->h2c_config_db;
-
- mutex_lock(&mvdev->mdev->mic_mutex);
- for (i = 0; i < mvdev->dd->num_vq; i++)
- mutex_lock_nested(&mvdev->mvr[i].vr_mutex, i + 1);
-
- if (db == -1 || mvdev->dd->type == -1) {
- ret = -EIO;
- goto exit;
- }
-
- if (copy_from_user(mic_vq_configspace(mvdev->dd),
- argp, mvdev->dd->config_len)) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, -EFAULT);
- ret = -EFAULT;
- goto exit;
- }
- mvdev->dc->config_change = MIC_VIRTIO_PARAM_CONFIG_CHANGED;
- mvdev->mdev->ops->send_intr(mvdev->mdev, db);
-
- for (retry = 100; retry--;) {
- ret = wait_event_timeout(wake,
- mvdev->dc->guest_ack, msecs_to_jiffies(100));
- if (ret)
- break;
- }
-
- dev_dbg(mic_dev(mvdev),
- "%s %d retry: %d\n", __func__, __LINE__, retry);
- mvdev->dc->config_change = 0;
- mvdev->dc->guest_ack = 0;
-exit:
- for (i = 0; i < mvdev->dd->num_vq; i++)
- mutex_unlock(&mvdev->mvr[i].vr_mutex);
- mutex_unlock(&mvdev->mdev->mic_mutex);
- return ret;
-}
-
-static int mic_copy_dp_entry(struct mic_vdev *mvdev,
- void __user *argp,
- __u8 *type,
- struct mic_device_desc **devpage)
-{
- struct mic_device *mdev = mvdev->mdev;
- struct mic_device_desc dd, *dd_config, *devp;
- struct mic_vqconfig *vqconfig;
- int ret = 0, i;
- bool slot_found = false;
-
- if (copy_from_user(&dd, argp, sizeof(dd))) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, -EFAULT);
- return -EFAULT;
- }
-
- if (mic_aligned_desc_size(&dd) > MIC_MAX_DESC_BLK_SIZE ||
- dd.num_vq > MIC_MAX_VRINGS) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, -EINVAL);
- return -EINVAL;
- }
-
- dd_config = kmalloc(mic_desc_size(&dd), GFP_KERNEL);
- if (dd_config == NULL) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, -ENOMEM);
- return -ENOMEM;
- }
- if (copy_from_user(dd_config, argp, mic_desc_size(&dd))) {
- ret = -EFAULT;
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- goto exit;
- }
-
- vqconfig = mic_vq_config(dd_config);
- for (i = 0; i < dd.num_vq; i++) {
- if (le16_to_cpu(vqconfig[i].num) > MIC_MAX_VRING_ENTRIES) {
- ret = -EINVAL;
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- goto exit;
- }
- }
-
- /* Find the first free device page entry */
- for (i = sizeof(struct mic_bootparam);
- i < MIC_DP_SIZE - mic_total_desc_size(dd_config);
- i += mic_total_desc_size(devp)) {
- devp = mdev->dp + i;
- if (devp->type == 0 || devp->type == -1) {
- slot_found = true;
- break;
- }
- }
- if (!slot_found) {
- ret = -EINVAL;
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- goto exit;
- }
- /*
- * Save off the type before doing the memcpy. Type will be set in the
- * end after completing all initialization for the new device.
- */
- *type = dd_config->type;
- dd_config->type = 0;
- memcpy(devp, dd_config, mic_desc_size(dd_config));
-
- *devpage = devp;
-exit:
- kfree(dd_config);
- return ret;
-}
-
-static void mic_init_device_ctrl(struct mic_vdev *mvdev,
- struct mic_device_desc *devpage)
-{
- struct mic_device_ctrl *dc;
-
- dc = (void *)devpage + mic_aligned_desc_size(devpage);
-
- dc->config_change = 0;
- dc->guest_ack = 0;
- dc->vdev_reset = 0;
- dc->host_ack = 0;
- dc->used_address_updated = 0;
- dc->c2h_vdev_db = -1;
- dc->h2c_vdev_db = -1;
- mvdev->dc = dc;
-}
-
-int mic_virtio_add_device(struct mic_vdev *mvdev,
- void __user *argp)
-{
- struct mic_device *mdev = mvdev->mdev;
- struct mic_device_desc *dd = NULL;
- struct mic_vqconfig *vqconfig;
- int vr_size, i, j, ret;
- u8 type = 0;
- s8 db;
- char irqname[10];
- struct mic_bootparam *bootparam = mdev->dp;
- u16 num;
- dma_addr_t vr_addr;
-
- mutex_lock(&mdev->mic_mutex);
-
- ret = mic_copy_dp_entry(mvdev, argp, &type, &dd);
- if (ret) {
- mutex_unlock(&mdev->mic_mutex);
- return ret;
- }
-
- mic_init_device_ctrl(mvdev, dd);
-
- mvdev->dd = dd;
- mvdev->virtio_id = type;
- vqconfig = mic_vq_config(dd);
- INIT_WORK(&mvdev->virtio_bh_work, mic_bh_handler);
-
- for (i = 0; i < dd->num_vq; i++) {
- struct mic_vringh *mvr = &mvdev->mvr[i];
- struct mic_vring *vr = &mvdev->mvr[i].vring;
- num = le16_to_cpu(vqconfig[i].num);
- mutex_init(&mvr->vr_mutex);
- vr_size = PAGE_ALIGN(vring_size(num, MIC_VIRTIO_RING_ALIGN) +
- sizeof(struct _mic_vring_info));
- vr->va = (void *)
- __get_free_pages(GFP_KERNEL | __GFP_ZERO,
- get_order(vr_size));
- if (!vr->va) {
- ret = -ENOMEM;
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- goto err;
- }
- vr->len = vr_size;
- vr->info = vr->va + vring_size(num, MIC_VIRTIO_RING_ALIGN);
- vr->info->magic = cpu_to_le32(MIC_MAGIC + mvdev->virtio_id + i);
- vr_addr = mic_map_single(mdev, vr->va, vr_size);
- if (mic_map_error(vr_addr)) {
- free_pages((unsigned long)vr->va, get_order(vr_size));
- ret = -ENOMEM;
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- goto err;
- }
- vqconfig[i].address = cpu_to_le64(vr_addr);
-
- vring_init(&vr->vr, num, vr->va, MIC_VIRTIO_RING_ALIGN);
- ret = vringh_init_kern(&mvr->vrh,
- *(u32 *)mic_vq_features(mvdev->dd), num, false,
- vr->vr.desc, vr->vr.avail, vr->vr.used);
- if (ret) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, ret);
- goto err;
- }
- vringh_kiov_init(&mvr->riov, NULL, 0);
- vringh_kiov_init(&mvr->wiov, NULL, 0);
- mvr->head = USHRT_MAX;
- mvr->mvdev = mvdev;
- mvr->vrh.notify = mic_notify;
- dev_dbg(&mdev->pdev->dev,
- "%s %d index %d va %p info %p vr_size 0x%x\n",
- __func__, __LINE__, i, vr->va, vr->info, vr_size);
- mvr->buf = (void *)__get_free_pages(GFP_KERNEL,
- get_order(MIC_INT_DMA_BUF_SIZE));
- mvr->buf_da = mic_map_single(mvdev->mdev, mvr->buf,
- MIC_INT_DMA_BUF_SIZE);
- }
-
- snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id,
- mvdev->virtio_id);
- mvdev->virtio_db = mic_next_db(mdev);
- mvdev->virtio_cookie = mic_request_threaded_irq(mdev,
- mic_virtio_intr_handler,
- NULL, irqname, mvdev,
- mvdev->virtio_db, MIC_INTR_DB);
- if (IS_ERR(mvdev->virtio_cookie)) {
- ret = PTR_ERR(mvdev->virtio_cookie);
- dev_dbg(&mdev->pdev->dev, "request irq failed\n");
- goto err;
- }
-
- mvdev->dc->c2h_vdev_db = mvdev->virtio_db;
-
- list_add_tail(&mvdev->list, &mdev->vdev_list);
- /*
- * Order the type update with previous stores. This write barrier
- * is paired with the corresponding read barrier before the uncached
- * system memory read of the type, on the card while scanning the
- * device page.
- */
- smp_wmb();
- dd->type = type;
-
- dev_dbg(&mdev->pdev->dev, "Added virtio device id %d\n", dd->type);
-
- db = bootparam->h2c_config_db;
- if (db != -1)
- mdev->ops->send_intr(mdev, db);
- mutex_unlock(&mdev->mic_mutex);
- return 0;
-err:
- vqconfig = mic_vq_config(dd);
- for (j = 0; j < i; j++) {
- struct mic_vringh *mvr = &mvdev->mvr[j];
- mic_unmap_single(mdev, le64_to_cpu(vqconfig[j].address),
- mvr->vring.len);
- free_pages((unsigned long)mvr->vring.va,
- get_order(mvr->vring.len));
- }
- mutex_unlock(&mdev->mic_mutex);
- return ret;
-}
-
-void mic_virtio_del_device(struct mic_vdev *mvdev)
-{
- struct list_head *pos, *tmp;
- struct mic_vdev *tmp_mvdev;
- struct mic_device *mdev = mvdev->mdev;
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
- int i, ret, retry;
- struct mic_vqconfig *vqconfig;
- struct mic_bootparam *bootparam = mdev->dp;
- s8 db;
-
- mutex_lock(&mdev->mic_mutex);
- db = bootparam->h2c_config_db;
- if (db == -1)
- goto skip_hot_remove;
- dev_dbg(&mdev->pdev->dev,
- "Requesting hot remove id %d\n", mvdev->virtio_id);
- mvdev->dc->config_change = MIC_VIRTIO_PARAM_DEV_REMOVE;
- mdev->ops->send_intr(mdev, db);
- for (retry = 100; retry--;) {
- ret = wait_event_timeout(wake,
- mvdev->dc->guest_ack, msecs_to_jiffies(100));
- if (ret)
- break;
- }
- dev_dbg(&mdev->pdev->dev,
- "Device id %d config_change %d guest_ack %d retry %d\n",
- mvdev->virtio_id, mvdev->dc->config_change,
- mvdev->dc->guest_ack, retry);
- mvdev->dc->config_change = 0;
- mvdev->dc->guest_ack = 0;
-skip_hot_remove:
- mic_free_irq(mdev, mvdev->virtio_cookie, mvdev);
- flush_work(&mvdev->virtio_bh_work);
- vqconfig = mic_vq_config(mvdev->dd);
- for (i = 0; i < mvdev->dd->num_vq; i++) {
- struct mic_vringh *mvr = &mvdev->mvr[i];
-
- mic_unmap_single(mvdev->mdev, mvr->buf_da,
- MIC_INT_DMA_BUF_SIZE);
- free_pages((unsigned long)mvr->buf,
- get_order(MIC_INT_DMA_BUF_SIZE));
- vringh_kiov_cleanup(&mvr->riov);
- vringh_kiov_cleanup(&mvr->wiov);
- mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address),
- mvr->vring.len);
- free_pages((unsigned long)mvr->vring.va,
- get_order(mvr->vring.len));
- }
-
- list_for_each_safe(pos, tmp, &mdev->vdev_list) {
- tmp_mvdev = list_entry(pos, struct mic_vdev, list);
- if (tmp_mvdev == mvdev) {
- list_del(pos);
- dev_dbg(&mdev->pdev->dev,
- "Removing virtio device id %d\n",
- mvdev->virtio_id);
- break;
- }
- }
- /*
- * Order the type update with previous stores. This write barrier
- * is paired with the corresponding read barrier before the uncached
- * system memory read of the type, on the card while scanning the
- * device page.
- */
- smp_wmb();
- mvdev->dd->type = -1;
- mutex_unlock(&mdev->mic_mutex);
-}
diff --git a/drivers/misc/mic/host/mic_x100.c b/drivers/misc/mic/host/mic_x100.c
index 8118ac48c764..82a973c85b5d 100644
--- a/drivers/misc/mic/host/mic_x100.c
+++ b/drivers/misc/mic/host/mic_x100.c
@@ -450,26 +450,29 @@ mic_x100_load_firmware(struct mic_device *mdev, const char *buf)
rc = mic_x100_get_boot_addr(mdev);
if (rc)
- goto error;
+ return rc;
/* load OS */
rc = request_firmware(&fw, mdev->cosm_dev->firmware, &mdev->pdev->dev);
if (rc < 0) {
dev_err(&mdev->pdev->dev,
"ramdisk request_firmware failed: %d %s\n",
rc, mdev->cosm_dev->firmware);
- goto error;
+ return rc;
}
if (mdev->bootaddr > mdev->aper.len - fw->size) {
rc = -EINVAL;
dev_err(&mdev->pdev->dev, "%s %d rc %d bootaddr 0x%x\n",
__func__, __LINE__, rc, mdev->bootaddr);
- release_firmware(fw);
goto error;
}
memcpy_toio(mdev->aper.va + mdev->bootaddr, fw->data, fw->size);
mdev->ops->write_spad(mdev, MIC_X100_FW_SIZE, fw->size);
- if (!strcmp(mdev->cosm_dev->bootmode, "flash"))
- goto done;
+ if (!strcmp(mdev->cosm_dev->bootmode, "flash")) {
+ rc = -EINVAL;
+ dev_err(&mdev->pdev->dev, "%s %d rc %d\n",
+ __func__, __LINE__, rc);
+ goto error;
+ }
/* load command line */
rc = mic_x100_load_command_line(mdev, fw);
if (rc) {
@@ -481,9 +484,11 @@ mic_x100_load_firmware(struct mic_device *mdev, const char *buf)
/* load ramdisk */
if (mdev->cosm_dev->ramdisk)
rc = mic_x100_load_ramdisk(mdev);
+
+ return rc;
+
error:
- dev_dbg(&mdev->pdev->dev, "%s %d rc %d\n", __func__, __LINE__, rc);
-done:
+ release_firmware(fw);
return rc;
}
diff --git a/drivers/misc/mic/scif/scif_dma.c b/drivers/misc/mic/scif/scif_dma.c
index 95a13c629a8e..cd01a0efda6b 100644
--- a/drivers/misc/mic/scif/scif_dma.c
+++ b/drivers/misc/mic/scif/scif_dma.c
@@ -74,11 +74,6 @@ struct scif_copy_work {
bool ordered;
};
-#ifndef list_entry_next
-#define list_entry_next(pos, member) \
- list_entry(pos->member.next, typeof(*pos), member)
-#endif
-
/**
* scif_reserve_dma_chan:
* @ep: Endpoint Descriptor.
@@ -276,13 +271,10 @@ static struct scif_mmu_notif *
scif_find_mmu_notifier(struct mm_struct *mm, struct scif_endpt_rma_info *rma)
{
struct scif_mmu_notif *mmn;
- struct list_head *item;
- list_for_each(item, &rma->mmn_list) {
- mmn = list_entry(item, struct scif_mmu_notif, list);
+ list_for_each_entry(mmn, &rma->mmn_list, list)
if (mmn->mm == mm)
return mmn;
- }
return NULL;
}
@@ -293,13 +285,12 @@ scif_add_mmu_notifier(struct mm_struct *mm, struct scif_endpt *ep)
= kzalloc(sizeof(*mmn), GFP_KERNEL);
if (!mmn)
- return ERR_PTR(ENOMEM);
+ return ERR_PTR(-ENOMEM);
scif_init_mmu_notifier(mmn, current->mm, ep);
- if (mmu_notifier_register(&mmn->ep_mmu_notifier,
- current->mm)) {
+ if (mmu_notifier_register(&mmn->ep_mmu_notifier, current->mm)) {
kfree(mmn);
- return ERR_PTR(EBUSY);
+ return ERR_PTR(-EBUSY);
}
list_add(&mmn->list, &ep->rma_info.mmn_list);
return mmn;
@@ -851,7 +842,7 @@ static void scif_rma_local_cpu_copy(s64 offset, struct scif_window *window,
(window->nr_pages << PAGE_SHIFT);
while (rem_len) {
if (offset == end_offset) {
- window = list_entry_next(window, list);
+ window = list_next_entry(window, list);
end_offset = window->offset +
(window->nr_pages << PAGE_SHIFT);
}
@@ -957,7 +948,7 @@ scif_rma_list_dma_copy_unaligned(struct scif_copy_work *work,
remaining_len -= tail_len;
while (remaining_len) {
if (offset == end_offset) {
- window = list_entry_next(window, list);
+ window = list_next_entry(window, list);
end_offset = window->offset +
(window->nr_pages << PAGE_SHIFT);
}
@@ -1064,7 +1055,7 @@ scif_rma_list_dma_copy_unaligned(struct scif_copy_work *work,
}
if (tail_len) {
if (offset == end_offset) {
- window = list_entry_next(window, list);
+ window = list_next_entry(window, list);
end_offset = window->offset +
(window->nr_pages << PAGE_SHIFT);
}
@@ -1147,13 +1138,13 @@ static int _scif_rma_list_dma_copy_aligned(struct scif_copy_work *work,
(dst_window->nr_pages << PAGE_SHIFT);
while (remaining_len) {
if (src_offset == end_src_offset) {
- src_window = list_entry_next(src_window, list);
+ src_window = list_next_entry(src_window, list);
end_src_offset = src_window->offset +
(src_window->nr_pages << PAGE_SHIFT);
scif_init_window_iter(src_window, &src_win_iter);
}
if (dst_offset == end_dst_offset) {
- dst_window = list_entry_next(dst_window, list);
+ dst_window = list_next_entry(dst_window, list);
end_dst_offset = dst_window->offset +
(dst_window->nr_pages << PAGE_SHIFT);
scif_init_window_iter(dst_window, &dst_win_iter);
@@ -1314,13 +1305,13 @@ static int scif_rma_list_dma_copy_aligned(struct scif_copy_work *work,
remaining_len -= tail_len;
while (remaining_len) {
if (src_offset == end_src_offset) {
- src_window = list_entry_next(src_window, list);
+ src_window = list_next_entry(src_window, list);
end_src_offset = src_window->offset +
(src_window->nr_pages << PAGE_SHIFT);
scif_init_window_iter(src_window, &src_win_iter);
}
if (dst_offset == end_dst_offset) {
- dst_window = list_entry_next(dst_window, list);
+ dst_window = list_next_entry(dst_window, list);
end_dst_offset = dst_window->offset +
(dst_window->nr_pages << PAGE_SHIFT);
scif_init_window_iter(dst_window, &dst_win_iter);
@@ -1405,9 +1396,9 @@ static int scif_rma_list_dma_copy_aligned(struct scif_copy_work *work,
if (remaining_len) {
loop_len = remaining_len;
if (src_offset == end_src_offset)
- src_window = list_entry_next(src_window, list);
+ src_window = list_next_entry(src_window, list);
if (dst_offset == end_dst_offset)
- dst_window = list_entry_next(dst_window, list);
+ dst_window = list_next_entry(dst_window, list);
src_dma_addr = __scif_off_to_dma_addr(src_window, src_offset);
dst_dma_addr = __scif_off_to_dma_addr(dst_window, dst_offset);
@@ -1550,12 +1541,12 @@ static int scif_rma_list_cpu_copy(struct scif_copy_work *work)
end_dst_offset = dst_window->offset +
(dst_window->nr_pages << PAGE_SHIFT);
if (src_offset == end_src_offset) {
- src_window = list_entry_next(src_window, list);
+ src_window = list_next_entry(src_window, list);
scif_init_window_iter(src_window,
&src_win_iter);
}
if (dst_offset == end_dst_offset) {
- dst_window = list_entry_next(dst_window, list);
+ dst_window = list_next_entry(dst_window, list);
scif_init_window_iter(dst_window,
&dst_win_iter);
}
@@ -1730,7 +1721,7 @@ static int scif_rma_copy(scif_epd_t epd, off_t loffset, unsigned long addr,
mutex_lock(&ep->rma_info.mmn_lock);
mmn = scif_find_mmu_notifier(current->mm, &ep->rma_info);
if (!mmn)
- scif_add_mmu_notifier(current->mm, ep);
+ mmn = scif_add_mmu_notifier(current->mm, ep);
mutex_unlock(&ep->rma_info.mmn_lock);
if (IS_ERR(mmn)) {
scif_put_peer_dev(spdev);
diff --git a/drivers/misc/mic/scif/scif_rma.c b/drivers/misc/mic/scif/scif_rma.c
index 8310b4dbff06..6a451bd65bf3 100644
--- a/drivers/misc/mic/scif/scif_rma.c
+++ b/drivers/misc/mic/scif/scif_rma.c
@@ -1511,7 +1511,7 @@ off_t scif_register_pinned_pages(scif_epd_t epd,
if ((map_flags & SCIF_MAP_FIXED) &&
((ALIGN(offset, PAGE_SIZE) != offset) ||
(offset < 0) ||
- (offset + (off_t)len < offset)))
+ (len > LONG_MAX - offset)))
return -EINVAL;
might_sleep();
@@ -1614,7 +1614,7 @@ off_t scif_register(scif_epd_t epd, void *addr, size_t len, off_t offset,
if ((map_flags & SCIF_MAP_FIXED) &&
((ALIGN(offset, PAGE_SIZE) != offset) ||
(offset < 0) ||
- (offset + (off_t)len < offset)))
+ (len > LONG_MAX - offset)))
return -EINVAL;
/* Unsupported protection requested */
@@ -1732,7 +1732,8 @@ scif_unregister(scif_epd_t epd, off_t offset, size_t len)
/* Offset is not page aligned or offset+len wraps around */
if ((ALIGN(offset, PAGE_SIZE) != offset) ||
- (offset + (off_t)len < offset))
+ (offset < 0) ||
+ (len > LONG_MAX - offset))
return -EINVAL;
err = scif_verify_epd(ep);
diff --git a/drivers/misc/mic/vop/Makefile b/drivers/misc/mic/vop/Makefile
new file mode 100644
index 000000000000..78819c8999f1
--- /dev/null
+++ b/drivers/misc/mic/vop/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile - Intel MIC Linux driver.
+# Copyright(c) 2016, Intel Corporation.
+#
+obj-m := vop.o
+
+vop-objs += vop_main.o
+vop-objs += vop_debugfs.o
+vop-objs += vop_vringh.o
diff --git a/drivers/misc/mic/vop/vop_debugfs.c b/drivers/misc/mic/vop/vop_debugfs.c
new file mode 100644
index 000000000000..ab43884e5cd7
--- /dev/null
+++ b/drivers/misc/mic/vop/vop_debugfs.c
@@ -0,0 +1,232 @@
+/*
+ * Intel MIC Platform Software Stack (MPSS)
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * 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
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Intel Virtio Over PCIe (VOP) driver.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include "vop_main.h"
+
+static int vop_dp_show(struct seq_file *s, void *pos)
+{
+ struct mic_device_desc *d;
+ struct mic_device_ctrl *dc;
+ struct mic_vqconfig *vqconfig;
+ __u32 *features;
+ __u8 *config;
+ struct vop_info *vi = s->private;
+ struct vop_device *vpdev = vi->vpdev;
+ struct mic_bootparam *bootparam = vpdev->hw_ops->get_dp(vpdev);
+ int j, k;
+
+ seq_printf(s, "Bootparam: magic 0x%x\n",
+ bootparam->magic);
+ seq_printf(s, "Bootparam: h2c_config_db %d\n",
+ bootparam->h2c_config_db);
+ seq_printf(s, "Bootparam: node_id %d\n",
+ bootparam->node_id);
+ seq_printf(s, "Bootparam: c2h_scif_db %d\n",
+ bootparam->c2h_scif_db);
+ seq_printf(s, "Bootparam: h2c_scif_db %d\n",
+ bootparam->h2c_scif_db);
+ seq_printf(s, "Bootparam: scif_host_dma_addr 0x%llx\n",
+ bootparam->scif_host_dma_addr);
+ seq_printf(s, "Bootparam: scif_card_dma_addr 0x%llx\n",
+ bootparam->scif_card_dma_addr);
+
+ for (j = sizeof(*bootparam);
+ j < MIC_DP_SIZE; j += mic_total_desc_size(d)) {
+ d = (void *)bootparam + j;
+ dc = (void *)d + mic_aligned_desc_size(d);
+
+ /* end of list */
+ if (d->type == 0)
+ break;
+
+ if (d->type == -1)
+ continue;
+
+ seq_printf(s, "Type %d ", d->type);
+ seq_printf(s, "Num VQ %d ", d->num_vq);
+ seq_printf(s, "Feature Len %d\n", d->feature_len);
+ seq_printf(s, "Config Len %d ", d->config_len);
+ seq_printf(s, "Shutdown Status %d\n", d->status);
+
+ for (k = 0; k < d->num_vq; k++) {
+ vqconfig = mic_vq_config(d) + k;
+ seq_printf(s, "vqconfig[%d]: ", k);
+ seq_printf(s, "address 0x%llx ",
+ vqconfig->address);
+ seq_printf(s, "num %d ", vqconfig->num);
+ seq_printf(s, "used address 0x%llx\n",
+ vqconfig->used_address);
+ }
+
+ features = (__u32 *)mic_vq_features(d);
+ seq_printf(s, "Features: Host 0x%x ", features[0]);
+ seq_printf(s, "Guest 0x%x\n", features[1]);
+
+ config = mic_vq_configspace(d);
+ for (k = 0; k < d->config_len; k++)
+ seq_printf(s, "config[%d]=%d\n", k, config[k]);
+
+ seq_puts(s, "Device control:\n");
+ seq_printf(s, "Config Change %d ", dc->config_change);
+ seq_printf(s, "Vdev reset %d\n", dc->vdev_reset);
+ seq_printf(s, "Guest Ack %d ", dc->guest_ack);
+ seq_printf(s, "Host ack %d\n", dc->host_ack);
+ seq_printf(s, "Used address updated %d ",
+ dc->used_address_updated);
+ seq_printf(s, "Vdev 0x%llx\n", dc->vdev);
+ seq_printf(s, "c2h doorbell %d ", dc->c2h_vdev_db);
+ seq_printf(s, "h2c doorbell %d\n", dc->h2c_vdev_db);
+ }
+ schedule_work(&vi->hotplug_work);
+ return 0;
+}
+
+static int vop_dp_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, vop_dp_show, inode->i_private);
+}
+
+static int vop_dp_debug_release(struct inode *inode, struct file *file)
+{
+ return single_release(inode, file);
+}
+
+static const struct file_operations dp_ops = {
+ .owner = THIS_MODULE,
+ .open = vop_dp_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = vop_dp_debug_release
+};
+
+static int vop_vdev_info_show(struct seq_file *s, void *unused)
+{
+ struct vop_info *vi = s->private;
+ struct list_head *pos, *tmp;
+ struct vop_vdev *vdev;
+ int i, j;
+
+ mutex_lock(&vi->vop_mutex);
+ list_for_each_safe(pos, tmp, &vi->vdev_list) {
+ vdev = list_entry(pos, struct vop_vdev, list);
+ seq_printf(s, "VDEV type %d state %s in %ld out %ld in_dma %ld out_dma %ld\n",
+ vdev->virtio_id,
+ vop_vdevup(vdev) ? "UP" : "DOWN",
+ vdev->in_bytes,
+ vdev->out_bytes,
+ vdev->in_bytes_dma,
+ vdev->out_bytes_dma);
+ for (i = 0; i < MIC_MAX_VRINGS; i++) {
+ struct vring_desc *desc;
+ struct vring_avail *avail;
+ struct vring_used *used;
+ struct vop_vringh *vvr = &vdev->vvr[i];
+ struct vringh *vrh = &vvr->vrh;
+ int num = vrh->vring.num;
+
+ if (!num)
+ continue;
+ desc = vrh->vring.desc;
+ seq_printf(s, "vring i %d avail_idx %d",
+ i, vvr->vring.info->avail_idx & (num - 1));
+ seq_printf(s, " vring i %d avail_idx %d\n",
+ i, vvr->vring.info->avail_idx);
+ seq_printf(s, "vrh i %d weak_barriers %d",
+ i, vrh->weak_barriers);
+ seq_printf(s, " last_avail_idx %d last_used_idx %d",
+ vrh->last_avail_idx, vrh->last_used_idx);
+ seq_printf(s, " completed %d\n", vrh->completed);
+ for (j = 0; j < num; j++) {
+ seq_printf(s, "desc[%d] addr 0x%llx len %d",
+ j, desc->addr, desc->len);
+ seq_printf(s, " flags 0x%x next %d\n",
+ desc->flags, desc->next);
+ desc++;
+ }
+ avail = vrh->vring.avail;
+ seq_printf(s, "avail flags 0x%x idx %d\n",
+ vringh16_to_cpu(vrh, avail->flags),
+ vringh16_to_cpu(vrh,
+ avail->idx) & (num - 1));
+ seq_printf(s, "avail flags 0x%x idx %d\n",
+ vringh16_to_cpu(vrh, avail->flags),
+ vringh16_to_cpu(vrh, avail->idx));
+ for (j = 0; j < num; j++)
+ seq_printf(s, "avail ring[%d] %d\n",
+ j, avail->ring[j]);
+ used = vrh->vring.used;
+ seq_printf(s, "used flags 0x%x idx %d\n",
+ vringh16_to_cpu(vrh, used->flags),
+ vringh16_to_cpu(vrh, used->idx) & (num - 1));
+ seq_printf(s, "used flags 0x%x idx %d\n",
+ vringh16_to_cpu(vrh, used->flags),
+ vringh16_to_cpu(vrh, used->idx));
+ for (j = 0; j < num; j++)
+ seq_printf(s, "used ring[%d] id %d len %d\n",
+ j, vringh32_to_cpu(vrh,
+ used->ring[j].id),
+ vringh32_to_cpu(vrh,
+ used->ring[j].len));
+ }
+ }
+ mutex_unlock(&vi->vop_mutex);
+
+ return 0;
+}
+
+static int vop_vdev_info_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, vop_vdev_info_show, inode->i_private);
+}
+
+static int vop_vdev_info_debug_release(struct inode *inode, struct file *file)
+{
+ return single_release(inode, file);
+}
+
+static const struct file_operations vdev_info_ops = {
+ .owner = THIS_MODULE,
+ .open = vop_vdev_info_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = vop_vdev_info_debug_release
+};
+
+void vop_init_debugfs(struct vop_info *vi)
+{
+ char name[16];
+
+ snprintf(name, sizeof(name), "%s%d", KBUILD_MODNAME, vi->vpdev->dnode);
+ vi->dbg = debugfs_create_dir(name, NULL);
+ if (!vi->dbg) {
+ pr_err("can't create debugfs dir vop\n");
+ return;
+ }
+ debugfs_create_file("dp", 0444, vi->dbg, vi, &dp_ops);
+ debugfs_create_file("vdev_info", 0444, vi->dbg, vi, &vdev_info_ops);
+}
+
+void vop_exit_debugfs(struct vop_info *vi)
+{
+ debugfs_remove_recursive(vi->dbg);
+}
diff --git a/drivers/misc/mic/vop/vop_main.c b/drivers/misc/mic/vop/vop_main.c
new file mode 100644
index 000000000000..1a2b67f3183d
--- /dev/null
+++ b/drivers/misc/mic/vop/vop_main.c
@@ -0,0 +1,755 @@
+/*
+ * Intel MIC Platform Software Stack (MPSS)
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * 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
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Adapted from:
+ *
+ * virtio for kvm on s390
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
+ *
+ * Intel Virtio Over PCIe (VOP) driver.
+ *
+ */
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+
+#include "vop_main.h"
+
+#define VOP_MAX_VRINGS 4
+
+/*
+ * _vop_vdev - Allocated per virtio device instance injected by the peer.
+ *
+ * @vdev: Virtio device
+ * @desc: Virtio device page descriptor
+ * @dc: Virtio device control
+ * @vpdev: VOP device which is the parent for this virtio device
+ * @vr: Buffer for accessing the VRING
+ * @used: Buffer for used
+ * @used_size: Size of the used buffer
+ * @reset_done: Track whether VOP reset is complete
+ * @virtio_cookie: Cookie returned upon requesting a interrupt
+ * @c2h_vdev_db: The doorbell used by the guest to interrupt the host
+ * @h2c_vdev_db: The doorbell used by the host to interrupt the guest
+ * @dnode: The destination node
+ */
+struct _vop_vdev {
+ struct virtio_device vdev;
+ struct mic_device_desc __iomem *desc;
+ struct mic_device_ctrl __iomem *dc;
+ struct vop_device *vpdev;
+ void __iomem *vr[VOP_MAX_VRINGS];
+ dma_addr_t used[VOP_MAX_VRINGS];
+ int used_size[VOP_MAX_VRINGS];
+ struct completion reset_done;
+ struct mic_irq *virtio_cookie;
+ int c2h_vdev_db;
+ int h2c_vdev_db;
+ int dnode;
+};
+
+#define to_vopvdev(vd) container_of(vd, struct _vop_vdev, vdev)
+
+#define _vop_aligned_desc_size(d) __mic_align(_vop_desc_size(d), 8)
+
+/* Helper API to obtain the parent of the virtio device */
+static inline struct device *_vop_dev(struct _vop_vdev *vdev)
+{
+ return vdev->vdev.dev.parent;
+}
+
+static inline unsigned _vop_desc_size(struct mic_device_desc __iomem *desc)
+{
+ return sizeof(*desc)
+ + ioread8(&desc->num_vq) * sizeof(struct mic_vqconfig)
+ + ioread8(&desc->feature_len) * 2
+ + ioread8(&desc->config_len);
+}
+
+static inline struct mic_vqconfig __iomem *
+_vop_vq_config(struct mic_device_desc __iomem *desc)
+{
+ return (struct mic_vqconfig __iomem *)(desc + 1);
+}
+
+static inline u8 __iomem *
+_vop_vq_features(struct mic_device_desc __iomem *desc)
+{
+ return (u8 __iomem *)(_vop_vq_config(desc) + ioread8(&desc->num_vq));
+}
+
+static inline u8 __iomem *
+_vop_vq_configspace(struct mic_device_desc __iomem *desc)
+{
+ return _vop_vq_features(desc) + ioread8(&desc->feature_len) * 2;
+}
+
+static inline unsigned
+_vop_total_desc_size(struct mic_device_desc __iomem *desc)
+{
+ return _vop_aligned_desc_size(desc) + sizeof(struct mic_device_ctrl);
+}
+
+/* This gets the device's feature bits. */
+static u64 vop_get_features(struct virtio_device *vdev)
+{
+ unsigned int i, bits;
+ u32 features = 0;
+ struct mic_device_desc __iomem *desc = to_vopvdev(vdev)->desc;
+ u8 __iomem *in_features = _vop_vq_features(desc);
+ int feature_len = ioread8(&desc->feature_len);
+
+ bits = min_t(unsigned, feature_len, sizeof(vdev->features)) * 8;
+ for (i = 0; i < bits; i++)
+ if (ioread8(&in_features[i / 8]) & (BIT(i % 8)))
+ features |= BIT(i);
+
+ return features;
+}
+
+static int vop_finalize_features(struct virtio_device *vdev)
+{
+ unsigned int i, bits;
+ struct mic_device_desc __iomem *desc = to_vopvdev(vdev)->desc;
+ u8 feature_len = ioread8(&desc->feature_len);
+ /* Second half of bitmap is features we accept. */
+ u8 __iomem *out_features =
+ _vop_vq_features(desc) + feature_len;
+
+ /* Give virtio_ring a chance to accept features. */
+ vring_transport_features(vdev);
+
+ memset_io(out_features, 0, feature_len);
+ bits = min_t(unsigned, feature_len,
+ sizeof(vdev->features)) * 8;
+ for (i = 0; i < bits; i++) {
+ if (__virtio_test_bit(vdev, i))
+ iowrite8(ioread8(&out_features[i / 8]) | (1 << (i % 8)),
+ &out_features[i / 8]);
+ }
+ return 0;
+}
+
+/*
+ * Reading and writing elements in config space
+ */
+static void vop_get(struct virtio_device *vdev, unsigned int offset,
+ void *buf, unsigned len)
+{
+ struct mic_device_desc __iomem *desc = to_vopvdev(vdev)->desc;
+
+ if (offset + len > ioread8(&desc->config_len))
+ return;
+ memcpy_fromio(buf, _vop_vq_configspace(desc) + offset, len);
+}
+
+static void vop_set(struct virtio_device *vdev, unsigned int offset,
+ const void *buf, unsigned len)
+{
+ struct mic_device_desc __iomem *desc = to_vopvdev(vdev)->desc;
+
+ if (offset + len > ioread8(&desc->config_len))
+ return;
+ memcpy_toio(_vop_vq_configspace(desc) + offset, buf, len);
+}
+
+/*
+ * The operations to get and set the status word just access the status
+ * field of the device descriptor. set_status also interrupts the host
+ * to tell about status changes.
+ */
+static u8 vop_get_status(struct virtio_device *vdev)
+{
+ return ioread8(&to_vopvdev(vdev)->desc->status);
+}
+
+static void vop_set_status(struct virtio_device *dev, u8 status)
+{
+ struct _vop_vdev *vdev = to_vopvdev(dev);
+ struct vop_device *vpdev = vdev->vpdev;
+
+ if (!status)
+ return;
+ iowrite8(status, &vdev->desc->status);
+ vpdev->hw_ops->send_intr(vpdev, vdev->c2h_vdev_db);
+}
+
+/* Inform host on a virtio device reset and wait for ack from host */
+static void vop_reset_inform_host(struct virtio_device *dev)
+{
+ struct _vop_vdev *vdev = to_vopvdev(dev);
+ struct mic_device_ctrl __iomem *dc = vdev->dc;
+ struct vop_device *vpdev = vdev->vpdev;
+ int retry;
+
+ iowrite8(0, &dc->host_ack);
+ iowrite8(1, &dc->vdev_reset);
+ vpdev->hw_ops->send_intr(vpdev, vdev->c2h_vdev_db);
+
+ /* Wait till host completes all card accesses and acks the reset */
+ for (retry = 100; retry--;) {
+ if (ioread8(&dc->host_ack))
+ break;
+ msleep(100);
+ };
+
+ dev_dbg(_vop_dev(vdev), "%s: retry: %d\n", __func__, retry);
+
+ /* Reset status to 0 in case we timed out */
+ iowrite8(0, &vdev->desc->status);
+}
+
+static void vop_reset(struct virtio_device *dev)
+{
+ struct _vop_vdev *vdev = to_vopvdev(dev);
+
+ dev_dbg(_vop_dev(vdev), "%s: virtio id %d\n",
+ __func__, dev->id.device);
+
+ vop_reset_inform_host(dev);
+ complete_all(&vdev->reset_done);
+}
+
+/*
+ * The virtio_ring code calls this API when it wants to notify the Host.
+ */
+static bool vop_notify(struct virtqueue *vq)
+{
+ struct _vop_vdev *vdev = vq->priv;
+ struct vop_device *vpdev = vdev->vpdev;
+
+ vpdev->hw_ops->send_intr(vpdev, vdev->c2h_vdev_db);
+ return true;
+}
+
+static void vop_del_vq(struct virtqueue *vq, int n)
+{
+ struct _vop_vdev *vdev = to_vopvdev(vq->vdev);
+ struct vring *vr = (struct vring *)(vq + 1);
+ struct vop_device *vpdev = vdev->vpdev;
+
+ dma_unmap_single(&vpdev->dev, vdev->used[n],
+ vdev->used_size[n], DMA_BIDIRECTIONAL);
+ free_pages((unsigned long)vr->used, get_order(vdev->used_size[n]));
+ vring_del_virtqueue(vq);
+ vpdev->hw_ops->iounmap(vpdev, vdev->vr[n]);
+ vdev->vr[n] = NULL;
+}
+
+static void vop_del_vqs(struct virtio_device *dev)
+{
+ struct _vop_vdev *vdev = to_vopvdev(dev);
+ struct virtqueue *vq, *n;
+ int idx = 0;
+
+ dev_dbg(_vop_dev(vdev), "%s\n", __func__);
+
+ list_for_each_entry_safe(vq, n, &dev->vqs, list)
+ vop_del_vq(vq, idx++);
+}
+
+/*
+ * This routine will assign vring's allocated in host/io memory. Code in
+ * virtio_ring.c however continues to access this io memory as if it were local
+ * memory without io accessors.
+ */
+static struct virtqueue *vop_find_vq(struct virtio_device *dev,
+ unsigned index,
+ void (*callback)(struct virtqueue *vq),
+ const char *name)
+{
+ struct _vop_vdev *vdev = to_vopvdev(dev);
+ struct vop_device *vpdev = vdev->vpdev;
+ struct mic_vqconfig __iomem *vqconfig;
+ struct mic_vqconfig config;
+ struct virtqueue *vq;
+ void __iomem *va;
+ struct _mic_vring_info __iomem *info;
+ void *used;
+ int vr_size, _vr_size, err, magic;
+ struct vring *vr;
+ u8 type = ioread8(&vdev->desc->type);
+
+ if (index >= ioread8(&vdev->desc->num_vq))
+ return ERR_PTR(-ENOENT);
+
+ if (!name)
+ return ERR_PTR(-ENOENT);
+
+ /* First assign the vring's allocated in host memory */
+ vqconfig = _vop_vq_config(vdev->desc) + index;
+ memcpy_fromio(&config, vqconfig, sizeof(config));
+ _vr_size = vring_size(le16_to_cpu(config.num), MIC_VIRTIO_RING_ALIGN);
+ vr_size = PAGE_ALIGN(_vr_size + sizeof(struct _mic_vring_info));
+ va = vpdev->hw_ops->ioremap(vpdev, le64_to_cpu(config.address),
+ vr_size);
+ if (!va)
+ return ERR_PTR(-ENOMEM);
+ vdev->vr[index] = va;
+ memset_io(va, 0x0, _vr_size);
+ vq = vring_new_virtqueue(
+ index,
+ le16_to_cpu(config.num), MIC_VIRTIO_RING_ALIGN,
+ dev,
+ false,
+ (void __force *)va, vop_notify, callback, name);
+ if (!vq) {
+ err = -ENOMEM;
+ goto unmap;
+ }
+ info = va + _vr_size;
+ magic = ioread32(&info->magic);
+
+ if (WARN(magic != MIC_MAGIC + type + index, "magic mismatch")) {
+ err = -EIO;
+ goto unmap;
+ }
+
+ /* Allocate and reassign used ring now */
+ vdev->used_size[index] = PAGE_ALIGN(sizeof(__u16) * 3 +
+ sizeof(struct vring_used_elem) *
+ le16_to_cpu(config.num));
+ used = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ get_order(vdev->used_size[index]));
+ if (!used) {
+ err = -ENOMEM;
+ dev_err(_vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ goto del_vq;
+ }
+ vdev->used[index] = dma_map_single(&vpdev->dev, used,
+ vdev->used_size[index],
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(&vpdev->dev, vdev->used[index])) {
+ err = -ENOMEM;
+ dev_err(_vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ goto free_used;
+ }
+ writeq(vdev->used[index], &vqconfig->used_address);
+ /*
+ * To reassign the used ring here we are directly accessing
+ * struct vring_virtqueue which is a private data structure
+ * in virtio_ring.c. At the minimum, a BUILD_BUG_ON() in
+ * vring_new_virtqueue() would ensure that
+ * (&vq->vring == (struct vring *) (&vq->vq + 1));
+ */
+ vr = (struct vring *)(vq + 1);
+ vr->used = used;
+
+ vq->priv = vdev;
+ return vq;
+free_used:
+ free_pages((unsigned long)used,
+ get_order(vdev->used_size[index]));
+del_vq:
+ vring_del_virtqueue(vq);
+unmap:
+ vpdev->hw_ops->iounmap(vpdev, vdev->vr[index]);
+ return ERR_PTR(err);
+}
+
+static int vop_find_vqs(struct virtio_device *dev, unsigned nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char * const names[])
+{
+ struct _vop_vdev *vdev = to_vopvdev(dev);
+ struct vop_device *vpdev = vdev->vpdev;
+ struct mic_device_ctrl __iomem *dc = vdev->dc;
+ int i, err, retry;
+
+ /* We must have this many virtqueues. */
+ if (nvqs > ioread8(&vdev->desc->num_vq))
+ return -ENOENT;
+
+ for (i = 0; i < nvqs; ++i) {
+ dev_dbg(_vop_dev(vdev), "%s: %d: %s\n",
+ __func__, i, names[i]);
+ vqs[i] = vop_find_vq(dev, i, callbacks[i], names[i]);
+ if (IS_ERR(vqs[i])) {
+ err = PTR_ERR(vqs[i]);
+ goto error;
+ }
+ }
+
+ iowrite8(1, &dc->used_address_updated);
+ /*
+ * Send an interrupt to the host to inform it that used
+ * rings have been re-assigned.
+ */
+ vpdev->hw_ops->send_intr(vpdev, vdev->c2h_vdev_db);
+ for (retry = 100; --retry;) {
+ if (!ioread8(&dc->used_address_updated))
+ break;
+ msleep(100);
+ };
+
+ dev_dbg(_vop_dev(vdev), "%s: retry: %d\n", __func__, retry);
+ if (!retry) {
+ err = -ENODEV;
+ goto error;
+ }
+
+ return 0;
+error:
+ vop_del_vqs(dev);
+ return err;
+}
+
+/*
+ * The config ops structure as defined by virtio config
+ */
+static struct virtio_config_ops vop_vq_config_ops = {
+ .get_features = vop_get_features,
+ .finalize_features = vop_finalize_features,
+ .get = vop_get,
+ .set = vop_set,
+ .get_status = vop_get_status,
+ .set_status = vop_set_status,
+ .reset = vop_reset,
+ .find_vqs = vop_find_vqs,
+ .del_vqs = vop_del_vqs,
+};
+
+static irqreturn_t vop_virtio_intr_handler(int irq, void *data)
+{
+ struct _vop_vdev *vdev = data;
+ struct vop_device *vpdev = vdev->vpdev;
+ struct virtqueue *vq;
+
+ vpdev->hw_ops->ack_interrupt(vpdev, vdev->h2c_vdev_db);
+ list_for_each_entry(vq, &vdev->vdev.vqs, list)
+ vring_interrupt(0, vq);
+
+ return IRQ_HANDLED;
+}
+
+static void vop_virtio_release_dev(struct device *_d)
+{
+ /*
+ * No need for a release method similar to virtio PCI.
+ * Provide an empty one to avoid getting a warning from core.
+ */
+}
+
+/*
+ * adds a new device and register it with virtio
+ * appropriate drivers are loaded by the device model
+ */
+static int _vop_add_device(struct mic_device_desc __iomem *d,
+ unsigned int offset, struct vop_device *vpdev,
+ int dnode)
+{
+ struct _vop_vdev *vdev;
+ int ret;
+ u8 type = ioread8(&d->type);
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev)
+ return -ENOMEM;
+
+ vdev->vpdev = vpdev;
+ vdev->vdev.dev.parent = &vpdev->dev;
+ vdev->vdev.dev.release = vop_virtio_release_dev;
+ vdev->vdev.id.device = type;
+ vdev->vdev.config = &vop_vq_config_ops;
+ vdev->desc = d;
+ vdev->dc = (void __iomem *)d + _vop_aligned_desc_size(d);
+ vdev->dnode = dnode;
+ vdev->vdev.priv = (void *)(u64)dnode;
+ init_completion(&vdev->reset_done);
+
+ vdev->h2c_vdev_db = vpdev->hw_ops->next_db(vpdev);
+ vdev->virtio_cookie = vpdev->hw_ops->request_irq(vpdev,
+ vop_virtio_intr_handler, "virtio intr",
+ vdev, vdev->h2c_vdev_db);
+ if (IS_ERR(vdev->virtio_cookie)) {
+ ret = PTR_ERR(vdev->virtio_cookie);
+ goto kfree;
+ }
+ iowrite8((u8)vdev->h2c_vdev_db, &vdev->dc->h2c_vdev_db);
+ vdev->c2h_vdev_db = ioread8(&vdev->dc->c2h_vdev_db);
+
+ ret = register_virtio_device(&vdev->vdev);
+ if (ret) {
+ dev_err(_vop_dev(vdev),
+ "Failed to register vop device %u type %u\n",
+ offset, type);
+ goto free_irq;
+ }
+ writeq((u64)vdev, &vdev->dc->vdev);
+ dev_dbg(_vop_dev(vdev), "%s: registered vop device %u type %u vdev %p\n",
+ __func__, offset, type, vdev);
+
+ return 0;
+
+free_irq:
+ vpdev->hw_ops->free_irq(vpdev, vdev->virtio_cookie, vdev);
+kfree:
+ kfree(vdev);
+ return ret;
+}
+
+/*
+ * match for a vop device with a specific desc pointer
+ */
+static int vop_match_desc(struct device *dev, void *data)
+{
+ struct virtio_device *_dev = dev_to_virtio(dev);
+ struct _vop_vdev *vdev = to_vopvdev(_dev);
+
+ return vdev->desc == (void __iomem *)data;
+}
+
+static void _vop_handle_config_change(struct mic_device_desc __iomem *d,
+ unsigned int offset,
+ struct vop_device *vpdev)
+{
+ struct mic_device_ctrl __iomem *dc
+ = (void __iomem *)d + _vop_aligned_desc_size(d);
+ struct _vop_vdev *vdev = (struct _vop_vdev *)readq(&dc->vdev);
+
+ if (ioread8(&dc->config_change) != MIC_VIRTIO_PARAM_CONFIG_CHANGED)
+ return;
+
+ dev_dbg(&vpdev->dev, "%s %d\n", __func__, __LINE__);
+ virtio_config_changed(&vdev->vdev);
+ iowrite8(1, &dc->guest_ack);
+}
+
+/*
+ * removes a virtio device if a hot remove event has been
+ * requested by the host.
+ */
+static int _vop_remove_device(struct mic_device_desc __iomem *d,
+ unsigned int offset, struct vop_device *vpdev)
+{
+ struct mic_device_ctrl __iomem *dc
+ = (void __iomem *)d + _vop_aligned_desc_size(d);
+ struct _vop_vdev *vdev = (struct _vop_vdev *)readq(&dc->vdev);
+ u8 status;
+ int ret = -1;
+
+ if (ioread8(&dc->config_change) == MIC_VIRTIO_PARAM_DEV_REMOVE) {
+ dev_dbg(&vpdev->dev,
+ "%s %d config_change %d type %d vdev %p\n",
+ __func__, __LINE__,
+ ioread8(&dc->config_change), ioread8(&d->type), vdev);
+ status = ioread8(&d->status);
+ reinit_completion(&vdev->reset_done);
+ unregister_virtio_device(&vdev->vdev);
+ vpdev->hw_ops->free_irq(vpdev, vdev->virtio_cookie, vdev);
+ iowrite8(-1, &dc->h2c_vdev_db);
+ if (status & VIRTIO_CONFIG_S_DRIVER_OK)
+ wait_for_completion(&vdev->reset_done);
+ kfree(vdev);
+ iowrite8(1, &dc->guest_ack);
+ dev_dbg(&vpdev->dev, "%s %d guest_ack %d\n",
+ __func__, __LINE__, ioread8(&dc->guest_ack));
+ iowrite8(-1, &d->type);
+ ret = 0;
+ }
+ return ret;
+}
+
+#define REMOVE_DEVICES true
+
+static void _vop_scan_devices(void __iomem *dp, struct vop_device *vpdev,
+ bool remove, int dnode)
+{
+ s8 type;
+ unsigned int i;
+ struct mic_device_desc __iomem *d;
+ struct mic_device_ctrl __iomem *dc;
+ struct device *dev;
+ int ret;
+
+ for (i = sizeof(struct mic_bootparam);
+ i < MIC_DP_SIZE; i += _vop_total_desc_size(d)) {
+ d = dp + i;
+ dc = (void __iomem *)d + _vop_aligned_desc_size(d);
+ /*
+ * This read barrier is paired with the corresponding write
+ * barrier on the host which is inserted before adding or
+ * removing a virtio device descriptor, by updating the type.
+ */
+ rmb();
+ type = ioread8(&d->type);
+
+ /* end of list */
+ if (type == 0)
+ break;
+
+ if (type == -1)
+ continue;
+
+ /* device already exists */
+ dev = device_find_child(&vpdev->dev, (void __force *)d,
+ vop_match_desc);
+ if (dev) {
+ if (remove)
+ iowrite8(MIC_VIRTIO_PARAM_DEV_REMOVE,
+ &dc->config_change);
+ put_device(dev);
+ _vop_handle_config_change(d, i, vpdev);
+ ret = _vop_remove_device(d, i, vpdev);
+ if (remove) {
+ iowrite8(0, &dc->config_change);
+ iowrite8(0, &dc->guest_ack);
+ }
+ continue;
+ }
+
+ /* new device */
+ dev_dbg(&vpdev->dev, "%s %d Adding new virtio device %p\n",
+ __func__, __LINE__, d);
+ if (!remove)
+ _vop_add_device(d, i, vpdev, dnode);
+ }
+}
+
+static void vop_scan_devices(struct vop_info *vi,
+ struct vop_device *vpdev, bool remove)
+{
+ void __iomem *dp = vpdev->hw_ops->get_remote_dp(vpdev);
+
+ if (!dp)
+ return;
+ mutex_lock(&vi->vop_mutex);
+ _vop_scan_devices(dp, vpdev, remove, vpdev->dnode);
+ mutex_unlock(&vi->vop_mutex);
+}
+
+/*
+ * vop_hotplug_device tries to find changes in the device page.
+ */
+static void vop_hotplug_devices(struct work_struct *work)
+{
+ struct vop_info *vi = container_of(work, struct vop_info,
+ hotplug_work);
+
+ vop_scan_devices(vi, vi->vpdev, !REMOVE_DEVICES);
+}
+
+/*
+ * Interrupt handler for hot plug/config changes etc.
+ */
+static irqreturn_t vop_extint_handler(int irq, void *data)
+{
+ struct vop_info *vi = data;
+ struct mic_bootparam __iomem *bp;
+ struct vop_device *vpdev = vi->vpdev;
+
+ bp = vpdev->hw_ops->get_remote_dp(vpdev);
+ dev_dbg(&vpdev->dev, "%s %d hotplug work\n",
+ __func__, __LINE__);
+ vpdev->hw_ops->ack_interrupt(vpdev, ioread8(&bp->h2c_config_db));
+ schedule_work(&vi->hotplug_work);
+ return IRQ_HANDLED;
+}
+
+static int vop_driver_probe(struct vop_device *vpdev)
+{
+ struct vop_info *vi;
+ int rc;
+
+ vi = kzalloc(sizeof(*vi), GFP_KERNEL);
+ if (!vi) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+ dev_set_drvdata(&vpdev->dev, vi);
+ vi->vpdev = vpdev;
+
+ mutex_init(&vi->vop_mutex);
+ INIT_WORK(&vi->hotplug_work, vop_hotplug_devices);
+ if (vpdev->dnode) {
+ rc = vop_host_init(vi);
+ if (rc < 0)
+ goto free;
+ } else {
+ struct mic_bootparam __iomem *bootparam;
+
+ vop_scan_devices(vi, vpdev, !REMOVE_DEVICES);
+
+ vi->h2c_config_db = vpdev->hw_ops->next_db(vpdev);
+ vi->cookie = vpdev->hw_ops->request_irq(vpdev,
+ vop_extint_handler,
+ "virtio_config_intr",
+ vi, vi->h2c_config_db);
+ if (IS_ERR(vi->cookie)) {
+ rc = PTR_ERR(vi->cookie);
+ goto free;
+ }
+ bootparam = vpdev->hw_ops->get_remote_dp(vpdev);
+ iowrite8(vi->h2c_config_db, &bootparam->h2c_config_db);
+ }
+ vop_init_debugfs(vi);
+ return 0;
+free:
+ kfree(vi);
+exit:
+ return rc;
+}
+
+static void vop_driver_remove(struct vop_device *vpdev)
+{
+ struct vop_info *vi = dev_get_drvdata(&vpdev->dev);
+
+ if (vpdev->dnode) {
+ vop_host_uninit(vi);
+ } else {
+ struct mic_bootparam __iomem *bootparam =
+ vpdev->hw_ops->get_remote_dp(vpdev);
+ if (bootparam)
+ iowrite8(-1, &bootparam->h2c_config_db);
+ vpdev->hw_ops->free_irq(vpdev, vi->cookie, vi);
+ flush_work(&vi->hotplug_work);
+ vop_scan_devices(vi, vpdev, REMOVE_DEVICES);
+ }
+ vop_exit_debugfs(vi);
+ kfree(vi);
+}
+
+static struct vop_device_id id_table[] = {
+ { VOP_DEV_TRNSP, VOP_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct vop_driver vop_driver = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = vop_driver_probe,
+ .remove = vop_driver_remove,
+};
+
+module_vop_driver(vop_driver);
+
+MODULE_DEVICE_TABLE(mbus, id_table);
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Virtio Over PCIe (VOP) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mic/host/mic_virtio.h b/drivers/misc/mic/vop/vop_main.h
index a80631f2790d..ba47ec7a6386 100644
--- a/drivers/misc/mic/host/mic_virtio.h
+++ b/drivers/misc/mic/vop/vop_main.h
@@ -1,7 +1,7 @@
/*
* Intel MIC Platform Software Stack (MPSS)
*
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2016 Intel Corporation.
*
* 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
@@ -15,14 +15,21 @@
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
- * Intel MIC Host driver.
+ * Intel Virtio Over PCIe (VOP) driver.
*
*/
-#ifndef MIC_VIRTIO_H
-#define MIC_VIRTIO_H
+#ifndef _VOP_MAIN_H_
+#define _VOP_MAIN_H_
+#include <linux/vringh.h>
#include <linux/virtio_config.h>
-#include <linux/mic_ioctl.h>
+#include <linux/virtio.h>
+#include <linux/miscdevice.h>
+
+#include <linux/mic_common.h>
+#include "../common/mic_dev.h"
+
+#include "../bus/vop_bus.h"
/*
* Note on endianness.
@@ -39,38 +46,68 @@
* in guest endianness.
*/
+/*
+ * vop_info - Allocated per invocation of VOP probe
+ *
+ * @vpdev: VOP device
+ * @hotplug_work: Handle virtio device creation, deletion and configuration
+ * @cookie: Cookie received upon requesting a virtio configuration interrupt
+ * @h2c_config_db: The doorbell used by the peer to indicate a config change
+ * @vdev_list: List of "active" virtio devices injected in the peer node
+ * @vop_mutex: Synchronize access to the device page as well as serialize
+ * creation/deletion of virtio devices on the peer node
+ * @dp: Peer device page information
+ * @dbg: Debugfs entry
+ * @dma_ch: The DMA channel used by this transport for data transfers.
+ * @name: Name for this transport used in misc device creation.
+ * @miscdev: The misc device registered.
+ */
+struct vop_info {
+ struct vop_device *vpdev;
+ struct work_struct hotplug_work;
+ struct mic_irq *cookie;
+ int h2c_config_db;
+ struct list_head vdev_list;
+ struct mutex vop_mutex;
+ void __iomem *dp;
+ struct dentry *dbg;
+ struct dma_chan *dma_ch;
+ char name[16];
+ struct miscdevice miscdev;
+};
+
/**
- * struct mic_vringh - Virtio ring host information.
+ * struct vop_vringh - Virtio ring host information.
*
- * @vring: The MIC vring used for setting up user space mappings.
+ * @vring: The VOP vring used for setting up user space mappings.
* @vrh: The host VRINGH used for accessing the card vrings.
* @riov: The VRINGH read kernel IOV.
* @wiov: The VRINGH write kernel IOV.
+ * @head: The VRINGH head index address passed to vringh_getdesc_kern(..).
* @vr_mutex: Mutex for synchronizing access to the VRING.
* @buf: Temporary kernel buffer used to copy in/out data
* from/to the card via DMA.
* @buf_da: dma address of buf.
- * @mvdev: Back pointer to MIC virtio device for vringh_notify(..).
- * @head: The VRINGH head index address passed to vringh_getdesc_kern(..).
+ * @vdev: Back pointer to VOP virtio device for vringh_notify(..).
*/
-struct mic_vringh {
+struct vop_vringh {
struct mic_vring vring;
struct vringh vrh;
struct vringh_kiov riov;
struct vringh_kiov wiov;
+ u16 head;
struct mutex vr_mutex;
void *buf;
dma_addr_t buf_da;
- struct mic_vdev *mvdev;
- u16 head;
+ struct vop_vdev *vdev;
};
/**
- * struct mic_vdev - Host information for a card Virtio device.
+ * struct vop_vdev - Host information for a card Virtio device.
*
* @virtio_id - Virtio device id.
* @waitq - Waitqueue to allow ring3 apps to poll.
- * @mdev - Back pointer to host MIC device.
+ * @vpdev - pointer to VOP bus device.
* @poll_wake - Used for waking up threads blocked in poll.
* @out_bytes - Debug stats for number of bytes copied from host to card.
* @in_bytes - Debug stats for number of bytes copied from card to host.
@@ -82,18 +119,23 @@ struct mic_vringh {
* the transfer length did not have the required DMA alignment.
* @tx_dst_unaligned - Debug stats for number of bytes copied where the
* destination address on the card did not have the required DMA alignment.
- * @mvr - Store per VRING data structures.
+ * @vvr - Store per VRING data structures.
* @virtio_bh_work - Work struct used to schedule virtio bottom half handling.
* @dd - Virtio device descriptor.
* @dc - Virtio device control fields.
* @list - List of Virtio devices.
* @virtio_db - The doorbell used by the card to interrupt the host.
* @virtio_cookie - The cookie returned while requesting interrupts.
+ * @vi: Transport information.
+ * @vdev_mutex: Mutex synchronizing virtio device injection,
+ * removal and data transfers.
+ * @destroy: Track if a virtio device is being destroyed.
+ * @deleted: The virtio device has been deleted.
*/
-struct mic_vdev {
+struct vop_vdev {
int virtio_id;
wait_queue_head_t waitq;
- struct mic_device *mdev;
+ struct vop_device *vpdev;
int poll_wake;
unsigned long out_bytes;
unsigned long in_bytes;
@@ -101,55 +143,28 @@ struct mic_vdev {
unsigned long in_bytes_dma;
unsigned long tx_len_unaligned;
unsigned long tx_dst_unaligned;
- struct mic_vringh mvr[MIC_MAX_VRINGS];
+ unsigned long rx_dst_unaligned;
+ struct vop_vringh vvr[MIC_MAX_VRINGS];
struct work_struct virtio_bh_work;
struct mic_device_desc *dd;
struct mic_device_ctrl *dc;
struct list_head list;
int virtio_db;
struct mic_irq *virtio_cookie;
+ struct vop_info *vi;
+ struct mutex vdev_mutex;
+ struct completion destroy;
+ bool deleted;
};
-void mic_virtio_uninit(struct mic_device *mdev);
-int mic_virtio_add_device(struct mic_vdev *mvdev,
- void __user *argp);
-void mic_virtio_del_device(struct mic_vdev *mvdev);
-int mic_virtio_config_change(struct mic_vdev *mvdev,
- void __user *argp);
-int mic_virtio_copy_desc(struct mic_vdev *mvdev,
- struct mic_copy_desc *request);
-void mic_virtio_reset_devices(struct mic_device *mdev);
-void mic_bh_handler(struct work_struct *work);
-
-/* Helper API to obtain the MIC PCIe device */
-static inline struct device *mic_dev(struct mic_vdev *mvdev)
-{
- return &mvdev->mdev->pdev->dev;
-}
-
-/* Helper API to check if a virtio device is initialized */
-static inline int mic_vdev_inited(struct mic_vdev *mvdev)
-{
- /* Device has not been created yet */
- if (!mvdev->dd || !mvdev->dd->type) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, -EINVAL);
- return -EINVAL;
- }
-
- /* Device has been removed/deleted */
- if (mvdev->dd->type == -1) {
- dev_err(mic_dev(mvdev), "%s %d err %d\n",
- __func__, __LINE__, -ENODEV);
- return -ENODEV;
- }
-
- return 0;
-}
-
/* Helper API to check if a virtio device is running */
-static inline bool mic_vdevup(struct mic_vdev *mvdev)
+static inline bool vop_vdevup(struct vop_vdev *vdev)
{
- return !!mvdev->dd->status;
+ return !!vdev->dd->status;
}
+
+void vop_init_debugfs(struct vop_info *vi);
+void vop_exit_debugfs(struct vop_info *vi);
+int vop_host_init(struct vop_info *vi);
+void vop_host_uninit(struct vop_info *vi);
#endif
diff --git a/drivers/misc/mic/vop/vop_vringh.c b/drivers/misc/mic/vop/vop_vringh.c
new file mode 100644
index 000000000000..e94c7fb6712a
--- /dev/null
+++ b/drivers/misc/mic/vop/vop_vringh.c
@@ -0,0 +1,1165 @@
+/*
+ * Intel MIC Platform Software Stack (MPSS)
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * 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
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Intel Virtio Over PCIe (VOP) driver.
+ *
+ */
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/mic_common.h>
+#include "../common/mic_dev.h"
+
+#include <linux/mic_ioctl.h>
+#include "vop_main.h"
+
+/* Helper API to obtain the VOP PCIe device */
+static inline struct device *vop_dev(struct vop_vdev *vdev)
+{
+ return vdev->vpdev->dev.parent;
+}
+
+/* Helper API to check if a virtio device is initialized */
+static inline int vop_vdev_inited(struct vop_vdev *vdev)
+{
+ if (!vdev)
+ return -EINVAL;
+ /* Device has not been created yet */
+ if (!vdev->dd || !vdev->dd->type) {
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, -EINVAL);
+ return -EINVAL;
+ }
+ /* Device has been removed/deleted */
+ if (vdev->dd->type == -1) {
+ dev_dbg(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, -ENODEV);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void _vop_notify(struct vringh *vrh)
+{
+ struct vop_vringh *vvrh = container_of(vrh, struct vop_vringh, vrh);
+ struct vop_vdev *vdev = vvrh->vdev;
+ struct vop_device *vpdev = vdev->vpdev;
+ s8 db = vdev->dc->h2c_vdev_db;
+
+ if (db != -1)
+ vpdev->hw_ops->send_intr(vpdev, db);
+}
+
+static void vop_virtio_init_post(struct vop_vdev *vdev)
+{
+ struct mic_vqconfig *vqconfig = mic_vq_config(vdev->dd);
+ struct vop_device *vpdev = vdev->vpdev;
+ int i, used_size;
+
+ for (i = 0; i < vdev->dd->num_vq; i++) {
+ used_size = PAGE_ALIGN(sizeof(u16) * 3 +
+ sizeof(struct vring_used_elem) *
+ le16_to_cpu(vqconfig->num));
+ if (!le64_to_cpu(vqconfig[i].used_address)) {
+ dev_warn(vop_dev(vdev), "used_address zero??\n");
+ continue;
+ }
+ vdev->vvr[i].vrh.vring.used =
+ (void __force *)vpdev->hw_ops->ioremap(
+ vpdev,
+ le64_to_cpu(vqconfig[i].used_address),
+ used_size);
+ }
+
+ vdev->dc->used_address_updated = 0;
+
+ dev_info(vop_dev(vdev), "%s: device type %d LINKUP\n",
+ __func__, vdev->virtio_id);
+}
+
+static inline void vop_virtio_device_reset(struct vop_vdev *vdev)
+{
+ int i;
+
+ dev_dbg(vop_dev(vdev), "%s: status %d device type %d RESET\n",
+ __func__, vdev->dd->status, vdev->virtio_id);
+
+ for (i = 0; i < vdev->dd->num_vq; i++)
+ /*
+ * Avoid lockdep false positive. The + 1 is for the vop
+ * mutex which is held in the reset devices code path.
+ */
+ mutex_lock_nested(&vdev->vvr[i].vr_mutex, i + 1);
+
+ /* 0 status means "reset" */
+ vdev->dd->status = 0;
+ vdev->dc->vdev_reset = 0;
+ vdev->dc->host_ack = 1;
+
+ for (i = 0; i < vdev->dd->num_vq; i++) {
+ struct vringh *vrh = &vdev->vvr[i].vrh;
+
+ vdev->vvr[i].vring.info->avail_idx = 0;
+ vrh->completed = 0;
+ vrh->last_avail_idx = 0;
+ vrh->last_used_idx = 0;
+ }
+
+ for (i = 0; i < vdev->dd->num_vq; i++)
+ mutex_unlock(&vdev->vvr[i].vr_mutex);
+}
+
+static void vop_virtio_reset_devices(struct vop_info *vi)
+{
+ struct list_head *pos, *tmp;
+ struct vop_vdev *vdev;
+
+ list_for_each_safe(pos, tmp, &vi->vdev_list) {
+ vdev = list_entry(pos, struct vop_vdev, list);
+ vop_virtio_device_reset(vdev);
+ vdev->poll_wake = 1;
+ wake_up(&vdev->waitq);
+ }
+}
+
+static void vop_bh_handler(struct work_struct *work)
+{
+ struct vop_vdev *vdev = container_of(work, struct vop_vdev,
+ virtio_bh_work);
+
+ if (vdev->dc->used_address_updated)
+ vop_virtio_init_post(vdev);
+
+ if (vdev->dc->vdev_reset)
+ vop_virtio_device_reset(vdev);
+
+ vdev->poll_wake = 1;
+ wake_up(&vdev->waitq);
+}
+
+static irqreturn_t _vop_virtio_intr_handler(int irq, void *data)
+{
+ struct vop_vdev *vdev = data;
+ struct vop_device *vpdev = vdev->vpdev;
+
+ vpdev->hw_ops->ack_interrupt(vpdev, vdev->virtio_db);
+ schedule_work(&vdev->virtio_bh_work);
+ return IRQ_HANDLED;
+}
+
+static int vop_virtio_config_change(struct vop_vdev *vdev, void *argp)
+{
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
+ int ret = 0, retry, i;
+ struct vop_device *vpdev = vdev->vpdev;
+ struct vop_info *vi = dev_get_drvdata(&vpdev->dev);
+ struct mic_bootparam *bootparam = vpdev->hw_ops->get_dp(vpdev);
+ s8 db = bootparam->h2c_config_db;
+
+ mutex_lock(&vi->vop_mutex);
+ for (i = 0; i < vdev->dd->num_vq; i++)
+ mutex_lock_nested(&vdev->vvr[i].vr_mutex, i + 1);
+
+ if (db == -1 || vdev->dd->type == -1) {
+ ret = -EIO;
+ goto exit;
+ }
+
+ memcpy(mic_vq_configspace(vdev->dd), argp, vdev->dd->config_len);
+ vdev->dc->config_change = MIC_VIRTIO_PARAM_CONFIG_CHANGED;
+ vpdev->hw_ops->send_intr(vpdev, db);
+
+ for (retry = 100; retry--;) {
+ ret = wait_event_timeout(wake, vdev->dc->guest_ack,
+ msecs_to_jiffies(100));
+ if (ret)
+ break;
+ }
+
+ dev_dbg(vop_dev(vdev),
+ "%s %d retry: %d\n", __func__, __LINE__, retry);
+ vdev->dc->config_change = 0;
+ vdev->dc->guest_ack = 0;
+exit:
+ for (i = 0; i < vdev->dd->num_vq; i++)
+ mutex_unlock(&vdev->vvr[i].vr_mutex);
+ mutex_unlock(&vi->vop_mutex);
+ return ret;
+}
+
+static int vop_copy_dp_entry(struct vop_vdev *vdev,
+ struct mic_device_desc *argp, __u8 *type,
+ struct mic_device_desc **devpage)
+{
+ struct vop_device *vpdev = vdev->vpdev;
+ struct mic_device_desc *devp;
+ struct mic_vqconfig *vqconfig;
+ int ret = 0, i;
+ bool slot_found = false;
+
+ vqconfig = mic_vq_config(argp);
+ for (i = 0; i < argp->num_vq; i++) {
+ if (le16_to_cpu(vqconfig[i].num) > MIC_MAX_VRING_ENTRIES) {
+ ret = -EINVAL;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ goto exit;
+ }
+ }
+
+ /* Find the first free device page entry */
+ for (i = sizeof(struct mic_bootparam);
+ i < MIC_DP_SIZE - mic_total_desc_size(argp);
+ i += mic_total_desc_size(devp)) {
+ devp = vpdev->hw_ops->get_dp(vpdev) + i;
+ if (devp->type == 0 || devp->type == -1) {
+ slot_found = true;
+ break;
+ }
+ }
+ if (!slot_found) {
+ ret = -EINVAL;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ goto exit;
+ }
+ /*
+ * Save off the type before doing the memcpy. Type will be set in the
+ * end after completing all initialization for the new device.
+ */
+ *type = argp->type;
+ argp->type = 0;
+ memcpy(devp, argp, mic_desc_size(argp));
+
+ *devpage = devp;
+exit:
+ return ret;
+}
+
+static void vop_init_device_ctrl(struct vop_vdev *vdev,
+ struct mic_device_desc *devpage)
+{
+ struct mic_device_ctrl *dc;
+
+ dc = (void *)devpage + mic_aligned_desc_size(devpage);
+
+ dc->config_change = 0;
+ dc->guest_ack = 0;
+ dc->vdev_reset = 0;
+ dc->host_ack = 0;
+ dc->used_address_updated = 0;
+ dc->c2h_vdev_db = -1;
+ dc->h2c_vdev_db = -1;
+ vdev->dc = dc;
+}
+
+static int vop_virtio_add_device(struct vop_vdev *vdev,
+ struct mic_device_desc *argp)
+{
+ struct vop_info *vi = vdev->vi;
+ struct vop_device *vpdev = vi->vpdev;
+ struct mic_device_desc *dd = NULL;
+ struct mic_vqconfig *vqconfig;
+ int vr_size, i, j, ret;
+ u8 type = 0;
+ s8 db = -1;
+ char irqname[16];
+ struct mic_bootparam *bootparam;
+ u16 num;
+ dma_addr_t vr_addr;
+
+ bootparam = vpdev->hw_ops->get_dp(vpdev);
+ init_waitqueue_head(&vdev->waitq);
+ INIT_LIST_HEAD(&vdev->list);
+ vdev->vpdev = vpdev;
+
+ ret = vop_copy_dp_entry(vdev, argp, &type, &dd);
+ if (ret) {
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ kfree(vdev);
+ return ret;
+ }
+
+ vop_init_device_ctrl(vdev, dd);
+
+ vdev->dd = dd;
+ vdev->virtio_id = type;
+ vqconfig = mic_vq_config(dd);
+ INIT_WORK(&vdev->virtio_bh_work, vop_bh_handler);
+
+ for (i = 0; i < dd->num_vq; i++) {
+ struct vop_vringh *vvr = &vdev->vvr[i];
+ struct mic_vring *vr = &vdev->vvr[i].vring;
+
+ num = le16_to_cpu(vqconfig[i].num);
+ mutex_init(&vvr->vr_mutex);
+ vr_size = PAGE_ALIGN(vring_size(num, MIC_VIRTIO_RING_ALIGN) +
+ sizeof(struct _mic_vring_info));
+ vr->va = (void *)
+ __get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ get_order(vr_size));
+ if (!vr->va) {
+ ret = -ENOMEM;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ goto err;
+ }
+ vr->len = vr_size;
+ vr->info = vr->va + vring_size(num, MIC_VIRTIO_RING_ALIGN);
+ vr->info->magic = cpu_to_le32(MIC_MAGIC + vdev->virtio_id + i);
+ vr_addr = dma_map_single(&vpdev->dev, vr->va, vr_size,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(&vpdev->dev, vr_addr)) {
+ free_pages((unsigned long)vr->va, get_order(vr_size));
+ ret = -ENOMEM;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ goto err;
+ }
+ vqconfig[i].address = cpu_to_le64(vr_addr);
+
+ vring_init(&vr->vr, num, vr->va, MIC_VIRTIO_RING_ALIGN);
+ ret = vringh_init_kern(&vvr->vrh,
+ *(u32 *)mic_vq_features(vdev->dd),
+ num, false, vr->vr.desc, vr->vr.avail,
+ vr->vr.used);
+ if (ret) {
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ goto err;
+ }
+ vringh_kiov_init(&vvr->riov, NULL, 0);
+ vringh_kiov_init(&vvr->wiov, NULL, 0);
+ vvr->head = USHRT_MAX;
+ vvr->vdev = vdev;
+ vvr->vrh.notify = _vop_notify;
+ dev_dbg(&vpdev->dev,
+ "%s %d index %d va %p info %p vr_size 0x%x\n",
+ __func__, __LINE__, i, vr->va, vr->info, vr_size);
+ vvr->buf = (void *)__get_free_pages(GFP_KERNEL,
+ get_order(VOP_INT_DMA_BUF_SIZE));
+ vvr->buf_da = dma_map_single(&vpdev->dev,
+ vvr->buf, VOP_INT_DMA_BUF_SIZE,
+ DMA_BIDIRECTIONAL);
+ }
+
+ snprintf(irqname, sizeof(irqname), "vop%dvirtio%d", vpdev->index,
+ vdev->virtio_id);
+ vdev->virtio_db = vpdev->hw_ops->next_db(vpdev);
+ vdev->virtio_cookie = vpdev->hw_ops->request_irq(vpdev,
+ _vop_virtio_intr_handler, irqname, vdev,
+ vdev->virtio_db);
+ if (IS_ERR(vdev->virtio_cookie)) {
+ ret = PTR_ERR(vdev->virtio_cookie);
+ dev_dbg(&vpdev->dev, "request irq failed\n");
+ goto err;
+ }
+
+ vdev->dc->c2h_vdev_db = vdev->virtio_db;
+
+ /*
+ * Order the type update with previous stores. This write barrier
+ * is paired with the corresponding read barrier before the uncached
+ * system memory read of the type, on the card while scanning the
+ * device page.
+ */
+ smp_wmb();
+ dd->type = type;
+ argp->type = type;
+
+ if (bootparam) {
+ db = bootparam->h2c_config_db;
+ if (db != -1)
+ vpdev->hw_ops->send_intr(vpdev, db);
+ }
+ dev_dbg(&vpdev->dev, "Added virtio id %d db %d\n", dd->type, db);
+ return 0;
+err:
+ vqconfig = mic_vq_config(dd);
+ for (j = 0; j < i; j++) {
+ struct vop_vringh *vvr = &vdev->vvr[j];
+
+ dma_unmap_single(&vpdev->dev, le64_to_cpu(vqconfig[j].address),
+ vvr->vring.len, DMA_BIDIRECTIONAL);
+ free_pages((unsigned long)vvr->vring.va,
+ get_order(vvr->vring.len));
+ }
+ return ret;
+}
+
+static void vop_dev_remove(struct vop_info *pvi, struct mic_device_ctrl *devp,
+ struct vop_device *vpdev)
+{
+ struct mic_bootparam *bootparam = vpdev->hw_ops->get_dp(vpdev);
+ s8 db;
+ int ret, retry;
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
+
+ devp->config_change = MIC_VIRTIO_PARAM_DEV_REMOVE;
+ db = bootparam->h2c_config_db;
+ if (db != -1)
+ vpdev->hw_ops->send_intr(vpdev, db);
+ else
+ goto done;
+ for (retry = 15; retry--;) {
+ ret = wait_event_timeout(wake, devp->guest_ack,
+ msecs_to_jiffies(1000));
+ if (ret)
+ break;
+ }
+done:
+ devp->config_change = 0;
+ devp->guest_ack = 0;
+}
+
+static void vop_virtio_del_device(struct vop_vdev *vdev)
+{
+ struct vop_info *vi = vdev->vi;
+ struct vop_device *vpdev = vdev->vpdev;
+ int i;
+ struct mic_vqconfig *vqconfig;
+ struct mic_bootparam *bootparam = vpdev->hw_ops->get_dp(vpdev);
+
+ if (!bootparam)
+ goto skip_hot_remove;
+ vop_dev_remove(vi, vdev->dc, vpdev);
+skip_hot_remove:
+ vpdev->hw_ops->free_irq(vpdev, vdev->virtio_cookie, vdev);
+ flush_work(&vdev->virtio_bh_work);
+ vqconfig = mic_vq_config(vdev->dd);
+ for (i = 0; i < vdev->dd->num_vq; i++) {
+ struct vop_vringh *vvr = &vdev->vvr[i];
+
+ dma_unmap_single(&vpdev->dev,
+ vvr->buf_da, VOP_INT_DMA_BUF_SIZE,
+ DMA_BIDIRECTIONAL);
+ free_pages((unsigned long)vvr->buf,
+ get_order(VOP_INT_DMA_BUF_SIZE));
+ vringh_kiov_cleanup(&vvr->riov);
+ vringh_kiov_cleanup(&vvr->wiov);
+ dma_unmap_single(&vpdev->dev, le64_to_cpu(vqconfig[i].address),
+ vvr->vring.len, DMA_BIDIRECTIONAL);
+ free_pages((unsigned long)vvr->vring.va,
+ get_order(vvr->vring.len));
+ }
+ /*
+ * Order the type update with previous stores. This write barrier
+ * is paired with the corresponding read barrier before the uncached
+ * system memory read of the type, on the card while scanning the
+ * device page.
+ */
+ smp_wmb();
+ vdev->dd->type = -1;
+}
+
+/*
+ * vop_sync_dma - Wrapper for synchronous DMAs.
+ *
+ * @dev - The address of the pointer to the device instance used
+ * for DMA registration.
+ * @dst - destination DMA address.
+ * @src - source DMA address.
+ * @len - size of the transfer.
+ *
+ * Return DMA_SUCCESS on success
+ */
+static int vop_sync_dma(struct vop_vdev *vdev, dma_addr_t dst, dma_addr_t src,
+ size_t len)
+{
+ int err = 0;
+ struct dma_device *ddev;
+ struct dma_async_tx_descriptor *tx;
+ struct vop_info *vi = dev_get_drvdata(&vdev->vpdev->dev);
+ struct dma_chan *vop_ch = vi->dma_ch;
+
+ if (!vop_ch) {
+ err = -EBUSY;
+ goto error;
+ }
+ ddev = vop_ch->device;
+ tx = ddev->device_prep_dma_memcpy(vop_ch, dst, src, len,
+ DMA_PREP_FENCE);
+ if (!tx) {
+ err = -ENOMEM;
+ goto error;
+ } else {
+ dma_cookie_t cookie;
+
+ cookie = tx->tx_submit(tx);
+ if (dma_submit_error(cookie)) {
+ err = -ENOMEM;
+ goto error;
+ }
+ dma_async_issue_pending(vop_ch);
+ err = dma_sync_wait(vop_ch, cookie);
+ }
+error:
+ if (err)
+ dev_err(&vi->vpdev->dev, "%s %d err %d\n",
+ __func__, __LINE__, err);
+ return err;
+}
+
+#define VOP_USE_DMA true
+
+/*
+ * Initiates the copies across the PCIe bus from card memory to a user
+ * space buffer. When transfers are done using DMA, source/destination
+ * addresses and transfer length must follow the alignment requirements of
+ * the MIC DMA engine.
+ */
+static int vop_virtio_copy_to_user(struct vop_vdev *vdev, void __user *ubuf,
+ size_t len, u64 daddr, size_t dlen,
+ int vr_idx)
+{
+ struct vop_device *vpdev = vdev->vpdev;
+ void __iomem *dbuf = vpdev->hw_ops->ioremap(vpdev, daddr, len);
+ struct vop_vringh *vvr = &vdev->vvr[vr_idx];
+ struct vop_info *vi = dev_get_drvdata(&vpdev->dev);
+ size_t dma_alignment = 1 << vi->dma_ch->device->copy_align;
+ bool x200 = is_dma_copy_aligned(vi->dma_ch->device, 1, 1, 1);
+ size_t dma_offset, partlen;
+ int err;
+
+ if (!VOP_USE_DMA) {
+ if (copy_to_user(ubuf, (void __force *)dbuf, len)) {
+ err = -EFAULT;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ goto err;
+ }
+ vdev->in_bytes += len;
+ err = 0;
+ goto err;
+ }
+
+ dma_offset = daddr - round_down(daddr, dma_alignment);
+ daddr -= dma_offset;
+ len += dma_offset;
+ /*
+ * X100 uses DMA addresses as seen by the card so adding
+ * the aperture base is not required for DMA. However x200
+ * requires DMA addresses to be an offset into the bar so
+ * add the aperture base for x200.
+ */
+ if (x200)
+ daddr += vpdev->aper->pa;
+ while (len) {
+ partlen = min_t(size_t, len, VOP_INT_DMA_BUF_SIZE);
+ err = vop_sync_dma(vdev, vvr->buf_da, daddr,
+ ALIGN(partlen, dma_alignment));
+ if (err) {
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ goto err;
+ }
+ if (copy_to_user(ubuf, vvr->buf + dma_offset,
+ partlen - dma_offset)) {
+ err = -EFAULT;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ goto err;
+ }
+ daddr += partlen;
+ ubuf += partlen;
+ dbuf += partlen;
+ vdev->in_bytes_dma += partlen;
+ vdev->in_bytes += partlen;
+ len -= partlen;
+ dma_offset = 0;
+ }
+ err = 0;
+err:
+ vpdev->hw_ops->iounmap(vpdev, dbuf);
+ dev_dbg(vop_dev(vdev),
+ "%s: ubuf %p dbuf %p len 0x%lx vr_idx 0x%x\n",
+ __func__, ubuf, dbuf, len, vr_idx);
+ return err;
+}
+
+/*
+ * Initiates copies across the PCIe bus from a user space buffer to card
+ * memory. When transfers are done using DMA, source/destination addresses
+ * and transfer length must follow the alignment requirements of the MIC
+ * DMA engine.
+ */
+static int vop_virtio_copy_from_user(struct vop_vdev *vdev, void __user *ubuf,
+ size_t len, u64 daddr, size_t dlen,
+ int vr_idx)
+{
+ struct vop_device *vpdev = vdev->vpdev;
+ void __iomem *dbuf = vpdev->hw_ops->ioremap(vpdev, daddr, len);
+ struct vop_vringh *vvr = &vdev->vvr[vr_idx];
+ struct vop_info *vi = dev_get_drvdata(&vdev->vpdev->dev);
+ size_t dma_alignment = 1 << vi->dma_ch->device->copy_align;
+ bool x200 = is_dma_copy_aligned(vi->dma_ch->device, 1, 1, 1);
+ size_t partlen;
+ bool dma = VOP_USE_DMA;
+ int err = 0;
+
+ if (daddr & (dma_alignment - 1)) {
+ vdev->tx_dst_unaligned += len;
+ dma = false;
+ } else if (ALIGN(len, dma_alignment) > dlen) {
+ vdev->tx_len_unaligned += len;
+ dma = false;
+ }
+
+ if (!dma)
+ goto memcpy;
+
+ /*
+ * X100 uses DMA addresses as seen by the card so adding
+ * the aperture base is not required for DMA. However x200
+ * requires DMA addresses to be an offset into the bar so
+ * add the aperture base for x200.
+ */
+ if (x200)
+ daddr += vpdev->aper->pa;
+ while (len) {
+ partlen = min_t(size_t, len, VOP_INT_DMA_BUF_SIZE);
+
+ if (copy_from_user(vvr->buf, ubuf, partlen)) {
+ err = -EFAULT;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ goto err;
+ }
+ err = vop_sync_dma(vdev, daddr, vvr->buf_da,
+ ALIGN(partlen, dma_alignment));
+ if (err) {
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ goto err;
+ }
+ daddr += partlen;
+ ubuf += partlen;
+ dbuf += partlen;
+ vdev->out_bytes_dma += partlen;
+ vdev->out_bytes += partlen;
+ len -= partlen;
+ }
+memcpy:
+ /*
+ * We are copying to IO below and should ideally use something
+ * like copy_from_user_toio(..) if it existed.
+ */
+ if (copy_from_user((void __force *)dbuf, ubuf, len)) {
+ err = -EFAULT;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ goto err;
+ }
+ vdev->out_bytes += len;
+ err = 0;
+err:
+ vpdev->hw_ops->iounmap(vpdev, dbuf);
+ dev_dbg(vop_dev(vdev),
+ "%s: ubuf %p dbuf %p len 0x%lx vr_idx 0x%x\n",
+ __func__, ubuf, dbuf, len, vr_idx);
+ return err;
+}
+
+#define MIC_VRINGH_READ true
+
+/* Determine the total number of bytes consumed in a VRINGH KIOV */
+static inline u32 vop_vringh_iov_consumed(struct vringh_kiov *iov)
+{
+ int i;
+ u32 total = iov->consumed;
+
+ for (i = 0; i < iov->i; i++)
+ total += iov->iov[i].iov_len;
+ return total;
+}
+
+/*
+ * Traverse the VRINGH KIOV and issue the APIs to trigger the copies.
+ * This API is heavily based on the vringh_iov_xfer(..) implementation
+ * in vringh.c. The reason we cannot reuse vringh_iov_pull_kern(..)
+ * and vringh_iov_push_kern(..) directly is because there is no
+ * way to override the VRINGH xfer(..) routines as of v3.10.
+ */
+static int vop_vringh_copy(struct vop_vdev *vdev, struct vringh_kiov *iov,
+ void __user *ubuf, size_t len, bool read, int vr_idx,
+ size_t *out_len)
+{
+ int ret = 0;
+ size_t partlen, tot_len = 0;
+
+ while (len && iov->i < iov->used) {
+ struct kvec *kiov = &iov->iov[iov->i];
+
+ partlen = min(kiov->iov_len, len);
+ if (read)
+ ret = vop_virtio_copy_to_user(vdev, ubuf, partlen,
+ (u64)kiov->iov_base,
+ kiov->iov_len,
+ vr_idx);
+ else
+ ret = vop_virtio_copy_from_user(vdev, ubuf, partlen,
+ (u64)kiov->iov_base,
+ kiov->iov_len,
+ vr_idx);
+ if (ret) {
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ break;
+ }
+ len -= partlen;
+ ubuf += partlen;
+ tot_len += partlen;
+ iov->consumed += partlen;
+ kiov->iov_len -= partlen;
+ kiov->iov_base += partlen;
+ if (!kiov->iov_len) {
+ /* Fix up old iov element then increment. */
+ kiov->iov_len = iov->consumed;
+ kiov->iov_base -= iov->consumed;
+
+ iov->consumed = 0;
+ iov->i++;
+ }
+ }
+ *out_len = tot_len;
+ return ret;
+}
+
+/*
+ * Use the standard VRINGH infrastructure in the kernel to fetch new
+ * descriptors, initiate the copies and update the used ring.
+ */
+static int _vop_virtio_copy(struct vop_vdev *vdev, struct mic_copy_desc *copy)
+{
+ int ret = 0;
+ u32 iovcnt = copy->iovcnt;
+ struct iovec iov;
+ struct iovec __user *u_iov = copy->iov;
+ void __user *ubuf = NULL;
+ struct vop_vringh *vvr = &vdev->vvr[copy->vr_idx];
+ struct vringh_kiov *riov = &vvr->riov;
+ struct vringh_kiov *wiov = &vvr->wiov;
+ struct vringh *vrh = &vvr->vrh;
+ u16 *head = &vvr->head;
+ struct mic_vring *vr = &vvr->vring;
+ size_t len = 0, out_len;
+
+ copy->out_len = 0;
+ /* Fetch a new IOVEC if all previous elements have been processed */
+ if (riov->i == riov->used && wiov->i == wiov->used) {
+ ret = vringh_getdesc_kern(vrh, riov, wiov,
+ head, GFP_KERNEL);
+ /* Check if there are available descriptors */
+ if (ret <= 0)
+ return ret;
+ }
+ while (iovcnt) {
+ if (!len) {
+ /* Copy over a new iovec from user space. */
+ ret = copy_from_user(&iov, u_iov, sizeof(*u_iov));
+ if (ret) {
+ ret = -EINVAL;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ break;
+ }
+ len = iov.iov_len;
+ ubuf = iov.iov_base;
+ }
+ /* Issue all the read descriptors first */
+ ret = vop_vringh_copy(vdev, riov, ubuf, len,
+ MIC_VRINGH_READ, copy->vr_idx, &out_len);
+ if (ret) {
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ break;
+ }
+ len -= out_len;
+ ubuf += out_len;
+ copy->out_len += out_len;
+ /* Issue the write descriptors next */
+ ret = vop_vringh_copy(vdev, wiov, ubuf, len,
+ !MIC_VRINGH_READ, copy->vr_idx, &out_len);
+ if (ret) {
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, ret);
+ break;
+ }
+ len -= out_len;
+ ubuf += out_len;
+ copy->out_len += out_len;
+ if (!len) {
+ /* One user space iovec is now completed */
+ iovcnt--;
+ u_iov++;
+ }
+ /* Exit loop if all elements in KIOVs have been processed. */
+ if (riov->i == riov->used && wiov->i == wiov->used)
+ break;
+ }
+ /*
+ * Update the used ring if a descriptor was available and some data was
+ * copied in/out and the user asked for a used ring update.
+ */
+ if (*head != USHRT_MAX && copy->out_len && copy->update_used) {
+ u32 total = 0;
+
+ /* Determine the total data consumed */
+ total += vop_vringh_iov_consumed(riov);
+ total += vop_vringh_iov_consumed(wiov);
+ vringh_complete_kern(vrh, *head, total);
+ *head = USHRT_MAX;
+ if (vringh_need_notify_kern(vrh) > 0)
+ vringh_notify(vrh);
+ vringh_kiov_cleanup(riov);
+ vringh_kiov_cleanup(wiov);
+ /* Update avail idx for user space */
+ vr->info->avail_idx = vrh->last_avail_idx;
+ }
+ return ret;
+}
+
+static inline int vop_verify_copy_args(struct vop_vdev *vdev,
+ struct mic_copy_desc *copy)
+{
+ if (!vdev || copy->vr_idx >= vdev->dd->num_vq)
+ return -EINVAL;
+ return 0;
+}
+
+/* Copy a specified number of virtio descriptors in a chain */
+static int vop_virtio_copy_desc(struct vop_vdev *vdev,
+ struct mic_copy_desc *copy)
+{
+ int err;
+ struct vop_vringh *vvr;
+
+ err = vop_verify_copy_args(vdev, copy);
+ if (err)
+ return err;
+
+ vvr = &vdev->vvr[copy->vr_idx];
+ mutex_lock(&vvr->vr_mutex);
+ if (!vop_vdevup(vdev)) {
+ err = -ENODEV;
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ goto err;
+ }
+ err = _vop_virtio_copy(vdev, copy);
+ if (err) {
+ dev_err(vop_dev(vdev), "%s %d err %d\n",
+ __func__, __LINE__, err);
+ }
+err:
+ mutex_unlock(&vvr->vr_mutex);
+ return err;
+}
+
+static int vop_open(struct inode *inode, struct file *f)
+{
+ struct vop_vdev *vdev;
+ struct vop_info *vi = container_of(f->private_data,
+ struct vop_info, miscdev);
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev)
+ return -ENOMEM;
+ vdev->vi = vi;
+ mutex_init(&vdev->vdev_mutex);
+ f->private_data = vdev;
+ init_completion(&vdev->destroy);
+ complete(&vdev->destroy);
+ return 0;
+}
+
+static int vop_release(struct inode *inode, struct file *f)
+{
+ struct vop_vdev *vdev = f->private_data, *vdev_tmp;
+ struct vop_info *vi = vdev->vi;
+ struct list_head *pos, *tmp;
+ bool found = false;
+
+ mutex_lock(&vdev->vdev_mutex);
+ if (vdev->deleted)
+ goto unlock;
+ mutex_lock(&vi->vop_mutex);
+ list_for_each_safe(pos, tmp, &vi->vdev_list) {
+ vdev_tmp = list_entry(pos, struct vop_vdev, list);
+ if (vdev == vdev_tmp) {
+ vop_virtio_del_device(vdev);
+ list_del(pos);
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&vi->vop_mutex);
+unlock:
+ mutex_unlock(&vdev->vdev_mutex);
+ if (!found)
+ wait_for_completion(&vdev->destroy);
+ f->private_data = NULL;
+ kfree(vdev);
+ return 0;
+}
+
+static long vop_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+ struct vop_vdev *vdev = f->private_data;
+ struct vop_info *vi = vdev->vi;
+ void __user *argp = (void __user *)arg;
+ int ret;
+
+ switch (cmd) {
+ case MIC_VIRTIO_ADD_DEVICE:
+ {
+ struct mic_device_desc dd, *dd_config;
+
+ if (copy_from_user(&dd, argp, sizeof(dd)))
+ return -EFAULT;
+
+ if (mic_aligned_desc_size(&dd) > MIC_MAX_DESC_BLK_SIZE ||
+ dd.num_vq > MIC_MAX_VRINGS)
+ return -EINVAL;
+
+ dd_config = kzalloc(mic_desc_size(&dd), GFP_KERNEL);
+ if (!dd_config)
+ return -ENOMEM;
+ if (copy_from_user(dd_config, argp, mic_desc_size(&dd))) {
+ ret = -EFAULT;
+ goto free_ret;
+ }
+ mutex_lock(&vdev->vdev_mutex);
+ mutex_lock(&vi->vop_mutex);
+ ret = vop_virtio_add_device(vdev, dd_config);
+ if (ret)
+ goto unlock_ret;
+ list_add_tail(&vdev->list, &vi->vdev_list);
+unlock_ret:
+ mutex_unlock(&vi->vop_mutex);
+ mutex_unlock(&vdev->vdev_mutex);
+free_ret:
+ kfree(dd_config);
+ return ret;
+ }
+ case MIC_VIRTIO_COPY_DESC:
+ {
+ struct mic_copy_desc copy;
+
+ mutex_lock(&vdev->vdev_mutex);
+ ret = vop_vdev_inited(vdev);
+ if (ret)
+ goto _unlock_ret;
+
+ if (copy_from_user(&copy, argp, sizeof(copy))) {
+ ret = -EFAULT;
+ goto _unlock_ret;
+ }
+
+ ret = vop_virtio_copy_desc(vdev, &copy);
+ if (ret < 0)
+ goto _unlock_ret;
+ if (copy_to_user(
+ &((struct mic_copy_desc __user *)argp)->out_len,
+ &copy.out_len, sizeof(copy.out_len)))
+ ret = -EFAULT;
+_unlock_ret:
+ mutex_unlock(&vdev->vdev_mutex);
+ return ret;
+ }
+ case MIC_VIRTIO_CONFIG_CHANGE:
+ {
+ void *buf;
+
+ mutex_lock(&vdev->vdev_mutex);
+ ret = vop_vdev_inited(vdev);
+ if (ret)
+ goto __unlock_ret;
+ buf = kzalloc(vdev->dd->config_len, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto __unlock_ret;
+ }
+ if (copy_from_user(buf, argp, vdev->dd->config_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ ret = vop_virtio_config_change(vdev, buf);
+done:
+ kfree(buf);
+__unlock_ret:
+ mutex_unlock(&vdev->vdev_mutex);
+ return ret;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ };
+ return 0;
+}
+
+/*
+ * We return POLLIN | POLLOUT from poll when new buffers are enqueued, and
+ * not when previously enqueued buffers may be available. This means that
+ * in the card->host (TX) path, when userspace is unblocked by poll it
+ * must drain all available descriptors or it can stall.
+ */
+static unsigned int vop_poll(struct file *f, poll_table *wait)
+{
+ struct vop_vdev *vdev = f->private_data;
+ int mask = 0;
+
+ mutex_lock(&vdev->vdev_mutex);
+ if (vop_vdev_inited(vdev)) {
+ mask = POLLERR;
+ goto done;
+ }
+ poll_wait(f, &vdev->waitq, wait);
+ if (vop_vdev_inited(vdev)) {
+ mask = POLLERR;
+ } else if (vdev->poll_wake) {
+ vdev->poll_wake = 0;
+ mask = POLLIN | POLLOUT;
+ }
+done:
+ mutex_unlock(&vdev->vdev_mutex);
+ return mask;
+}
+
+static inline int
+vop_query_offset(struct vop_vdev *vdev, unsigned long offset,
+ unsigned long *size, unsigned long *pa)
+{
+ struct vop_device *vpdev = vdev->vpdev;
+ unsigned long start = MIC_DP_SIZE;
+ int i;
+
+ /*
+ * MMAP interface is as follows:
+ * offset region
+ * 0x0 virtio device_page
+ * 0x1000 first vring
+ * 0x1000 + size of 1st vring second vring
+ * ....
+ */
+ if (!offset) {
+ *pa = virt_to_phys(vpdev->hw_ops->get_dp(vpdev));
+ *size = MIC_DP_SIZE;
+ return 0;
+ }
+
+ for (i = 0; i < vdev->dd->num_vq; i++) {
+ struct vop_vringh *vvr = &vdev->vvr[i];
+
+ if (offset == start) {
+ *pa = virt_to_phys(vvr->vring.va);
+ *size = vvr->vring.len;
+ return 0;
+ }
+ start += vvr->vring.len;
+ }
+ return -1;
+}
+
+/*
+ * Maps the device page and virtio rings to user space for readonly access.
+ */
+static int vop_mmap(struct file *f, struct vm_area_struct *vma)
+{
+ struct vop_vdev *vdev = f->private_data;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long pa, size = vma->vm_end - vma->vm_start, size_rem = size;
+ int i, err;
+
+ err = vop_vdev_inited(vdev);
+ if (err)
+ goto ret;
+ if (vma->vm_flags & VM_WRITE) {
+ err = -EACCES;
+ goto ret;
+ }
+ while (size_rem) {
+ i = vop_query_offset(vdev, offset, &size, &pa);
+ if (i < 0) {
+ err = -EINVAL;
+ goto ret;
+ }
+ err = remap_pfn_range(vma, vma->vm_start + offset,
+ pa >> PAGE_SHIFT, size,
+ vma->vm_page_prot);
+ if (err)
+ goto ret;
+ size_rem -= size;
+ offset += size;
+ }
+ret:
+ return err;
+}
+
+static const struct file_operations vop_fops = {
+ .open = vop_open,
+ .release = vop_release,
+ .unlocked_ioctl = vop_ioctl,
+ .poll = vop_poll,
+ .mmap = vop_mmap,
+ .owner = THIS_MODULE,
+};
+
+int vop_host_init(struct vop_info *vi)
+{
+ int rc;
+ struct miscdevice *mdev;
+ struct vop_device *vpdev = vi->vpdev;
+
+ INIT_LIST_HEAD(&vi->vdev_list);
+ vi->dma_ch = vpdev->dma_ch;
+ mdev = &vi->miscdev;
+ mdev->minor = MISC_DYNAMIC_MINOR;
+ snprintf(vi->name, sizeof(vi->name), "vop_virtio%d", vpdev->index);
+ mdev->name = vi->name;
+ mdev->fops = &vop_fops;
+ mdev->parent = &vpdev->dev;
+
+ rc = misc_register(mdev);
+ if (rc)
+ dev_err(&vpdev->dev, "%s failed rc %d\n", __func__, rc);
+ return rc;
+}
+
+void vop_host_uninit(struct vop_info *vi)
+{
+ struct list_head *pos, *tmp;
+ struct vop_vdev *vdev;
+
+ mutex_lock(&vi->vop_mutex);
+ vop_virtio_reset_devices(vi);
+ list_for_each_safe(pos, tmp, &vi->vdev_list) {
+ vdev = list_entry(pos, struct vop_vdev, list);
+ list_del(pos);
+ reinit_completion(&vdev->destroy);
+ mutex_unlock(&vi->vop_mutex);
+ mutex_lock(&vdev->vdev_mutex);
+ vop_virtio_del_device(vdev);
+ vdev->deleted = true;
+ mutex_unlock(&vdev->vdev_mutex);
+ complete(&vdev->destroy);
+ mutex_lock(&vi->vop_mutex);
+ }
+ mutex_unlock(&vi->vop_mutex);
+ misc_deregister(&vi->miscdev);
+}
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index 9a17a9bab8d6..4810e039bbec 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -503,8 +503,7 @@ static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj,
int err;
ssize_t rom_size;
- struct pch_phub_reg *chip =
- dev_get_drvdata(container_of(kobj, struct device, kobj));
+ struct pch_phub_reg *chip = dev_get_drvdata(kobj_to_dev(kobj));
ret = mutex_lock_interruptible(&pch_phub_mutex);
if (ret) {
@@ -514,8 +513,10 @@ static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj,
/* Get Rom signature */
chip->pch_phub_extrom_base_address = pci_map_rom(chip->pdev, &rom_size);
- if (!chip->pch_phub_extrom_base_address)
+ if (!chip->pch_phub_extrom_base_address) {
+ err = -ENODATA;
goto exrom_map_err;
+ }
pch_phub_read_serial_rom(chip, chip->pch_opt_rom_start_address,
(unsigned char *)&rom_signature);
@@ -567,8 +568,7 @@ static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj,
unsigned int addr_offset;
int ret;
ssize_t rom_size;
- struct pch_phub_reg *chip =
- dev_get_drvdata(container_of(kobj, struct device, kobj));
+ struct pch_phub_reg *chip = dev_get_drvdata(kobj_to_dev(kobj));
ret = mutex_lock_interruptible(&pch_phub_mutex);
if (ret)
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 6e3af8b42cdd..dcdbd58672cc 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -632,7 +632,6 @@ long st_register(struct st_proto_s *new_proto)
spin_unlock_irqrestore(&st_gdata->lock, flags);
return err;
}
- pr_debug("done %s(%d) ", __func__, new_proto->chnl_id);
}
EXPORT_SYMBOL_GPL(st_register);
diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c
index b823f9a6e464..896be150e28f 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.c
+++ b/drivers/misc/vmw_vmci/vmci_driver.c
@@ -113,5 +113,5 @@ module_exit(vmci_drv_exit);
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
-MODULE_VERSION("1.1.3.0-k");
+MODULE_VERSION("1.1.4.0-k");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index d2de5925b73e..5415056f9aa5 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -493,7 +493,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
if (status & UART_MSR_DCTS) {
port->icount.cts++;
tty = tty_port_tty_get(&port->port);
- if (tty && (tty->termios.c_cflag & CRTSCTS)) {
+ if (tty && C_CRTSCTS(tty)) {
int cts = (status & UART_MSR_CTS);
if (tty->hw_stopped) {
if (cts) {
@@ -648,10 +648,10 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
sdio_uart_change_speed(port, &tty->termios, NULL);
- if (tty->termios.c_cflag & CBAUD)
+ if (C_BAUD(tty))
sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
tty->hw_stopped = 1;
@@ -833,7 +833,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
- if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
+ if (!I_IXOFF(tty) && !C_CRTSCTS(tty))
return;
if (sdio_uart_claim_func(port) != 0)
@@ -844,7 +844,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
sdio_uart_start_tx(port);
}
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
sdio_uart_clear_mctrl(port, TIOCM_RTS);
sdio_uart_irq(port->func);
@@ -855,7 +855,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
- if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
+ if (!I_IXOFF(tty) && !C_CRTSCTS(tty))
return;
if (sdio_uart_claim_func(port) != 0)
@@ -870,7 +870,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
}
}
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
sdio_uart_set_mctrl(port, TIOCM_RTS);
sdio_uart_irq(port->func);
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index b6639ea0bf18..f6e4d9718035 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -2232,6 +2232,7 @@ err_irq:
dma_release_channel(host->tx_chan);
if (host->rx_chan)
dma_release_channel(host->rx_chan);
+ pm_runtime_dont_use_autosuspend(host->dev);
pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev);
if (host->dbclk)
@@ -2253,6 +2254,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
dma_release_channel(host->tx_chan);
dma_release_channel(host->rx_chan);
+ pm_runtime_dont_use_autosuspend(host->dev);
pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev);
device_init_wakeup(&pdev->dev, false);
diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c
index 79316159eec6..88b6c81cebbe 100644
--- a/drivers/mtd/tests/mtd_nandecctest.c
+++ b/drivers/mtd/tests/mtd_nandecctest.c
@@ -187,7 +187,7 @@ static int double_bit_error_detect(void *error_data, void *error_ecc,
__nand_calculate_ecc(error_data, size, calc_ecc);
ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
- return (ret == -1) ? 0 : -EINVAL;
+ return (ret == -EBADMSG) ? 0 : -EINVAL;
}
static const struct nand_ecc_test nand_ecc_test[] = {
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 2a1b6e037e1a..0134ba32a057 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -193,7 +193,7 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
vol->changing_leb = 1;
vol->ch_lnum = req->lnum;
- vol->upd_buf = vmalloc(req->bytes);
+ vol->upd_buf = vmalloc(ALIGN((int)req->bytes, ubi->min_io_size));
if (!vol->upd_buf)
return -ENOMEM;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 56b560558884..b7f1a9919033 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -214,6 +214,8 @@ static void bond_uninit(struct net_device *bond_dev);
static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
struct rtnl_link_stats64 *stats);
static void bond_slave_arr_handler(struct work_struct *work);
+static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act,
+ int mod);
/*---------------------------- General routines -----------------------------*/
@@ -2127,6 +2129,7 @@ static void bond_miimon_commit(struct bonding *bond)
continue;
case BOND_LINK_UP:
+ bond_update_speed_duplex(slave);
bond_set_slave_link_state(slave, BOND_LINK_UP,
BOND_SLAVE_NOTIFY_NOW);
slave->last_link_up = jiffies;
@@ -2459,7 +2462,7 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave)
{
struct arphdr *arp = (struct arphdr *)skb->data;
- struct slave *curr_active_slave;
+ struct slave *curr_active_slave, *curr_arp_slave;
unsigned char *arp_ptr;
__be32 sip, tip;
int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP);
@@ -2506,26 +2509,41 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
&sip, &tip);
curr_active_slave = rcu_dereference(bond->curr_active_slave);
+ curr_arp_slave = rcu_dereference(bond->current_arp_slave);
- /* Backup slaves won't see the ARP reply, but do come through
- * here for each ARP probe (so we swap the sip/tip to validate
- * the probe). In a "redundant switch, common router" type of
- * configuration, the ARP probe will (hopefully) travel from
- * the active, through one switch, the router, then the other
- * switch before reaching the backup.
+ /* We 'trust' the received ARP enough to validate it if:
+ *
+ * (a) the slave receiving the ARP is active (which includes the
+ * current ARP slave, if any), or
+ *
+ * (b) the receiving slave isn't active, but there is a currently
+ * active slave and it received valid arp reply(s) after it became
+ * the currently active slave, or
+ *
+ * (c) there is an ARP slave that sent an ARP during the prior ARP
+ * interval, and we receive an ARP reply on any slave. We accept
+ * these because switch FDB update delays may deliver the ARP
+ * reply to a slave other than the sender of the ARP request.
*
- * We 'trust' the arp requests if there is an active slave and
- * it received valid arp reply(s) after it became active. This
- * is done to avoid endless looping when we can't reach the
+ * Note: for (b), backup slaves are receiving the broadcast ARP
+ * request, not a reply. This request passes from the sending
+ * slave through the L2 switch(es) to the receiving slave. Since
+ * this is checking the request, sip/tip are swapped for
+ * validation.
+ *
+ * This is done to avoid endless looping when we can't reach the
* arp_ip_target and fool ourselves with our own arp requests.
*/
-
if (bond_is_active_slave(slave))
bond_validate_arp(bond, slave, sip, tip);
else if (curr_active_slave &&
time_after(slave_last_rx(bond, curr_active_slave),
curr_active_slave->last_link_up))
bond_validate_arp(bond, slave, tip, sip);
+ else if (curr_arp_slave && (arp->ar_op == htons(ARPOP_REPLY)) &&
+ bond_time_in_interval(bond,
+ dev_trans_start(curr_arp_slave->dev), 1))
+ bond_validate_arp(bond, slave, sip, tip);
out_unlock:
if (arp != (struct arphdr *)skb->data)
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index 575790e8a75a..74a7dfecee27 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -843,7 +843,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
if (clear_intf)
mcp251x_write_bits(spi, CANINTF, clear_intf, 0x00);
- if (eflag)
+ if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR))
mcp251x_write_bits(spi, EFLG, eflag, 0x00);
/* Update can state */
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index fc5b75675cd8..eb7192fab593 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -117,6 +117,9 @@ MODULE_LICENSE("GPL v2");
*/
#define EMS_USB_ARM7_CLOCK 8000000
+#define CPC_TX_QUEUE_TRIGGER_LOW 25
+#define CPC_TX_QUEUE_TRIGGER_HIGH 35
+
/*
* CAN-Message representation in a CPC_MSG. Message object type is
* CPC_MSG_TYPE_CAN_FRAME or CPC_MSG_TYPE_RTR_FRAME or
@@ -278,6 +281,11 @@ static void ems_usb_read_interrupt_callback(struct urb *urb)
switch (urb->status) {
case 0:
dev->free_slots = dev->intr_in_buffer[1];
+ if(dev->free_slots > CPC_TX_QUEUE_TRIGGER_HIGH){
+ if (netif_queue_stopped(netdev)){
+ netif_wake_queue(netdev);
+ }
+ }
break;
case -ECONNRESET: /* unlink */
@@ -526,8 +534,6 @@ static void ems_usb_write_bulk_callback(struct urb *urb)
/* Release context */
context->echo_index = MAX_TX_URBS;
- if (netif_queue_stopped(netdev))
- netif_wake_queue(netdev);
}
/*
@@ -587,7 +593,7 @@ static int ems_usb_start(struct ems_usb *dev)
int err, i;
dev->intr_in_buffer[0] = 0;
- dev->free_slots = 15; /* initial size */
+ dev->free_slots = 50; /* initial size */
for (i = 0; i < MAX_RX_URBS; i++) {
struct urb *urb = NULL;
@@ -835,7 +841,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
/* Slow down tx path */
if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS ||
- dev->free_slots < 5) {
+ dev->free_slots < CPC_TX_QUEUE_TRIGGER_LOW) {
netif_stop_queue(netdev);
}
}
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 5eee62badf45..cbc99d5649af 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -826,9 +826,8 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface
static void gs_destroy_candev(struct gs_can *dev)
{
unregister_candev(dev->netdev);
- free_candev(dev->netdev);
usb_kill_anchored_urbs(&dev->tx_submitted);
- kfree(dev);
+ free_candev(dev->netdev);
}
static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -913,12 +912,15 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
for (i = 0; i < icount; i++) {
dev->canch[i] = gs_make_candev(i, intf);
if (IS_ERR_OR_NULL(dev->canch[i])) {
+ /* save error code to return later */
+ rc = PTR_ERR(dev->canch[i]);
+
/* on failure destroy previously created candevs */
icount = i;
- for (i = 0; i < icount; i++) {
+ for (i = 0; i < icount; i++)
gs_destroy_candev(dev->canch[i]);
- dev->canch[i] = NULL;
- }
+
+ usb_kill_anchored_urbs(&dev->rx_submitted);
kfree(dev);
return rc;
}
@@ -939,16 +941,12 @@ static void gs_usb_disconnect(struct usb_interface *intf)
return;
}
- for (i = 0; i < GS_MAX_INTF; i++) {
- struct gs_can *can = dev->canch[i];
-
- if (!can)
- continue;
-
- gs_destroy_candev(can);
- }
+ for (i = 0; i < GS_MAX_INTF; i++)
+ if (dev->canch[i])
+ gs_destroy_candev(dev->canch[i]);
usb_kill_anchored_urbs(&dev->rx_submitted);
+ kfree(dev);
}
static const struct usb_device_id gs_usb_table[] = {
diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index cc6c54553418..a47f52f44b0d 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -25,6 +25,7 @@
static const struct mv88e6xxx_switch_id mv88e6352_table[] = {
{ PORT_SWITCH_ID_6172, "Marvell 88E6172" },
{ PORT_SWITCH_ID_6176, "Marvell 88E6176" },
+ { PORT_SWITCH_ID_6240, "Marvell 88E6240" },
{ PORT_SWITCH_ID_6320, "Marvell 88E6320" },
{ PORT_SWITCH_ID_6320_A1, "Marvell 88E6320 (A1)" },
{ PORT_SWITCH_ID_6320_A2, "Marvell 88e6320 (A2)" },
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index cf34681af4f6..512c8c0be1b4 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1555,7 +1555,7 @@ static int _mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
if (vlan.vid != vid || !vlan.valid ||
vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
- return -ENOENT;
+ return -EOPNOTSUPP;
vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
@@ -1582,6 +1582,7 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ const u16 defpvid = 4000 + ds->index * DSA_MAX_PORTS + port;
u16 pvid, vid;
int err = 0;
@@ -1597,7 +1598,8 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
goto unlock;
if (vid == pvid) {
- err = _mv88e6xxx_port_pvid_set(ds, port, 0);
+ /* restore reserved VLAN ID */
+ err = _mv88e6xxx_port_pvid_set(ds, port, defpvid);
if (err)
goto unlock;
}
@@ -1889,26 +1891,20 @@ unlock:
int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members)
{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
- int err;
-
- /* The port joined a bridge, so leave its reserved VLAN */
- mutex_lock(&ps->smi_mutex);
- err = _mv88e6xxx_port_vlan_del(ds, port, pvid);
- if (!err)
- err = _mv88e6xxx_port_pvid_set(ds, port, 0);
- mutex_unlock(&ps->smi_mutex);
- return err;
+ return 0;
}
int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members)
{
+ return 0;
+}
+
+static int mv88e6xxx_setup_port_default_vlan(struct dsa_switch *ds, int port)
+{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
int err;
- /* The port left the bridge, so join its reserved VLAN */
mutex_lock(&ps->smi_mutex);
err = _mv88e6xxx_port_vlan_add(ds, port, pvid, true);
if (!err)
@@ -2192,8 +2188,7 @@ int mv88e6xxx_setup_ports(struct dsa_switch *ds)
if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
continue;
- /* setup the unbridged state */
- ret = mv88e6xxx_port_bridge_leave(ds, i, 0);
+ ret = mv88e6xxx_setup_port_default_vlan(ds, i);
if (ret < 0)
return ret;
}
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index 79e1a0282163..17b2126075e0 100644
--- a/drivers/net/ethernet/3com/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -2461,7 +2461,7 @@ boomerang_interrupt(int irq, void *dev_id)
int i;
pci_unmap_single(VORTEX_PCI(vp),
le32_to_cpu(vp->tx_ring[entry].frag[0].addr),
- le32_to_cpu(vp->tx_ring[entry].frag[0].length),
+ le32_to_cpu(vp->tx_ring[entry].frag[0].length)&0xFFF,
PCI_DMA_TODEVICE);
for (i=1; i<=skb_shinfo(skb)->nr_frags; i++)
diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
index 2777289a26c0..2f79d29f17f2 100644
--- a/drivers/net/ethernet/8390/pcnet_cs.c
+++ b/drivers/net/ethernet/8390/pcnet_cs.c
@@ -1501,6 +1501,7 @@ static const struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1103),
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1121),
+ PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0009),
PCMCIA_DEVICE_PROD_ID12("2408LAN", "Ethernet", 0x352fff7f, 0x00b2e941),
PCMCIA_DEVICE_PROD_ID1234("Socket", "CF 10/100 Ethernet Card", "Revision B", "05/11/06", 0xb38bcc2e, 0x4de88352, 0xeaca6c8d, 0x7e57c22e),
PCMCIA_DEVICE_PROD_ID123("Cardwell", "PCMCIA", "ETHERNET", 0x9533672e, 0x281f1c5d, 0x3ff7175b),
diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c
index 3f3bcbea15bd..0907ab6ff309 100644
--- a/drivers/net/ethernet/agere/et131x.c
+++ b/drivers/net/ethernet/agere/et131x.c
@@ -2380,7 +2380,7 @@ static int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter)
sizeof(u32),
&tx_ring->tx_status_pa,
GFP_KERNEL);
- if (!tx_ring->tx_status_pa) {
+ if (!tx_ring->tx_status) {
dev_err(&adapter->pdev->dev,
"Cannot alloc memory for Tx status block\n");
return -ENOMEM;
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
index 17472851674f..f749e4d389eb 100644
--- a/drivers/net/ethernet/altera/altera_tse_main.c
+++ b/drivers/net/ethernet/altera/altera_tse_main.c
@@ -193,7 +193,6 @@ static void altera_tse_mdio_destroy(struct net_device *dev)
priv->mdio->id);
mdiobus_unregister(priv->mdio);
- kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
priv->mdio = NULL;
}
diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c
index 87e727b921dc..fcdf5dda448f 100644
--- a/drivers/net/ethernet/amd/am79c961a.c
+++ b/drivers/net/ethernet/amd/am79c961a.c
@@ -50,8 +50,8 @@ static const char version[] =
static void write_rreg(u_long base, u_int reg, u_int val)
{
asm volatile(
- "str%?h %1, [%2] @ NET_RAP\n\t"
- "str%?h %0, [%2, #-4] @ NET_RDP"
+ "strh %1, [%2] @ NET_RAP\n\t"
+ "strh %0, [%2, #-4] @ NET_RDP"
:
: "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
}
@@ -60,8 +60,8 @@ static inline unsigned short read_rreg(u_long base_addr, u_int reg)
{
unsigned short v;
asm volatile(
- "str%?h %1, [%2] @ NET_RAP\n\t"
- "ldr%?h %0, [%2, #-4] @ NET_RDP"
+ "strh %1, [%2] @ NET_RAP\n\t"
+ "ldrh %0, [%2, #-4] @ NET_RDP"
: "=r" (v)
: "r" (reg), "r" (ISAIO_BASE + 0x0464));
return v;
@@ -70,8 +70,8 @@ static inline unsigned short read_rreg(u_long base_addr, u_int reg)
static inline void write_ireg(u_long base, u_int reg, u_int val)
{
asm volatile(
- "str%?h %1, [%2] @ NET_RAP\n\t"
- "str%?h %0, [%2, #8] @ NET_IDP"
+ "strh %1, [%2] @ NET_RAP\n\t"
+ "strh %0, [%2, #8] @ NET_IDP"
:
: "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
}
@@ -80,8 +80,8 @@ static inline unsigned short read_ireg(u_long base_addr, u_int reg)
{
u_short v;
asm volatile(
- "str%?h %1, [%2] @ NAT_RAP\n\t"
- "ldr%?h %0, [%2, #8] @ NET_IDP\n\t"
+ "strh %1, [%2] @ NAT_RAP\n\t"
+ "ldrh %0, [%2, #8] @ NET_IDP\n\t"
: "=r" (v)
: "r" (reg), "r" (ISAIO_BASE + 0x0464));
return v;
@@ -96,7 +96,7 @@ am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigne
offset = ISAMEM_BASE + (offset << 1);
length = (length + 1) & ~1;
if ((int)buf & 2) {
- asm volatile("str%?h %2, [%0], #4"
+ asm volatile("strh %2, [%0], #4"
: "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
buf += 2;
length -= 2;
@@ -104,20 +104,20 @@ am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigne
while (length > 8) {
register unsigned int tmp asm("r2"), tmp2 asm("r3");
asm volatile(
- "ldm%?ia %0!, {%1, %2}"
+ "ldmia %0!, {%1, %2}"
: "+r" (buf), "=&r" (tmp), "=&r" (tmp2));
length -= 8;
asm volatile(
- "str%?h %1, [%0], #4\n\t"
- "mov%? %1, %1, lsr #16\n\t"
- "str%?h %1, [%0], #4\n\t"
- "str%?h %2, [%0], #4\n\t"
- "mov%? %2, %2, lsr #16\n\t"
- "str%?h %2, [%0], #4"
+ "strh %1, [%0], #4\n\t"
+ "mov %1, %1, lsr #16\n\t"
+ "strh %1, [%0], #4\n\t"
+ "strh %2, [%0], #4\n\t"
+ "mov %2, %2, lsr #16\n\t"
+ "strh %2, [%0], #4"
: "+r" (offset), "=&r" (tmp), "=&r" (tmp2));
}
while (length > 0) {
- asm volatile("str%?h %2, [%0], #4"
+ asm volatile("strh %2, [%0], #4"
: "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
buf += 2;
length -= 2;
@@ -132,23 +132,23 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned
if ((int)buf & 2) {
unsigned int tmp;
asm volatile(
- "ldr%?h %2, [%0], #4\n\t"
- "str%?b %2, [%1], #1\n\t"
- "mov%? %2, %2, lsr #8\n\t"
- "str%?b %2, [%1], #1"
+ "ldrh %2, [%0], #4\n\t"
+ "strb %2, [%1], #1\n\t"
+ "mov %2, %2, lsr #8\n\t"
+ "strb %2, [%1], #1"
: "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
length -= 2;
}
while (length > 8) {
register unsigned int tmp asm("r2"), tmp2 asm("r3"), tmp3;
asm volatile(
- "ldr%?h %2, [%0], #4\n\t"
- "ldr%?h %4, [%0], #4\n\t"
- "ldr%?h %3, [%0], #4\n\t"
- "orr%? %2, %2, %4, lsl #16\n\t"
- "ldr%?h %4, [%0], #4\n\t"
- "orr%? %3, %3, %4, lsl #16\n\t"
- "stm%?ia %1!, {%2, %3}"
+ "ldrh %2, [%0], #4\n\t"
+ "ldrh %4, [%0], #4\n\t"
+ "ldrh %3, [%0], #4\n\t"
+ "orr %2, %2, %4, lsl #16\n\t"
+ "ldrh %4, [%0], #4\n\t"
+ "orr %3, %3, %4, lsl #16\n\t"
+ "stmia %1!, {%2, %3}"
: "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
: "0" (offset), "1" (buf));
length -= 8;
@@ -156,10 +156,10 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned
while (length > 0) {
unsigned int tmp;
asm volatile(
- "ldr%?h %2, [%0], #4\n\t"
- "str%?b %2, [%1], #1\n\t"
- "mov%? %2, %2, lsr #8\n\t"
- "str%?b %2, [%1], #1"
+ "ldrh %2, [%0], #4\n\t"
+ "strb %2, [%1], #1\n\t"
+ "mov %2, %2, lsr #8\n\t"
+ "strb %2, [%1], #1"
: "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
length -= 2;
}
diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/lance.c
index 256f590f6bb1..3a7ebfdda57d 100644
--- a/drivers/net/ethernet/amd/lance.c
+++ b/drivers/net/ethernet/amd/lance.c
@@ -547,8 +547,8 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
/* Make certain the data structures used by the LANCE are aligned and DMAble. */
lp = kzalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
- if(lp==NULL)
- return -ENODEV;
+ if (!lp)
+ return -ENOMEM;
if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
dev->ml_priv = lp;
lp->name = chipname;
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index abe1eabc0171..6446af1403f7 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -163,7 +163,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
struct sk_buff *skb = tx_buff->skb;
unsigned int info = le32_to_cpu(txbd->info);
- if ((info & FOR_EMAC) || !txbd->data)
+ if ((info & FOR_EMAC) || !txbd->data || !skb)
break;
if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
@@ -191,6 +191,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
txbd->data = 0;
txbd->info = 0;
+ tx_buff->skb = NULL;
*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
}
@@ -446,6 +447,9 @@ static int arc_emac_open(struct net_device *ndev)
*last_rx_bd = (*last_rx_bd + 1) % RX_BD_NUM;
}
+ priv->txbd_curr = 0;
+ priv->txbd_dirty = 0;
+
/* Clean Tx BD's */
memset(priv->txbd, 0, TX_RING_SZ);
@@ -514,6 +518,64 @@ static void arc_emac_set_rx_mode(struct net_device *ndev)
}
/**
+ * arc_free_tx_queue - free skb from tx queue
+ * @ndev: Pointer to the network device.
+ *
+ * This function must be called while EMAC disable
+ */
+static void arc_free_tx_queue(struct net_device *ndev)
+{
+ struct arc_emac_priv *priv = netdev_priv(ndev);
+ unsigned int i;
+
+ for (i = 0; i < TX_BD_NUM; i++) {
+ struct arc_emac_bd *txbd = &priv->txbd[i];
+ struct buffer_state *tx_buff = &priv->tx_buff[i];
+
+ if (tx_buff->skb) {
+ dma_unmap_single(&ndev->dev, dma_unmap_addr(tx_buff, addr),
+ dma_unmap_len(tx_buff, len), DMA_TO_DEVICE);
+
+ /* return the sk_buff to system */
+ dev_kfree_skb_irq(tx_buff->skb);
+ }
+
+ txbd->info = 0;
+ txbd->data = 0;
+ tx_buff->skb = NULL;
+ }
+}
+
+/**
+ * arc_free_rx_queue - free skb from rx queue
+ * @ndev: Pointer to the network device.
+ *
+ * This function must be called while EMAC disable
+ */
+static void arc_free_rx_queue(struct net_device *ndev)
+{
+ struct arc_emac_priv *priv = netdev_priv(ndev);
+ unsigned int i;
+
+ for (i = 0; i < RX_BD_NUM; i++) {
+ struct arc_emac_bd *rxbd = &priv->rxbd[i];
+ struct buffer_state *rx_buff = &priv->rx_buff[i];
+
+ if (rx_buff->skb) {
+ dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr),
+ dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE);
+
+ /* return the sk_buff to system */
+ dev_kfree_skb_irq(rx_buff->skb);
+ }
+
+ rxbd->info = 0;
+ rxbd->data = 0;
+ rx_buff->skb = NULL;
+ }
+}
+
+/**
* arc_emac_stop - Close the network device.
* @ndev: Pointer to the network device.
*
@@ -534,6 +596,10 @@ static int arc_emac_stop(struct net_device *ndev)
/* Disable EMAC */
arc_reg_clr(priv, R_CTRL, EN_MASK);
+ /* Return the sk_buff to system */
+ arc_free_tx_queue(ndev);
+ arc_free_rx_queue(ndev);
+
return 0;
}
@@ -610,7 +676,6 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
dma_unmap_addr_set(&priv->tx_buff[*txbd_curr], addr, addr);
dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
- priv->tx_buff[*txbd_curr].skb = skb;
priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
/* Make sure pointer to data buffer is set */
@@ -620,6 +685,11 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
+ /* Make sure info word is set */
+ wmb();
+
+ priv->tx_buff[*txbd_curr].skb = skb;
+
/* Increment index to point to the next BD */
*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c
index f71ab2647a3b..08a23e6b60e9 100644
--- a/drivers/net/ethernet/aurora/nb8800.c
+++ b/drivers/net/ethernet/aurora/nb8800.c
@@ -1460,7 +1460,19 @@ static int nb8800_probe(struct platform_device *pdev)
goto err_disable_clk;
}
- priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+ if (of_phy_is_fixed_link(pdev->dev.of_node)) {
+ ret = of_phy_register_fixed_link(pdev->dev.of_node);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "bad fixed-link spec\n");
+ goto err_free_bus;
+ }
+ priv->phy_node = of_node_get(pdev->dev.of_node);
+ }
+
+ if (!priv->phy_node)
+ priv->phy_node = of_parse_phandle(pdev->dev.of_node,
+ "phy-handle", 0);
+
if (!priv->phy_node) {
dev_err(&pdev->dev, "no PHY specified\n");
ret = -ENODEV;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index 27aa0802d87d..91874d24fd56 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -4896,9 +4896,9 @@ struct c2s_pri_trans_table_entry {
* cfc delete event data
*/
struct cfc_del_event_data {
- u32 cid;
- u32 reserved0;
- u32 reserved1;
+ __le32 cid;
+ __le32 reserved0;
+ __le32 reserved1;
};
@@ -5114,15 +5114,9 @@ struct vf_pf_channel_zone_trigger {
* zone that triggers the in-bound interrupt
*/
struct trigger_vf_zone {
-#if defined(__BIG_ENDIAN)
- u16 reserved1;
- u8 reserved0;
- struct vf_pf_channel_zone_trigger vf_pf_channel;
-#elif defined(__LITTLE_ENDIAN)
struct vf_pf_channel_zone_trigger vf_pf_channel;
u8 reserved0;
u16 reserved1;
-#endif
u32 reserved2;
};
@@ -5207,9 +5201,9 @@ struct e2_integ_data {
* set mac event data
*/
struct eth_event_data {
- u32 echo;
- u32 reserved0;
- u32 reserved1;
+ __le32 echo;
+ __le32 reserved0;
+ __le32 reserved1;
};
@@ -5219,9 +5213,9 @@ struct eth_event_data {
struct vf_pf_event_data {
u8 vf_id;
u8 reserved0;
- u16 reserved1;
- u32 msg_addr_lo;
- u32 msg_addr_hi;
+ __le16 reserved1;
+ __le32 msg_addr_lo;
+ __le32 msg_addr_hi;
};
/*
@@ -5230,9 +5224,9 @@ struct vf_pf_event_data {
struct vf_flr_event_data {
u8 vf_id;
u8 reserved0;
- u16 reserved1;
- u32 reserved2;
- u32 reserved3;
+ __le16 reserved1;
+ __le32 reserved2;
+ __le32 reserved3;
};
/*
@@ -5241,9 +5235,9 @@ struct vf_flr_event_data {
struct malicious_vf_event_data {
u8 vf_id;
u8 err_id;
- u16 reserved1;
- u32 reserved2;
- u32 reserved3;
+ __le16 reserved1;
+ __le32 reserved2;
+ __le32 reserved3;
};
/*
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index d946bba43726..1fb80100e5e7 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -6185,26 +6185,80 @@ static int bnx2x_format_ver(u32 num, u8 *str, u16 *len)
shift -= 4;
digit = ((num & mask) >> shift);
if (digit == 0 && remove_leading_zeros) {
- mask = mask >> 4;
- continue;
- } else if (digit < 0xa)
- *str_ptr = digit + '0';
- else
- *str_ptr = digit - 0xa + 'a';
- remove_leading_zeros = 0;
- str_ptr++;
- (*len)--;
+ *str_ptr = '0';
+ } else {
+ if (digit < 0xa)
+ *str_ptr = digit + '0';
+ else
+ *str_ptr = digit - 0xa + 'a';
+
+ remove_leading_zeros = 0;
+ str_ptr++;
+ (*len)--;
+ }
mask = mask >> 4;
if (shift == 4*4) {
+ if (remove_leading_zeros) {
+ str_ptr++;
+ (*len)--;
+ }
*str_ptr = '.';
str_ptr++;
(*len)--;
remove_leading_zeros = 1;
}
}
+ if (remove_leading_zeros)
+ (*len)--;
return 0;
}
+static int bnx2x_3_seq_format_ver(u32 num, u8 *str, u16 *len)
+{
+ u8 *str_ptr = str;
+ u32 mask = 0x00f00000;
+ u8 shift = 8*3;
+ u8 digit;
+ u8 remove_leading_zeros = 1;
+
+ if (*len < 10) {
+ /* Need more than 10chars for this format */
+ *str_ptr = '\0';
+ (*len)--;
+ return -EINVAL;
+ }
+
+ while (shift > 0) {
+ shift -= 4;
+ digit = ((num & mask) >> shift);
+ if (digit == 0 && remove_leading_zeros) {
+ *str_ptr = '0';
+ } else {
+ if (digit < 0xa)
+ *str_ptr = digit + '0';
+ else
+ *str_ptr = digit - 0xa + 'a';
+
+ remove_leading_zeros = 0;
+ str_ptr++;
+ (*len)--;
+ }
+ mask = mask >> 4;
+ if ((shift == 4*4) || (shift == 4*2)) {
+ if (remove_leading_zeros) {
+ str_ptr++;
+ (*len)--;
+ }
+ *str_ptr = '.';
+ str_ptr++;
+ (*len)--;
+ remove_leading_zeros = 1;
+ }
+ }
+ if (remove_leading_zeros)
+ (*len)--;
+ return 0;
+}
static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
{
@@ -9677,8 +9731,9 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
if (bnx2x_is_8483x_8485x(phy)) {
bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1);
- bnx2x_save_spirom_version(bp, port, fw_ver1 & 0xfff,
- phy->ver_addr);
+ if (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858)
+ fw_ver1 &= 0xfff;
+ bnx2x_save_spirom_version(bp, port, fw_ver1, phy->ver_addr);
} else {
/* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
/* (1) set reg 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
@@ -9732,16 +9787,32 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
static void bnx2x_848xx_set_led(struct bnx2x *bp,
struct bnx2x_phy *phy)
{
- u16 val, offset, i;
+ u16 val, led3_blink_rate, offset, i;
static struct bnx2x_reg_set reg_set[] = {
{MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED1_MASK, 0x0080},
{MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED2_MASK, 0x0018},
{MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED3_MASK, 0x0006},
- {MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED3_BLINK, 0x0000},
{MDIO_PMA_DEVAD, MDIO_PMA_REG_84823_CTL_SLOW_CLK_CNT_HIGH,
MDIO_PMA_REG_84823_BLINK_RATE_VAL_15P9HZ},
{MDIO_AN_DEVAD, 0xFFFB, 0xFFFD}
};
+
+ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+ /* Set LED5 source */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED5_MASK,
+ 0x90);
+ led3_blink_rate = 0x000f;
+ } else {
+ led3_blink_rate = 0x0000;
+ }
+ /* Set LED3 BLINK */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_BLINK,
+ led3_blink_rate);
+
/* PHYC_CTL_LED_CTL */
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
@@ -9749,6 +9820,9 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,
val &= 0xFE00;
val |= 0x0092;
+ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858)
+ val |= 2 << 12; /* LED5 ON based on source */
+
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LINK_SIGNAL, val);
@@ -9762,10 +9836,17 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,
else
offset = MDIO_PMA_REG_84823_CTL_LED_CTL_1;
- /* stretch_en for LED3*/
+ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858)
+ val = MDIO_PMA_REG_84858_ALLOW_GPHY_ACT |
+ MDIO_PMA_REG_84823_LED3_STRETCH_EN;
+ else
+ val = MDIO_PMA_REG_84823_LED3_STRETCH_EN;
+
+ /* stretch_en for LEDs */
bnx2x_cl45_read_or_write(bp, phy,
- MDIO_PMA_DEVAD, offset,
- MDIO_PMA_REG_84823_LED3_STRETCH_EN);
+ MDIO_PMA_DEVAD,
+ offset,
+ val);
}
static void bnx2x_848xx_specific_func(struct bnx2x_phy *phy,
@@ -9775,7 +9856,7 @@ static void bnx2x_848xx_specific_func(struct bnx2x_phy *phy,
struct bnx2x *bp = params->bp;
switch (action) {
case PHY_INIT:
- if (!bnx2x_is_8483x_8485x(phy)) {
+ if (bnx2x_is_8483x_8485x(phy)) {
/* Save spirom version */
bnx2x_save_848xx_spirom_version(phy, bp, params->port);
}
@@ -10036,15 +10117,20 @@ static int bnx2x_84858_cmd_hdlr(struct bnx2x_phy *phy,
static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
struct link_params *params, u16 fw_cmd,
- u16 cmd_args[], int argc)
+ u16 cmd_args[], int argc, int process)
{
int idx;
u16 val;
struct bnx2x *bp = params->bp;
- /* Write CMD_OPEN_OVERRIDE to STATUS reg */
- bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
- MDIO_848xx_CMD_HDLR_STATUS,
- PHY84833_STATUS_CMD_OPEN_OVERRIDE);
+ int rc = 0;
+
+ if (process == PHY84833_MB_PROCESS2) {
+ /* Write CMD_OPEN_OVERRIDE to STATUS reg */
+ bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+ MDIO_848xx_CMD_HDLR_STATUS,
+ PHY84833_STATUS_CMD_OPEN_OVERRIDE);
+ }
+
for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) {
bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
MDIO_848xx_CMD_HDLR_STATUS, &val);
@@ -10054,15 +10140,27 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
}
if (idx >= PHY848xx_CMDHDLR_WAIT) {
DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n");
+ /* if the status is CMD_COMPLETE_PASS or CMD_COMPLETE_ERROR
+ * clear the status to CMD_CLEAR_COMPLETE
+ */
+ if (val == PHY84833_STATUS_CMD_COMPLETE_PASS ||
+ val == PHY84833_STATUS_CMD_COMPLETE_ERROR) {
+ bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+ MDIO_848xx_CMD_HDLR_STATUS,
+ PHY84833_STATUS_CMD_CLEAR_COMPLETE);
+ }
return -EINVAL;
}
-
- /* Prepare argument(s) and issue command */
- for (idx = 0; idx < argc; idx++) {
- bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
- MDIO_848xx_CMD_HDLR_DATA1 + idx,
- cmd_args[idx]);
+ if (process == PHY84833_MB_PROCESS1 ||
+ process == PHY84833_MB_PROCESS2) {
+ /* Prepare argument(s) */
+ for (idx = 0; idx < argc; idx++) {
+ bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+ MDIO_848xx_CMD_HDLR_DATA1 + idx,
+ cmd_args[idx]);
+ }
}
+
bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
MDIO_848xx_CMD_HDLR_COMMAND, fw_cmd);
for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) {
@@ -10076,24 +10174,30 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
if ((idx >= PHY848xx_CMDHDLR_WAIT) ||
(val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) {
DP(NETIF_MSG_LINK, "FW cmd failed.\n");
- return -EINVAL;
+ rc = -EINVAL;
}
- /* Gather returning data */
- for (idx = 0; idx < argc; idx++) {
- bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
- MDIO_848xx_CMD_HDLR_DATA1 + idx,
- &cmd_args[idx]);
+ if (process == PHY84833_MB_PROCESS3 && rc == 0) {
+ /* Gather returning data */
+ for (idx = 0; idx < argc; idx++) {
+ bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
+ MDIO_848xx_CMD_HDLR_DATA1 + idx,
+ &cmd_args[idx]);
+ }
}
- bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
- MDIO_848xx_CMD_HDLR_STATUS,
- PHY84833_STATUS_CMD_CLEAR_COMPLETE);
- return 0;
+ if (val == PHY84833_STATUS_CMD_COMPLETE_ERROR ||
+ val == PHY84833_STATUS_CMD_COMPLETE_PASS) {
+ bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+ MDIO_848xx_CMD_HDLR_STATUS,
+ PHY84833_STATUS_CMD_CLEAR_COMPLETE);
+ }
+ return rc;
}
static int bnx2x_848xx_cmd_hdlr(struct bnx2x_phy *phy,
struct link_params *params,
u16 fw_cmd,
- u16 cmd_args[], int argc)
+ u16 cmd_args[], int argc,
+ int process)
{
struct bnx2x *bp = params->bp;
@@ -10106,7 +10210,7 @@ static int bnx2x_848xx_cmd_hdlr(struct bnx2x_phy *phy,
argc);
} else {
return bnx2x_84833_cmd_hdlr(phy, params, fw_cmd, cmd_args,
- argc);
+ argc, process);
}
}
@@ -10133,7 +10237,7 @@ static int bnx2x_848xx_pair_swap_cfg(struct bnx2x_phy *phy,
status = bnx2x_848xx_cmd_hdlr(phy, params,
PHY848xx_CMD_SET_PAIR_SWAP, data,
- PHY848xx_CMDHDLR_MAX_ARGS);
+ 2, PHY84833_MB_PROCESS2);
if (status == 0)
DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data[1]);
@@ -10222,8 +10326,8 @@ static int bnx2x_8483x_disable_eee(struct bnx2x_phy *phy,
DP(NETIF_MSG_LINK, "Don't Advertise 10GBase-T EEE\n");
/* Prevent Phy from working in EEE and advertising it */
- rc = bnx2x_848xx_cmd_hdlr(phy, params,
- PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1);
+ rc = bnx2x_848xx_cmd_hdlr(phy, params, PHY848xx_CMD_SET_EEE_MODE,
+ &cmd_args, 1, PHY84833_MB_PROCESS1);
if (rc) {
DP(NETIF_MSG_LINK, "EEE disable failed.\n");
return rc;
@@ -10240,8 +10344,8 @@ static int bnx2x_8483x_enable_eee(struct bnx2x_phy *phy,
struct bnx2x *bp = params->bp;
u16 cmd_args = 1;
- rc = bnx2x_848xx_cmd_hdlr(phy, params,
- PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1);
+ rc = bnx2x_848xx_cmd_hdlr(phy, params, PHY848xx_CMD_SET_EEE_MODE,
+ &cmd_args, 1, PHY84833_MB_PROCESS1);
if (rc) {
DP(NETIF_MSG_LINK, "EEE enable failed.\n");
return rc;
@@ -10362,7 +10466,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
cmd_args[3] = PHY84833_CONSTANT_LATENCY;
rc = bnx2x_848xx_cmd_hdlr(phy, params,
PHY848xx_CMD_SET_EEE_MODE, cmd_args,
- PHY848xx_CMDHDLR_MAX_ARGS);
+ 4, PHY84833_MB_PROCESS1);
if (rc)
DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n");
}
@@ -10416,6 +10520,32 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
vars->eee_status &= ~SHMEM_EEE_SUPPORTED_MASK;
}
+ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
+ /* Additional settings for jumbo packets in 1000BASE-T mode */
+ /* Allow rx extended length */
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_AUX_CTRL, &val);
+ val |= 0x4000;
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_AUX_CTRL, val);
+ /* TX FIFO Elasticity LSB */
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_1G_100T_EXT_CTRL, &val);
+ val |= 0x1;
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_1G_100T_EXT_CTRL, val);
+ /* TX FIFO Elasticity MSB */
+ /* Enable expansion register 0x46 (Pattern Generator status) */
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf46);
+
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, &val);
+ val |= 0x4000;
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, val);
+ }
+
if (bnx2x_is_8483x_8485x(phy)) {
/* Bring PHY out of super isolate mode as the final step. */
bnx2x_cl45_read_and_write(bp, phy,
@@ -10555,6 +10685,17 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
return link_up;
}
+static int bnx2x_8485x_format_ver(u32 raw_ver, u8 *str, u16 *len)
+{
+ int status = 0;
+ u32 num;
+
+ num = ((raw_ver & 0xF80) >> 7) << 16 | ((raw_ver & 0x7F) << 8) |
+ ((raw_ver & 0xF000) >> 12);
+ status = bnx2x_3_seq_format_ver(num, str, len);
+ return status;
+}
+
static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
{
int status = 0;
@@ -10651,10 +10792,25 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
0x0);
} else {
+ /* LED 1 OFF */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED1_MASK,
0x0);
+
+ if (phy->type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+ /* LED 2 OFF */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED2_MASK,
+ 0x0);
+ /* LED 3 OFF */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_MASK,
+ 0x0);
+ }
}
break;
case LED_MODE_FRONT_PANEL_OFF:
@@ -10713,6 +10869,19 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
MDIO_PMA_REG_8481_SIGNAL_MASK,
0x0);
}
+ if (phy->type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+ /* LED 2 OFF */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED2_MASK,
+ 0x0);
+ /* LED 3 OFF */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_MASK,
+ 0x0);
+ }
}
break;
case LED_MODE_ON:
@@ -10776,6 +10945,25 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
params->port*4,
NIG_MASK_MI_INT);
}
+ }
+ if (phy->type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+ /* Tell LED3 to constant on */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LINK_SIGNAL,
+ &val);
+ val &= ~(7<<6);
+ val |= (2<<6); /* A83B[8:6]= 2 */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LINK_SIGNAL,
+ val);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_MASK,
+ 0x20);
+ } else {
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_SIGNAL_MASK,
@@ -10854,6 +11042,17 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
MDIO_PMA_REG_8481_LINK_SIGNAL,
val);
if (phy->type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED2_MASK,
+ 0x18);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_MASK,
+ 0x06);
+ }
+ if (phy->type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) {
/* Restore LED4 source to external link,
* and re-enable interrupts.
@@ -11982,7 +12181,7 @@ static const struct bnx2x_phy phy_84858 = {
.read_status = (read_status_t)bnx2x_848xx_read_status,
.link_reset = (link_reset_t)bnx2x_848x3_link_reset,
.config_loopback = (config_loopback_t)NULL,
- .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
+ .format_fw_ver = (format_fw_ver_t)bnx2x_8485x_format_ver,
.hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy,
.set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
.phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func
@@ -13807,8 +14006,10 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
if (CHIP_IS_E3(bp)) {
struct bnx2x_phy *phy = &params->phy[INT_PHY];
bnx2x_set_aer_mmd(params, phy);
- if ((phy->supported & SUPPORTED_20000baseKR2_Full) &&
- (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G))
+ if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+ (phy->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)) ||
+ (phy->req_line_speed == SPEED_20000))
bnx2x_check_kr2_wa(params, vars, phy);
bnx2x_check_over_curr(params, vars);
if (vars->rx_tx_asic_rst)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 6c4e3a69976f..2bf9c871144f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -5280,14 +5280,14 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,
{
unsigned long ramrod_flags = 0;
int rc = 0;
- u32 cid = elem->message.data.eth_event.echo & BNX2X_SWCID_MASK;
+ u32 echo = le32_to_cpu(elem->message.data.eth_event.echo);
+ u32 cid = echo & BNX2X_SWCID_MASK;
struct bnx2x_vlan_mac_obj *vlan_mac_obj;
/* Always push next commands out, don't wait here */
__set_bit(RAMROD_CONT, &ramrod_flags);
- switch (le32_to_cpu((__force __le32)elem->message.data.eth_event.echo)
- >> BNX2X_SWCID_SHIFT) {
+ switch (echo >> BNX2X_SWCID_SHIFT) {
case BNX2X_FILTER_MAC_PENDING:
DP(BNX2X_MSG_SP, "Got SETUP_MAC completions\n");
if (CNIC_LOADED(bp) && (cid == BNX2X_ISCSI_ETH_CID(bp)))
@@ -5308,8 +5308,7 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,
bnx2x_handle_mcast_eqe(bp);
return;
default:
- BNX2X_ERR("Unsupported classification command: %d\n",
- elem->message.data.eth_event.echo);
+ BNX2X_ERR("Unsupported classification command: 0x%x\n", echo);
return;
}
@@ -5478,9 +5477,6 @@ static void bnx2x_eq_int(struct bnx2x *bp)
goto next_spqe;
}
- /* elem CID originates from FW; actually LE */
- cid = SW_CID((__force __le32)
- elem->message.data.cfc_del_event.cid);
opcode = elem->message.opcode;
/* handle eq element */
@@ -5503,6 +5499,10 @@ static void bnx2x_eq_int(struct bnx2x *bp)
* we may want to verify here that the bp state is
* HALTING
*/
+
+ /* elem CID originates from FW; actually LE */
+ cid = SW_CID(elem->message.data.cfc_del_event.cid);
+
DP(BNX2X_MSG_SP,
"got delete ramrod for MULTI[%d]\n", cid);
@@ -5596,10 +5596,8 @@ static void bnx2x_eq_int(struct bnx2x *bp)
BNX2X_STATE_OPENING_WAIT4_PORT):
case (EVENT_RING_OPCODE_RSS_UPDATE_RULES |
BNX2X_STATE_CLOSING_WAIT4_HALT):
- cid = elem->message.data.eth_event.echo &
- BNX2X_SWCID_MASK;
DP(BNX2X_MSG_SP, "got RSS_UPDATE ramrod. CID %d\n",
- cid);
+ SW_CID(elem->message.data.eth_event.echo));
rss_raw->clear_pending(rss_raw);
break;
@@ -5684,7 +5682,7 @@ static void bnx2x_sp_task(struct work_struct *work)
if (status & BNX2X_DEF_SB_IDX) {
struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
- if (FCOE_INIT(bp) &&
+ if (FCOE_INIT(bp) &&
(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
/* Prevent local bottom-halves from running as
* we are going to change the local NAPI list.
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
index 4dead49bd5cb..a43dea259b12 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
@@ -7296,6 +7296,8 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_PMA_REG_84823_CTL_LED_CTL_1 0xa8e3
#define MDIO_PMA_REG_84833_CTL_LED_CTL_1 0xa8ec
#define MDIO_PMA_REG_84823_LED3_STRETCH_EN 0x0080
+/* BCM84858 only */
+#define MDIO_PMA_REG_84858_ALLOW_GPHY_ACT 0x8000
/* BCM84833 only */
#define MDIO_84833_TOP_CFG_FW_REV 0x400f
@@ -7337,6 +7339,10 @@ Theotherbitsarereservedandshouldbezero*/
#define PHY84833_STATUS_CMD_NOT_OPEN_FOR_CMDS 0x0040
#define PHY84833_STATUS_CMD_CLEAR_COMPLETE 0x0080
#define PHY84833_STATUS_CMD_OPEN_OVERRIDE 0xa5a5
+/* Mailbox Process */
+#define PHY84833_MB_PROCESS1 1
+#define PHY84833_MB_PROCESS2 2
+#define PHY84833_MB_PROCESS3 3
/* Mailbox status set used by 84858 only */
#define PHY84858_STATUS_CMD_RECEIVED 0x0001
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 9d027348cd09..632daff117d3 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -1672,11 +1672,12 @@ void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,
{
unsigned long ramrod_flags = 0;
int rc = 0;
+ u32 echo = le32_to_cpu(elem->message.data.eth_event.echo);
/* Always push next commands out, don't wait here */
set_bit(RAMROD_CONT, &ramrod_flags);
- switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) {
+ switch (echo >> BNX2X_SWCID_SHIFT) {
case BNX2X_FILTER_MAC_PENDING:
rc = vfq->mac_obj.complete(bp, &vfq->mac_obj, elem,
&ramrod_flags);
@@ -1686,8 +1687,7 @@ void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,
&ramrod_flags);
break;
default:
- BNX2X_ERR("Unsupported classification command: %d\n",
- elem->message.data.eth_event.echo);
+ BNX2X_ERR("Unsupported classification command: 0x%x\n", echo);
return;
}
if (rc < 0)
@@ -1747,16 +1747,14 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
switch (opcode) {
case EVENT_RING_OPCODE_CFC_DEL:
- cid = SW_CID((__force __le32)
- elem->message.data.cfc_del_event.cid);
+ cid = SW_CID(elem->message.data.cfc_del_event.cid);
DP(BNX2X_MSG_IOV, "checking cfc-del comp cid=%d\n", cid);
break;
case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
case EVENT_RING_OPCODE_MULTICAST_RULES:
case EVENT_RING_OPCODE_FILTERS_RULES:
case EVENT_RING_OPCODE_RSS_UPDATE_RULES:
- cid = (elem->message.data.eth_event.echo &
- BNX2X_SWCID_MASK);
+ cid = SW_CID(elem->message.data.eth_event.echo);
DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid);
break;
case EVENT_RING_OPCODE_VF_FLR:
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
index 1374e5394a79..bfae300cf25f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -2187,8 +2187,10 @@ void bnx2x_vf_mbx_schedule(struct bnx2x *bp,
/* Update VFDB with current message and schedule its handling */
mutex_lock(&BP_VFDB(bp)->event_mutex);
- BP_VF_MBX(bp, vf_idx)->vf_addr_hi = vfpf_event->msg_addr_hi;
- BP_VF_MBX(bp, vf_idx)->vf_addr_lo = vfpf_event->msg_addr_lo;
+ BP_VF_MBX(bp, vf_idx)->vf_addr_hi =
+ le32_to_cpu(vfpf_event->msg_addr_hi);
+ BP_VF_MBX(bp, vf_idx)->vf_addr_lo =
+ le32_to_cpu(vfpf_event->msg_addr_lo);
BP_VFDB(bp)->event_occur |= (1ULL << vf_idx);
mutex_unlock(&BP_VFDB(bp)->event_mutex);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 5dc89e527e7d..82f191382989 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -69,7 +69,7 @@ MODULE_VERSION(DRV_MODULE_VERSION);
#define BNXT_RX_DMA_OFFSET NET_SKB_PAD
#define BNXT_RX_COPY_THRESH 256
-#define BNXT_TX_PUSH_THRESH 92
+#define BNXT_TX_PUSH_THRESH 164
enum board_idx {
BCM57301,
@@ -223,11 +223,12 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (free_size == bp->tx_ring_size && length <= bp->tx_push_thresh) {
- struct tx_push_bd *push = txr->tx_push;
- struct tx_bd *tx_push = &push->txbd1;
- struct tx_bd_ext *tx_push1 = &push->txbd2;
- void *pdata = tx_push1 + 1;
- int j;
+ struct tx_push_buffer *tx_push_buf = txr->tx_push;
+ struct tx_push_bd *tx_push = &tx_push_buf->push_bd;
+ struct tx_bd_ext *tx_push1 = &tx_push->txbd2;
+ void *pdata = tx_push_buf->data;
+ u64 *end;
+ int j, push_len;
/* Set COAL_NOW to be ready quickly for the next push */
tx_push->tx_bd_len_flags_type =
@@ -247,6 +248,10 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_push1->tx_bd_cfa_meta = cpu_to_le32(vlan_tag_flags);
tx_push1->tx_bd_cfa_action = cpu_to_le32(cfa_action);
+ end = pdata + length;
+ end = PTR_ALIGN(end, 8) - 1;
+ *end = 0;
+
skb_copy_from_linear_data(skb, pdata, len);
pdata += len;
for (j = 0; j < last_frag; j++) {
@@ -261,22 +266,29 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
pdata += skb_frag_size(frag);
}
- memcpy(txbd, tx_push, sizeof(*txbd));
+ txbd->tx_bd_len_flags_type = tx_push->tx_bd_len_flags_type;
+ txbd->tx_bd_haddr = txr->data_mapping;
prod = NEXT_TX(prod);
txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
memcpy(txbd, tx_push1, sizeof(*txbd));
prod = NEXT_TX(prod);
- push->doorbell =
+ tx_push->doorbell =
cpu_to_le32(DB_KEY_TX_PUSH | DB_LONG_TX_PUSH | prod);
txr->tx_prod = prod;
netdev_tx_sent_queue(txq, skb->len);
- __iowrite64_copy(txr->tx_doorbell, push,
- (length + sizeof(*push) + 8) / 8);
+ push_len = (length + sizeof(*tx_push) + 7) / 8;
+ if (push_len > 16) {
+ __iowrite64_copy(txr->tx_doorbell, tx_push_buf, 16);
+ __iowrite64_copy(txr->tx_doorbell + 4, tx_push_buf + 1,
+ push_len - 16);
+ } else {
+ __iowrite64_copy(txr->tx_doorbell, tx_push_buf,
+ push_len);
+ }
tx_buf->is_push = 1;
-
goto tx_done;
}
@@ -1753,7 +1765,7 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
push_size = L1_CACHE_ALIGN(sizeof(struct tx_push_bd) +
bp->tx_push_thresh);
- if (push_size > 128) {
+ if (push_size > 256) {
push_size = 0;
bp->tx_push_thresh = 0;
}
@@ -1772,7 +1784,6 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
return rc;
if (bp->tx_push_size) {
- struct tx_bd *txbd;
dma_addr_t mapping;
/* One pre-allocated DMA buffer to backup
@@ -1786,13 +1797,11 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
if (!txr->tx_push)
return -ENOMEM;
- txbd = &txr->tx_push->txbd1;
-
mapping = txr->tx_push_mapping +
sizeof(struct tx_push_bd);
- txbd->tx_bd_haddr = cpu_to_le64(mapping);
+ txr->data_mapping = cpu_to_le64(mapping);
- memset(txbd + 1, 0, sizeof(struct tx_bd_ext));
+ memset(txr->tx_push, 0, sizeof(struct tx_push_bd));
}
ring->queue_id = bp->q_info[j].queue_id;
if (i % bp->tx_nr_rings_per_tc == (bp->tx_nr_rings_per_tc - 1))
@@ -4546,20 +4555,18 @@ static int bnxt_update_phy_setting(struct bnxt *bp)
if (!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) &&
link_info->force_pause_setting != link_info->req_flow_ctrl)
update_pause = true;
- if (link_info->req_duplex != link_info->duplex_setting)
- update_link = true;
if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
if (BNXT_AUTO_MODE(link_info->auto_mode))
update_link = true;
if (link_info->req_link_speed != link_info->force_link_speed)
update_link = true;
+ if (link_info->req_duplex != link_info->duplex_setting)
+ update_link = true;
} else {
if (link_info->auto_mode == BNXT_LINK_AUTO_NONE)
update_link = true;
if (link_info->advertising != link_info->auto_link_speeds)
update_link = true;
- if (link_info->req_link_speed != link_info->auto_link_speed)
- update_link = true;
}
if (update_link)
@@ -4636,7 +4643,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
if (link_re_init) {
rc = bnxt_update_phy_setting(bp);
if (rc)
- goto open_err;
+ netdev_warn(bp->dev, "failed to update phy settings\n");
}
if (irq_re_init) {
@@ -4654,6 +4661,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
/* Enable TX queues */
bnxt_tx_enable(bp);
mod_timer(&bp->timer, jiffies + bp->current_interval);
+ bnxt_update_link(bp, true);
return 0;
@@ -5670,22 +5678,16 @@ static int bnxt_probe_phy(struct bnxt *bp)
}
/*initialize the ethool setting copy with NVM settings */
- if (BNXT_AUTO_MODE(link_info->auto_mode))
- link_info->autoneg |= BNXT_AUTONEG_SPEED;
-
- if (link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) {
- if (link_info->auto_pause_setting == BNXT_LINK_PAUSE_BOTH)
- link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
+ if (BNXT_AUTO_MODE(link_info->auto_mode)) {
+ link_info->autoneg = BNXT_AUTONEG_SPEED |
+ BNXT_AUTONEG_FLOW_CTRL;
+ link_info->advertising = link_info->auto_link_speeds;
link_info->req_flow_ctrl = link_info->auto_pause_setting;
- } else if (link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) {
+ } else {
+ link_info->req_link_speed = link_info->force_link_speed;
+ link_info->req_duplex = link_info->duplex_setting;
link_info->req_flow_ctrl = link_info->force_pause_setting;
}
- link_info->req_duplex = link_info->duplex_setting;
- if (link_info->autoneg & BNXT_AUTONEG_SPEED)
- link_info->req_link_speed = link_info->auto_link_speed;
- else
- link_info->req_link_speed = link_info->force_link_speed;
- link_info->advertising = link_info->auto_link_speeds;
snprintf(phy_ver, PHY_VER_STR_LEN, " ph %d.%d.%d",
link_info->phy_ver[0],
link_info->phy_ver[1],
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 8af3ca8efcef..2be51b332652 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -411,8 +411,8 @@ struct rx_tpa_end_cmp_ext {
#define BNXT_NUM_TESTS(bp) 0
-#define BNXT_DEFAULT_RX_RING_SIZE 1023
-#define BNXT_DEFAULT_TX_RING_SIZE 512
+#define BNXT_DEFAULT_RX_RING_SIZE 511
+#define BNXT_DEFAULT_TX_RING_SIZE 511
#define MAX_TPA 64
@@ -523,10 +523,16 @@ struct bnxt_ring_struct {
struct tx_push_bd {
__le32 doorbell;
- struct tx_bd txbd1;
+ __le32 tx_bd_len_flags_type;
+ u32 tx_bd_opaque;
struct tx_bd_ext txbd2;
};
+struct tx_push_buffer {
+ struct tx_push_bd push_bd;
+ u32 data[25];
+};
+
struct bnxt_tx_ring_info {
struct bnxt_napi *bnapi;
u16 tx_prod;
@@ -538,8 +544,9 @@ struct bnxt_tx_ring_info {
dma_addr_t tx_desc_mapping[MAX_TX_PAGES];
- struct tx_push_bd *tx_push;
+ struct tx_push_buffer *tx_push;
dma_addr_t tx_push_mapping;
+ __le64 data_mapping;
#define BNXT_DEV_STATE_CLOSING 0x1
u32 dev_state;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index 922b898e7a32..3238817dfd5f 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -486,15 +486,8 @@ static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info)
speed_mask |= SUPPORTED_2500baseX_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
speed_mask |= SUPPORTED_10000baseT_Full;
- /* TODO: support 25GB, 50GB with different cable type */
- if (fw_speeds & BNXT_LINK_SPEED_MSK_20GB)
- speed_mask |= SUPPORTED_20000baseMLD2_Full |
- SUPPORTED_20000baseKR2_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
- speed_mask |= SUPPORTED_40000baseKR4_Full |
- SUPPORTED_40000baseCR4_Full |
- SUPPORTED_40000baseSR4_Full |
- SUPPORTED_40000baseLR4_Full;
+ speed_mask |= SUPPORTED_40000baseCR4_Full;
return speed_mask;
}
@@ -514,15 +507,8 @@ static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info)
speed_mask |= ADVERTISED_2500baseX_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
speed_mask |= ADVERTISED_10000baseT_Full;
- /* TODO: how to advertise 20, 25, 40, 50GB with different cable type ?*/
- if (fw_speeds & BNXT_LINK_SPEED_MSK_20GB)
- speed_mask |= ADVERTISED_20000baseMLD2_Full |
- ADVERTISED_20000baseKR2_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
- speed_mask |= ADVERTISED_40000baseKR4_Full |
- ADVERTISED_40000baseCR4_Full |
- ADVERTISED_40000baseSR4_Full |
- ADVERTISED_40000baseLR4_Full;
+ speed_mask |= ADVERTISED_40000baseCR4_Full;
return speed_mask;
}
@@ -557,11 +543,12 @@ static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
u16 ethtool_speed;
cmd->supported = bnxt_fw_to_ethtool_support_spds(link_info);
+ cmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
if (link_info->auto_link_speeds)
cmd->supported |= SUPPORTED_Autoneg;
- if (BNXT_AUTO_MODE(link_info->auto_mode)) {
+ if (link_info->autoneg) {
cmd->advertising =
bnxt_fw_to_ethtool_advertised_spds(link_info);
cmd->advertising |= ADVERTISED_Autoneg;
@@ -570,28 +557,16 @@ static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->autoneg = AUTONEG_DISABLE;
cmd->advertising = 0;
}
- if (link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) {
+ if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) {
if ((link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) ==
BNXT_LINK_PAUSE_BOTH) {
cmd->advertising |= ADVERTISED_Pause;
- cmd->supported |= SUPPORTED_Pause;
} else {
cmd->advertising |= ADVERTISED_Asym_Pause;
- cmd->supported |= SUPPORTED_Asym_Pause;
if (link_info->auto_pause_setting &
BNXT_LINK_PAUSE_RX)
cmd->advertising |= ADVERTISED_Pause;
}
- } else if (link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) {
- if ((link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) ==
- BNXT_LINK_PAUSE_BOTH) {
- cmd->supported |= SUPPORTED_Pause;
- } else {
- cmd->supported |= SUPPORTED_Asym_Pause;
- if (link_info->force_pause_setting &
- BNXT_LINK_PAUSE_RX)
- cmd->supported |= SUPPORTED_Pause;
- }
}
cmd->port = PORT_NONE;
@@ -670,6 +645,9 @@ static u16 bnxt_get_fw_auto_link_speeds(u32 advertising)
if (advertising & ADVERTISED_10000baseT_Full)
fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB;
+ if (advertising & ADVERTISED_40000baseCR4_Full)
+ fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB;
+
return fw_speed_mask;
}
@@ -729,7 +707,7 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
speed = ethtool_cmd_speed(cmd);
link_info->req_link_speed = bnxt_get_fw_speed(dev, speed);
link_info->req_duplex = BNXT_LINK_DUPLEX_FULL;
- link_info->autoneg &= ~BNXT_AUTONEG_SPEED;
+ link_info->autoneg = 0;
link_info->advertising = 0;
}
@@ -748,8 +726,7 @@ static void bnxt_get_pauseparam(struct net_device *dev,
if (BNXT_VF(bp))
return;
- epause->autoneg = !!(link_info->auto_pause_setting &
- BNXT_LINK_PAUSE_BOTH);
+ epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL);
epause->rx_pause = ((link_info->pause & BNXT_LINK_PAUSE_RX) != 0);
epause->tx_pause = ((link_info->pause & BNXT_LINK_PAUSE_TX) != 0);
}
@@ -765,6 +742,9 @@ static int bnxt_set_pauseparam(struct net_device *dev,
return rc;
if (epause->autoneg) {
+ if (!(link_info->autoneg & BNXT_AUTONEG_SPEED))
+ return -EINVAL;
+
link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_BOTH;
} else {
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index b15a60d787c7..d7e01a74e927 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2445,8 +2445,7 @@ static void bcmgenet_irq_task(struct work_struct *work)
}
/* Link UP/DOWN event */
- if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
- (priv->irq0_stat & UMAC_IRQ_LINK_EVENT)) {
+ if (priv->irq0_stat & UMAC_IRQ_LINK_EVENT) {
phy_mac_interrupt(priv->phydev,
!!(priv->irq0_stat & UMAC_IRQ_LINK_UP));
priv->irq0_stat &= ~UMAC_IRQ_LINK_EVENT;
diff --git a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
index 04b0d16b210e..95bc470ae441 100644
--- a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
+++ b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
@@ -987,7 +987,7 @@ bna_rxf_ucast_cfg_apply(struct bna_rxf *rxf)
if (!list_empty(&rxf->ucast_pending_add_q)) {
mac = list_first_entry(&rxf->ucast_pending_add_q,
struct bna_mac, qe);
- list_add_tail(&mac->qe, &rxf->ucast_active_q);
+ list_move_tail(&mac->qe, &rxf->ucast_active_q);
bna_bfi_ucast_req(rxf, mac, BFI_ENET_H2I_MAC_UCAST_ADD_REQ);
return 1;
}
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index 872765527081..34d269cd5579 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -1683,7 +1683,7 @@ static int octeon_setup_droq(struct octeon_device *oct, int q_no, int num_descs,
dev_dbg(&oct->pci_dev->dev, "Creating Droq: %d\n", q_no);
/* droq creation and local register settings. */
ret_val = octeon_create_droq(oct, q_no, num_descs, desc_size, app_ctx);
- if (ret_val == -1)
+ if (ret_val < 0)
return ret_val;
if (ret_val == 1) {
@@ -2524,7 +2524,7 @@ static void handle_timestamp(struct octeon_device *oct,
octeon_swap_8B_data(&resp->timestamp, 1);
- if (unlikely((skb_shinfo(skb)->tx_flags | SKBTX_IN_PROGRESS) != 0)) {
+ if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) != 0)) {
struct skb_shared_hwtstamps ts;
u64 ns = resp->timestamp;
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
index 4dba86eaa045..174072b3740b 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
@@ -983,5 +983,5 @@ int octeon_create_droq(struct octeon_device *oct,
create_droq_fail:
octeon_delete_droq(oct, q_no);
- return -1;
+ return -ENOMEM;
}
diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
index 688828865c48..34e9acea8747 100644
--- a/drivers/net/ethernet/cavium/thunder/nic.h
+++ b/drivers/net/ethernet/cavium/thunder/nic.h
@@ -116,6 +116,15 @@
#define NIC_PF_INTR_ID_MBOX0 8
#define NIC_PF_INTR_ID_MBOX1 9
+/* Minimum FIFO level before all packets for the CQ are dropped
+ *
+ * This value ensures that once a packet has been "accepted"
+ * for reception it will not get dropped due to non-availability
+ * of CQ descriptor. An errata in HW mandates this value to be
+ * atleast 0x100.
+ */
+#define NICPF_CQM_MIN_DROP_LEVEL 0x100
+
/* Global timer for CQ timer thresh interrupts
* Calculated for SCLK of 700Mhz
* value written should be a 1/16th of what is expected
diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
index 4dded90076c8..95f17f8cadac 100644
--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -304,6 +304,7 @@ static void nic_set_lmac_vf_mapping(struct nicpf *nic)
static void nic_init_hw(struct nicpf *nic)
{
int i;
+ u64 cqm_cfg;
/* Enable NIC HW block */
nic_reg_write(nic, NIC_PF_CFG, 0x3);
@@ -340,6 +341,11 @@ static void nic_init_hw(struct nicpf *nic)
/* Enable VLAN ethertype matching and stripping */
nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7,
(2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q);
+
+ /* Check if HW expected value is higher (could be in future chips) */
+ cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG);
+ if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL)
+ nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL);
}
/* Channel parse index configuration */
diff --git a/drivers/net/ethernet/cavium/thunder/nic_reg.h b/drivers/net/ethernet/cavium/thunder/nic_reg.h
index dd536be20193..afb10e326b4f 100644
--- a/drivers/net/ethernet/cavium/thunder/nic_reg.h
+++ b/drivers/net/ethernet/cavium/thunder/nic_reg.h
@@ -21,7 +21,7 @@
#define NIC_PF_TCP_TIMER (0x0060)
#define NIC_PF_BP_CFG (0x0080)
#define NIC_PF_RRM_CFG (0x0088)
-#define NIC_PF_CQM_CF (0x00A0)
+#define NIC_PF_CQM_CFG (0x00A0)
#define NIC_PF_CNM_CF (0x00A8)
#define NIC_PF_CNM_STATUS (0x00B0)
#define NIC_PF_CQ_AVG_CFG (0x00C0)
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
index c24cb2a86a42..a009bc30dc4d 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -574,8 +574,7 @@ static inline void nicvf_set_rxhash(struct net_device *netdev,
static void nicvf_rcv_pkt_handler(struct net_device *netdev,
struct napi_struct *napi,
- struct cmp_queue *cq,
- struct cqe_rx_t *cqe_rx, int cqe_type)
+ struct cqe_rx_t *cqe_rx)
{
struct sk_buff *skb;
struct nicvf *nic = netdev_priv(netdev);
@@ -591,7 +590,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
}
/* Check for errors */
- err = nicvf_check_cqe_rx_errs(nic, cq, cqe_rx);
+ err = nicvf_check_cqe_rx_errs(nic, cqe_rx);
if (err && !cqe_rx->rb_cnt)
return;
@@ -682,8 +681,7 @@ loop:
cq_idx, cq_desc->cqe_type);
switch (cq_desc->cqe_type) {
case CQE_TYPE_RX:
- nicvf_rcv_pkt_handler(netdev, napi, cq,
- cq_desc, CQE_TYPE_RX);
+ nicvf_rcv_pkt_handler(netdev, napi, cq_desc);
work_done++;
break;
case CQE_TYPE_SEND:
@@ -1125,7 +1123,6 @@ int nicvf_stop(struct net_device *netdev)
/* Clear multiqset info */
nic->pnicvf = nic;
- nic->sqs_count = 0;
return 0;
}
@@ -1354,6 +1351,9 @@ void nicvf_update_stats(struct nicvf *nic)
drv_stats->tx_frames_ok = stats->tx_ucast_frames_ok +
stats->tx_bcast_frames_ok +
stats->tx_mcast_frames_ok;
+ drv_stats->rx_frames_ok = stats->rx_ucast_frames +
+ stats->rx_bcast_frames +
+ stats->rx_mcast_frames;
drv_stats->rx_drops = stats->rx_drop_red +
stats->rx_drop_overrun;
drv_stats->tx_drops = stats->tx_drops;
@@ -1538,6 +1538,9 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
nicvf_send_vf_struct(nic);
+ if (!pass1_silicon(nic->pdev))
+ nic->hw_tso = true;
+
/* Check if this VF is in QS only mode */
if (nic->sqs_mode)
return 0;
@@ -1557,9 +1560,6 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
- if (!pass1_silicon(nic->pdev))
- nic->hw_tso = true;
-
netdev->netdev_ops = &nicvf_netdev_ops;
netdev->watchdog_timeo = NICVF_TX_TIMEOUT;
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
index d0d1b5490061..767347b1f631 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
@@ -1329,16 +1329,12 @@ void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx)
}
/* Check for errors in the receive cmp.queue entry */
-int nicvf_check_cqe_rx_errs(struct nicvf *nic,
- struct cmp_queue *cq, struct cqe_rx_t *cqe_rx)
+int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
{
struct nicvf_hw_stats *stats = &nic->hw_stats;
- struct nicvf_drv_stats *drv_stats = &nic->drv_stats;
- if (!cqe_rx->err_level && !cqe_rx->err_opcode) {
- drv_stats->rx_frames_ok++;
+ if (!cqe_rx->err_level && !cqe_rx->err_opcode)
return 0;
- }
if (netif_msg_rx_err(nic))
netdev_err(nic->netdev,
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
index c5030a7f213a..6673e1133523 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
@@ -338,8 +338,7 @@ u64 nicvf_queue_reg_read(struct nicvf *nic,
/* Stats */
void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx);
void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx);
-int nicvf_check_cqe_rx_errs(struct nicvf *nic,
- struct cmp_queue *cq, struct cqe_rx_t *cqe_rx);
+int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx);
int nicvf_check_cqe_tx_errs(struct nicvf *nic,
struct cmp_queue *cq, struct cqe_send_t *cqe_tx);
#endif /* NICVF_QUEUES_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
index ee04caa6c4d8..a89721fad633 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
@@ -681,6 +681,24 @@ int t3_seeprom_wp(struct adapter *adapter, int enable)
return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
}
+static int vpdstrtouint(char *s, int len, unsigned int base, unsigned int *val)
+{
+ char tok[len + 1];
+
+ memcpy(tok, s, len);
+ tok[len] = 0;
+ return kstrtouint(strim(tok), base, val);
+}
+
+static int vpdstrtou16(char *s, int len, unsigned int base, u16 *val)
+{
+ char tok[len + 1];
+
+ memcpy(tok, s, len);
+ tok[len] = 0;
+ return kstrtou16(strim(tok), base, val);
+}
+
/**
* get_vpd_params - read VPD parameters from VPD EEPROM
* @adapter: adapter to read
@@ -709,19 +727,19 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
return ret;
}
- ret = kstrtouint(vpd.cclk_data, 10, &p->cclk);
+ ret = vpdstrtouint(vpd.cclk_data, vpd.cclk_len, 10, &p->cclk);
if (ret)
return ret;
- ret = kstrtouint(vpd.mclk_data, 10, &p->mclk);
+ ret = vpdstrtouint(vpd.mclk_data, vpd.mclk_len, 10, &p->mclk);
if (ret)
return ret;
- ret = kstrtouint(vpd.uclk_data, 10, &p->uclk);
+ ret = vpdstrtouint(vpd.uclk_data, vpd.uclk_len, 10, &p->uclk);
if (ret)
return ret;
- ret = kstrtouint(vpd.mdc_data, 10, &p->mdc);
+ ret = vpdstrtouint(vpd.mdc_data, vpd.mdc_len, 10, &p->mdc);
if (ret)
return ret;
- ret = kstrtouint(vpd.mt_data, 10, &p->mem_timing);
+ ret = vpdstrtouint(vpd.mt_data, vpd.mt_len, 10, &p->mem_timing);
if (ret)
return ret;
memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
@@ -733,10 +751,12 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
} else {
p->port_type[0] = hex_to_bin(vpd.port0_data[0]);
p->port_type[1] = hex_to_bin(vpd.port1_data[0]);
- ret = kstrtou16(vpd.xaui0cfg_data, 16, &p->xauicfg[0]);
+ ret = vpdstrtou16(vpd.xaui0cfg_data, vpd.xaui0cfg_len, 16,
+ &p->xauicfg[0]);
if (ret)
return ret;
- ret = kstrtou16(vpd.xaui1cfg_data, 16, &p->xauicfg[1]);
+ ret = vpdstrtou16(vpd.xaui1cfg_data, vpd.xaui1cfg_len, 16,
+ &p->xauicfg[1]);
if (ret)
return ret;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
index a8dda635456d..06bc2d2e7a73 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
@@ -165,6 +165,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN
CH_PCI_ID_TABLE_FENTRY(0x5098), /* Custom 2x40G QSFP */
CH_PCI_ID_TABLE_FENTRY(0x5099), /* Custom 2x40G QSFP */
CH_PCI_ID_TABLE_FENTRY(0x509a), /* Custom T520-CR */
+ CH_PCI_ID_TABLE_FENTRY(0x509b), /* Custom T540-CR LOM */
/* T6 adapters:
*/
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index cf94b72dbacd..48d91941408d 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -128,7 +128,6 @@ struct board_info {
struct resource *data_res;
struct resource *addr_req; /* resources requested */
struct resource *data_req;
- struct resource *irq_res;
int irq_wake;
@@ -1300,22 +1299,16 @@ static int
dm9000_open(struct net_device *dev)
{
struct board_info *db = netdev_priv(dev);
- unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
if (netif_msg_ifup(db))
dev_dbg(db->dev, "enabling %s\n", dev->name);
- /* If there is no IRQ type specified, default to something that
- * may work, and tell the user that this is a problem */
-
- if (irqflags == IRQF_TRIGGER_NONE)
- irqflags = irq_get_trigger_type(dev->irq);
-
- if (irqflags == IRQF_TRIGGER_NONE)
+ /* If there is no IRQ type specified, tell the user that this is a
+ * problem
+ */
+ if (irq_get_trigger_type(dev->irq) == IRQF_TRIGGER_NONE)
dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
- irqflags |= IRQF_SHARED;
-
/* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
mdelay(1); /* delay needs by DM9000B */
@@ -1323,7 +1316,8 @@ dm9000_open(struct net_device *dev)
/* Initialize DM9000 board */
dm9000_init_dm9000(dev);
- if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
+ if (request_irq(dev->irq, dm9000_interrupt, IRQF_SHARED,
+ dev->name, dev))
return -EAGAIN;
/* Now that we have an interrupt handler hooked up we can unmask
* our interrupts
@@ -1500,15 +1494,22 @@ dm9000_probe(struct platform_device *pdev)
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (db->addr_res == NULL || db->data_res == NULL ||
- db->irq_res == NULL) {
- dev_err(db->dev, "insufficient resources\n");
+ if (!db->addr_res || !db->data_res) {
+ dev_err(db->dev, "insufficient resources addr=%p data=%p\n",
+ db->addr_res, db->data_res);
ret = -ENOENT;
goto out;
}
+ ndev->irq = platform_get_irq(pdev, 0);
+ if (ndev->irq < 0) {
+ dev_err(db->dev, "interrupt resource unavailable: %d\n",
+ ndev->irq);
+ ret = ndev->irq;
+ goto out;
+ }
+
db->irq_wake = platform_get_irq(pdev, 1);
if (db->irq_wake >= 0) {
dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
@@ -1570,7 +1571,6 @@ dm9000_probe(struct platform_device *pdev)
/* fill in parameters for net-dev structure */
ndev->base_addr = (unsigned long)db->io_addr;
- ndev->irq = db->irq_res->start;
/* ensure at least we have a default set of IO routines */
dm9000_set_io(db, iosize);
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index cf837831304b..f9751294ece7 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -531,6 +531,7 @@ struct be_adapter {
struct delayed_work be_err_detection_work;
u8 err_flags;
+ bool pcicfg_mapped; /* pcicfg obtained via pci_iomap() */
u32 flags;
u32 cmd_privileges;
/* Ethtool knobs and info */
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 241819b36ca7..6d9a8d78e8ad 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -622,10 +622,13 @@ enum be_if_flags {
BE_IF_FLAGS_VLAN_PROMISCUOUS |\
BE_IF_FLAGS_MCAST_PROMISCUOUS)
-#define BE_IF_EN_FLAGS (BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |\
- BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_UNTAGGED)
+#define BE_IF_FILT_FLAGS_BASIC (BE_IF_FLAGS_BROADCAST | \
+ BE_IF_FLAGS_PASS_L3L4_ERRORS | \
+ BE_IF_FLAGS_UNTAGGED)
-#define BE_IF_ALL_FILT_FLAGS (BE_IF_EN_FLAGS | BE_IF_FLAGS_ALL_PROMISCUOUS)
+#define BE_IF_ALL_FILT_FLAGS (BE_IF_FILT_FLAGS_BASIC | \
+ BE_IF_FLAGS_MULTICAST | \
+ BE_IF_FLAGS_ALL_PROMISCUOUS)
/* An RX interface is an object with one or more MAC addresses and
* filtering capabilities. */
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index f99de3657ce3..d1cf1274fc2f 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -125,6 +125,11 @@ static const char * const ue_status_hi_desc[] = {
"Unknown"
};
+#define BE_VF_IF_EN_FLAGS (BE_IF_FLAGS_UNTAGGED | \
+ BE_IF_FLAGS_BROADCAST | \
+ BE_IF_FLAGS_MULTICAST | \
+ BE_IF_FLAGS_PASS_L3L4_ERRORS)
+
static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
{
struct be_dma_mem *mem = &q->dma_mem;
@@ -3537,7 +3542,7 @@ static int be_enable_if_filters(struct be_adapter *adapter)
{
int status;
- status = be_cmd_rx_filter(adapter, BE_IF_EN_FLAGS, ON);
+ status = be_cmd_rx_filter(adapter, BE_IF_FILT_FLAGS_BASIC, ON);
if (status)
return status;
@@ -3857,8 +3862,7 @@ static int be_vfs_if_create(struct be_adapter *adapter)
int status;
/* If a FW profile exists, then cap_flags are updated */
- cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
- BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
+ cap_flags = BE_VF_IF_EN_FLAGS;
for_all_vfs(adapter, vf_cfg, vf) {
if (!BE3_chip(adapter)) {
@@ -3874,10 +3878,8 @@ static int be_vfs_if_create(struct be_adapter *adapter)
}
}
- en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
- BE_IF_FLAGS_BROADCAST |
- BE_IF_FLAGS_MULTICAST |
- BE_IF_FLAGS_PASS_L3L4_ERRORS);
+ /* PF should enable IF flags during proxy if_create call */
+ en_flags = cap_flags & BE_VF_IF_EN_FLAGS;
status = be_cmd_if_create(adapter, cap_flags, en_flags,
&vf_cfg->if_handle, vf + 1);
if (status)
@@ -4968,6 +4970,8 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
pci_iounmap(adapter->pdev, adapter->csr);
if (adapter->db)
pci_iounmap(adapter->pdev, adapter->db);
+ if (adapter->pcicfg && adapter->pcicfg_mapped)
+ pci_iounmap(adapter->pdev, adapter->pcicfg);
}
static int db_bar(struct be_adapter *adapter)
@@ -5019,8 +5023,10 @@ static int be_map_pci_bars(struct be_adapter *adapter)
if (!addr)
goto pci_map_err;
adapter->pcicfg = addr;
+ adapter->pcicfg_mapped = true;
} else {
adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
+ adapter->pcicfg_mapped = false;
}
}
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index 62fa136554ac..41b010645100 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -1265,7 +1265,6 @@ static int ethoc_remove(struct platform_device *pdev)
if (priv->mdio) {
mdiobus_unregister(priv->mdio);
- kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
}
if (priv->clk)
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
index 623aa1c8ebc6..79a210aaf0bb 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -2791,6 +2791,8 @@ static struct fman *read_dts_node(struct platform_device *of_dev)
goto fman_free;
}
+ fman->dev = &of_dev->dev;
+
return fman;
fman_node_put:
@@ -2845,8 +2847,6 @@ static int fman_probe(struct platform_device *of_dev)
dev_set_drvdata(dev, fman);
- fman->dev = dev;
-
dev_dbg(dev, "FMan%d probed\n", fman->dts_params.id);
return 0;
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 2aa7b401cc3b..b9ecf197ad11 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -1111,8 +1111,10 @@ static void __gfar_detect_errata_85xx(struct gfar_private *priv)
if ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) == 0x20))
priv->errata |= GFAR_ERRATA_12;
+ /* P2020/P1010 Rev 1; MPC8548 Rev 2 */
if (((SVR_SOC_VER(svr) == SVR_P2020) && (SVR_REV(svr) < 0x20)) ||
- ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)))
+ ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)) ||
+ ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) < 0x31)))
priv->errata |= GFAR_ERRATA_76; /* aka eTSEC 20 */
}
#endif
diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
index a7139f588ad2..678f5018d0be 100644
--- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
@@ -469,8 +469,8 @@ static int fmvj18x_config(struct pcmcia_device *link)
goto failed;
}
/* Read MACID from CIS */
- for (i = 5; i < 11; i++)
- dev->dev_addr[i] = buf[i];
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = buf[i + 5];
kfree(buf);
} else {
if (pcmcia_get_mac_from_cis(link, dev))
diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig
index 74beb1867230..4ccc032633c4 100644
--- a/drivers/net/ethernet/hisilicon/Kconfig
+++ b/drivers/net/ethernet/hisilicon/Kconfig
@@ -25,6 +25,7 @@ config HIX5HD2_GMAC
config HIP04_ETH
tristate "HISILICON P04 Ethernet support"
+ depends on HAS_IOMEM # For MFD_SYSCON
select MARVELL_PHY
select MFD_SYSCON
select HNS_MDIO
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index a0070d0e740d..d4f92ed322d6 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -675,8 +675,12 @@ static int hns_ae_config_loopback(struct hnae_handle *handle,
{
int ret;
struct hnae_vf_cb *vf_cb = hns_ae_get_vf_cb(handle);
+ struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle);
switch (loop) {
+ case MAC_INTERNALLOOP_PHY:
+ ret = 0;
+ break;
case MAC_INTERNALLOOP_SERDES:
ret = hns_mac_config_sds_loopback(vf_cb->mac_cb, en);
break;
@@ -686,6 +690,10 @@ static int hns_ae_config_loopback(struct hnae_handle *handle,
default:
ret = -EINVAL;
}
+
+ if (!ret)
+ hns_dsaf_set_inner_lb(mac_cb->dsaf_dev, mac_cb->mac_id, en);
+
return ret;
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
index 9439f04962e1..38fc5be3870c 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
@@ -230,6 +230,30 @@ static void hns_dsaf_mix_def_qid_cfg(struct dsaf_device *dsaf_dev)
}
}
+static void hns_dsaf_inner_qid_cfg(struct dsaf_device *dsaf_dev)
+{
+ u16 max_q_per_vf, max_vfn;
+ u32 q_id, q_num_per_port;
+ u32 mac_id;
+
+ if (AE_IS_VER1(dsaf_dev->dsaf_ver))
+ return;
+
+ hns_rcb_get_queue_mode(dsaf_dev->dsaf_mode,
+ HNS_DSAF_COMM_SERVICE_NW_IDX,
+ &max_vfn, &max_q_per_vf);
+ q_num_per_port = max_vfn * max_q_per_vf;
+
+ for (mac_id = 0, q_id = 0; mac_id < DSAF_SERVICE_NW_NUM; mac_id++) {
+ dsaf_set_dev_field(dsaf_dev,
+ DSAFV2_SERDES_LBK_0_REG + 4 * mac_id,
+ DSAFV2_SERDES_LBK_QID_M,
+ DSAFV2_SERDES_LBK_QID_S,
+ q_id);
+ q_id += q_num_per_port;
+ }
+}
+
/**
* hns_dsaf_sw_port_type_cfg - cfg sw type
* @dsaf_id: dsa fabric id
@@ -691,6 +715,16 @@ void hns_dsaf_set_promisc_mode(struct dsaf_device *dsaf_dev, u32 en)
dsaf_set_dev_bit(dsaf_dev, DSAF_CFG_0_REG, DSAF_CFG_MIX_MODE_S, !!en);
}
+void hns_dsaf_set_inner_lb(struct dsaf_device *dsaf_dev, u32 mac_id, u32 en)
+{
+ if (AE_IS_VER1(dsaf_dev->dsaf_ver) ||
+ dsaf_dev->mac_cb[mac_id].mac_type == HNAE_PORT_DEBUG)
+ return;
+
+ dsaf_set_dev_bit(dsaf_dev, DSAFV2_SERDES_LBK_0_REG + 4 * mac_id,
+ DSAFV2_SERDES_LBK_EN_B, !!en);
+}
+
/**
* hns_dsaf_tbl_stat_en - tbl
* @dsaf_id: dsa fabric id
@@ -1022,6 +1056,9 @@ static void hns_dsaf_comm_init(struct dsaf_device *dsaf_dev)
/* set promisc def queue id */
hns_dsaf_mix_def_qid_cfg(dsaf_dev);
+ /* set inner loopback queue id */
+ hns_dsaf_inner_qid_cfg(dsaf_dev);
+
/* in non switch mode, set all port to access mode */
hns_dsaf_sw_port_type_cfg(dsaf_dev, DSAF_SW_PORT_TYPE_NON_VLAN);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
index 40205b910f80..5fea226efaf3 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
@@ -417,5 +417,6 @@ void hns_dsaf_get_strings(int stringset, u8 *data, int port);
void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data);
int hns_dsaf_get_regs_count(void);
void hns_dsaf_set_promisc_mode(struct dsaf_device *dsaf_dev, u32 en);
+void hns_dsaf_set_inner_lb(struct dsaf_device *dsaf_dev, u32 mac_id, u32 en);
#endif /* __HNS_DSAF_MAIN_H__ */
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
index f0c4f9b09d5b..60d695daa471 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
@@ -134,6 +134,7 @@
#define DSAF_XGE_INT_STS_0_REG 0x1C0
#define DSAF_PPE_INT_STS_0_REG 0x1E0
#define DSAF_ROCEE_INT_STS_0_REG 0x200
+#define DSAFV2_SERDES_LBK_0_REG 0x220
#define DSAF_PPE_QID_CFG_0_REG 0x300
#define DSAF_SW_PORT_TYPE_0_REG 0x320
#define DSAF_STP_PORT_TYPE_0_REG 0x340
@@ -857,6 +858,10 @@
#define PPEV2_CFG_RSS_TBL_4N3_S 24
#define PPEV2_CFG_RSS_TBL_4N3_M (((1UL << 5) - 1) << PPEV2_CFG_RSS_TBL_4N3_S)
+#define DSAFV2_SERDES_LBK_EN_B 8
+#define DSAFV2_SERDES_LBK_QID_S 0
+#define DSAFV2_SERDES_LBK_QID_M (((1UL << 8) - 1) << DSAFV2_SERDES_LBK_QID_S)
+
#define PPE_CNT_CLR_CE_B 0
#define PPE_CNT_CLR_SNAP_EN_B 1
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index 3df22840fcd1..3c4a3bc31a89 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -295,8 +295,10 @@ static int __lb_setup(struct net_device *ndev,
switch (loop) {
case MAC_INTERNALLOOP_PHY:
- if ((phy_dev) && (!phy_dev->is_c45))
+ if ((phy_dev) && (!phy_dev->is_c45)) {
ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
+ ret |= h->dev->ops->set_loopback(h, loop, 0x1);
+ }
break;
case MAC_INTERNALLOOP_MAC:
if ((h->dev->ops->set_loopback) &&
@@ -376,6 +378,7 @@ static void __lb_other_process(struct hns_nic_ring_data *ring_data,
struct sk_buff *skb)
{
struct net_device *ndev;
+ struct hns_nic_priv *priv;
struct hnae_ring *ring;
struct netdev_queue *dev_queue;
struct sk_buff *new_skb;
@@ -385,8 +388,17 @@ static void __lb_other_process(struct hns_nic_ring_data *ring_data,
char buff[33]; /* 32B data and the last character '\0' */
if (!ring_data) { /* Just for doing create frame*/
+ ndev = skb->dev;
+ priv = netdev_priv(ndev);
+
frame_size = skb->len;
memset(skb->data, 0xFF, frame_size);
+ if ((!AE_IS_VER1(priv->enet_ver)) &&
+ (priv->ae_handle->port_type == HNAE_PORT_SERVICE)) {
+ memcpy(skb->data, ndev->dev_addr, 6);
+ skb->data[5] += 0x1f;
+ }
+
frame_size &= ~1ul;
memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
memset(&skb->data[frame_size / 2 + 10], 0xBE,
@@ -486,6 +498,7 @@ static int __lb_run_test(struct net_device *ndev,
/* place data into test skb */
(void)skb_put(skb, size);
+ skb->dev = ndev;
__lb_other_process(NULL, skb);
skb->queue_mapping = NIC_LB_TEST_RING_ID;
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 335417b4756b..ebe60719e489 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1166,7 +1166,10 @@ map_failed:
if (!firmware_has_feature(FW_FEATURE_CMO))
netdev_err(netdev, "tx: unable to map xmit buffer\n");
adapter->tx_map_failed++;
- skb_linearize(skb);
+ if (skb_linearize(skb)) {
+ netdev->stats.tx_dropped++;
+ goto out;
+ }
force_bounce = 1;
goto retry_bounce;
}
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 7d6570843723..6e9e16eee5d0 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -1348,44 +1348,44 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
crq.request_capability.cmd = REQUEST_CAPABILITY;
crq.request_capability.capability = cpu_to_be16(REQ_TX_QUEUES);
- crq.request_capability.number = cpu_to_be32(adapter->req_tx_queues);
+ crq.request_capability.number = cpu_to_be64(adapter->req_tx_queues);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability = cpu_to_be16(REQ_RX_QUEUES);
- crq.request_capability.number = cpu_to_be32(adapter->req_rx_queues);
+ crq.request_capability.number = cpu_to_be64(adapter->req_rx_queues);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability = cpu_to_be16(REQ_RX_ADD_QUEUES);
- crq.request_capability.number = cpu_to_be32(adapter->req_rx_add_queues);
+ crq.request_capability.number = cpu_to_be64(adapter->req_rx_add_queues);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability =
cpu_to_be16(REQ_TX_ENTRIES_PER_SUBCRQ);
crq.request_capability.number =
- cpu_to_be32(adapter->req_tx_entries_per_subcrq);
+ cpu_to_be64(adapter->req_tx_entries_per_subcrq);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability =
cpu_to_be16(REQ_RX_ADD_ENTRIES_PER_SUBCRQ);
crq.request_capability.number =
- cpu_to_be32(adapter->req_rx_add_entries_per_subcrq);
+ cpu_to_be64(adapter->req_rx_add_entries_per_subcrq);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability = cpu_to_be16(REQ_MTU);
- crq.request_capability.number = cpu_to_be32(adapter->req_mtu);
+ crq.request_capability.number = cpu_to_be64(adapter->req_mtu);
ibmvnic_send_crq(adapter, &crq);
if (adapter->netdev->flags & IFF_PROMISC) {
if (adapter->promisc_supported) {
crq.request_capability.capability =
cpu_to_be16(PROMISC_REQUESTED);
- crq.request_capability.number = cpu_to_be32(1);
+ crq.request_capability.number = cpu_to_be64(1);
ibmvnic_send_crq(adapter, &crq);
}
} else {
crq.request_capability.capability =
cpu_to_be16(PROMISC_REQUESTED);
- crq.request_capability.number = cpu_to_be32(0);
+ crq.request_capability.number = cpu_to_be64(0);
ibmvnic_send_crq(adapter, &crq);
}
@@ -2312,93 +2312,93 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
switch (be16_to_cpu(crq->query_capability.capability)) {
case MIN_TX_QUEUES:
adapter->min_tx_queues =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "min_tx_queues = %lld\n",
adapter->min_tx_queues);
break;
case MIN_RX_QUEUES:
adapter->min_rx_queues =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "min_rx_queues = %lld\n",
adapter->min_rx_queues);
break;
case MIN_RX_ADD_QUEUES:
adapter->min_rx_add_queues =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "min_rx_add_queues = %lld\n",
adapter->min_rx_add_queues);
break;
case MAX_TX_QUEUES:
adapter->max_tx_queues =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "max_tx_queues = %lld\n",
adapter->max_tx_queues);
break;
case MAX_RX_QUEUES:
adapter->max_rx_queues =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "max_rx_queues = %lld\n",
adapter->max_rx_queues);
break;
case MAX_RX_ADD_QUEUES:
adapter->max_rx_add_queues =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "max_rx_add_queues = %lld\n",
adapter->max_rx_add_queues);
break;
case MIN_TX_ENTRIES_PER_SUBCRQ:
adapter->min_tx_entries_per_subcrq =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "min_tx_entries_per_subcrq = %lld\n",
adapter->min_tx_entries_per_subcrq);
break;
case MIN_RX_ADD_ENTRIES_PER_SUBCRQ:
adapter->min_rx_add_entries_per_subcrq =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "min_rx_add_entrs_per_subcrq = %lld\n",
adapter->min_rx_add_entries_per_subcrq);
break;
case MAX_TX_ENTRIES_PER_SUBCRQ:
adapter->max_tx_entries_per_subcrq =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "max_tx_entries_per_subcrq = %lld\n",
adapter->max_tx_entries_per_subcrq);
break;
case MAX_RX_ADD_ENTRIES_PER_SUBCRQ:
adapter->max_rx_add_entries_per_subcrq =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "max_rx_add_entrs_per_subcrq = %lld\n",
adapter->max_rx_add_entries_per_subcrq);
break;
case TCP_IP_OFFLOAD:
adapter->tcp_ip_offload =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "tcp_ip_offload = %lld\n",
adapter->tcp_ip_offload);
break;
case PROMISC_SUPPORTED:
adapter->promisc_supported =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "promisc_supported = %lld\n",
adapter->promisc_supported);
break;
case MIN_MTU:
- adapter->min_mtu = be32_to_cpu(crq->query_capability.number);
+ adapter->min_mtu = be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "min_mtu = %lld\n", adapter->min_mtu);
break;
case MAX_MTU:
- adapter->max_mtu = be32_to_cpu(crq->query_capability.number);
+ adapter->max_mtu = be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "max_mtu = %lld\n", adapter->max_mtu);
break;
case MAX_MULTICAST_FILTERS:
adapter->max_multicast_filters =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "max_multicast_filters = %lld\n",
adapter->max_multicast_filters);
break;
case VLAN_HEADER_INSERTION:
adapter->vlan_header_insertion =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
if (adapter->vlan_header_insertion)
netdev->features |= NETIF_F_HW_VLAN_STAG_TX;
netdev_dbg(netdev, "vlan_header_insertion = %lld\n",
@@ -2406,43 +2406,43 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
break;
case MAX_TX_SG_ENTRIES:
adapter->max_tx_sg_entries =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "max_tx_sg_entries = %lld\n",
adapter->max_tx_sg_entries);
break;
case RX_SG_SUPPORTED:
adapter->rx_sg_supported =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "rx_sg_supported = %lld\n",
adapter->rx_sg_supported);
break;
case OPT_TX_COMP_SUB_QUEUES:
adapter->opt_tx_comp_sub_queues =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "opt_tx_comp_sub_queues = %lld\n",
adapter->opt_tx_comp_sub_queues);
break;
case OPT_RX_COMP_QUEUES:
adapter->opt_rx_comp_queues =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "opt_rx_comp_queues = %lld\n",
adapter->opt_rx_comp_queues);
break;
case OPT_RX_BUFADD_Q_PER_RX_COMP_Q:
adapter->opt_rx_bufadd_q_per_rx_comp_q =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "opt_rx_bufadd_q_per_rx_comp_q = %lld\n",
adapter->opt_rx_bufadd_q_per_rx_comp_q);
break;
case OPT_TX_ENTRIES_PER_SUBCRQ:
adapter->opt_tx_entries_per_subcrq =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "opt_tx_entries_per_subcrq = %lld\n",
adapter->opt_tx_entries_per_subcrq);
break;
case OPT_RXBA_ENTRIES_PER_SUBCRQ:
adapter->opt_rxba_entries_per_subcrq =
- be32_to_cpu(crq->query_capability.number);
+ be64_to_cpu(crq->query_capability.number);
netdev_dbg(netdev, "opt_rxba_entries_per_subcrq = %lld\n",
adapter->opt_rxba_entries_per_subcrq);
break;
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index 1242925ad34c..1a9993cc79b5 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -319,10 +319,8 @@ struct ibmvnic_capability {
u8 first;
u8 cmd;
__be16 capability; /* one of ibmvnic_capabilities */
+ __be64 number;
struct ibmvnic_rc rc;
- __be32 number; /*FIX: should be __be64, but I'm getting the least
- * significant word first
- */
} __packed __aligned(8);
struct ibmvnic_login {
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index fa593dd3efe1..3772f3ac956e 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -83,6 +83,15 @@ config E1000E
To compile this driver as a module, choose M here. The module
will be called e1000e.
+config E1000E_HWTS
+ bool "Support HW cross-timestamp on PCH devices"
+ default y
+ depends on E1000E && X86
+ ---help---
+ Say Y to enable hardware supported cross-timestamping on PCH
+ devices. The cross-timestamp is available through the PTP clock
+ driver precise cross-timestamp ioctl (PTP_SYS_OFFSET_PRECISE).
+
config IGB
tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
depends on PCI
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index f7c7804d79e5..0641c0098738 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -528,6 +528,11 @@
#define E1000_RXCW_C 0x20000000 /* Receive config */
#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */
+/* HH Time Sync */
+#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
+#define E1000_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete */
+#define E1000_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
+
#define E1000_TSYNCTXCTL_VALID 0x00000001 /* Tx timestamp valid */
#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
index 25a0ad5102d6..e2ff3ef75d5d 100644
--- a/drivers/net/ethernet/intel/e1000e/ptp.c
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -26,6 +26,12 @@
#include "e1000.h"
+#ifdef CONFIG_E1000E_HWTS
+#include <linux/clocksource.h>
+#include <linux/ktime.h>
+#include <asm/tsc.h>
+#endif
+
/**
* e1000e_phc_adjfreq - adjust the frequency of the hardware clock
* @ptp: ptp clock structure
@@ -98,6 +104,78 @@ static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
return 0;
}
+#ifdef CONFIG_E1000E_HWTS
+#define MAX_HW_WAIT_COUNT (3)
+
+/**
+ * e1000e_phc_get_syncdevicetime - Callback given to timekeeping code reads system/device registers
+ * @device: current device time
+ * @system: system counter value read synchronously with device time
+ * @ctx: context provided by timekeeping code
+ *
+ * Read device and system (ART) clock simultaneously and return the corrected
+ * clock values in ns.
+ **/
+static int e1000e_phc_get_syncdevicetime(ktime_t *device,
+ struct system_counterval_t *system,
+ void *ctx)
+{
+ struct e1000_adapter *adapter = (struct e1000_adapter *)ctx;
+ struct e1000_hw *hw = &adapter->hw;
+ unsigned long flags;
+ int i;
+ u32 tsync_ctrl;
+ cycle_t dev_cycles;
+ cycle_t sys_cycles;
+
+ tsync_ctrl = er32(TSYNCTXCTL);
+ tsync_ctrl |= E1000_TSYNCTXCTL_START_SYNC |
+ E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK;
+ ew32(TSYNCTXCTL, tsync_ctrl);
+ for (i = 0; i < MAX_HW_WAIT_COUNT; ++i) {
+ udelay(1);
+ tsync_ctrl = er32(TSYNCTXCTL);
+ if (tsync_ctrl & E1000_TSYNCTXCTL_SYNC_COMP)
+ break;
+ }
+
+ if (i == MAX_HW_WAIT_COUNT)
+ return -ETIMEDOUT;
+
+ dev_cycles = er32(SYSSTMPH);
+ dev_cycles <<= 32;
+ dev_cycles |= er32(SYSSTMPL);
+ spin_lock_irqsave(&adapter->systim_lock, flags);
+ *device = ns_to_ktime(timecounter_cyc2time(&adapter->tc, dev_cycles));
+ spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+ sys_cycles = er32(PLTSTMPH);
+ sys_cycles <<= 32;
+ sys_cycles |= er32(PLTSTMPL);
+ *system = convert_art_to_tsc(sys_cycles);
+
+ return 0;
+}
+
+/**
+ * e1000e_phc_getsynctime - Reads the current system/device cross timestamp
+ * @ptp: ptp clock structure
+ * @cts: structure containing timestamp
+ *
+ * Read device and system (ART) clock simultaneously and return the scaled
+ * clock values in ns.
+ **/
+static int e1000e_phc_getcrosststamp(struct ptp_clock_info *ptp,
+ struct system_device_crosststamp *xtstamp)
+{
+ struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+ ptp_clock_info);
+
+ return get_device_system_crosststamp(e1000e_phc_get_syncdevicetime,
+ adapter, NULL, xtstamp);
+}
+#endif/*CONFIG_E1000E_HWTS*/
+
/**
* e1000e_phc_gettime - Reads the current time from the hardware clock
* @ptp: ptp clock structure
@@ -236,6 +314,13 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
break;
}
+#ifdef CONFIG_E1000E_HWTS
+ /* CPU must have ART and GBe must be from Sunrise Point or greater */
+ if (hw->mac.type >= e1000_pch_spt && boot_cpu_has(X86_FEATURE_ART))
+ adapter->ptp_clock_info.getcrosststamp =
+ e1000e_phc_getcrosststamp;
+#endif/*CONFIG_E1000E_HWTS*/
+
INIT_DELAYED_WORK(&adapter->systim_overflow_work,
e1000e_systim_overflow_work);
diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h
index 1d5e0b77062a..0cb4d365e5ad 100644
--- a/drivers/net/ethernet/intel/e1000e/regs.h
+++ b/drivers/net/ethernet/intel/e1000e/regs.h
@@ -245,6 +245,10 @@
#define E1000_SYSTIML 0x0B600 /* System time register Low - RO */
#define E1000_SYSTIMH 0x0B604 /* System time register High - RO */
#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */
+#define E1000_SYSSTMPL 0x0B648 /* HH Timesync system stamp low register */
+#define E1000_SYSSTMPH 0x0B64C /* HH Timesync system stamp hi register */
+#define E1000_PLTSTMPL 0x0B640 /* HH Timesync platform stamp low register */
+#define E1000_PLTSTMPH 0x0B644 /* HH Timesync platform stamp hi register */
#define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Msg Type - RW */
#define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index b1de7afd4116..3ddf657bc10b 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -270,11 +270,17 @@ jme_reset_mac_processor(struct jme_adapter *jme)
}
static inline void
-jme_clear_pm(struct jme_adapter *jme)
+jme_clear_pm_enable_wol(struct jme_adapter *jme)
{
jwrite32(jme, JME_PMCS, PMCS_STMASK | jme->reg_pmcs);
}
+static inline void
+jme_clear_pm_disable_wol(struct jme_adapter *jme)
+{
+ jwrite32(jme, JME_PMCS, PMCS_STMASK);
+}
+
static int
jme_reload_eeprom(struct jme_adapter *jme)
{
@@ -1853,7 +1859,7 @@ jme_open(struct net_device *netdev)
struct jme_adapter *jme = netdev_priv(netdev);
int rc;
- jme_clear_pm(jme);
+ jme_clear_pm_disable_wol(jme);
JME_NAPI_ENABLE(jme);
tasklet_init(&jme->linkch_task, jme_link_change_tasklet,
@@ -1925,11 +1931,11 @@ jme_wait_link(struct jme_adapter *jme)
static void
jme_powersave_phy(struct jme_adapter *jme)
{
- if (jme->reg_pmcs) {
+ if (jme->reg_pmcs && device_may_wakeup(&jme->pdev->dev)) {
jme_set_100m_half(jme);
if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
jme_wait_link(jme);
- jme_clear_pm(jme);
+ jme_clear_pm_enable_wol(jme);
} else {
jme_phy_off(jme);
}
@@ -2646,9 +2652,6 @@ jme_set_wol(struct net_device *netdev,
if (wol->wolopts & WAKE_MAGIC)
jme->reg_pmcs |= PMCS_MFEN;
- jwrite32(jme, JME_PMCS, jme->reg_pmcs);
- device_set_wakeup_enable(&jme->pdev->dev, !!(jme->reg_pmcs));
-
return 0;
}
@@ -3172,8 +3175,8 @@ jme_init_one(struct pci_dev *pdev,
jme->mii_if.mdio_read = jme_mdio_read;
jme->mii_if.mdio_write = jme_mdio_write;
- jme_clear_pm(jme);
- device_set_wakeup_enable(&pdev->dev, true);
+ jme_clear_pm_disable_wol(jme);
+ device_init_wakeup(&pdev->dev, true);
jme_set_phyfifo_5level(jme);
jme->pcirev = pdev->revision;
@@ -3304,7 +3307,7 @@ jme_resume(struct device *dev)
if (!netif_running(netdev))
return 0;
- jme_clear_pm(jme);
+ jme_clear_pm_disable_wol(jme);
jme_phy_on(jme);
if (test_bit(JME_FLAG_SSET, &jme->flags))
jme_set_settings(netdev, &jme->old_ecmd);
@@ -3312,13 +3315,14 @@ jme_resume(struct device *dev)
jme_reset_phy_processor(jme);
jme_phy_calibration(jme);
jme_phy_setEA(jme);
- jme_start_irq(jme);
netif_device_attach(netdev);
atomic_inc(&jme->link_changing);
jme_reset_link(jme);
+ jme_start_irq(jme);
+
return 0;
}
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 662c2ee268c7..b0ae69f84493 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -370,6 +370,11 @@ struct mvneta_port {
struct net_device *dev;
struct notifier_block cpu_notifier;
int rxq_def;
+ /* Protect the access to the percpu interrupt registers,
+ * ensuring that the configuration remains coherent.
+ */
+ spinlock_t lock;
+ bool is_stopped;
/* Core clock */
struct clk *clk;
@@ -1038,6 +1043,43 @@ static void mvneta_set_autoneg(struct mvneta_port *pp, int enable)
}
}
+static void mvneta_percpu_unmask_interrupt(void *arg)
+{
+ struct mvneta_port *pp = arg;
+
+ /* All the queue are unmasked, but actually only the ones
+ * mapped to this CPU will be unmasked
+ */
+ mvreg_write(pp, MVNETA_INTR_NEW_MASK,
+ MVNETA_RX_INTR_MASK_ALL |
+ MVNETA_TX_INTR_MASK_ALL |
+ MVNETA_MISCINTR_INTR_MASK);
+}
+
+static void mvneta_percpu_mask_interrupt(void *arg)
+{
+ struct mvneta_port *pp = arg;
+
+ /* All the queue are masked, but actually only the ones
+ * mapped to this CPU will be masked
+ */
+ mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
+ mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
+ mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+}
+
+static void mvneta_percpu_clear_intr_cause(void *arg)
+{
+ struct mvneta_port *pp = arg;
+
+ /* All the queue are cleared, but actually only the ones
+ * mapped to this CPU will be cleared
+ */
+ mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0);
+ mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
+ mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
+}
+
/* This method sets defaults to the NETA port:
* Clears interrupt Cause and Mask registers.
* Clears all MAC tables.
@@ -1055,14 +1097,10 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
int max_cpu = num_present_cpus();
/* Clear all Cause registers */
- mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0);
- mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
- mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
+ on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true);
/* Mask all interrupts */
- mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+ on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
mvreg_write(pp, MVNETA_INTR_ENABLE, 0);
/* Enable MBUS Retry bit16 */
@@ -2528,34 +2566,9 @@ static int mvneta_setup_txqs(struct mvneta_port *pp)
return 0;
}
-static void mvneta_percpu_unmask_interrupt(void *arg)
-{
- struct mvneta_port *pp = arg;
-
- /* All the queue are unmasked, but actually only the ones
- * maped to this CPU will be unmasked
- */
- mvreg_write(pp, MVNETA_INTR_NEW_MASK,
- MVNETA_RX_INTR_MASK_ALL |
- MVNETA_TX_INTR_MASK_ALL |
- MVNETA_MISCINTR_INTR_MASK);
-}
-
-static void mvneta_percpu_mask_interrupt(void *arg)
-{
- struct mvneta_port *pp = arg;
-
- /* All the queue are masked, but actually only the ones
- * maped to this CPU will be masked
- */
- mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
-}
-
static void mvneta_start_dev(struct mvneta_port *pp)
{
- unsigned int cpu;
+ int cpu;
mvneta_max_rx_size_set(pp, pp->pkt_size);
mvneta_txq_max_tx_size_set(pp, pp->pkt_size);
@@ -2564,16 +2577,15 @@ static void mvneta_start_dev(struct mvneta_port *pp)
mvneta_port_enable(pp);
/* Enable polling on the port */
- for_each_present_cpu(cpu) {
+ for_each_online_cpu(cpu) {
struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
napi_enable(&port->napi);
}
/* Unmask interrupts. It has to be done from each CPU */
- for_each_online_cpu(cpu)
- smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt,
- pp, true);
+ on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
+
mvreg_write(pp, MVNETA_INTR_MISC_MASK,
MVNETA_CAUSE_PHY_STATUS_CHANGE |
MVNETA_CAUSE_LINK_CHANGE |
@@ -2589,7 +2601,7 @@ static void mvneta_stop_dev(struct mvneta_port *pp)
phy_stop(pp->phy_dev);
- for_each_present_cpu(cpu) {
+ for_each_online_cpu(cpu) {
struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
napi_disable(&port->napi);
@@ -2604,13 +2616,10 @@ static void mvneta_stop_dev(struct mvneta_port *pp)
mvneta_port_disable(pp);
/* Clear all ethernet port interrupts */
- mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
- mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
+ on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true);
/* Mask all ethernet port interrupts */
- mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+ on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
mvneta_tx_reset(pp);
mvneta_rx_reset(pp);
@@ -2847,11 +2856,20 @@ static void mvneta_percpu_disable(void *arg)
disable_percpu_irq(pp->dev->irq);
}
+/* Electing a CPU must be done in an atomic way: it should be done
+ * after or before the removal/insertion of a CPU and this function is
+ * not reentrant.
+ */
static void mvneta_percpu_elect(struct mvneta_port *pp)
{
- int online_cpu_idx, max_cpu, cpu, i = 0;
+ int elected_cpu = 0, max_cpu, cpu, i = 0;
+
+ /* Use the cpu associated to the rxq when it is online, in all
+ * the other cases, use the cpu 0 which can't be offline.
+ */
+ if (cpu_online(pp->rxq_def))
+ elected_cpu = pp->rxq_def;
- online_cpu_idx = pp->rxq_def % num_online_cpus();
max_cpu = num_present_cpus();
for_each_online_cpu(cpu) {
@@ -2862,7 +2880,7 @@ static void mvneta_percpu_elect(struct mvneta_port *pp)
if ((rxq % max_cpu) == cpu)
rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
- if (i == online_cpu_idx)
+ if (cpu == elected_cpu)
/* Map the default receive queue queue to the
* elected CPU
*/
@@ -2873,7 +2891,7 @@ static void mvneta_percpu_elect(struct mvneta_port *pp)
* the CPU bound to the default RX queue
*/
if (txq_number == 1)
- txq_map = (i == online_cpu_idx) ?
+ txq_map = (cpu == elected_cpu) ?
MVNETA_CPU_TXQ_ACCESS(1) : 0;
else
txq_map = mvreg_read(pp, MVNETA_CPU_MAP(cpu)) &
@@ -2902,6 +2920,14 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
+ spin_lock(&pp->lock);
+ /* Configuring the driver for a new CPU while the
+ * driver is stopping is racy, so just avoid it.
+ */
+ if (pp->is_stopped) {
+ spin_unlock(&pp->lock);
+ break;
+ }
netif_tx_stop_all_queues(pp->dev);
/* We have to synchronise on tha napi of each CPU
@@ -2917,9 +2943,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
}
/* Mask all ethernet port interrupts */
- mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+ on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
napi_enable(&port->napi);
@@ -2934,27 +2958,25 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
*/
mvneta_percpu_elect(pp);
- /* Unmask all ethernet port interrupts, as this
- * notifier is called for each CPU then the CPU to
- * Queue mapping is applied
- */
- mvreg_write(pp, MVNETA_INTR_NEW_MASK,
- MVNETA_RX_INTR_MASK(rxq_number) |
- MVNETA_TX_INTR_MASK(txq_number) |
- MVNETA_MISCINTR_INTR_MASK);
+ /* Unmask all ethernet port interrupts */
+ on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
mvreg_write(pp, MVNETA_INTR_MISC_MASK,
MVNETA_CAUSE_PHY_STATUS_CHANGE |
MVNETA_CAUSE_LINK_CHANGE |
MVNETA_CAUSE_PSC_SYNC_CHANGE);
netif_tx_start_all_queues(pp->dev);
+ spin_unlock(&pp->lock);
break;
case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
netif_tx_stop_all_queues(pp->dev);
+ /* Thanks to this lock we are sure that any pending
+ * cpu election is done
+ */
+ spin_lock(&pp->lock);
/* Mask all ethernet port interrupts */
- mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
- mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+ on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
+ spin_unlock(&pp->lock);
napi_synchronize(&port->napi);
napi_disable(&port->napi);
@@ -2968,12 +2990,11 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
case CPU_DEAD:
case CPU_DEAD_FROZEN:
/* Check if a new CPU must be elected now this on is down */
+ spin_lock(&pp->lock);
mvneta_percpu_elect(pp);
+ spin_unlock(&pp->lock);
/* Unmask all ethernet port interrupts */
- mvreg_write(pp, MVNETA_INTR_NEW_MASK,
- MVNETA_RX_INTR_MASK(rxq_number) |
- MVNETA_TX_INTR_MASK(txq_number) |
- MVNETA_MISCINTR_INTR_MASK);
+ on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
mvreg_write(pp, MVNETA_INTR_MISC_MASK,
MVNETA_CAUSE_PHY_STATUS_CHANGE |
MVNETA_CAUSE_LINK_CHANGE |
@@ -2988,7 +3009,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
static int mvneta_open(struct net_device *dev)
{
struct mvneta_port *pp = netdev_priv(dev);
- int ret, cpu;
+ int ret;
pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu);
pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) +
@@ -3010,22 +3031,12 @@ static int mvneta_open(struct net_device *dev)
goto err_cleanup_txqs;
}
- /* Even though the documentation says that request_percpu_irq
- * doesn't enable the interrupts automatically, it actually
- * does so on the local CPU.
- *
- * Make sure it's disabled.
- */
- mvneta_percpu_disable(pp);
-
/* Enable per-CPU interrupt on all the CPU to handle our RX
* queue interrupts
*/
- for_each_online_cpu(cpu)
- smp_call_function_single(cpu, mvneta_percpu_enable,
- pp, true);
-
+ on_each_cpu(mvneta_percpu_enable, pp, true);
+ pp->is_stopped = false;
/* Register a CPU notifier to handle the case where our CPU
* might be taken offline.
*/
@@ -3057,13 +3068,20 @@ err_cleanup_rxqs:
static int mvneta_stop(struct net_device *dev)
{
struct mvneta_port *pp = netdev_priv(dev);
- int cpu;
+ /* Inform that we are stopping so we don't want to setup the
+ * driver for new CPUs in the notifiers
+ */
+ spin_lock(&pp->lock);
+ pp->is_stopped = true;
mvneta_stop_dev(pp);
mvneta_mdio_remove(pp);
unregister_cpu_notifier(&pp->cpu_notifier);
- for_each_present_cpu(cpu)
- smp_call_function_single(cpu, mvneta_percpu_disable, pp, true);
+ /* Now that the notifier are unregistered, we can release le
+ * lock
+ */
+ spin_unlock(&pp->lock);
+ on_each_cpu(mvneta_percpu_disable, pp, true);
free_percpu_irq(dev->irq, pp->ports);
mvneta_cleanup_rxqs(pp);
mvneta_cleanup_txqs(pp);
@@ -3312,9 +3330,7 @@ static int mvneta_config_rss(struct mvneta_port *pp)
netif_tx_stop_all_queues(pp->dev);
- for_each_online_cpu(cpu)
- smp_call_function_single(cpu, mvneta_percpu_mask_interrupt,
- pp, true);
+ on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
/* We have to synchronise on the napi of each CPU */
for_each_online_cpu(cpu) {
@@ -3335,7 +3351,9 @@ static int mvneta_config_rss(struct mvneta_port *pp)
mvreg_write(pp, MVNETA_PORT_CONFIG, val);
/* Update the elected CPU matching the new rxq_def */
+ spin_lock(&pp->lock);
mvneta_percpu_elect(pp);
+ spin_unlock(&pp->lock);
/* We have to synchronise on the napi of each CPU */
for_each_online_cpu(cpu) {
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index a4beccf1fd46..c797971aefab 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -3061,7 +3061,7 @@ static int mvpp2_prs_mac_da_accept(struct mvpp2 *priv, int port,
pe = kzalloc(sizeof(*pe), GFP_KERNEL);
if (!pe)
- return -1;
+ return -ENOMEM;
mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC);
pe->index = tid;
@@ -3077,7 +3077,7 @@ static int mvpp2_prs_mac_da_accept(struct mvpp2 *priv, int port,
if (pmap == 0) {
if (add) {
kfree(pe);
- return -1;
+ return -EINVAL;
}
mvpp2_prs_hw_inv(priv, pe->index);
priv->prs_shadow[pe->index].valid = false;
diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c
index 715de8affcc9..c7e939945259 100644
--- a/drivers/net/ethernet/mellanox/mlx4/catas.c
+++ b/drivers/net/ethernet/mellanox/mlx4/catas.c
@@ -182,10 +182,17 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist)
err = mlx4_reset_slave(dev);
else
err = mlx4_reset_master(dev);
- BUG_ON(err != 0);
+ if (!err) {
+ mlx4_err(dev, "device was reset successfully\n");
+ } else {
+ /* EEH could have disabled the PCI channel during reset. That's
+ * recoverable and the PCI error flow will handle it.
+ */
+ if (!pci_channel_offline(dev->persist->pdev))
+ BUG_ON(1);
+ }
dev->persist->state |= MLX4_DEVICE_STATE_INTERNAL_ERROR;
- mlx4_err(dev, "device was reset successfully\n");
mutex_unlock(&persist->device_state_mutex);
/* At that step HW was already reset, now notify clients */
diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
index 3348e646db70..a849da92f857 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
@@ -318,7 +318,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
if (timestamp_en)
cq_context->flags |= cpu_to_be32(1 << 19);
- cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
+ cq_context->logsize_usrpage =
+ cpu_to_be32((ilog2(nent) << 24) |
+ mlx4_to_hw_uar_index(dev, uar->index));
cq_context->comp_eqn = priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn;
cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
index 038f9ce391e6..1494997c4f7e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
@@ -236,6 +236,24 @@ static const struct ptp_clock_info mlx4_en_ptp_clock_info = {
.enable = mlx4_en_phc_enable,
};
+#define MLX4_EN_WRAP_AROUND_SEC 10ULL
+
+/* This function calculates the max shift that enables the user range
+ * of MLX4_EN_WRAP_AROUND_SEC values in the cycles register.
+ */
+static u32 freq_to_shift(u16 freq)
+{
+ u32 freq_khz = freq * 1000;
+ u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC;
+ u64 max_val_cycles_rounded = is_power_of_2(max_val_cycles + 1) ?
+ max_val_cycles : roundup_pow_of_two(max_val_cycles) - 1;
+ /* calculate max possible multiplier in order to fit in 64bit */
+ u64 max_mul = div_u64(0xffffffffffffffffULL, max_val_cycles_rounded);
+
+ /* This comes from the reverse of clocksource_khz2mult */
+ return ilog2(div_u64(max_mul * freq_khz, 1000000));
+}
+
void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
{
struct mlx4_dev *dev = mdev->dev;
@@ -254,12 +272,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
memset(&mdev->cycles, 0, sizeof(mdev->cycles));
mdev->cycles.read = mlx4_en_read_clock;
mdev->cycles.mask = CLOCKSOURCE_MASK(48);
- /* Using shift to make calculation more accurate. Since current HW
- * clock frequency is 427 MHz, and cycles are given using a 48 bits
- * register, the biggest shift when calculating using u64, is 14
- * (max_cycles * multiplier < 2^64)
- */
- mdev->cycles.shift = 14;
+ mdev->cycles.shift = freq_to_shift(dev->caps.hca_core_clock);
mdev->cycles.mult =
clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);
mdev->nominal_c_mult = mdev->cycles.mult;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 0c7e3f69a73b..21e2c0960271 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -2245,7 +2245,7 @@ static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
struct mlx4_en_dev *mdev = en_priv->mdev;
u64 mac_u64 = mlx4_mac_to_u64(mac);
- if (!is_valid_ether_addr(mac))
+ if (is_multicast_ether_addr(mac))
return -EINVAL;
return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac_u64);
@@ -2344,8 +2344,6 @@ out:
/* set offloads */
priv->dev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL;
- priv->dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
- priv->dev->features |= NETIF_F_GSO_UDP_TUNNEL;
}
static void mlx4_en_del_vxlan_offloads(struct work_struct *work)
@@ -2356,8 +2354,6 @@ static void mlx4_en_del_vxlan_offloads(struct work_struct *work)
/* unset offloads */
priv->dev->hw_enc_features &= ~(NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL);
- priv->dev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL;
- priv->dev->features &= ~NETIF_F_GSO_UDP_TUNNEL;
ret = mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port,
VXLAN_STEER_BY_OUTER_MAC, 0);
@@ -2980,6 +2976,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
priv->rss_hash_fn = ETH_RSS_HASH_TOP;
}
+ if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
+ dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
+ dev->features |= NETIF_F_GSO_UDP_TUNNEL;
+ }
+
mdev->pndev[port] = dev;
mdev->upper[port] = NULL;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c
index ee99e67187f5..3904b5fc0b7c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c
@@ -238,11 +238,11 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
stats->collisions = 0;
stats->rx_dropped = be32_to_cpu(mlx4_en_stats->RDROP);
stats->rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength);
- stats->rx_over_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
+ stats->rx_over_errors = 0;
stats->rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC);
stats->rx_frame_errors = 0;
stats->rx_fifo_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
- stats->rx_missed_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
+ stats->rx_missed_errors = 0;
stats->tx_aborted_errors = 0;
stats->tx_carrier_errors = 0;
stats->tx_fifo_errors = 0;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
index 12aab5a659d3..02e925d6f734 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
@@ -58,7 +58,8 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
} else {
context->sq_size_stride = ilog2(TXBB_SIZE) - 4;
}
- context->usr_page = cpu_to_be32(mdev->priv_uar.index);
+ context->usr_page = cpu_to_be32(mlx4_to_hw_uar_index(mdev->dev,
+ mdev->priv_uar.index));
context->local_qpn = cpu_to_be32(qpn);
context->pri_path.ackto = 1 & 0x07;
context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 4421bf5463f6..e0946ab22010 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -213,7 +213,9 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,
ring->cqn, user_prio, &ring->context);
if (ring->bf_alloced)
- ring->context.usr_page = cpu_to_be32(ring->bf.uar->index);
+ ring->context.usr_page =
+ cpu_to_be32(mlx4_to_hw_uar_index(mdev->dev,
+ ring->bf.uar->index));
err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context,
&ring->qp, &ring->qp_state);
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 4696053165f8..f613977455e0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -940,9 +940,10 @@ static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
if (!priv->eq_table.uar_map[index]) {
priv->eq_table.uar_map[index] =
- ioremap(pci_resource_start(dev->persist->pdev, 2) +
- ((eq->eqn / 4) << PAGE_SHIFT),
- PAGE_SIZE);
+ ioremap(
+ pci_resource_start(dev->persist->pdev, 2) +
+ ((eq->eqn / 4) << (dev->uar_page_shift)),
+ (1 << (dev->uar_page_shift)));
if (!priv->eq_table.uar_map[index]) {
mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n",
eq->eqn);
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index f1b6d219e445..f8674ae62752 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -168,6 +168,20 @@ struct mlx4_port_config {
static atomic_t pf_loading = ATOMIC_INIT(0);
+static inline void mlx4_set_num_reserved_uars(struct mlx4_dev *dev,
+ struct mlx4_dev_cap *dev_cap)
+{
+ /* The reserved_uars is calculated by system page size unit.
+ * Therefore, adjustment is added when the uar page size is less
+ * than the system page size
+ */
+ dev->caps.reserved_uars =
+ max_t(int,
+ mlx4_get_num_reserved_uar(dev),
+ dev_cap->reserved_uars /
+ (1 << (PAGE_SHIFT - dev->uar_page_shift)));
+}
+
int mlx4_check_port_params(struct mlx4_dev *dev,
enum mlx4_port_type *port_type)
{
@@ -386,8 +400,6 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.reserved_mtts = dev_cap->reserved_mtts;
dev->caps.reserved_mrws = dev_cap->reserved_mrws;
- /* The first 128 UARs are used for EQ doorbells */
- dev->caps.reserved_uars = max_t(int, 128, dev_cap->reserved_uars);
dev->caps.reserved_pds = dev_cap->reserved_pds;
dev->caps.reserved_xrcds = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ?
dev_cap->reserved_xrcds : 0;
@@ -405,6 +417,15 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.max_gso_sz = dev_cap->max_gso_sz;
dev->caps.max_rss_tbl_sz = dev_cap->max_rss_tbl_sz;
+ /* Save uar page shift */
+ if (!mlx4_is_slave(dev)) {
+ /* Virtual PCI function needs to determine UAR page size from
+ * firmware. Only master PCI function can set the uar page size
+ */
+ dev->uar_page_shift = DEFAULT_UAR_PAGE_SHIFT;
+ mlx4_set_num_reserved_uars(dev, dev_cap);
+ }
+
if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN) {
struct mlx4_init_hca_param hca_param;
@@ -815,16 +836,25 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
return -ENODEV;
}
- /* slave gets uar page size from QUERY_HCA fw command */
- dev->caps.uar_page_size = 1 << (hca_param.uar_page_sz + 12);
+ /* Set uar_page_shift for VF */
+ dev->uar_page_shift = hca_param.uar_page_sz + 12;
- /* TODO: relax this assumption */
- if (dev->caps.uar_page_size != PAGE_SIZE) {
- mlx4_err(dev, "UAR size:%d != kernel PAGE_SIZE of %ld\n",
- dev->caps.uar_page_size, PAGE_SIZE);
- return -ENODEV;
+ /* Make sure the master uar page size is valid */
+ if (dev->uar_page_shift > PAGE_SHIFT) {
+ mlx4_err(dev,
+ "Invalid configuration: uar page size is larger than system page size\n");
+ return -ENODEV;
}
+ /* Set reserved_uars based on the uar_page_shift */
+ mlx4_set_num_reserved_uars(dev, &dev_cap);
+
+ /* Although uar page size in FW differs from system page size,
+ * upper software layers (mlx4_ib, mlx4_en and part of mlx4_core)
+ * still works with assumption that uar page size == system page size
+ */
+ dev->caps.uar_page_size = PAGE_SIZE;
+
memset(&func_cap, 0, sizeof(func_cap));
err = mlx4_QUERY_FUNC_CAP(dev, 0, &func_cap);
if (err) {
@@ -1226,6 +1256,7 @@ err_set_port:
static int mlx4_mf_bond(struct mlx4_dev *dev)
{
int err = 0;
+ int nvfs;
struct mlx4_slaves_pport slaves_port1;
struct mlx4_slaves_pport slaves_port2;
DECLARE_BITMAP(slaves_port_1_2, MLX4_MFUNC_MAX);
@@ -1242,11 +1273,18 @@ static int mlx4_mf_bond(struct mlx4_dev *dev)
return -EINVAL;
}
+ /* number of virtual functions is number of total functions minus one
+ * physical function for each port.
+ */
+ nvfs = bitmap_weight(slaves_port1.slaves, dev->persist->num_vfs + 1) +
+ bitmap_weight(slaves_port2.slaves, dev->persist->num_vfs + 1) - 2;
+
/* limit on maximum allowed VFs */
- if ((bitmap_weight(slaves_port1.slaves, dev->persist->num_vfs + 1) +
- bitmap_weight(slaves_port2.slaves, dev->persist->num_vfs + 1)) >
- MAX_MF_BOND_ALLOWED_SLAVES)
+ if (nvfs > MAX_MF_BOND_ALLOWED_SLAVES) {
+ mlx4_warn(dev, "HA mode is not supported for %d VFs (max %d are allowed)\n",
+ nvfs, MAX_MF_BOND_ALLOWED_SLAVES);
return -EINVAL;
+ }
if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) {
mlx4_warn(dev, "HA mode unsupported for NON DMFS steering\n");
@@ -2179,8 +2217,12 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1;
- init_hca.log_uar_sz = ilog2(dev->caps.num_uars);
- init_hca.uar_page_sz = PAGE_SHIFT - 12;
+ /* Always set UAR page size 4KB, set log_uar_sz accordingly */
+ init_hca.log_uar_sz = ilog2(dev->caps.num_uars) +
+ PAGE_SHIFT -
+ DEFAULT_UAR_PAGE_SHIFT;
+ init_hca.uar_page_sz = DEFAULT_UAR_PAGE_SHIFT - 12;
+
init_hca.mw_enabled = 0;
if (dev->caps.flags & MLX4_DEV_CAP_FLAG_MEM_WINDOW ||
dev->caps.bmme_flags & MLX4_BMME_FLAG_TYPE_2_WIN)
diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c
index 609c59dc854e..b3cc3ab63799 100644
--- a/drivers/net/ethernet/mellanox/mlx4/pd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/pd.c
@@ -269,9 +269,15 @@ EXPORT_SYMBOL_GPL(mlx4_bf_free);
int mlx4_init_uar_table(struct mlx4_dev *dev)
{
- if (dev->caps.num_uars <= 128) {
- mlx4_err(dev, "Only %d UAR pages (need more than 128)\n",
- dev->caps.num_uars);
+ int num_reserved_uar = mlx4_get_num_reserved_uar(dev);
+
+ mlx4_dbg(dev, "uar_page_shift = %d", dev->uar_page_shift);
+ mlx4_dbg(dev, "Effective reserved_uars=%d", dev->caps.reserved_uars);
+
+ if (dev->caps.num_uars <= num_reserved_uar) {
+ mlx4_err(
+ dev, "Only %d UAR pages (need more than %d)\n",
+ dev->caps.num_uars, num_reserved_uar);
mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n");
return -ENODEV;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 787b7bb54d52..211c65087997 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -193,10 +193,10 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
if (need_mf_bond) {
if (port == 1) {
mutex_lock(&table->mutex);
- mutex_lock(&dup_table->mutex);
+ mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
} else {
mutex_lock(&dup_table->mutex);
- mutex_lock(&table->mutex);
+ mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
}
} else {
mutex_lock(&table->mutex);
@@ -389,10 +389,10 @@ void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
if (dup) {
if (port == 1) {
mutex_lock(&table->mutex);
- mutex_lock(&dup_table->mutex);
+ mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
} else {
mutex_lock(&dup_table->mutex);
- mutex_lock(&table->mutex);
+ mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
}
} else {
mutex_lock(&table->mutex);
@@ -479,10 +479,10 @@ int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
if (dup) {
if (port == 1) {
mutex_lock(&table->mutex);
- mutex_lock(&dup_table->mutex);
+ mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
} else {
mutex_lock(&dup_table->mutex);
- mutex_lock(&table->mutex);
+ mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
}
} else {
mutex_lock(&table->mutex);
@@ -588,10 +588,10 @@ int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
if (need_mf_bond) {
if (port == 1) {
mutex_lock(&table->mutex);
- mutex_lock(&dup_table->mutex);
+ mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
} else {
mutex_lock(&dup_table->mutex);
- mutex_lock(&table->mutex);
+ mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
}
} else {
mutex_lock(&table->mutex);
@@ -764,10 +764,10 @@ void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
if (dup) {
if (port == 1) {
mutex_lock(&table->mutex);
- mutex_lock(&dup_table->mutex);
+ mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
} else {
mutex_lock(&dup_table->mutex);
- mutex_lock(&table->mutex);
+ mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
}
} else {
mutex_lock(&table->mutex);
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index b46dbe29ef6c..25ce1b030a00 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -915,11 +915,13 @@ static int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port,
spin_lock_irq(mlx4_tlock(dev));
r = find_res(dev, counter_index, RES_COUNTER);
- if (!r || r->owner != slave)
+ if (!r || r->owner != slave) {
ret = -EINVAL;
- counter = container_of(r, struct res_counter, com);
- if (!counter->port)
- counter->port = port;
+ } else {
+ counter = container_of(r, struct res_counter, com);
+ if (!counter->port)
+ counter->port = port;
+ }
spin_unlock_irq(mlx4_tlock(dev));
return ret;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index aac071a7e830..5b1753233c5d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -223,6 +223,7 @@ struct mlx5e_pport_stats {
static const char rq_stats_strings[][ETH_GSTRING_LEN] = {
"packets",
+ "bytes",
"csum_none",
"csum_sw",
"lro_packets",
@@ -232,16 +233,18 @@ static const char rq_stats_strings[][ETH_GSTRING_LEN] = {
struct mlx5e_rq_stats {
u64 packets;
+ u64 bytes;
u64 csum_none;
u64 csum_sw;
u64 lro_packets;
u64 lro_bytes;
u64 wqe_err;
-#define NUM_RQ_STATS 6
+#define NUM_RQ_STATS 7
};
static const char sq_stats_strings[][ETH_GSTRING_LEN] = {
"packets",
+ "bytes",
"tso_packets",
"tso_bytes",
"csum_offload_none",
@@ -253,6 +256,7 @@ static const char sq_stats_strings[][ETH_GSTRING_LEN] = {
struct mlx5e_sq_stats {
u64 packets;
+ u64 bytes;
u64 tso_packets;
u64 tso_bytes;
u64 csum_offload_none;
@@ -260,7 +264,7 @@ struct mlx5e_sq_stats {
u64 wake;
u64 dropped;
u64 nop;
-#define NUM_SQ_STATS 8
+#define NUM_SQ_STATS 9
};
struct mlx5e_stats {
@@ -304,14 +308,9 @@ enum {
MLX5E_RQ_STATE_POST_WQES_ENABLE,
};
-enum cq_flags {
- MLX5E_CQ_HAS_CQES = 1,
-};
-
struct mlx5e_cq {
/* data path - accessed per cqe */
struct mlx5_cqwq wq;
- unsigned long flags;
/* data path - accessed per napi poll */
struct napi_struct *napi;
@@ -452,6 +451,8 @@ enum mlx5e_traffic_types {
MLX5E_NUM_TT,
};
+#define IS_HASHING_TT(tt) (tt != MLX5E_TT_ANY)
+
enum mlx5e_rqt_ix {
MLX5E_INDIRECTION_RQT,
MLX5E_SINGLE_RQ_RQT,
@@ -618,9 +619,12 @@ void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv);
void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv);
int mlx5e_redirect_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix);
+void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv);
int mlx5e_open_locked(struct net_device *netdev);
int mlx5e_close_locked(struct net_device *netdev);
+void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len,
+ int num_channels);
static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq,
struct mlx5e_tx_wqe *wqe, int bf_sz)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
index be6543570b2b..2018eebe1531 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
@@ -62,10 +62,11 @@ static void mlx5e_timestamp_overflow(struct work_struct *work)
struct delayed_work *dwork = to_delayed_work(work);
struct mlx5e_tstamp *tstamp = container_of(dwork, struct mlx5e_tstamp,
overflow_work);
+ unsigned long flags;
- write_lock(&tstamp->lock);
+ write_lock_irqsave(&tstamp->lock, flags);
timecounter_read(&tstamp->clock);
- write_unlock(&tstamp->lock);
+ write_unlock_irqrestore(&tstamp->lock, flags);
schedule_delayed_work(&tstamp->overflow_work, tstamp->overflow_period);
}
@@ -136,10 +137,11 @@ static int mlx5e_ptp_settime(struct ptp_clock_info *ptp,
struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
ptp_info);
u64 ns = timespec64_to_ns(ts);
+ unsigned long flags;
- write_lock(&tstamp->lock);
+ write_lock_irqsave(&tstamp->lock, flags);
timecounter_init(&tstamp->clock, &tstamp->cycles, ns);
- write_unlock(&tstamp->lock);
+ write_unlock_irqrestore(&tstamp->lock, flags);
return 0;
}
@@ -150,10 +152,11 @@ static int mlx5e_ptp_gettime(struct ptp_clock_info *ptp,
struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
ptp_info);
u64 ns;
+ unsigned long flags;
- write_lock(&tstamp->lock);
+ write_lock_irqsave(&tstamp->lock, flags);
ns = timecounter_read(&tstamp->clock);
- write_unlock(&tstamp->lock);
+ write_unlock_irqrestore(&tstamp->lock, flags);
*ts = ns_to_timespec64(ns);
@@ -164,10 +167,11 @@ static int mlx5e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
ptp_info);
+ unsigned long flags;
- write_lock(&tstamp->lock);
+ write_lock_irqsave(&tstamp->lock, flags);
timecounter_adjtime(&tstamp->clock, delta);
- write_unlock(&tstamp->lock);
+ write_unlock_irqrestore(&tstamp->lock, flags);
return 0;
}
@@ -176,6 +180,7 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
{
u64 adj;
u32 diff;
+ unsigned long flags;
int neg_adj = 0;
struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
ptp_info);
@@ -189,11 +194,11 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
adj *= delta;
diff = div_u64(adj, 1000000000ULL);
- write_lock(&tstamp->lock);
+ write_lock_irqsave(&tstamp->lock, flags);
timecounter_read(&tstamp->clock);
tstamp->cycles.mult = neg_adj ? tstamp->nominal_c_mult - diff :
tstamp->nominal_c_mult + diff;
- write_unlock(&tstamp->lock);
+ write_unlock_irqrestore(&tstamp->lock, flags);
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 65624ac65b4c..5abeb00fceb8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -385,6 +385,8 @@ static int mlx5e_set_channels(struct net_device *dev,
mlx5e_close_locked(dev);
priv->params.num_channels = count;
+ mlx5e_build_default_indir_rqt(priv->params.indirection_rqt,
+ MLX5E_INDIR_RQT_SIZE, count);
if (was_opened)
err = mlx5e_open_locked(dev);
@@ -703,18 +705,36 @@ static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
return 0;
}
+static void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen)
+{
+ struct mlx5_core_dev *mdev = priv->mdev;
+ void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx);
+ int i;
+
+ MLX5_SET(modify_tir_in, in, bitmask.hash, 1);
+ mlx5e_build_tir_ctx_hash(tirc, priv);
+
+ for (i = 0; i < MLX5E_NUM_TT; i++)
+ if (IS_HASHING_TT(i))
+ mlx5_core_modify_tir(mdev, priv->tirn[i], in, inlen);
+}
+
static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
const u8 *key, const u8 hfunc)
{
struct mlx5e_priv *priv = netdev_priv(dev);
- bool close_open;
- int err = 0;
+ int inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
+ void *in;
if ((hfunc != ETH_RSS_HASH_NO_CHANGE) &&
(hfunc != ETH_RSS_HASH_XOR) &&
(hfunc != ETH_RSS_HASH_TOP))
return -EINVAL;
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
mutex_lock(&priv->state_lock);
if (indir) {
@@ -723,11 +743,6 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
mlx5e_redirect_rqt(priv, MLX5E_INDIRECTION_RQT);
}
- close_open = (key || (hfunc != ETH_RSS_HASH_NO_CHANGE)) &&
- test_bit(MLX5E_STATE_OPENED, &priv->state);
- if (close_open)
- mlx5e_close_locked(dev);
-
if (key)
memcpy(priv->params.toeplitz_hash_key, key,
sizeof(priv->params.toeplitz_hash_key));
@@ -735,12 +750,13 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
if (hfunc != ETH_RSS_HASH_NO_CHANGE)
priv->params.rss_hfunc = hfunc;
- if (close_open)
- err = mlx5e_open_locked(priv->netdev);
+ mlx5e_modify_tirs_hash(priv, in, inlen);
mutex_unlock(&priv->state_lock);
- return err;
+ kvfree(in);
+
+ return 0;
}
static int mlx5e_get_rxnfc(struct net_device *netdev,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 6a3e430f1062..402994bf7e16 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -141,6 +141,10 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
return;
/* Collect firts the SW counters and then HW for consistency */
+ s->rx_packets = 0;
+ s->rx_bytes = 0;
+ s->tx_packets = 0;
+ s->tx_bytes = 0;
s->tso_packets = 0;
s->tso_bytes = 0;
s->tx_queue_stopped = 0;
@@ -155,6 +159,8 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
for (i = 0; i < priv->params.num_channels; i++) {
rq_stats = &priv->channel[i]->rq.stats;
+ s->rx_packets += rq_stats->packets;
+ s->rx_bytes += rq_stats->bytes;
s->lro_packets += rq_stats->lro_packets;
s->lro_bytes += rq_stats->lro_bytes;
s->rx_csum_none += rq_stats->csum_none;
@@ -164,6 +170,8 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
for (j = 0; j < priv->params.num_tc; j++) {
sq_stats = &priv->channel[i]->sq[j].stats;
+ s->tx_packets += sq_stats->packets;
+ s->tx_bytes += sq_stats->bytes;
s->tso_packets += sq_stats->tso_packets;
s->tso_bytes += sq_stats->tso_bytes;
s->tx_queue_stopped += sq_stats->stopped;
@@ -225,23 +233,6 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
s->tx_broadcast_bytes =
MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
- s->rx_packets =
- s->rx_unicast_packets +
- s->rx_multicast_packets +
- s->rx_broadcast_packets;
- s->rx_bytes =
- s->rx_unicast_bytes +
- s->rx_multicast_bytes +
- s->rx_broadcast_bytes;
- s->tx_packets =
- s->tx_unicast_packets +
- s->tx_multicast_packets +
- s->tx_broadcast_packets;
- s->tx_bytes =
- s->tx_unicast_bytes +
- s->tx_multicast_bytes +
- s->tx_broadcast_bytes;
-
/* Update calculated offload counters */
s->tx_csum_offload = s->tx_packets - tx_offload_none;
s->rx_csum_good = s->rx_packets - s->rx_csum_none -
@@ -1199,7 +1190,6 @@ static void mlx5e_fill_indir_rqt_rqns(struct mlx5e_priv *priv, void *rqtc)
ix = mlx5e_bits_invert(i, MLX5E_LOG_INDIR_RQT_SIZE);
ix = priv->params.indirection_rqt[ix];
- ix = ix % priv->params.num_channels;
MLX5_SET(rqtc, rqtc, rq_num[i],
test_bit(MLX5E_STATE_OPENED, &priv->state) ?
priv->channel[ix]->rq.rqn :
@@ -1317,7 +1307,22 @@ static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv)
lro_timer_supported_periods[2]));
}
-static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
+void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv)
+{
+ MLX5_SET(tirc, tirc, rx_hash_fn,
+ mlx5e_rx_hash_fn(priv->params.rss_hfunc));
+ if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) {
+ void *rss_key = MLX5_ADDR_OF(tirc, tirc,
+ rx_hash_toeplitz_key);
+ size_t len = MLX5_FLD_SZ_BYTES(tirc,
+ rx_hash_toeplitz_key);
+
+ MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
+ memcpy(rss_key, priv->params.toeplitz_hash_key, len);
+ }
+}
+
+static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
@@ -1325,6 +1330,7 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
void *tirc;
int inlen;
int err;
+ int tt;
inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
in = mlx5_vzalloc(inlen);
@@ -1336,7 +1342,11 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
mlx5e_build_tir_ctx_lro(tirc, priv);
- err = mlx5_core_modify_tir(mdev, priv->tirn[tt], in, inlen);
+ for (tt = 0; tt < MLX5E_NUM_TT; tt++) {
+ err = mlx5_core_modify_tir(mdev, priv->tirn[tt], in, inlen);
+ if (err)
+ break;
+ }
kvfree(in);
@@ -1672,17 +1682,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt)
default:
MLX5_SET(tirc, tirc, indirect_table,
priv->rqtn[MLX5E_INDIRECTION_RQT]);
- MLX5_SET(tirc, tirc, rx_hash_fn,
- mlx5e_rx_hash_fn(priv->params.rss_hfunc));
- if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) {
- void *rss_key = MLX5_ADDR_OF(tirc, tirc,
- rx_hash_toeplitz_key);
- size_t len = MLX5_FLD_SZ_BYTES(tirc,
- rx_hash_toeplitz_key);
-
- MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
- memcpy(rss_key, priv->params.toeplitz_hash_key, len);
- }
+ mlx5e_build_tir_ctx_hash(tirc, priv);
break;
}
@@ -1885,8 +1885,10 @@ static int mlx5e_set_features(struct net_device *netdev,
mlx5e_close_locked(priv->netdev);
priv->params.lro_en = !!(features & NETIF_F_LRO);
- mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV4_TCP);
- mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV6_TCP);
+ err = mlx5e_modify_tirs_lro(priv);
+ if (err)
+ mlx5_core_warn(priv->mdev, "lro modify failed, %d\n",
+ err);
if (was_opened)
err = mlx5e_open_locked(priv->netdev);
@@ -2024,18 +2026,37 @@ static int mlx5e_get_vf_stats(struct net_device *dev,
vf_stats);
}
-static struct net_device_ops mlx5e_netdev_ops = {
+static const struct net_device_ops mlx5e_netdev_ops_basic = {
+ .ndo_open = mlx5e_open,
+ .ndo_stop = mlx5e_close,
+ .ndo_start_xmit = mlx5e_xmit,
+ .ndo_get_stats64 = mlx5e_get_stats,
+ .ndo_set_rx_mode = mlx5e_set_rx_mode,
+ .ndo_set_mac_address = mlx5e_set_mac,
+ .ndo_vlan_rx_add_vid = mlx5e_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = mlx5e_vlan_rx_kill_vid,
+ .ndo_set_features = mlx5e_set_features,
+ .ndo_change_mtu = mlx5e_change_mtu,
+ .ndo_do_ioctl = mlx5e_ioctl,
+};
+
+static const struct net_device_ops mlx5e_netdev_ops_sriov = {
.ndo_open = mlx5e_open,
.ndo_stop = mlx5e_close,
.ndo_start_xmit = mlx5e_xmit,
.ndo_get_stats64 = mlx5e_get_stats,
.ndo_set_rx_mode = mlx5e_set_rx_mode,
.ndo_set_mac_address = mlx5e_set_mac,
- .ndo_vlan_rx_add_vid = mlx5e_vlan_rx_add_vid,
- .ndo_vlan_rx_kill_vid = mlx5e_vlan_rx_kill_vid,
+ .ndo_vlan_rx_add_vid = mlx5e_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = mlx5e_vlan_rx_kill_vid,
.ndo_set_features = mlx5e_set_features,
- .ndo_change_mtu = mlx5e_change_mtu,
- .ndo_do_ioctl = mlx5e_ioctl,
+ .ndo_change_mtu = mlx5e_change_mtu,
+ .ndo_do_ioctl = mlx5e_ioctl,
+ .ndo_set_vf_mac = mlx5e_set_vf_mac,
+ .ndo_set_vf_vlan = mlx5e_set_vf_vlan,
+ .ndo_get_vf_config = mlx5e_get_vf_config,
+ .ndo_set_vf_link_state = mlx5e_set_vf_link_state,
+ .ndo_get_vf_stats = mlx5e_get_vf_stats,
};
static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
@@ -2070,12 +2091,20 @@ u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev)
2 /*sizeof(mlx5e_tx_wqe.inline_hdr_start)*/;
}
+void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len,
+ int num_channels)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ indirection_rqt[i] = i % num_channels;
+}
+
static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
struct net_device *netdev,
int num_channels)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
- int i;
priv->params.log_sq_size =
MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
@@ -2099,8 +2128,8 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
netdev_rss_key_fill(priv->params.toeplitz_hash_key,
sizeof(priv->params.toeplitz_hash_key));
- for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++)
- priv->params.indirection_rqt[i] = i % num_channels;
+ mlx5e_build_default_indir_rqt(priv->params.indirection_rqt,
+ MLX5E_INDIR_RQT_SIZE, num_channels);
priv->params.lro_wqe_sz =
MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ;
@@ -2137,18 +2166,11 @@ static void mlx5e_build_netdev(struct net_device *netdev)
SET_NETDEV_DEV(netdev, &mdev->pdev->dev);
- if (priv->params.num_tc > 1)
- mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue;
-
- if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
- mlx5e_netdev_ops.ndo_set_vf_mac = mlx5e_set_vf_mac;
- mlx5e_netdev_ops.ndo_set_vf_vlan = mlx5e_set_vf_vlan;
- mlx5e_netdev_ops.ndo_get_vf_config = mlx5e_get_vf_config;
- mlx5e_netdev_ops.ndo_set_vf_link_state = mlx5e_set_vf_link_state;
- mlx5e_netdev_ops.ndo_get_vf_stats = mlx5e_get_vf_stats;
- }
+ if (MLX5_CAP_GEN(mdev, vport_group_manager))
+ netdev->netdev_ops = &mlx5e_netdev_ops_sriov;
+ else
+ netdev->netdev_ops = &mlx5e_netdev_ops_basic;
- netdev->netdev_ops = &mlx5e_netdev_ops;
netdev->watchdog_timeo = 15 * HZ;
netdev->ethtool_ops = &mlx5e_ethtool_ops;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index dd959d929aad..59658b9d05d1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -230,10 +230,6 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
struct mlx5e_rq *rq = container_of(cq, struct mlx5e_rq, cq);
int work_done;
- /* avoid accessing cq (dma coherent memory) if not needed */
- if (!test_and_clear_bit(MLX5E_CQ_HAS_CQES, &cq->flags))
- return 0;
-
for (work_done = 0; work_done < budget; work_done++) {
struct mlx5e_rx_wqe *wqe;
struct mlx5_cqe64 *cqe;
@@ -267,6 +263,7 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
mlx5e_build_rx_skb(cqe, rq, skb);
rq->stats.packets++;
+ rq->stats.bytes += be32_to_cpu(cqe->byte_cnt);
napi_gro_receive(cq->napi, skb);
wq_ll_pop:
@@ -279,8 +276,5 @@ wq_ll_pop:
/* ensure cq space is freed before enabling more cqes */
wmb();
- if (work_done == budget)
- set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);
-
return work_done;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index 2c3fba0fff54..bb4eeeb007de 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -179,6 +179,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
unsigned int skb_len = skb->len;
u8 opcode = MLX5_OPCODE_SEND;
dma_addr_t dma_addr = 0;
+ unsigned int num_bytes;
bool bf = false;
u16 headlen;
u16 ds_cnt;
@@ -204,8 +205,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
opcode = MLX5_OPCODE_LSO;
ihs = skb_transport_offset(skb) + tcp_hdrlen(skb);
payload_len = skb->len - ihs;
- wi->num_bytes = skb->len +
- (skb_shinfo(skb)->gso_segs - 1) * ihs;
+ num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs;
sq->stats.tso_packets++;
sq->stats.tso_bytes += payload_len;
} else {
@@ -213,9 +213,11 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
!skb->xmit_more &&
!skb_shinfo(skb)->nr_frags;
ihs = mlx5e_get_inline_hdr_size(sq, skb, bf);
- wi->num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
+ num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
}
+ wi->num_bytes = num_bytes;
+
if (skb_vlan_tag_present(skb)) {
mlx5e_insert_vlan(eseg->inline_hdr_start, skb, ihs, &skb_data,
&skb_len);
@@ -307,6 +309,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
sq->bf_budget = bf ? sq->bf_budget - 1 : 0;
sq->stats.packets++;
+ sq->stats.bytes += num_bytes;
return NETDEV_TX_OK;
dma_unmap_wqe_err:
@@ -335,10 +338,6 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)
u16 sqcc;
int i;
- /* avoid accessing cq (dma coherent memory) if not needed */
- if (!test_and_clear_bit(MLX5E_CQ_HAS_CQES, &cq->flags))
- return false;
-
sq = container_of(cq, struct mlx5e_sq, cq);
npkts = 0;
@@ -422,10 +421,6 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)
netif_tx_wake_queue(sq->txq);
sq->stats.wake++;
}
- if (i == MLX5E_TX_CQ_POLL_BUDGET) {
- set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);
- return true;
- }
- return false;
+ return (i == MLX5E_TX_CQ_POLL_BUDGET);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
index 4ac8d716dbdd..66d51a77609e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
@@ -88,7 +88,6 @@ void mlx5e_completion_event(struct mlx5_core_cq *mcq)
{
struct mlx5e_cq *cq = container_of(mcq, struct mlx5e_cq, mcq);
- set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);
set_bit(MLX5E_CHANNEL_NAPI_SCHED, &cq->channel->flags);
barrier();
napi_schedule(cq->napi);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index c071077aafbd..7992c553c1f5 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -215,7 +215,7 @@ mlxsw_pci_queue_elem_info_producer_get(struct mlxsw_pci_queue *q)
{
int index = q->producer_counter & (q->count - 1);
- if ((q->producer_counter - q->consumer_counter) == q->count)
+ if ((u16) (q->producer_counter - q->consumer_counter) == q->count)
return NULL;
return mlxsw_pci_queue_elem_info_get(q, index);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/port.h b/drivers/net/ethernet/mellanox/mlxsw/port.h
index 726f5435b32f..ae65b9940aed 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/port.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/port.h
@@ -49,7 +49,7 @@
#define MLXSW_PORT_MID 0xd000
#define MLXSW_PORT_MAX_PHY_PORTS 0x40
-#define MLXSW_PORT_MAX_PORTS MLXSW_PORT_MAX_PHY_PORTS
+#define MLXSW_PORT_MAX_PORTS (MLXSW_PORT_MAX_PHY_PORTS + 1)
#define MLXSW_PORT_DEVID_BITS_OFFSET 10
#define MLXSW_PORT_PHY_BITS_OFFSET 4
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index bb77e2207804..ffe4c0305733 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -873,6 +873,62 @@ static inline void mlxsw_reg_spvm_pack(char *payload, u8 local_port,
}
}
+/* SPAFT - Switch Port Acceptable Frame Types
+ * ------------------------------------------
+ * The Switch Port Acceptable Frame Types register configures the frame
+ * admittance of the port.
+ */
+#define MLXSW_REG_SPAFT_ID 0x2010
+#define MLXSW_REG_SPAFT_LEN 0x08
+
+static const struct mlxsw_reg_info mlxsw_reg_spaft = {
+ .id = MLXSW_REG_SPAFT_ID,
+ .len = MLXSW_REG_SPAFT_LEN,
+};
+
+/* reg_spaft_local_port
+ * Local port number.
+ * Access: Index
+ *
+ * Note: CPU port is not supported (all tag types are allowed).
+ */
+MLXSW_ITEM32(reg, spaft, local_port, 0x00, 16, 8);
+
+/* reg_spaft_sub_port
+ * Virtual port within the physical port.
+ * Should be set to 0 when virtual ports are not enabled on the port.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, spaft, sub_port, 0x00, 8, 8);
+
+/* reg_spaft_allow_untagged
+ * When set, untagged frames on the ingress are allowed (default).
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, spaft, allow_untagged, 0x04, 31, 1);
+
+/* reg_spaft_allow_prio_tagged
+ * When set, priority tagged frames on the ingress are allowed (default).
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, spaft, allow_prio_tagged, 0x04, 30, 1);
+
+/* reg_spaft_allow_tagged
+ * When set, tagged frames on the ingress are allowed (default).
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, spaft, allow_tagged, 0x04, 29, 1);
+
+static inline void mlxsw_reg_spaft_pack(char *payload, u8 local_port,
+ bool allow_untagged)
+{
+ MLXSW_REG_ZERO(spaft, payload);
+ mlxsw_reg_spaft_local_port_set(payload, local_port);
+ mlxsw_reg_spaft_allow_untagged_set(payload, allow_untagged);
+ mlxsw_reg_spaft_allow_prio_tagged_set(payload, true);
+ mlxsw_reg_spaft_allow_tagged_set(payload, true);
+}
+
/* SFGC - Switch Flooding Group Configuration
* ------------------------------------------
* The following register controls the association of flooding tables and MIDs
@@ -3203,6 +3259,8 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id)
return "SPVID";
case MLXSW_REG_SPVM_ID:
return "SPVM";
+ case MLXSW_REG_SPAFT_ID:
+ return "SPAFT";
case MLXSW_REG_SFGC_ID:
return "SFGC";
case MLXSW_REG_SFTR_ID:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 217856bdd400..a94daa8c346c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -2123,6 +2123,8 @@ static int mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
if (flush_fdb && mlxsw_sp_port_fdb_flush(mlxsw_sp_port))
netdev_err(mlxsw_sp_port->dev, "Failed to flush FDB\n");
+ mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
+
mlxsw_sp_port->learning = 0;
mlxsw_sp_port->learning_sync = 0;
mlxsw_sp_port->uc_flood = 0;
@@ -2356,9 +2358,7 @@ static int mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
if (mlxsw_sp_port->bridged) {
mlxsw_sp_port_active_vlans_del(mlxsw_sp_port);
mlxsw_sp_port_bridge_leave(mlxsw_sp_port, false);
-
- if (lag->ref_count == 1)
- mlxsw_sp_master_bridge_dec(mlxsw_sp, NULL);
+ mlxsw_sp_master_bridge_dec(mlxsw_sp, NULL);
}
if (lag->ref_count == 1) {
@@ -2746,6 +2746,13 @@ static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport,
goto err_vport_flood_set;
}
+ err = mlxsw_sp_port_stp_state_set(mlxsw_sp_vport, vid,
+ MLXSW_REG_SPMS_STATE_FORWARDING);
+ if (err) {
+ netdev_err(dev, "Failed to set STP state\n");
+ goto err_port_stp_state_set;
+ }
+
if (flush_fdb && mlxsw_sp_vport_fdb_flush(mlxsw_sp_vport))
netdev_err(dev, "Failed to flush FDB\n");
@@ -2763,6 +2770,7 @@ static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport,
return 0;
+err_port_stp_state_set:
err_vport_flood_set:
err_port_vid_learning_set:
err_port_vid_to_fid_validate:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 7f42eb1c320e..3b89ed2f3c76 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -254,5 +254,6 @@ int mlxsw_sp_port_kill_vid(struct net_device *dev,
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
bool set, bool only_uc);
void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port);
+int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
#endif
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index e492ca2cdecd..7b56098acc58 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -370,7 +370,8 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
return err;
}
-static int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ u16 vid)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char spvid_pl[MLXSW_REG_SPVID_LEN];
@@ -379,6 +380,53 @@ static int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl);
}
+static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ bool allow)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ char spaft_pl[MLXSW_REG_SPAFT_LEN];
+
+ mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl);
+}
+
+int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+{
+ struct net_device *dev = mlxsw_sp_port->dev;
+ int err;
+
+ if (!vid) {
+ err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false);
+ if (err) {
+ netdev_err(dev, "Failed to disallow untagged traffic\n");
+ return err;
+ }
+ } else {
+ err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid);
+ if (err) {
+ netdev_err(dev, "Failed to set PVID\n");
+ return err;
+ }
+
+ /* Only allow if not already allowed. */
+ if (!mlxsw_sp_port->pvid) {
+ err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port,
+ true);
+ if (err) {
+ netdev_err(dev, "Failed to allow untagged traffic\n");
+ goto err_port_allow_untagged_set;
+ }
+ }
+ }
+
+ mlxsw_sp_port->pvid = vid;
+ return 0;
+
+err_port_allow_untagged_set:
+ __mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid);
+ return err;
+}
+
static int mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid)
{
char sfmr_pl[MLXSW_REG_SFMR_LEN];
@@ -540,7 +588,12 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
netdev_err(dev, "Unable to add PVID %d\n", vid_begin);
goto err_port_pvid_set;
}
- mlxsw_sp_port->pvid = vid_begin;
+ } else if (!flag_pvid && old_pvid >= vid_begin && old_pvid <= vid_end) {
+ err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0);
+ if (err) {
+ netdev_err(dev, "Unable to del PVID\n");
+ goto err_port_pvid_set;
+ }
}
/* Changing activity bits only if HW operation succeded */
@@ -892,20 +945,18 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
return err;
}
+ if (init)
+ goto out;
+
pvid = mlxsw_sp_port->pvid;
- if (pvid >= vid_begin && pvid <= vid_end && pvid != 1) {
- /* Default VLAN is always 1 */
- err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
+ if (pvid >= vid_begin && pvid <= vid_end) {
+ err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0);
if (err) {
netdev_err(dev, "Unable to del PVID %d\n", pvid);
return err;
}
- mlxsw_sp_port->pvid = 1;
}
- if (init)
- goto out;
-
err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid_begin, vid_end,
false, false);
if (err) {
diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c
index 00cfd95ca59d..3e67f451f2ab 100644
--- a/drivers/net/ethernet/moxa/moxart_ether.c
+++ b/drivers/net/ethernet/moxa/moxart_ether.c
@@ -474,9 +474,9 @@ static int moxart_mac_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ndev->base_addr = res->start;
priv->base = devm_ioremap_resource(p_dev, res);
- ret = IS_ERR(priv->base);
- if (ret) {
+ if (IS_ERR(priv->base)) {
dev_err(p_dev, "devm_ioremap_resource failed\n");
+ ret = PTR_ERR(priv->base);
goto init_fail;
}
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 689a4a5c8dcf..1ef03939d25f 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -811,7 +811,7 @@ qcaspi_netdev_setup(struct net_device *dev)
dev->netdev_ops = &qcaspi_netdev_ops;
qcaspi_set_ethtool_ops(dev);
dev->watchdog_timeo = QCASPI_TX_TIMEOUT;
- dev->flags = IFF_MULTICAST;
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->tx_queue_len = 100;
qca = netdev_priv(dev);
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 17d5571d0432..dd2cf3738b73 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -4933,8 +4933,6 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
break;
case RTL_GIGA_MAC_VER_40:
- RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
- break;
case RTL_GIGA_MAC_VER_41:
case RTL_GIGA_MAC_VER_42:
case RTL_GIGA_MAC_VER_43:
@@ -4943,8 +4941,6 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_46:
case RTL_GIGA_MAC_VER_47:
case RTL_GIGA_MAC_VER_48:
- RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
- break;
case RTL_GIGA_MAC_VER_49:
case RTL_GIGA_MAC_VER_50:
case RTL_GIGA_MAC_VER_51:
@@ -6137,28 +6133,28 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp)
sw_cnt_1ms_ini = 16000000/rg_saw_cnt;
sw_cnt_1ms_ini &= 0x0fff;
data = r8168_mac_ocp_read(tp, 0xd412);
- data &= 0x0fff;
+ data &= ~0x0fff;
data |= sw_cnt_1ms_ini;
r8168_mac_ocp_write(tp, 0xd412, data);
}
data = r8168_mac_ocp_read(tp, 0xe056);
- data &= 0xf0;
- data |= 0x07;
+ data &= ~0xf0;
+ data |= 0x70;
r8168_mac_ocp_write(tp, 0xe056, data);
data = r8168_mac_ocp_read(tp, 0xe052);
- data &= 0x8008;
- data |= 0x6000;
+ data &= ~0x6000;
+ data |= 0x8008;
r8168_mac_ocp_write(tp, 0xe052, data);
data = r8168_mac_ocp_read(tp, 0xe0d6);
- data &= 0x01ff;
+ data &= ~0x01ff;
data |= 0x017f;
r8168_mac_ocp_write(tp, 0xe0d6, data);
data = r8168_mac_ocp_read(tp, 0xd420);
- data &= 0x0fff;
+ data &= ~0x0fff;
data |= 0x047f;
r8168_mac_ocp_write(tp, 0xd420, data);
@@ -7730,10 +7726,13 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
+ struct pci_dev *pdev = tp->pci_dev;
struct rtl8169_counters *counters = tp->counters;
unsigned int start;
- if (netif_running(dev))
+ pm_runtime_get_noresume(&pdev->dev);
+
+ if (netif_running(dev) && pm_runtime_active(&pdev->dev))
rtl8169_rx_missed(dev, ioaddr);
do {
@@ -7761,7 +7760,8 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
* Fetch additonal counter values missing in stats collected by driver
* from tally counters.
*/
- rtl8169_update_counters(dev);
+ if (pm_runtime_active(&pdev->dev))
+ rtl8169_update_counters(dev);
/*
* Subtract values fetched during initalization.
@@ -7774,6 +7774,8 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
stats->tx_aborted_errors = le16_to_cpu(counters->tx_aborted) -
le16_to_cpu(tp->tc_offset.tx_aborted);
+ pm_runtime_put_noidle(&pdev->dev);
+
return stats;
}
@@ -7853,6 +7855,10 @@ static int rtl8169_runtime_suspend(struct device *device)
rtl8169_net_suspend(dev);
+ /* Update counters before going runtime suspend */
+ rtl8169_rx_missed(dev, tp->mmio_addr);
+ rtl8169_update_counters(dev);
+
return 0;
}
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index ac43ed914fcf..86449c357168 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1139,7 +1139,8 @@ static int ravb_set_ringparam(struct net_device *ndev,
if (netif_running(ndev)) {
netif_device_detach(ndev);
/* Stop PTP Clock driver */
- ravb_ptp_stop(ndev);
+ if (priv->chip_id == RCAR_GEN2)
+ ravb_ptp_stop(ndev);
/* Wait for DMA stopping */
error = ravb_stop_dma(ndev);
if (error) {
@@ -1170,7 +1171,8 @@ static int ravb_set_ringparam(struct net_device *ndev,
ravb_emac_init(ndev);
/* Initialise PTP Clock driver */
- ravb_ptp_init(ndev, priv->pdev);
+ if (priv->chip_id == RCAR_GEN2)
+ ravb_ptp_init(ndev, priv->pdev);
netif_device_attach(ndev);
}
@@ -1298,7 +1300,8 @@ static void ravb_tx_timeout_work(struct work_struct *work)
netif_tx_stop_all_queues(ndev);
/* Stop PTP Clock driver */
- ravb_ptp_stop(ndev);
+ if (priv->chip_id == RCAR_GEN2)
+ ravb_ptp_stop(ndev);
/* Wait for DMA stopping */
ravb_stop_dma(ndev);
@@ -1311,7 +1314,8 @@ static void ravb_tx_timeout_work(struct work_struct *work)
ravb_emac_init(ndev);
/* Initialise PTP Clock driver */
- ravb_ptp_init(ndev, priv->pdev);
+ if (priv->chip_id == RCAR_GEN2)
+ ravb_ptp_init(ndev, priv->pdev);
netif_tx_start_all_queues(ndev);
}
@@ -1718,7 +1722,6 @@ static int ravb_set_gti(struct net_device *ndev)
static int ravb_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- const struct of_device_id *match;
struct ravb_private *priv;
enum ravb_chip_id chip_id;
struct net_device *ndev;
@@ -1750,8 +1753,7 @@ static int ravb_probe(struct platform_device *pdev)
ndev->base_addr = res->start;
ndev->dma = -1;
- match = of_match_device(of_match_ptr(ravb_match_table), &pdev->dev);
- chip_id = (enum ravb_chip_id)match->data;
+ chip_id = (enum ravb_chip_id)of_device_get_match_data(&pdev->dev);
if (chip_id == RCAR_GEN3)
irq = platform_get_irq_byname(pdev, "ch22");
@@ -1814,10 +1816,6 @@ static int ravb_probe(struct platform_device *pdev)
CCC_OPC_CONFIG | CCC_GAC | CCC_CSEL_HPB, CCC);
}
- /* Set CSEL value */
- ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_CSEL) | CCC_CSEL_HPB,
- CCC);
-
/* Set GTI value */
error = ravb_set_gti(ndev);
if (error)
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index dfa9e59c9442..738449992876 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -3061,15 +3061,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
mdp->ether_link_active_low = pd->ether_link_active_low;
/* set cpu data */
- if (id) {
+ if (id)
mdp->cd = (struct sh_eth_cpu_data *)id->driver_data;
- } else {
- const struct of_device_id *match;
+ else
+ mdp->cd = (struct sh_eth_cpu_data *)of_device_get_match_data(&pdev->dev);
- match = of_match_device(of_match_ptr(sh_eth_match_table),
- &pdev->dev);
- mdp->cd = (struct sh_eth_cpu_data *)match->data;
- }
mdp->reg_offset = sh_eth_get_register_offset(mdp->cd->register_type);
if (!mdp->reg_offset) {
dev_err(&pdev->dev, "Unknown register type (%d)\n",
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 0e2fc1a844ab..db7db8ac4ca3 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -2342,8 +2342,8 @@ static int smc_drv_probe(struct platform_device *pdev)
}
ndev->irq = platform_get_irq(pdev, 0);
- if (ndev->irq <= 0) {
- ret = -ENODEV;
+ if (ndev->irq < 0) {
+ ret = ndev->irq;
goto out_release_io;
}
/*
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 0faf16336035..efb54f356a67 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -199,21 +199,12 @@ int stmmac_mdio_register(struct net_device *ndev)
struct stmmac_priv *priv = netdev_priv(ndev);
struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
int addr, found;
- struct device_node *mdio_node = NULL;
- struct device_node *child_node = NULL;
+ struct device_node *mdio_node = priv->plat->mdio_node;
if (!mdio_bus_data)
return 0;
if (IS_ENABLED(CONFIG_OF)) {
- for_each_child_of_node(priv->device->of_node, child_node) {
- if (of_device_is_compatible(child_node,
- "snps,dwmac-mdio")) {
- mdio_node = child_node;
- break;
- }
- }
-
if (mdio_node) {
netdev_dbg(ndev, "FOUND MDIO subnode\n");
} else {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 6a52fa18cbf2..4514ba73d961 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -110,6 +110,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
struct device_node *np = pdev->dev.of_node;
struct plat_stmmacenet_data *plat;
struct stmmac_dma_cfg *dma_cfg;
+ struct device_node *child_node = NULL;
plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
if (!plat)
@@ -140,13 +141,19 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
plat->phy_node = of_node_get(np);
}
+ for_each_child_of_node(np, child_node)
+ if (of_device_is_compatible(child_node, "snps,dwmac-mdio")) {
+ plat->mdio_node = child_node;
+ break;
+ }
+
/* "snps,phy-addr" is not a standard property. Mark it as deprecated
* and warn of its use. Remove this when phy node support is added.
*/
if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
- if ((plat->phy_node && !of_phy_is_fixed_link(np)) || plat->phy_bus_name)
+ if ((plat->phy_node && !of_phy_is_fixed_link(np)) || !plat->mdio_node)
plat->mdio_bus_data = NULL;
else
plat->mdio_bus_data =
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index e23a642357e7..2437227712dc 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -51,7 +51,6 @@
#endif
#ifdef CONFIG_PPC_PMAC
-#include <asm/pci-bridge.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c
index fc8bbff2d7e3..af11ed1e0bcc 100644
--- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c
+++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c
@@ -426,7 +426,7 @@
#define DWC_MMC_RXOCTETCOUNT_GB 0x0784
#define DWC_MMC_RXPACKETCOUNT_GB 0x0780
-static int debug = 3;
+static int debug = -1;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "DWC_eth_qos debug level (0=none,...,16=all)");
@@ -650,6 +650,11 @@ struct net_local {
u32 mmc_tx_counters_mask;
struct dwceqos_flowcontrol flowcontrol;
+
+ /* Tracks the intermediate state of phy started but hardware
+ * init not finished yet.
+ */
+ bool phy_defer;
};
static void dwceqos_read_mmc_counters(struct net_local *lp, u32 rx_mask,
@@ -901,6 +906,9 @@ static void dwceqos_adjust_link(struct net_device *ndev)
struct phy_device *phydev = lp->phy_dev;
int status_change = 0;
+ if (lp->phy_defer)
+ return;
+
if (phydev->link) {
if ((lp->speed != phydev->speed) ||
(lp->duplex != phydev->duplex)) {
@@ -1113,7 +1121,7 @@ static int dwceqos_descriptor_init(struct net_local *lp)
/* Allocate DMA descriptors */
size = DWCEQOS_RX_DCNT * sizeof(struct dwceqos_dma_desc);
lp->rx_descs = dma_alloc_coherent(lp->ndev->dev.parent, size,
- &lp->rx_descs_addr, 0);
+ &lp->rx_descs_addr, GFP_KERNEL);
if (!lp->rx_descs)
goto err_out;
lp->rx_descs_tail_addr = lp->rx_descs_addr +
@@ -1121,7 +1129,7 @@ static int dwceqos_descriptor_init(struct net_local *lp)
size = DWCEQOS_TX_DCNT * sizeof(struct dwceqos_dma_desc);
lp->tx_descs = dma_alloc_coherent(lp->ndev->dev.parent, size,
- &lp->tx_descs_addr, 0);
+ &lp->tx_descs_addr, GFP_KERNEL);
if (!lp->tx_descs)
goto err_out;
lp->tx_descs_tail_addr = lp->tx_descs_addr +
@@ -1635,6 +1643,12 @@ static void dwceqos_init_hw(struct net_local *lp)
regval = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG);
dwceqos_write(lp, REG_DWCEQOS_MAC_CFG,
regval | DWCEQOS_MAC_CFG_TE | DWCEQOS_MAC_CFG_RE);
+
+ lp->phy_defer = false;
+ mutex_lock(&lp->phy_dev->lock);
+ phy_read_status(lp->phy_dev);
+ dwceqos_adjust_link(lp->ndev);
+ mutex_unlock(&lp->phy_dev->lock);
}
static void dwceqos_tx_reclaim(unsigned long data)
@@ -1880,9 +1894,13 @@ static int dwceqos_open(struct net_device *ndev)
}
netdev_reset_queue(ndev);
+ /* The dwceqos reset state machine requires all phy clocks to complete,
+ * hence the unusual init order with phy_start first.
+ */
+ lp->phy_defer = true;
+ phy_start(lp->phy_dev);
dwceqos_init_hw(lp);
napi_enable(&lp->napi);
- phy_start(lp->phy_dev);
netif_start_queue(ndev);
tasklet_enable(&lp->tx_bdreclaim_tasklet);
@@ -1915,18 +1933,19 @@ static int dwceqos_stop(struct net_device *ndev)
{
struct net_local *lp = netdev_priv(ndev);
- phy_stop(lp->phy_dev);
-
tasklet_disable(&lp->tx_bdreclaim_tasklet);
- netif_stop_queue(ndev);
napi_disable(&lp->napi);
- dwceqos_drain_dma(lp);
+ /* Stop all tx before we drain the tx dma. */
+ netif_tx_lock_bh(lp->ndev);
+ netif_stop_queue(ndev);
+ netif_tx_unlock_bh(lp->ndev);
- netif_tx_lock(lp->ndev);
+ dwceqos_drain_dma(lp);
dwceqos_reset_hw(lp);
+ phy_stop(lp->phy_dev);
+
dwceqos_descriptor_free(lp);
- netif_tx_unlock(lp->ndev);
return 0;
}
@@ -2178,12 +2197,10 @@ static int dwceqos_start_xmit(struct sk_buff *skb, struct net_device *ndev)
((trans.initial_descriptor + trans.nr_descriptors) %
DWCEQOS_TX_DCNT));
- dwceqos_tx_finalize(skb, lp, &trans);
-
- netdev_sent_queue(ndev, skb->len);
-
spin_lock_bh(&lp->tx_lock);
lp->tx_free -= trans.nr_descriptors;
+ dwceqos_tx_finalize(skb, lp, &trans);
+ netdev_sent_queue(ndev, skb->len);
spin_unlock_bh(&lp->tx_lock);
ndev->trans_start = jiffies;
diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c
index e9cc61e1ec74..c3e85acfdc70 100644
--- a/drivers/net/ethernet/ti/cpsw-phy-sel.c
+++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c
@@ -63,8 +63,12 @@ static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv,
mode = AM33XX_GMII_SEL_MODE_RGMII;
break;
- case PHY_INTERFACE_MODE_MII:
default:
+ dev_warn(priv->dev,
+ "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
+ phy_modes(phy_mode));
+ /* fallthrough */
+ case PHY_INTERFACE_MODE_MII:
mode = AM33XX_GMII_SEL_MODE_MII;
break;
};
@@ -106,8 +110,12 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv,
mode = AM33XX_GMII_SEL_MODE_RGMII;
break;
- case PHY_INTERFACE_MODE_MII:
default:
+ dev_warn(priv->dev,
+ "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
+ phy_modes(phy_mode));
+ /* fallthrough */
+ case PHY_INTERFACE_MODE_MII:
mode = AM33XX_GMII_SEL_MODE_MII;
break;
};
diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c
index c61d66d38634..029841f98c32 100644
--- a/drivers/net/ethernet/ti/netcp_core.c
+++ b/drivers/net/ethernet/ti/netcp_core.c
@@ -117,21 +117,17 @@ static void get_pkt_info(dma_addr_t *buff, u32 *buff_len, dma_addr_t *ndesc,
*ndesc = le32_to_cpu(desc->next_desc);
}
-static void get_pad_info(u32 *pad0, u32 *pad1, u32 *pad2, struct knav_dma_desc *desc)
+static u32 get_sw_data(int index, struct knav_dma_desc *desc)
{
- *pad0 = le32_to_cpu(desc->pad[0]);
- *pad1 = le32_to_cpu(desc->pad[1]);
- *pad2 = le32_to_cpu(desc->pad[2]);
+ /* No Endian conversion needed as this data is untouched by hw */
+ return desc->sw_data[index];
}
-static void get_pad_ptr(void **padptr, struct knav_dma_desc *desc)
-{
- u64 pad64;
-
- pad64 = le32_to_cpu(desc->pad[0]) +
- ((u64)le32_to_cpu(desc->pad[1]) << 32);
- *padptr = (void *)(uintptr_t)pad64;
-}
+/* use these macros to get sw data */
+#define GET_SW_DATA0(desc) get_sw_data(0, desc)
+#define GET_SW_DATA1(desc) get_sw_data(1, desc)
+#define GET_SW_DATA2(desc) get_sw_data(2, desc)
+#define GET_SW_DATA3(desc) get_sw_data(3, desc)
static void get_org_pkt_info(dma_addr_t *buff, u32 *buff_len,
struct knav_dma_desc *desc)
@@ -163,13 +159,18 @@ static void set_desc_info(u32 desc_info, u32 pkt_info,
desc->packet_info = cpu_to_le32(pkt_info);
}
-static void set_pad_info(u32 pad0, u32 pad1, u32 pad2, struct knav_dma_desc *desc)
+static void set_sw_data(int index, u32 data, struct knav_dma_desc *desc)
{
- desc->pad[0] = cpu_to_le32(pad0);
- desc->pad[1] = cpu_to_le32(pad1);
- desc->pad[2] = cpu_to_le32(pad1);
+ /* No Endian conversion needed as this data is untouched by hw */
+ desc->sw_data[index] = data;
}
+/* use these macros to set sw data */
+#define SET_SW_DATA0(data, desc) set_sw_data(0, data, desc)
+#define SET_SW_DATA1(data, desc) set_sw_data(1, data, desc)
+#define SET_SW_DATA2(data, desc) set_sw_data(2, data, desc)
+#define SET_SW_DATA3(data, desc) set_sw_data(3, data, desc)
+
static void set_org_pkt_info(dma_addr_t buff, u32 buff_len,
struct knav_dma_desc *desc)
{
@@ -581,7 +582,6 @@ static void netcp_free_rx_desc_chain(struct netcp_intf *netcp,
dma_addr_t dma_desc, dma_buf;
unsigned int buf_len, dma_sz = sizeof(*ndesc);
void *buf_ptr;
- u32 pad[2];
u32 tmp;
get_words(&dma_desc, 1, &desc->next_desc);
@@ -593,14 +593,20 @@ static void netcp_free_rx_desc_chain(struct netcp_intf *netcp,
break;
}
get_pkt_info(&dma_buf, &tmp, &dma_desc, ndesc);
- get_pad_ptr(&buf_ptr, ndesc);
+ /* warning!!!! We are retrieving the virtual ptr in the sw_data
+ * field as a 32bit value. Will not work on 64bit machines
+ */
+ buf_ptr = (void *)GET_SW_DATA0(ndesc);
+ buf_len = (int)GET_SW_DATA1(desc);
dma_unmap_page(netcp->dev, dma_buf, PAGE_SIZE, DMA_FROM_DEVICE);
__free_page(buf_ptr);
knav_pool_desc_put(netcp->rx_pool, desc);
}
-
- get_pad_info(&pad[0], &pad[1], &buf_len, desc);
- buf_ptr = (void *)(uintptr_t)(pad[0] + ((u64)pad[1] << 32));
+ /* warning!!!! We are retrieving the virtual ptr in the sw_data
+ * field as a 32bit value. Will not work on 64bit machines
+ */
+ buf_ptr = (void *)GET_SW_DATA0(desc);
+ buf_len = (int)GET_SW_DATA1(desc);
if (buf_ptr)
netcp_frag_free(buf_len <= PAGE_SIZE, buf_ptr);
@@ -639,7 +645,6 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
dma_addr_t dma_desc, dma_buff;
struct netcp_packet p_info;
struct sk_buff *skb;
- u32 pad[2];
void *org_buf_ptr;
dma_desc = knav_queue_pop(netcp->rx_queue, &dma_sz);
@@ -653,8 +658,11 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
}
get_pkt_info(&dma_buff, &buf_len, &dma_desc, desc);
- get_pad_info(&pad[0], &pad[1], &org_buf_len, desc);
- org_buf_ptr = (void *)(uintptr_t)(pad[0] + ((u64)pad[1] << 32));
+ /* warning!!!! We are retrieving the virtual ptr in the sw_data
+ * field as a 32bit value. Will not work on 64bit machines
+ */
+ org_buf_ptr = (void *)GET_SW_DATA0(desc);
+ org_buf_len = (int)GET_SW_DATA1(desc);
if (unlikely(!org_buf_ptr)) {
dev_err(netcp->ndev_dev, "NULL bufptr in desc\n");
@@ -679,7 +687,6 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
/* Fill in the page fragment list */
while (dma_desc) {
struct page *page;
- void *ptr;
ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz);
if (unlikely(!ndesc)) {
@@ -688,8 +695,10 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
}
get_pkt_info(&dma_buff, &buf_len, &dma_desc, ndesc);
- get_pad_ptr(&ptr, ndesc);
- page = ptr;
+ /* warning!!!! We are retrieving the virtual ptr in the sw_data
+ * field as a 32bit value. Will not work on 64bit machines
+ */
+ page = (struct page *)GET_SW_DATA0(desc);
if (likely(dma_buff && buf_len && page)) {
dma_unmap_page(netcp->dev, dma_buff, PAGE_SIZE,
@@ -777,7 +786,10 @@ static void netcp_free_rx_buf(struct netcp_intf *netcp, int fdq)
}
get_org_pkt_info(&dma, &buf_len, desc);
- get_pad_ptr(&buf_ptr, desc);
+ /* warning!!!! We are retrieving the virtual ptr in the sw_data
+ * field as a 32bit value. Will not work on 64bit machines
+ */
+ buf_ptr = (void *)GET_SW_DATA0(desc);
if (unlikely(!dma)) {
dev_err(netcp->ndev_dev, "NULL orig_buff in desc\n");
@@ -829,7 +841,7 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
struct page *page;
dma_addr_t dma;
void *bufptr;
- u32 pad[3];
+ u32 sw_data[2];
/* Allocate descriptor */
hwdesc = knav_pool_desc_get(netcp->rx_pool);
@@ -846,7 +858,7 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
bufptr = netdev_alloc_frag(primary_buf_len);
- pad[2] = primary_buf_len;
+ sw_data[1] = primary_buf_len;
if (unlikely(!bufptr)) {
dev_warn_ratelimited(netcp->ndev_dev,
@@ -858,9 +870,10 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
if (unlikely(dma_mapping_error(netcp->dev, dma)))
goto fail;
- pad[0] = lower_32_bits((uintptr_t)bufptr);
- pad[1] = upper_32_bits((uintptr_t)bufptr);
-
+ /* warning!!!! We are saving the virtual ptr in the sw_data
+ * field as a 32bit value. Will not work on 64bit machines
+ */
+ sw_data[0] = (u32)bufptr;
} else {
/* Allocate a secondary receive queue entry */
page = alloc_page(GFP_ATOMIC | GFP_DMA | __GFP_COLD);
@@ -870,9 +883,11 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
}
buf_len = PAGE_SIZE;
dma = dma_map_page(netcp->dev, page, 0, buf_len, DMA_TO_DEVICE);
- pad[0] = lower_32_bits(dma);
- pad[1] = upper_32_bits(dma);
- pad[2] = 0;
+ /* warning!!!! We are saving the virtual ptr in the sw_data
+ * field as a 32bit value. Will not work on 64bit machines
+ */
+ sw_data[0] = (u32)page;
+ sw_data[1] = 0;
}
desc_info = KNAV_DMA_DESC_PS_INFO_IN_DESC;
@@ -882,7 +897,8 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
pkt_info |= (netcp->rx_queue_id & KNAV_DMA_DESC_RETQ_MASK) <<
KNAV_DMA_DESC_RETQ_SHIFT;
set_org_pkt_info(dma, buf_len, hwdesc);
- set_pad_info(pad[0], pad[1], pad[2], hwdesc);
+ SET_SW_DATA0(sw_data[0], hwdesc);
+ SET_SW_DATA1(sw_data[1], hwdesc);
set_desc_info(desc_info, pkt_info, hwdesc);
/* Push to FDQs */
@@ -971,7 +987,6 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
unsigned int budget)
{
struct knav_dma_desc *desc;
- void *ptr;
struct sk_buff *skb;
unsigned int dma_sz;
dma_addr_t dma;
@@ -988,8 +1003,10 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
continue;
}
- get_pad_ptr(&ptr, desc);
- skb = ptr;
+ /* warning!!!! We are retrieving the virtual ptr in the sw_data
+ * field as a 32bit value. Will not work on 64bit machines
+ */
+ skb = (struct sk_buff *)GET_SW_DATA0(desc);
netcp_free_tx_desc_chain(netcp, desc, dma_sz);
if (!skb) {
dev_err(netcp->ndev_dev, "No skb in Tx desc\n");
@@ -1194,10 +1211,10 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
}
set_words(&tmp, 1, &desc->packet_info);
- tmp = lower_32_bits((uintptr_t)&skb);
- set_words(&tmp, 1, &desc->pad[0]);
- tmp = upper_32_bits((uintptr_t)&skb);
- set_words(&tmp, 1, &desc->pad[1]);
+ /* warning!!!! We are saving the virtual ptr in the sw_data
+ * field as a 32bit value. Will not work on 64bit machines
+ */
+ SET_SW_DATA0((u32)skb, desc);
if (tx_pipe->flags & SWITCH_TO_PORT_IN_TAGINFO) {
tmp = tx_pipe->switch_to_port;
diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c
index 3c54a2cae5df..67610270d171 100644
--- a/drivers/net/ethernet/toshiba/spider_net.c
+++ b/drivers/net/ethernet/toshiba/spider_net.c
@@ -48,7 +48,6 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
-#include <asm/pci-bridge.h>
#include <net/checksum.h>
#include "spider_net.h"
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 028e3873c310..0bf7edd99573 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1039,17 +1039,34 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
return geneve_xmit_skb(skb, dev, info);
}
-static int geneve_change_mtu(struct net_device *dev, int new_mtu)
+static int __geneve_change_mtu(struct net_device *dev, int new_mtu, bool strict)
{
- /* GENEVE overhead is not fixed, so we can't enforce a more
- * precise max MTU.
+ /* The max_mtu calculation does not take account of GENEVE
+ * options, to avoid excluding potentially valid
+ * configurations.
*/
- if (new_mtu < 68 || new_mtu > IP_MAX_MTU)
+ int max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - sizeof(struct iphdr)
+ - dev->hard_header_len;
+
+ if (new_mtu < 68)
return -EINVAL;
+
+ if (new_mtu > max_mtu) {
+ if (strict)
+ return -EINVAL;
+
+ new_mtu = max_mtu;
+ }
+
dev->mtu = new_mtu;
return 0;
}
+static int geneve_change_mtu(struct net_device *dev, int new_mtu)
+{
+ return __geneve_change_mtu(dev, new_mtu, true);
+}
+
static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
{
struct ip_tunnel_info *info = skb_tunnel_info(skb);
@@ -1161,6 +1178,7 @@ static void geneve_setup(struct net_device *dev)
dev->hw_features |= NETIF_F_GSO_SOFTWARE;
netif_keep_dst(dev);
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
eth_hw_addr_random(dev);
}
@@ -1452,14 +1470,15 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
return dev;
err = geneve_configure(net, dev, &geneve_remote_unspec,
- 0, 0, 0, htons(dst_port), true, 0);
+ 0, 0, 0, htons(dst_port), true,
+ GENEVE_F_UDP_ZERO_CSUM6_RX);
if (err)
goto err;
/* openvswitch users expect packet sizes to be unrestricted,
* so set the largest MTU we can.
*/
- err = geneve_change_mtu(dev, IP_MAX_MTU);
+ err = __geneve_change_mtu(dev, IP_MAX_MTU, false);
if (err)
goto err;
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 1d3a66563bac..98e34fee45c7 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1089,6 +1089,9 @@ static int netvsc_probe(struct hv_device *dev,
net->ethtool_ops = &ethtool_ops;
SET_NETDEV_DEV(net, &dev->device);
+ /* We always need headroom for rndis header */
+ net->needed_headroom = RNDIS_AND_PPI_SIZE;
+
/* Notify the netvsc driver of the new device */
memset(&device_info, 0, sizeof(device_info));
device_info.ring_size = ring_size;
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 696852eb23c3..7a3f990c1935 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -430,16 +430,6 @@ static int irtty_open(struct tty_struct *tty)
/* Module stuff handled via irda_ldisc.owner - Jean II */
- /* First make sure we're not already connected. */
- if (tty->disc_data != NULL) {
- priv = tty->disc_data;
- if (priv && priv->magic == IRTTY_MAGIC) {
- ret = -EEXIST;
- goto out;
- }
- tty->disc_data = NULL; /* ### */
- }
-
/* stop the underlying driver */
irtty_stop_receiver(tty, TRUE);
if (tty->ops->stop)
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index bf241a3ec5e5..db507e3bcab9 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -250,10 +250,6 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
phy_read(phydev, MII_BCM7XXX_AUX_MODE);
- /* Workaround only required for 100Mbits/sec capable PHYs */
- if (phydev->supported & PHY_GBIT_FEATURES)
- return 0;
-
/* set shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
@@ -270,7 +266,7 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
/* reset shadow mode 2 */
- ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0);
+ ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
if (ret < 0)
return ret;
@@ -307,11 +303,6 @@ static int bcm7xxx_suspend(struct phy_device *phydev)
return 0;
}
-static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
-{
- return 0;
-}
-
#define BCM7XXX_28NM_GPHY(_oui, _name) \
{ \
.phy_id = (_oui), \
@@ -337,7 +328,7 @@ static struct phy_driver bcm7xxx_driver[] = {
.phy_id = PHY_ID_BCM7425,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM7425",
- .features = PHY_GBIT_FEATURES |
+ .features = PHY_BASIC_FEATURES |
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
.flags = PHY_IS_INTERNAL,
.config_init = bcm7xxx_config_init,
@@ -349,7 +340,7 @@ static struct phy_driver bcm7xxx_driver[] = {
.phy_id = PHY_ID_BCM7429,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM7429",
- .features = PHY_GBIT_FEATURES |
+ .features = PHY_BASIC_FEATURES |
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
.flags = PHY_IS_INTERNAL,
.config_init = bcm7xxx_config_init,
@@ -361,7 +352,7 @@ static struct phy_driver bcm7xxx_driver[] = {
.phy_id = PHY_ID_BCM7435,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM7435",
- .features = PHY_GBIT_FEATURES |
+ .features = PHY_BASIC_FEATURES |
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
.flags = PHY_IS_INTERNAL,
.config_init = bcm7xxx_config_init,
@@ -369,30 +360,6 @@ static struct phy_driver bcm7xxx_driver[] = {
.read_status = genphy_read_status,
.suspend = bcm7xxx_suspend,
.resume = bcm7xxx_config_init,
-}, {
- .phy_id = PHY_BCM_OUI_4,
- .phy_id_mask = 0xffff0000,
- .name = "Broadcom BCM7XXX 40nm",
- .features = PHY_GBIT_FEATURES |
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
- .flags = PHY_IS_INTERNAL,
- .config_init = bcm7xxx_config_init,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .suspend = bcm7xxx_suspend,
- .resume = bcm7xxx_config_init,
-}, {
- .phy_id = PHY_BCM_OUI_5,
- .phy_id_mask = 0xffffff00,
- .name = "Broadcom BCM7XXX 65nm",
- .features = PHY_BASIC_FEATURES |
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
- .flags = PHY_IS_INTERNAL,
- .config_init = bcm7xxx_dummy_config_init,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .suspend = bcm7xxx_suspend,
- .resume = bcm7xxx_config_init,
} };
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
@@ -404,8 +371,6 @@ static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
{ PHY_ID_BCM7439, 0xfffffff0, },
{ PHY_ID_BCM7435, 0xfffffff0, },
{ PHY_ID_BCM7445, 0xfffffff0, },
- { PHY_BCM_OUI_4, 0xffff0000 },
- { PHY_BCM_OUI_5, 0xffffff00 },
{ }
};
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index e3eb96443c97..ab1d0fcaf1d9 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -446,6 +446,12 @@ static int m88e1510_config_aneg(struct phy_device *phydev)
if (err < 0)
return err;
+ return 0;
+}
+
+static int marvell_config_init(struct phy_device *phydev)
+{
+ /* Set registers from marvell,reg-init DT property */
return marvell_of_reg_init(phydev);
}
@@ -495,7 +501,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)
mdelay(500);
- return 0;
+ return marvell_config_init(phydev);
}
static int m88e3016_config_init(struct phy_device *phydev)
@@ -514,7 +520,7 @@ static int m88e3016_config_init(struct phy_device *phydev)
if (reg < 0)
return reg;
- return 0;
+ return marvell_config_init(phydev);
}
static int m88e1111_config_init(struct phy_device *phydev)
@@ -1078,6 +1084,7 @@ static struct phy_driver marvell_drivers[] = {
.features = PHY_GBIT_FEATURES,
.probe = marvell_probe,
.flags = PHY_HAS_INTERRUPT,
+ .config_init = &marvell_config_init,
.config_aneg = &marvell_config_aneg,
.read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
@@ -1149,6 +1156,7 @@ static struct phy_driver marvell_drivers[] = {
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.probe = marvell_probe,
+ .config_init = &marvell_config_init,
.config_aneg = &m88e1121_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
@@ -1167,6 +1175,7 @@ static struct phy_driver marvell_drivers[] = {
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.probe = marvell_probe,
+ .config_init = &marvell_config_init,
.config_aneg = &m88e1318_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
@@ -1259,6 +1268,7 @@ static struct phy_driver marvell_drivers[] = {
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.probe = marvell_probe,
+ .config_init = &marvell_config_init,
.config_aneg = &m88e1510_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
@@ -1277,6 +1287,7 @@ static struct phy_driver marvell_drivers[] = {
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.probe = marvell_probe,
+ .config_init = &marvell_config_init,
.config_aneg = &m88e1510_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 03833dbfca67..dc85f7095e51 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -297,6 +297,17 @@ static int kszphy_config_init(struct phy_device *phydev)
if (priv->led_mode >= 0)
kszphy_setup_led(phydev, type->led_mode_reg, priv->led_mode);
+ if (phy_interrupt_is_valid(phydev)) {
+ int ctl = phy_read(phydev, MII_BMCR);
+
+ if (ctl < 0)
+ return ctl;
+
+ ret = phy_write(phydev, MII_BMCR, ctl & ~BMCR_ANENABLE);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
@@ -635,6 +646,21 @@ static void kszphy_get_stats(struct phy_device *phydev,
data[i] = kszphy_get_stat(phydev, i);
}
+static int kszphy_resume(struct phy_device *phydev)
+{
+ int value;
+
+ mutex_lock(&phydev->lock);
+
+ value = phy_read(phydev, MII_BMCR);
+ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+
+ kszphy_config_intr(phydev);
+ mutex_unlock(&phydev->lock);
+
+ return 0;
+}
+
static int kszphy_probe(struct phy_device *phydev)
{
const struct kszphy_type *type = phydev->drv->driver_data;
@@ -844,7 +870,7 @@ static struct phy_driver ksphy_driver[] = {
.get_strings = kszphy_get_strings,
.get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
- .resume = genphy_resume,
+ .resume = kszphy_resume,
}, {
.phy_id = PHY_ID_KSZ8061,
.name = "Micrel KSZ8061",
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index bad3f005faee..e551f3a89cfd 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1410,7 +1410,7 @@ int genphy_config_init(struct phy_device *phydev)
features = (SUPPORTED_TP | SUPPORTED_MII
| SUPPORTED_AUI | SUPPORTED_FIBRE |
- SUPPORTED_BNC);
+ SUPPORTED_BNC | SUPPORTED_Pause | SUPPORTED_Asym_Pause);
/* Do we support autonegotiation? */
val = phy_read(phydev, MII_BMSR);
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index fc8ad001bc94..d61da9ece3ba 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -443,9 +443,14 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
* network traffic (demand mode).
*/
struct ppp *ppp = PF_TO_PPP(pf);
+
+ ppp_recv_lock(ppp);
if (ppp->n_channels == 0 &&
- (ppp->flags & SC_LOOP_TRAFFIC) == 0)
+ (ppp->flags & SC_LOOP_TRAFFIC) == 0) {
+ ppp_recv_unlock(ppp);
break;
+ }
+ ppp_recv_unlock(ppp);
}
ret = -EAGAIN;
if (file->f_flags & O_NONBLOCK)
@@ -532,9 +537,12 @@ static unsigned int ppp_poll(struct file *file, poll_table *wait)
else if (pf->kind == INTERFACE) {
/* see comment in ppp_read */
struct ppp *ppp = PF_TO_PPP(pf);
+
+ ppp_recv_lock(ppp);
if (ppp->n_channels == 0 &&
(ppp->flags & SC_LOOP_TRAFFIC) == 0)
mask |= POLLIN | POLLRDNORM;
+ ppp_recv_unlock(ppp);
}
return mask;
@@ -2808,6 +2816,7 @@ static struct ppp *ppp_create_interface(struct net *net, int unit,
out2:
mutex_unlock(&pn->all_ppp_mutex);
+ rtnl_unlock();
free_netdev(dev);
out1:
*retp = ret;
diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c
index 05005c660d4d..f60f7660b451 100644
--- a/drivers/net/ppp/ppp_mppe.c
+++ b/drivers/net/ppp/ppp_mppe.c
@@ -42,6 +42,8 @@
* deprecated in 2.6
*/
+#include <crypto/hash.h>
+#include <crypto/skcipher.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -49,7 +51,6 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/crypto.h>
#include <linux/mm.h>
#include <linux/ppp_defs.h>
#include <linux/ppp-comp.h>
@@ -94,8 +95,8 @@ static inline void sha_pad_init(struct sha_pad *shapad)
* State for an MPPE (de)compressor.
*/
struct ppp_mppe_state {
- struct crypto_blkcipher *arc4;
- struct crypto_hash *sha1;
+ struct crypto_skcipher *arc4;
+ struct crypto_ahash *sha1;
unsigned char *sha1_digest;
unsigned char master_key[MPPE_MAX_KEY_LEN];
unsigned char session_key[MPPE_MAX_KEY_LEN];
@@ -135,7 +136,7 @@ struct ppp_mppe_state {
*/
static void get_new_key_from_sha(struct ppp_mppe_state * state)
{
- struct hash_desc desc;
+ AHASH_REQUEST_ON_STACK(req, state->sha1);
struct scatterlist sg[4];
unsigned int nbytes;
@@ -148,10 +149,12 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state)
nbytes += setup_sg(&sg[3], sha_pad->sha_pad2,
sizeof(sha_pad->sha_pad2));
- desc.tfm = state->sha1;
- desc.flags = 0;
+ ahash_request_set_tfm(req, state->sha1);
+ ahash_request_set_callback(req, 0, NULL, NULL);
+ ahash_request_set_crypt(req, sg, state->sha1_digest, nbytes);
- crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest);
+ crypto_ahash_digest(req);
+ ahash_request_zero(req);
}
/*
@@ -161,20 +164,23 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state)
static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
{
struct scatterlist sg_in[1], sg_out[1];
- struct blkcipher_desc desc = { .tfm = state->arc4 };
+ SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+
+ skcipher_request_set_tfm(req, state->arc4);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
get_new_key_from_sha(state);
if (!initial_key) {
- crypto_blkcipher_setkey(state->arc4, state->sha1_digest,
- state->keylen);
+ crypto_skcipher_setkey(state->arc4, state->sha1_digest,
+ state->keylen);
sg_init_table(sg_in, 1);
sg_init_table(sg_out, 1);
setup_sg(sg_in, state->sha1_digest, state->keylen);
setup_sg(sg_out, state->session_key, state->keylen);
- if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
- state->keylen) != 0) {
+ skcipher_request_set_crypt(req, sg_in, sg_out, state->keylen,
+ NULL);
+ if (crypto_skcipher_encrypt(req))
printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
- }
} else {
memcpy(state->session_key, state->sha1_digest, state->keylen);
}
@@ -184,7 +190,8 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
state->session_key[1] = 0x26;
state->session_key[2] = 0x9e;
}
- crypto_blkcipher_setkey(state->arc4, state->session_key, state->keylen);
+ crypto_skcipher_setkey(state->arc4, state->session_key, state->keylen);
+ skcipher_request_zero(req);
}
/*
@@ -204,19 +211,19 @@ static void *mppe_alloc(unsigned char *options, int optlen)
goto out;
- state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ state->arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(state->arc4)) {
state->arc4 = NULL;
goto out_free;
}
- state->sha1 = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+ state->sha1 = crypto_alloc_ahash("sha1", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(state->sha1)) {
state->sha1 = NULL;
goto out_free;
}
- digestsize = crypto_hash_digestsize(state->sha1);
+ digestsize = crypto_ahash_digestsize(state->sha1);
if (digestsize < MPPE_MAX_KEY_LEN)
goto out_free;
@@ -237,15 +244,12 @@ static void *mppe_alloc(unsigned char *options, int optlen)
return (void *)state;
- out_free:
- if (state->sha1_digest)
- kfree(state->sha1_digest);
- if (state->sha1)
- crypto_free_hash(state->sha1);
- if (state->arc4)
- crypto_free_blkcipher(state->arc4);
- kfree(state);
- out:
+out_free:
+ kfree(state->sha1_digest);
+ crypto_free_ahash(state->sha1);
+ crypto_free_skcipher(state->arc4);
+ kfree(state);
+out:
return NULL;
}
@@ -256,13 +260,10 @@ static void mppe_free(void *arg)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
if (state) {
- if (state->sha1_digest)
kfree(state->sha1_digest);
- if (state->sha1)
- crypto_free_hash(state->sha1);
- if (state->arc4)
- crypto_free_blkcipher(state->arc4);
- kfree(state);
+ crypto_free_ahash(state->sha1);
+ crypto_free_skcipher(state->arc4);
+ kfree(state);
}
}
@@ -368,8 +369,9 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
int isize, int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
- struct blkcipher_desc desc = { .tfm = state->arc4 };
+ SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
int proto;
+ int err;
struct scatterlist sg_in[1], sg_out[1];
/*
@@ -426,7 +428,13 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
sg_init_table(sg_out, 1);
setup_sg(sg_in, ibuf, isize);
setup_sg(sg_out, obuf, osize);
- if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, isize) != 0) {
+
+ skcipher_request_set_tfm(req, state->arc4);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, sg_in, sg_out, isize, NULL);
+ err = crypto_skcipher_encrypt(req);
+ skcipher_request_zero(req);
+ if (err) {
printk(KERN_DEBUG "crypto_cypher_encrypt failed\n");
return -1;
}
@@ -475,7 +483,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
- struct blkcipher_desc desc = { .tfm = state->arc4 };
+ SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
unsigned ccount;
int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
struct scatterlist sg_in[1], sg_out[1];
@@ -609,9 +617,14 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
sg_init_table(sg_out, 1);
setup_sg(sg_in, ibuf, 1);
setup_sg(sg_out, obuf, 1);
- if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, 1) != 0) {
+
+ skcipher_request_set_tfm(req, state->arc4);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, sg_in, sg_out, 1, NULL);
+ if (crypto_skcipher_decrypt(req)) {
printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
- return DECOMP_ERROR;
+ osize = DECOMP_ERROR;
+ goto out_zap_req;
}
/*
@@ -629,9 +642,11 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
/* And finally, decrypt the rest of the packet. */
setup_sg(sg_in, ibuf + 1, isize - 1);
setup_sg(sg_out, obuf + 1, osize - 1);
- if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, isize - 1)) {
+ skcipher_request_set_crypt(req, sg_in, sg_out, isize - 1, NULL);
+ if (crypto_skcipher_decrypt(req)) {
printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
- return DECOMP_ERROR;
+ osize = DECOMP_ERROR;
+ goto out_zap_req;
}
state->stats.unc_bytes += osize;
@@ -642,6 +657,8 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
/* good packet credit */
state->sanity_errors >>= 1;
+out_zap_req:
+ skcipher_request_zero(req);
return osize;
sanity_error:
@@ -714,8 +731,8 @@ static struct compressor ppp_mppe = {
static int __init ppp_mppe_init(void)
{
int answer;
- if (!(crypto_has_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) &&
- crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC)))
+ if (!(crypto_has_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) &&
+ crypto_has_ahash("sha1", 0, CRYPTO_ALG_ASYNC)))
return -ENODEV;
sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index f3c63022eb3c..4ddae8118c85 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -395,6 +395,8 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
if (!__pppoe_xmit(sk_pppox(relay_po), skb))
goto abort_put;
+
+ sock_put(sk_pppox(relay_po));
} else {
if (sock_queue_rcv_skb(sk, skb))
goto abort_kfree;
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 7f83504dfa69..cdde59089f72 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -395,6 +395,10 @@ config USB_NET_RNDIS_HOST
The protocol specification is incomplete, and is controlled by
(and for) Microsoft; it isn't an "Open" ecosystem or market.
+config USB_NET_CDC_SUBSET_ENABLE
+ tristate
+ depends on USB_NET_CDC_SUBSET
+
config USB_NET_CDC_SUBSET
tristate "Simple USB Network Links (CDC Ethernet subset)"
depends on USB_USBNET
@@ -413,6 +417,7 @@ config USB_NET_CDC_SUBSET
config USB_ALI_M5632
bool "ALi M5632 based 'USB 2.0 Data Link' cables"
depends on USB_NET_CDC_SUBSET
+ select USB_NET_CDC_SUBSET_ENABLE
help
Choose this option if you're using a host-to-host cable
based on this design, which supports USB 2.0 high speed.
@@ -420,6 +425,7 @@ config USB_ALI_M5632
config USB_AN2720
bool "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
depends on USB_NET_CDC_SUBSET
+ select USB_NET_CDC_SUBSET_ENABLE
help
Choose this option if you're using a host-to-host cable
based on this design. Note that AnchorChips is now a
@@ -428,6 +434,7 @@ config USB_AN2720
config USB_BELKIN
bool "eTEK based host-to-host cables (Advance, Belkin, ...)"
depends on USB_NET_CDC_SUBSET
+ select USB_NET_CDC_SUBSET_ENABLE
default y
help
Choose this option if you're using a host-to-host cable
@@ -437,6 +444,7 @@ config USB_BELKIN
config USB_ARMLINUX
bool "Embedded ARM Linux links (iPaq, ...)"
depends on USB_NET_CDC_SUBSET
+ select USB_NET_CDC_SUBSET_ENABLE
default y
help
Choose this option to support the "usb-eth" networking driver
@@ -454,6 +462,7 @@ config USB_ARMLINUX
config USB_EPSON2888
bool "Epson 2888 based firmware (DEVELOPMENT)"
depends on USB_NET_CDC_SUBSET
+ select USB_NET_CDC_SUBSET_ENABLE
help
Choose this option to support the usb networking links used
by some sample firmware from Epson.
@@ -461,6 +470,7 @@ config USB_EPSON2888
config USB_KC2190
bool "KT Technology KC2190 based cables (InstaNet)"
depends on USB_NET_CDC_SUBSET
+ select USB_NET_CDC_SUBSET_ENABLE
help
Choose this option if you're using a host-to-host cable
with one of these chips.
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index b5f04068dbe4..37fb46aee341 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -23,7 +23,7 @@ obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
obj-$(CONFIG_USB_NET_NET1080) += net1080.o
obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o
-obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o
+obj-$(CONFIG_USB_NET_CDC_SUBSET_ENABLE) += cdc_subset.o
obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o
obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c
index 224e7d82de6d..cf77f2dffa69 100644
--- a/drivers/net/usb/ax88172a.c
+++ b/drivers/net/usb/ax88172a.c
@@ -134,7 +134,6 @@ static void ax88172a_remove_mdio(struct usbnet *dev)
netdev_info(dev->net, "deregistering mdio bus %s\n", priv->mdio->id);
mdiobus_unregister(priv->mdio);
- kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
}
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index dc0212c3cc28..86ba30ba35e8 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -837,7 +837,11 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
- /* reset data interface */
+ /* Reset data interface. Some devices will not reset properly
+ * unless they are configured first. Toggle the altsetting to
+ * force a reset
+ */
+ usb_set_interface(dev->udev, iface_no, data_altsetting);
temp = usb_set_interface(dev->udev, iface_no, 0);
if (temp) {
dev_dbg(&intf->dev, "set interface failed\n");
@@ -984,8 +988,6 @@ EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting);
static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
{
- int ret;
-
/* MBIM backwards compatible function? */
if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
return -ENODEV;
@@ -994,16 +996,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
* Additionally, generic NCM devices are assumed to accept arbitrarily
* placed NDP.
*/
- ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
-
- /*
- * We should get an event when network connection is "connected" or
- * "disconnected". Set network connection in "disconnected" state
- * (carrier is OFF) during attach, so the IP network stack does not
- * start IPv6 negotiation and more.
- */
- usbnet_link_change(dev, 0, 0);
- return ret;
+ return cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
}
static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max)
@@ -1586,7 +1579,8 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
static const struct driver_info cdc_ncm_info = {
.description = "CDC NCM",
- .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET,
+ .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
+ | FLAG_LINK_INTR,
.bind = cdc_ncm_bind,
.unbind = cdc_ncm_unbind,
.manage_power = usbnet_manage_power,
@@ -1599,7 +1593,7 @@ static const struct driver_info cdc_ncm_info = {
static const struct driver_info wwan_info = {
.description = "Mobile Broadband Network Device",
.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
- | FLAG_WWAN,
+ | FLAG_LINK_INTR | FLAG_WWAN,
.bind = cdc_ncm_bind,
.unbind = cdc_ncm_unbind,
.manage_power = usbnet_manage_power,
@@ -1612,7 +1606,7 @@ static const struct driver_info wwan_info = {
static const struct driver_info wwan_noarp_info = {
.description = "Mobile Broadband Network Device (NO ARP)",
.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
- | FLAG_WWAN | FLAG_NOARP,
+ | FLAG_LINK_INTR | FLAG_WWAN | FLAG_NOARP,
.bind = cdc_ncm_bind,
.unbind = cdc_ncm_unbind,
.manage_power = usbnet_manage_power,
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 23e9880791fc..a3a4ccf7cf52 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -637,6 +637,7 @@ static const struct usb_device_id products[] = {
/* 3. Combined interface devices matching on interface number */
{QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */
+ {QMI_FIXED_INTF(0x05c6, 0x6001, 3)}, /* 4G LTE usb-modem U901 */
{QMI_FIXED_INTF(0x05c6, 0x7000, 0)},
{QMI_FIXED_INTF(0x05c6, 0x7001, 1)},
{QMI_FIXED_INTF(0x05c6, 0x7002, 1)},
@@ -860,8 +861,10 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x1199, 0x9056, 8)}, /* Sierra Wireless Modem */
{QMI_FIXED_INTF(0x1199, 0x9057, 8)},
{QMI_FIXED_INTF(0x1199, 0x9061, 8)}, /* Sierra Wireless Modem */
- {QMI_FIXED_INTF(0x1199, 0x9071, 8)}, /* Sierra Wireless MC74xx/EM74xx */
- {QMI_FIXED_INTF(0x1199, 0x9071, 10)}, /* Sierra Wireless MC74xx/EM74xx */
+ {QMI_FIXED_INTF(0x1199, 0x9071, 8)}, /* Sierra Wireless MC74xx */
+ {QMI_FIXED_INTF(0x1199, 0x9071, 10)}, /* Sierra Wireless MC74xx */
+ {QMI_FIXED_INTF(0x1199, 0x9079, 8)}, /* Sierra Wireless EM74xx */
+ {QMI_FIXED_INTF(0x1199, 0x9079, 10)}, /* Sierra Wireless EM74xx */
{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
{QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */
@@ -884,6 +887,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
+ {QMI_FIXED_INTF(0x413c, 0x81b3, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
{QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */
{QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 0b0ba7ef14e4..10798128c03f 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1769,6 +1769,13 @@ out3:
if (info->unbind)
info->unbind (dev, udev);
out1:
+ /* subdrivers must undo all they did in bind() if they
+ * fail it, but we may fail later and a deferred kevent
+ * may trigger an error resubmitting itself and, worse,
+ * schedule a timer. So we kill it all just in case.
+ */
+ cancel_work_sync(&dev->kevent);
+ del_timer_sync(&dev->delay);
free_netdev(net);
out:
return status;
diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h
index 221a53025fd0..72ba8ae7f09a 100644
--- a/drivers/net/vmxnet3/vmxnet3_defs.h
+++ b/drivers/net/vmxnet3/vmxnet3_defs.h
@@ -377,7 +377,7 @@ union Vmxnet3_GenericDesc {
#define VMXNET3_TX_RING_MAX_SIZE 4096
#define VMXNET3_TC_RING_MAX_SIZE 4096
#define VMXNET3_RX_RING_MAX_SIZE 4096
-#define VMXNET3_RX_RING2_MAX_SIZE 2048
+#define VMXNET3_RX_RING2_MAX_SIZE 4096
#define VMXNET3_RC_RING_MAX_SIZE 8192
/* a list of reasons for queue stop */
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 0cbf520cea77..fc895d0e85d9 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -814,7 +814,7 @@ vmxnet3_tq_init_all(struct vmxnet3_adapter *adapter)
/*
- * parse and copy relevant protocol headers:
+ * parse relevant protocol headers:
* For a tso pkt, relevant headers are L2/3/4 including options
* For a pkt requesting csum offloading, they are L2/3 and may include L4
* if it's a TCP/UDP pkt
@@ -827,15 +827,14 @@ vmxnet3_tq_init_all(struct vmxnet3_adapter *adapter)
* Other effects:
* 1. related *ctx fields are updated.
* 2. ctx->copy_size is # of bytes copied
- * 3. the portion copied is guaranteed to be in the linear part
+ * 3. the portion to be copied is guaranteed to be in the linear part
*
*/
static int
-vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
- struct vmxnet3_tx_ctx *ctx,
- struct vmxnet3_adapter *adapter)
+vmxnet3_parse_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_tx_ctx *ctx,
+ struct vmxnet3_adapter *adapter)
{
- struct Vmxnet3_TxDataDesc *tdd;
u8 protocol = 0;
if (ctx->mss) { /* TSO */
@@ -892,16 +891,34 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
return 0;
}
+ return 1;
+err:
+ return -1;
+}
+
+/*
+ * copy relevant protocol headers to the transmit ring:
+ * For a tso pkt, relevant headers are L2/3/4 including options
+ * For a pkt requesting csum offloading, they are L2/3 and may include L4
+ * if it's a TCP/UDP pkt
+ *
+ *
+ * Note that this requires that vmxnet3_parse_hdr be called first to set the
+ * appropriate bits in ctx first
+ */
+static void
+vmxnet3_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_tx_ctx *ctx,
+ struct vmxnet3_adapter *adapter)
+{
+ struct Vmxnet3_TxDataDesc *tdd;
+
tdd = tq->data_ring.base + tq->tx_ring.next2fill;
memcpy(tdd->data, skb->data, ctx->copy_size);
netdev_dbg(adapter->netdev,
"copy %u bytes to dataRing[%u]\n",
ctx->copy_size, tq->tx_ring.next2fill);
- return 1;
-
-err:
- return -1;
}
@@ -998,22 +1015,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
}
}
- spin_lock_irqsave(&tq->tx_lock, flags);
-
- if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
- tq->stats.tx_ring_full++;
- netdev_dbg(adapter->netdev,
- "tx queue stopped on %s, next2comp %u"
- " next2fill %u\n", adapter->netdev->name,
- tq->tx_ring.next2comp, tq->tx_ring.next2fill);
-
- vmxnet3_tq_stop(tq, adapter);
- spin_unlock_irqrestore(&tq->tx_lock, flags);
- return NETDEV_TX_BUSY;
- }
-
-
- ret = vmxnet3_parse_and_copy_hdr(skb, tq, &ctx, adapter);
+ ret = vmxnet3_parse_hdr(skb, tq, &ctx, adapter);
if (ret >= 0) {
BUG_ON(ret <= 0 && ctx.copy_size != 0);
/* hdrs parsed, check against other limits */
@@ -1033,9 +1035,26 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
}
} else {
tq->stats.drop_hdr_inspect_err++;
- goto unlock_drop_pkt;
+ goto drop_pkt;
}
+ spin_lock_irqsave(&tq->tx_lock, flags);
+
+ if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
+ tq->stats.tx_ring_full++;
+ netdev_dbg(adapter->netdev,
+ "tx queue stopped on %s, next2comp %u"
+ " next2fill %u\n", adapter->netdev->name,
+ tq->tx_ring.next2comp, tq->tx_ring.next2fill);
+
+ vmxnet3_tq_stop(tq, adapter);
+ spin_unlock_irqrestore(&tq->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+
+
+ vmxnet3_copy_hdr(skb, tq, &ctx, adapter);
+
/* fill tx descs related to addr & len */
if (vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter))
goto unlock_drop_pkt;
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index bdb8a6c0f8aa..729c344e6774 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -69,10 +69,10 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.4.5.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.4.6.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01040500
+#define VMXNET3_DRIVER_VERSION_NUM 0x01040600
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 66addb7a7911..bdcf617a9d52 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -104,20 +104,23 @@ static struct dst_ops vrf_dst_ops = {
#if IS_ENABLED(CONFIG_IPV6)
static bool check_ipv6_frame(const struct sk_buff *skb)
{
- const struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->data;
- size_t hlen = sizeof(*ipv6h);
+ const struct ipv6hdr *ipv6h;
+ struct ipv6hdr _ipv6h;
bool rc = true;
- if (skb->len < hlen)
+ ipv6h = skb_header_pointer(skb, 0, sizeof(_ipv6h), &_ipv6h);
+ if (!ipv6h)
goto out;
if (ipv6h->nexthdr == NEXTHDR_ICMP) {
const struct icmp6hdr *icmph;
+ struct icmp6hdr _icmph;
- if (skb->len < hlen + sizeof(*icmph))
+ icmph = skb_header_pointer(skb, sizeof(_ipv6h),
+ sizeof(_icmph), &_icmph);
+ if (!icmph)
goto out;
- icmph = (struct icmp6hdr *)(skb->data + sizeof(*ipv6h));
switch (icmph->icmp6_type) {
case NDISC_ROUTER_SOLICITATION:
case NDISC_ROUTER_ADVERTISEMENT:
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index a31cd954b308..1c32bd104797 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -931,8 +931,10 @@ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
cb->nlh->nlmsg_seq,
RTM_NEWNEIGH,
NLM_F_MULTI, rd);
- if (err < 0)
+ if (err < 0) {
+ cb->args[1] = err;
goto out;
+ }
skip:
++idx;
}
@@ -1306,8 +1308,10 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
gbp = (struct vxlanhdr_gbp *)vxh;
md->gbp = ntohs(gbp->policy_id);
- if (tun_dst)
+ if (tun_dst) {
tun_dst->u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
+ tun_dst->u.tun_info.options_len = sizeof(*md);
+ }
if (gbp->dont_learn)
md->gbp |= VXLAN_GBP_DONT_LEARN;
@@ -2171,9 +2175,11 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
}
- if (vxlan->flags & VXLAN_F_COLLECT_METADATA &&
- info && info->mode & IP_TUNNEL_INFO_TX) {
- vxlan_xmit_one(skb, dev, NULL, false);
+ if (vxlan->flags & VXLAN_F_COLLECT_METADATA) {
+ if (info && info->mode & IP_TUNNEL_INFO_TX)
+ vxlan_xmit_one(skb, dev, NULL, false);
+ else
+ kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -2537,6 +2543,7 @@ static void vxlan_setup(struct net_device *dev)
dev->hw_features |= NETIF_F_GSO_SOFTWARE;
dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
netif_keep_dst(dev);
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
INIT_LIST_HEAD(&vxlan->next);
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 7a72407208b1..629225980463 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -1626,7 +1626,7 @@ try:
if (state & Xpr) {
void __iomem *scc_addr;
unsigned long ring;
- int i;
+ unsigned int i;
/*
* - the busy condition happens (sometimes);
diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig
index 866067789330..7438fbeef744 100644
--- a/drivers/net/wireless/intel/iwlwifi/Kconfig
+++ b/drivers/net/wireless/intel/iwlwifi/Kconfig
@@ -53,7 +53,6 @@ config IWLWIFI_LEDS
config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support"
- depends on m
help
This is the driver that supports the DVM firmware. The list
of the devices that use this firmware is available here:
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
index c84a0299d43e..bce9b3420a13 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
@@ -7,6 +7,7 @@
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -70,12 +71,15 @@
/* Highest firmware API version supported */
#define IWL8000_UCODE_API_MAX 20
+#define IWL8265_UCODE_API_MAX 20
/* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 13
+#define IWL8265_UCODE_API_OK 20
/* Lowest firmware API version supported */
#define IWL8000_UCODE_API_MIN 13
+#define IWL8265_UCODE_API_MIN 20
/* NVM versions */
#define IWL8000_NVM_VERSION 0x0a1d
@@ -93,6 +97,10 @@
#define IWL8000_MODULE_FIRMWARE(api) \
IWL8000_FW_PRE "-" __stringify(api) ".ucode"
+#define IWL8265_FW_PRE "iwlwifi-8265-"
+#define IWL8265_MODULE_FIRMWARE(api) \
+ IWL8265_FW_PRE __stringify(api) ".ucode"
+
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
#define DEFAULT_NVM_FILE_FAMILY_8000B "nvmData-8000B"
#define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C"
@@ -144,10 +152,7 @@ static const struct iwl_tt_params iwl8000_tt_params = {
.support_tx_backoff = true,
};
-#define IWL_DEVICE_8000 \
- .ucode_api_max = IWL8000_UCODE_API_MAX, \
- .ucode_api_ok = IWL8000_UCODE_API_OK, \
- .ucode_api_min = IWL8000_UCODE_API_MIN, \
+#define IWL_DEVICE_8000_COMMON \
.device_family = IWL_DEVICE_FAMILY_8000, \
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
@@ -167,10 +172,28 @@ static const struct iwl_tt_params iwl8000_tt_params = {
.thermal_params = &iwl8000_tt_params, \
.apmg_not_supported = true
+#define IWL_DEVICE_8000 \
+ IWL_DEVICE_8000_COMMON, \
+ .ucode_api_max = IWL8000_UCODE_API_MAX, \
+ .ucode_api_ok = IWL8000_UCODE_API_OK, \
+ .ucode_api_min = IWL8000_UCODE_API_MIN \
+
+#define IWL_DEVICE_8260 \
+ IWL_DEVICE_8000_COMMON, \
+ .ucode_api_max = IWL8000_UCODE_API_MAX, \
+ .ucode_api_ok = IWL8000_UCODE_API_OK, \
+ .ucode_api_min = IWL8000_UCODE_API_MIN \
+
+#define IWL_DEVICE_8265 \
+ IWL_DEVICE_8000_COMMON, \
+ .ucode_api_max = IWL8265_UCODE_API_MAX, \
+ .ucode_api_ok = IWL8265_UCODE_API_OK, \
+ .ucode_api_min = IWL8265_UCODE_API_MIN \
+
const struct iwl_cfg iwl8260_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 8260",
.fw_name_pre = IWL8000_FW_PRE,
- IWL_DEVICE_8000,
+ IWL_DEVICE_8260,
.ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
@@ -179,7 +202,7 @@ const struct iwl_cfg iwl8260_2n_cfg = {
const struct iwl_cfg iwl8260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 8260",
.fw_name_pre = IWL8000_FW_PRE,
- IWL_DEVICE_8000,
+ IWL_DEVICE_8260,
.ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
@@ -188,8 +211,8 @@ const struct iwl_cfg iwl8260_2ac_cfg = {
const struct iwl_cfg iwl8265_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 8265",
- .fw_name_pre = IWL8000_FW_PRE,
- IWL_DEVICE_8000,
+ .fw_name_pre = IWL8265_FW_PRE,
+ IWL_DEVICE_8265,
.ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
@@ -209,7 +232,7 @@ const struct iwl_cfg iwl4165_2ac_cfg = {
const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.name = "Intel(R) Dual Band Wireless-AC 8260",
.fw_name_pre = IWL8000_FW_PRE,
- IWL_DEVICE_8000,
+ IWL_DEVICE_8260,
.ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
@@ -236,3 +259,4 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = {
};
MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL8265_MODULE_FIRMWARE(IWL8265_UCODE_API_OK));
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 7acb49075683..ab4c2a0470b2 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -243,8 +243,10 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
char rev_step = 'A' + CSR_HW_REV_STEP(drv->trans->hw_rev);
- snprintf(drv->firmware_name, sizeof(drv->firmware_name),
- "%s%c-%s.ucode", name_pre, rev_step, tag);
+ if (rev_step != 'A')
+ snprintf(drv->firmware_name,
+ sizeof(drv->firmware_name), "%s%c-%s.ucode",
+ name_pre, rev_step, tag);
}
IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n",
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 4ed5180c547b..0ccc697fef76 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -107,7 +107,7 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)
sizeof(tx_ant_cmd), &tx_ant_cmd);
}
-static void iwl_free_fw_paging(struct iwl_mvm *mvm)
+void iwl_free_fw_paging(struct iwl_mvm *mvm)
{
int i;
@@ -127,6 +127,8 @@ static void iwl_free_fw_paging(struct iwl_mvm *mvm)
get_order(mvm->fw_paging_db[i].fw_paging_size));
}
kfree(mvm->trans->paging_download_buf);
+ mvm->trans->paging_download_buf = NULL;
+
memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db));
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 5f3ac8cccf49..ff7c6df9f941 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1225,6 +1225,9 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
+/* Paging */
+void iwl_free_fw_paging(struct iwl_mvm *mvm);
+
/* MVM debugfs */
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 89ea70deeb84..e80be9a59520 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -684,6 +684,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++)
kfree(mvm->nvm_sections[i].data);
+ iwl_free_fw_paging(mvm);
+
iwl_mvm_tof_clean(mvm);
ieee80211_free_hw(mvm->hw);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index 9a15642f80dd..ea1e177c2ea1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -1298,6 +1298,10 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
return -EBUSY;
}
+ /* we don't support "match all" in the firmware */
+ if (!req->n_match_sets)
+ return -EOPNOTSUPP;
+
ret = iwl_mvm_check_running_scans(mvm, type);
if (ret)
return ret;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 0914ec2fd574..a040edc55057 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -423,6 +423,15 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
return -1;
}
+ /*
+ * Increase the pending frames counter, so that later when a reply comes
+ * in and the counter is decreased - we don't start getting negative
+ * values.
+ * Note that we don't need to make sure it isn't agg'd, since we're
+ * TXing non-sta
+ */
+ atomic_inc(&mvm->pending_frames[sta_id]);
+
return 0;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index cc3888e2700d..73c95594eabe 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -490,6 +490,15 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
}
+static inline void iwl_enable_fw_load_int(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ IWL_DEBUG_ISR(trans, "Enabling FW load interrupt\n");
+ trans_pcie->inta_mask = CSR_INT_BIT_FH_TX;
+ iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+}
+
static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index ccafbd8cf4b3..152cf9ad9566 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -1438,9 +1438,11 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
inta & ~trans_pcie->inta_mask);
}
- /* Re-enable all interrupts */
- /* only Re-enable if disabled by irq */
- if (test_bit(STATUS_INT_ENABLED, &trans->status))
+ /* we are loading the firmware, enable FH_TX interrupt only */
+ if (handled & CSR_INT_BIT_FH_TX)
+ iwl_enable_fw_load_int(trans);
+ /* only Re-enable all interrupt if disabled by irq */
+ else if (test_bit(STATUS_INT_ENABLED, &trans->status))
iwl_enable_interrupts(trans);
/* Re-enable RF_KILL if it occurred */
else if (handled & CSR_INT_BIT_RF_KILL)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index d60a467a983c..5a854c609477 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1021,82 +1021,6 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans,
&first_ucode_section);
}
-static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
- const struct fw_img *fw, bool run_in_rfkill)
-{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- bool hw_rfkill;
- int ret;
-
- mutex_lock(&trans_pcie->mutex);
-
- /* Someone called stop_device, don't try to start_fw */
- if (trans_pcie->is_down) {
- IWL_WARN(trans,
- "Can't start_fw since the HW hasn't been started\n");
- ret = EIO;
- goto out;
- }
-
- /* This may fail if AMT took ownership of the device */
- if (iwl_pcie_prepare_card_hw(trans)) {
- IWL_WARN(trans, "Exit HW not ready\n");
- ret = -EIO;
- goto out;
- }
-
- iwl_enable_rfkill_int(trans);
-
- /* If platform's RF_KILL switch is NOT set to KILL */
- hw_rfkill = iwl_is_rfkill_set(trans);
- if (hw_rfkill)
- set_bit(STATUS_RFKILL, &trans->status);
- else
- clear_bit(STATUS_RFKILL, &trans->status);
- iwl_trans_pcie_rf_kill(trans, hw_rfkill);
- if (hw_rfkill && !run_in_rfkill) {
- ret = -ERFKILL;
- goto out;
- }
-
- iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-
- ret = iwl_pcie_nic_init(trans);
- if (ret) {
- IWL_ERR(trans, "Unable to init nic\n");
- goto out;
- }
-
- /* make sure rfkill handshake bits are cleared */
- iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
- iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
- CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
- /* clear (again), then enable host interrupts */
- iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
- iwl_enable_interrupts(trans);
-
- /* really make sure rfkill handshake bits are cleared */
- iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
- iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
- /* Load the given image to the HW */
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
- ret = iwl_pcie_load_given_ucode_8000(trans, fw);
- else
- ret = iwl_pcie_load_given_ucode(trans, fw);
-
-out:
- mutex_unlock(&trans_pcie->mutex);
- return ret;
-}
-
-static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
-{
- iwl_pcie_reset_ict(trans);
- iwl_pcie_tx_start(trans, scd_addr);
-}
-
static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1127,7 +1051,8 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
* already dead.
*/
if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
- IWL_DEBUG_INFO(trans, "DEVICE_ENABLED bit was set and is now cleared\n");
+ IWL_DEBUG_INFO(trans,
+ "DEVICE_ENABLED bit was set and is now cleared\n");
iwl_pcie_tx_stop(trans);
iwl_pcie_rx_stop(trans);
@@ -1161,7 +1086,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
iwl_disable_interrupts(trans);
spin_unlock(&trans_pcie->irq_lock);
-
/* clear all status bits */
clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
clear_bit(STATUS_INT_ENABLED, &trans->status);
@@ -1194,10 +1118,116 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
if (hw_rfkill != was_hw_rfkill)
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
- /* re-take ownership to prevent other users from stealing the deivce */
+ /* re-take ownership to prevent other users from stealing the device */
iwl_pcie_prepare_card_hw(trans);
}
+static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
+ const struct fw_img *fw, bool run_in_rfkill)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ bool hw_rfkill;
+ int ret;
+
+ /* This may fail if AMT took ownership of the device */
+ if (iwl_pcie_prepare_card_hw(trans)) {
+ IWL_WARN(trans, "Exit HW not ready\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ iwl_enable_rfkill_int(trans);
+
+ iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+ /*
+ * We enabled the RF-Kill interrupt and the handler may very
+ * well be running. Disable the interrupts to make sure no other
+ * interrupt can be fired.
+ */
+ iwl_disable_interrupts(trans);
+
+ /* Make sure it finished running */
+ synchronize_irq(trans_pcie->pci_dev->irq);
+
+ mutex_lock(&trans_pcie->mutex);
+
+ /* If platform's RF_KILL switch is NOT set to KILL */
+ hw_rfkill = iwl_is_rfkill_set(trans);
+ if (hw_rfkill)
+ set_bit(STATUS_RFKILL, &trans->status);
+ else
+ clear_bit(STATUS_RFKILL, &trans->status);
+ iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+ if (hw_rfkill && !run_in_rfkill) {
+ ret = -ERFKILL;
+ goto out;
+ }
+
+ /* Someone called stop_device, don't try to start_fw */
+ if (trans_pcie->is_down) {
+ IWL_WARN(trans,
+ "Can't start_fw since the HW hasn't been started\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ /* make sure rfkill handshake bits are cleared */
+ iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ /* clear (again), then enable host interrupts */
+ iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+ ret = iwl_pcie_nic_init(trans);
+ if (ret) {
+ IWL_ERR(trans, "Unable to init nic\n");
+ goto out;
+ }
+
+ /*
+ * Now, we load the firmware and don't want to be interrupted, even
+ * by the RF-Kill interrupt (hence mask all the interrupt besides the
+ * FH_TX interrupt which is needed to load the firmware). If the
+ * RF-Kill switch is toggled, we will find out after having loaded
+ * the firmware and return the proper value to the caller.
+ */
+ iwl_enable_fw_load_int(trans);
+
+ /* really make sure rfkill handshake bits are cleared */
+ iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ /* Load the given image to the HW */
+ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+ ret = iwl_pcie_load_given_ucode_8000(trans, fw);
+ else
+ ret = iwl_pcie_load_given_ucode(trans, fw);
+ iwl_enable_interrupts(trans);
+
+ /* re-check RF-Kill state since we may have missed the interrupt */
+ hw_rfkill = iwl_is_rfkill_set(trans);
+ if (hw_rfkill)
+ set_bit(STATUS_RFKILL, &trans->status);
+ else
+ clear_bit(STATUS_RFKILL, &trans->status);
+
+ iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+ if (hw_rfkill && !run_in_rfkill)
+ ret = -ERFKILL;
+
+out:
+ mutex_unlock(&trans_pcie->mutex);
+ return ret;
+}
+
+static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
+{
+ iwl_pcie_reset_ict(trans);
+ iwl_pcie_tx_start(trans, scd_addr);
+}
+
static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
diff --git a/drivers/net/wireless/intersil/orinoco/mic.c b/drivers/net/wireless/intersil/orinoco/mic.c
index fce4a843e656..bc7397d709d3 100644
--- a/drivers/net/wireless/intersil/orinoco/mic.c
+++ b/drivers/net/wireless/intersil/orinoco/mic.c
@@ -6,7 +6,7 @@
#include <linux/string.h>
#include <linux/if_ether.h>
#include <linux/scatterlist.h>
-#include <linux/crypto.h>
+#include <crypto/hash.h>
#include "orinoco.h"
#include "mic.h"
@@ -16,7 +16,8 @@
/********************************************************************/
int orinoco_mic_init(struct orinoco_private *priv)
{
- priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
+ priv->tx_tfm_mic = crypto_alloc_ahash("michael_mic", 0,
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm_mic)) {
printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
"crypto API michael_mic\n");
@@ -24,7 +25,8 @@ int orinoco_mic_init(struct orinoco_private *priv)
return -ENOMEM;
}
- priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
+ priv->rx_tfm_mic = crypto_alloc_ahash("michael_mic", 0,
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm_mic)) {
printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
"crypto API michael_mic\n");
@@ -38,18 +40,19 @@ int orinoco_mic_init(struct orinoco_private *priv)
void orinoco_mic_free(struct orinoco_private *priv)
{
if (priv->tx_tfm_mic)
- crypto_free_hash(priv->tx_tfm_mic);
+ crypto_free_ahash(priv->tx_tfm_mic);
if (priv->rx_tfm_mic)
- crypto_free_hash(priv->rx_tfm_mic);
+ crypto_free_ahash(priv->rx_tfm_mic);
}
-int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,
+int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key,
u8 *da, u8 *sa, u8 priority,
u8 *data, size_t data_len, u8 *mic)
{
- struct hash_desc desc;
+ AHASH_REQUEST_ON_STACK(req, tfm_michael);
struct scatterlist sg[2];
u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
+ int err;
if (tfm_michael == NULL) {
printk(KERN_WARNING "orinoco_mic: tfm_michael == NULL\n");
@@ -69,11 +72,13 @@ int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,
sg_set_buf(&sg[0], hdr, sizeof(hdr));
sg_set_buf(&sg[1], data, data_len);
- if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN))
+ if (crypto_ahash_setkey(tfm_michael, key, MIC_KEYLEN))
return -1;
- desc.tfm = tfm_michael;
- desc.flags = 0;
- return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr),
- mic);
+ ahash_request_set_tfm(req, tfm_michael);
+ ahash_request_set_callback(req, 0, NULL, NULL);
+ ahash_request_set_crypt(req, sg, mic, data_len + sizeof(hdr));
+ err = crypto_ahash_digest(req);
+ ahash_request_zero(req);
+ return err;
}
diff --git a/drivers/net/wireless/intersil/orinoco/mic.h b/drivers/net/wireless/intersil/orinoco/mic.h
index 04d05bc566d6..ce731d05cc98 100644
--- a/drivers/net/wireless/intersil/orinoco/mic.h
+++ b/drivers/net/wireless/intersil/orinoco/mic.h
@@ -11,11 +11,11 @@
/* Forward declarations */
struct orinoco_private;
-struct crypto_hash;
+struct crypto_ahash;
int orinoco_mic_init(struct orinoco_private *priv);
void orinoco_mic_free(struct orinoco_private *priv);
-int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,
+int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key,
u8 *da, u8 *sa, u8 priority,
u8 *data, size_t data_len, u8 *mic);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco.h b/drivers/net/wireless/intersil/orinoco/orinoco.h
index eebd2be21ee9..2f0c84b1c440 100644
--- a/drivers/net/wireless/intersil/orinoco/orinoco.h
+++ b/drivers/net/wireless/intersil/orinoco/orinoco.h
@@ -152,8 +152,8 @@ struct orinoco_private {
u8 *wpa_ie;
int wpa_ie_len;
- struct crypto_hash *rx_tfm_mic;
- struct crypto_hash *tx_tfm_mic;
+ struct crypto_ahash *rx_tfm_mic;
+ struct crypto_ahash *tx_tfm_mic;
unsigned int wpa_enabled:1;
unsigned int tkip_cm_active:1;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rc.c b/drivers/net/wireless/realtek/rtlwifi/rc.c
index 74c14ce28238..28f7010e7108 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rc.c
@@ -138,6 +138,11 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
((wireless_mode == WIRELESS_MODE_N_5G) ||
(wireless_mode == WIRELESS_MODE_N_24G)))
rate->flags |= IEEE80211_TX_RC_MCS;
+ if (sta && sta->vht_cap.vht_supported &&
+ (wireless_mode == WIRELESS_MODE_AC_5G ||
+ wireless_mode == WIRELESS_MODE_AC_24G ||
+ wireless_mode == WIRELESS_MODE_AC_ONLY))
+ rate->flags |= IEEE80211_TX_RC_VHT_MCS;
}
}
diff --git a/drivers/net/wireless/ti/wlcore/io.c b/drivers/net/wireless/ti/wlcore/io.c
index 9ac118e727e9..564ca750c5ee 100644
--- a/drivers/net/wireless/ti/wlcore/io.c
+++ b/drivers/net/wireless/ti/wlcore/io.c
@@ -175,14 +175,14 @@ int wlcore_set_partition(struct wl1271 *wl,
if (ret < 0)
goto out;
+ /* We don't need the size of the last partition, as it is
+ * automatically calculated based on the total memory size and
+ * the sizes of the previous partitions.
+ */
ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
if (ret < 0)
goto out;
- ret = wlcore_raw_write32(wl, HW_PART3_SIZE_ADDR, p->mem3.size);
- if (ret < 0)
- goto out;
-
out:
return ret;
}
diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
index 6c257b54f415..10cf3747694d 100644
--- a/drivers/net/wireless/ti/wlcore/io.h
+++ b/drivers/net/wireless/ti/wlcore/io.h
@@ -36,8 +36,8 @@
#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12)
#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16)
#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20)
-#define HW_PART3_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 24)
-#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 28)
+#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24)
+
#define HW_ACCESS_REGISTER_SIZE 4
#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
diff --git a/drivers/nfc/s3fwrn5/firmware.c b/drivers/nfc/s3fwrn5/firmware.c
index 64a90252c57f..5f97da1947e3 100644
--- a/drivers/nfc/s3fwrn5/firmware.c
+++ b/drivers/nfc/s3fwrn5/firmware.c
@@ -19,7 +19,7 @@
#include <linux/completion.h>
#include <linux/firmware.h>
-#include <linux/crypto.h>
+#include <crypto/hash.h>
#include <crypto/sha.h>
#include "s3fwrn5.h"
@@ -429,8 +429,7 @@ int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
{
struct s3fwrn5_fw_image *fw = &fw_info->fw;
u8 hash_data[SHA1_DIGEST_SIZE];
- struct scatterlist sg;
- struct hash_desc desc;
+ struct crypto_shash *tfm;
u32 image_size, off;
int ret;
@@ -438,12 +437,31 @@ int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
/* Compute SHA of firmware data */
- sg_init_one(&sg, fw->image, image_size);
- desc.tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
- crypto_hash_init(&desc);
- crypto_hash_update(&desc, &sg, image_size);
- crypto_hash_final(&desc, hash_data);
- crypto_free_hash(desc.tfm);
+ tfm = crypto_alloc_shash("sha1", 0, 0);
+ if (IS_ERR(tfm)) {
+ ret = PTR_ERR(tfm);
+ dev_err(&fw_info->ndev->nfc_dev->dev,
+ "Cannot allocate shash (code=%d)\n", ret);
+ goto out;
+ }
+
+ {
+ SHASH_DESC_ON_STACK(desc, tfm);
+
+ desc->tfm = tfm;
+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ ret = crypto_shash_digest(desc, fw->image, image_size,
+ hash_data);
+ shash_desc_zero(desc);
+ }
+
+ crypto_free_shash(tfm);
+ if (ret) {
+ dev_err(&fw_info->ndev->nfc_dev->dev,
+ "Cannot compute hash (code=%d)\n", ret);
+ goto out;
+ }
/* Firmware update process */
diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index 91a336ea8c4f..e9ff9229d942 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -31,8 +31,6 @@ struct nd_blk_device {
u32 internal_lbasize;
};
-static int nd_blk_major;
-
static u32 nd_blk_meta_size(struct nd_blk_device *blk_dev)
{
return blk_dev->nsblk->lbasize - blk_dev->sector_size;
@@ -264,7 +262,6 @@ static int nd_blk_attach_disk(struct nd_namespace_common *ndns,
}
disk->driverfs_dev = &ndns->dev;
- disk->major = nd_blk_major;
disk->first_minor = 0;
disk->fops = &nd_blk_fops;
disk->private_data = blk_dev;
@@ -358,25 +355,12 @@ static struct nd_device_driver nd_blk_driver = {
static int __init nd_blk_init(void)
{
- int rc;
-
- rc = register_blkdev(0, "nd_blk");
- if (rc < 0)
- return rc;
-
- nd_blk_major = rc;
- rc = nd_driver_register(&nd_blk_driver);
-
- if (rc < 0)
- unregister_blkdev(nd_blk_major, "nd_blk");
-
- return rc;
+ return nd_driver_register(&nd_blk_driver);
}
static void __exit nd_blk_exit(void)
{
driver_unregister(&nd_blk_driver.drv);
- unregister_blkdev(nd_blk_major, "nd_blk");
}
MODULE_AUTHOR("Ross Zwisler <ross.zwisler@linux.intel.com>");
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index efb2c1ceef98..c32cbb593600 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -31,8 +31,6 @@ enum log_ent_request {
LOG_OLD_ENT
};
-static int btt_major;
-
static int arena_read_bytes(struct arena_info *arena, resource_size_t offset,
void *buf, size_t n)
{
@@ -1246,7 +1244,6 @@ static int btt_blk_init(struct btt *btt)
nvdimm_namespace_disk_name(ndns, btt->btt_disk->disk_name);
btt->btt_disk->driverfs_dev = &btt->nd_btt->dev;
- btt->btt_disk->major = btt_major;
btt->btt_disk->first_minor = 0;
btt->btt_disk->fops = &btt_fops;
btt->btt_disk->private_data = btt;
@@ -1423,22 +1420,11 @@ EXPORT_SYMBOL(nvdimm_namespace_detach_btt);
static int __init nd_btt_init(void)
{
- int rc;
-
- btt_major = register_blkdev(0, "btt");
- if (btt_major < 0)
- return btt_major;
+ int rc = 0;
debugfs_root = debugfs_create_dir("btt", NULL);
- if (IS_ERR_OR_NULL(debugfs_root)) {
+ if (IS_ERR_OR_NULL(debugfs_root))
rc = -ENXIO;
- goto err_debugfs;
- }
-
- return 0;
-
- err_debugfs:
- unregister_blkdev(btt_major, "btt");
return rc;
}
@@ -1446,7 +1432,6 @@ static int __init nd_btt_init(void)
static void __exit nd_btt_exit(void)
{
debugfs_remove_recursive(debugfs_root);
- unregister_blkdev(btt_major, "btt");
}
MODULE_ALIAS_ND_DEVICE(ND_DEVICE_BTT);
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 7e2c43f701bc..33557481d452 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -133,6 +133,78 @@ static int nvdimm_bus_remove(struct device *dev)
return rc;
}
+void nd_device_notify(struct device *dev, enum nvdimm_event event)
+{
+ device_lock(dev);
+ if (dev->driver) {
+ struct nd_device_driver *nd_drv;
+
+ nd_drv = to_nd_device_driver(dev->driver);
+ if (nd_drv->notify)
+ nd_drv->notify(dev, event);
+ }
+ device_unlock(dev);
+}
+EXPORT_SYMBOL(nd_device_notify);
+
+void nvdimm_region_notify(struct nd_region *nd_region, enum nvdimm_event event)
+{
+ struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(&nd_region->dev);
+
+ if (!nvdimm_bus)
+ return;
+
+ /* caller is responsible for holding a reference on the device */
+ nd_device_notify(&nd_region->dev, event);
+}
+EXPORT_SYMBOL_GPL(nvdimm_region_notify);
+
+long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
+ unsigned int len)
+{
+ struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+ struct nvdimm_bus_descriptor *nd_desc;
+ struct nd_cmd_clear_error clear_err;
+ struct nd_cmd_ars_cap ars_cap;
+ u32 clear_err_unit, mask;
+ int cmd_rc, rc;
+
+ if (!nvdimm_bus)
+ return -ENXIO;
+
+ nd_desc = nvdimm_bus->nd_desc;
+ if (!nd_desc->ndctl)
+ return -ENXIO;
+
+ memset(&ars_cap, 0, sizeof(ars_cap));
+ ars_cap.address = phys;
+ ars_cap.length = len;
+ rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, &ars_cap,
+ sizeof(ars_cap), &cmd_rc);
+ if (rc < 0)
+ return rc;
+ if (cmd_rc < 0)
+ return cmd_rc;
+ clear_err_unit = ars_cap.clear_err_unit;
+ if (!clear_err_unit || !is_power_of_2(clear_err_unit))
+ return -ENXIO;
+
+ mask = clear_err_unit - 1;
+ if ((phys | len) & mask)
+ return -ENXIO;
+ memset(&clear_err, 0, sizeof(clear_err));
+ clear_err.address = phys;
+ clear_err.length = len;
+ rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_CLEAR_ERROR, &clear_err,
+ sizeof(clear_err), &cmd_rc);
+ if (rc < 0)
+ return rc;
+ if (cmd_rc < 0)
+ return cmd_rc;
+ return clear_err.cleared;
+}
+EXPORT_SYMBOL_GPL(nvdimm_clear_poison);
+
static struct bus_type nvdimm_bus_type = {
.name = "nd",
.uevent = nvdimm_bus_uevent,
@@ -382,18 +454,24 @@ static const struct nd_cmd_desc __nd_cmd_bus_descs[] = {
[ND_CMD_ARS_CAP] = {
.in_num = 2,
.in_sizes = { 8, 8, },
- .out_num = 2,
- .out_sizes = { 4, 4, },
+ .out_num = 4,
+ .out_sizes = { 4, 4, 4, 4, },
},
[ND_CMD_ARS_START] = {
- .in_num = 4,
- .in_sizes = { 8, 8, 2, 6, },
- .out_num = 1,
- .out_sizes = { 4, },
+ .in_num = 5,
+ .in_sizes = { 8, 8, 2, 1, 5, },
+ .out_num = 2,
+ .out_sizes = { 4, 4, },
},
[ND_CMD_ARS_STATUS] = {
- .out_num = 2,
- .out_sizes = { 4, UINT_MAX, },
+ .out_num = 3,
+ .out_sizes = { 4, 4, UINT_MAX, },
+ },
+ [ND_CMD_CLEAR_ERROR] = {
+ .in_num = 2,
+ .in_sizes = { 8, 8, },
+ .out_num = 3,
+ .out_sizes = { 4, 4, 8, },
},
};
@@ -442,8 +520,8 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
return in_field[1];
else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2)
return out_field[1];
- else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 1)
- return ND_CMD_ARS_STATUS_MAX;
+ else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2)
+ return out_field[1] - 8;
return UINT_MAX;
}
@@ -463,17 +541,37 @@ void wait_nvdimm_bus_probe_idle(struct device *dev)
} while (true);
}
+static int pmem_active(struct device *dev, void *data)
+{
+ if (is_nd_pmem(dev) && dev->driver)
+ return -EBUSY;
+ return 0;
+}
+
/* set_config requires an idle interleave set */
-static int nd_cmd_clear_to_send(struct nvdimm *nvdimm, unsigned int cmd)
+static int nd_cmd_clear_to_send(struct nvdimm_bus *nvdimm_bus,
+ struct nvdimm *nvdimm, unsigned int cmd)
{
- struct nvdimm_bus *nvdimm_bus;
+ struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
+
+ /* ask the bus provider if it would like to block this request */
+ if (nd_desc->clear_to_send) {
+ int rc = nd_desc->clear_to_send(nd_desc, nvdimm, cmd);
+
+ if (rc)
+ return rc;
+ }
+
+ /* require clear error to go through the pmem driver */
+ if (!nvdimm && cmd == ND_CMD_CLEAR_ERROR)
+ return device_for_each_child(&nvdimm_bus->dev, NULL,
+ pmem_active);
if (!nvdimm || cmd != ND_CMD_SET_CONFIG_DATA)
return 0;
- nvdimm_bus = walk_to_nvdimm_bus(&nvdimm->dev);
+ /* prevent label manipulation while the kernel owns label updates */
wait_nvdimm_bus_probe_idle(&nvdimm_bus->dev);
-
if (atomic_read(&nvdimm->busy))
return -EBUSY;
return 0;
@@ -513,10 +611,11 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
/* fail write commands (when read-only) */
if (read_only)
- switch (ioctl_cmd) {
- case ND_IOCTL_VENDOR:
- case ND_IOCTL_SET_CONFIG_DATA:
- case ND_IOCTL_ARS_START:
+ switch (cmd) {
+ case ND_CMD_VENDOR:
+ case ND_CMD_SET_CONFIG_DATA:
+ case ND_CMD_ARS_START:
+ case ND_CMD_CLEAR_ERROR:
dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n",
nvdimm ? nvdimm_cmd_name(cmd)
: nvdimm_bus_cmd_name(cmd));
@@ -583,11 +682,11 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
}
nvdimm_bus_lock(&nvdimm_bus->dev);
- rc = nd_cmd_clear_to_send(nvdimm, cmd);
+ rc = nd_cmd_clear_to_send(nvdimm_bus, nvdimm, cmd);
if (rc)
goto out_unlock;
- rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len);
+ rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len, NULL);
if (rc < 0)
goto out_unlock;
if (copy_to_user(p, buf, buf_len))
@@ -602,14 +701,14 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
static long nd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long id = (long) file->private_data;
- int rc = -ENXIO, read_only;
+ int rc = -ENXIO, ro;
struct nvdimm_bus *nvdimm_bus;
- read_only = (O_RDWR != (file->f_flags & O_ACCMODE));
+ ro = ((file->f_flags & O_ACCMODE) == O_RDONLY);
mutex_lock(&nvdimm_bus_list_mutex);
list_for_each_entry(nvdimm_bus, &nvdimm_bus_list, list) {
if (nvdimm_bus->id == id) {
- rc = __nd_ioctl(nvdimm_bus, NULL, read_only, cmd, arg);
+ rc = __nd_ioctl(nvdimm_bus, NULL, ro, cmd, arg);
break;
}
}
@@ -633,10 +732,10 @@ static int match_dimm(struct device *dev, void *data)
static long nvdimm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- int rc = -ENXIO, read_only;
+ int rc = -ENXIO, ro;
struct nvdimm_bus *nvdimm_bus;
- read_only = (O_RDWR != (file->f_flags & O_ACCMODE));
+ ro = ((file->f_flags & O_ACCMODE) == O_RDONLY);
mutex_lock(&nvdimm_bus_list_mutex);
list_for_each_entry(nvdimm_bus, &nvdimm_bus_list, list) {
struct device *dev = device_find_child(&nvdimm_bus->dev,
@@ -647,7 +746,7 @@ static long nvdimm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
continue;
nvdimm = to_nvdimm(dev);
- rc = __nd_ioctl(nvdimm_bus, nvdimm, read_only, cmd, arg);
+ rc = __nd_ioctl(nvdimm_bus, nvdimm, ro, cmd, arg);
put_device(dev);
break;
}
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index 2e2832b83c93..79646d0c3277 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -298,6 +298,15 @@ static int flush_regions_dimms(struct device *dev, void *data)
static ssize_t wait_probe_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
+ struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
+ int rc;
+
+ if (nd_desc->flush_probe) {
+ rc = nd_desc->flush_probe(nd_desc);
+ if (rc)
+ return rc;
+ }
nd_synchronize();
device_for_each_child(dev, NULL, flush_regions_dimms);
return sprintf(buf, "1\n");
@@ -408,33 +417,11 @@ static void __add_badblock_range(struct badblocks *bb, u64 ns_offset, u64 len)
set_badblock(bb, start_sector, num_sectors);
}
-/**
- * nvdimm_namespace_add_poison() - Convert a list of poison ranges to badblocks
- * @ndns: the namespace containing poison ranges
- * @bb: badblocks instance to populate
- * @offset: offset at the start of the namespace before 'sector 0'
- *
- * The poison list generated during NFIT initialization may contain multiple,
- * possibly overlapping ranges in the SPA (System Physical Address) space.
- * Compare each of these ranges to the namespace currently being initialized,
- * and add badblocks to the gendisk for all matching sub-ranges
- */
-void nvdimm_namespace_add_poison(struct nd_namespace_common *ndns,
- struct badblocks *bb, resource_size_t offset)
+static void namespace_add_poison(struct list_head *poison_list,
+ struct badblocks *bb, struct resource *res)
{
- struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
- struct nd_region *nd_region = to_nd_region(ndns->dev.parent);
- struct nvdimm_bus *nvdimm_bus;
- struct list_head *poison_list;
- u64 ns_start, ns_end, ns_size;
struct nd_poison *pl;
- ns_size = nvdimm_namespace_capacity(ndns) - offset;
- ns_start = nsio->res.start + offset;
- ns_end = nsio->res.end;
-
- nvdimm_bus = to_nvdimm_bus(nd_region->dev.parent);
- poison_list = &nvdimm_bus->poison_list;
if (list_empty(poison_list))
return;
@@ -442,37 +429,69 @@ void nvdimm_namespace_add_poison(struct nd_namespace_common *ndns,
u64 pl_end = pl->start + pl->length - 1;
/* Discard intervals with no intersection */
- if (pl_end < ns_start)
+ if (pl_end < res->start)
continue;
- if (pl->start > ns_end)
+ if (pl->start > res->end)
continue;
/* Deal with any overlap after start of the namespace */
- if (pl->start >= ns_start) {
+ if (pl->start >= res->start) {
u64 start = pl->start;
u64 len;
- if (pl_end <= ns_end)
+ if (pl_end <= res->end)
len = pl->length;
else
- len = ns_start + ns_size - pl->start;
- __add_badblock_range(bb, start - ns_start, len);
+ len = res->start + resource_size(res)
+ - pl->start;
+ __add_badblock_range(bb, start - res->start, len);
continue;
}
/* Deal with overlap for poison starting before the namespace */
- if (pl->start < ns_start) {
+ if (pl->start < res->start) {
u64 len;
- if (pl_end < ns_end)
- len = pl->start + pl->length - ns_start;
+ if (pl_end < res->end)
+ len = pl->start + pl->length - res->start;
else
- len = ns_size;
+ len = resource_size(res);
__add_badblock_range(bb, 0, len);
}
}
}
+
+/**
+ * nvdimm_namespace_add_poison() - Convert a list of poison ranges to badblocks
+ * @ndns: the namespace containing poison ranges
+ * @bb: badblocks instance to populate
+ * @offset: offset at the start of the namespace before 'sector 0'
+ *
+ * The poison list generated during NFIT initialization may contain multiple,
+ * possibly overlapping ranges in the SPA (System Physical Address) space.
+ * Compare each of these ranges to the namespace currently being initialized,
+ * and add badblocks to the gendisk for all matching sub-ranges
+ */
+void nvdimm_namespace_add_poison(struct nd_namespace_common *ndns,
+ struct badblocks *bb, resource_size_t offset)
+{
+ struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+ struct nd_region *nd_region = to_nd_region(ndns->dev.parent);
+ struct nvdimm_bus *nvdimm_bus;
+ struct list_head *poison_list;
+ struct resource res = {
+ .start = nsio->res.start + offset,
+ .end = nsio->res.end,
+ };
+
+ nvdimm_bus = to_nvdimm_bus(nd_region->dev.parent);
+ poison_list = &nvdimm_bus->poison_list;
+
+ nvdimm_bus_lock(&nvdimm_bus->dev);
+ namespace_add_poison(poison_list, bb, &res);
+ nvdimm_bus_unlock(&nvdimm_bus->dev);
+}
EXPORT_SYMBOL_GPL(nvdimm_namespace_add_poison);
-static int __add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
+static int add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
{
struct nd_poison *pl;
@@ -487,12 +506,12 @@ static int __add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
return 0;
}
-int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
+static int bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
{
struct nd_poison *pl;
if (list_empty(&nvdimm_bus->poison_list))
- return __add_poison(nvdimm_bus, addr, length);
+ return add_poison(nvdimm_bus, addr, length);
/*
* There is a chance this is a duplicate, check for those first.
@@ -512,7 +531,18 @@ int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
* as any overlapping ranges will get resolved when the list is consumed
* and converted to badblocks
*/
- return __add_poison(nvdimm_bus, addr, length);
+ return add_poison(nvdimm_bus, addr, length);
+}
+
+int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
+{
+ int rc;
+
+ nvdimm_bus_lock(&nvdimm_bus->dev);
+ rc = bus_add_poison(nvdimm_bus, addr, length);
+ nvdimm_bus_unlock(&nvdimm_bus->dev);
+
+ return rc;
}
EXPORT_SYMBOL_GPL(nvdimm_bus_add_poison);
@@ -553,7 +583,11 @@ void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus)
nd_synchronize();
device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
+
+ nvdimm_bus_lock(&nvdimm_bus->dev);
free_poison_list(&nvdimm_bus->poison_list);
+ nvdimm_bus_unlock(&nvdimm_bus->dev);
+
nvdimm_bus_destroy_ndctl(nvdimm_bus);
device_unregister(&nvdimm_bus->dev);
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index 651b8d19d324..c56f88217924 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -75,7 +75,7 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
memset(cmd, 0, sizeof(*cmd));
nd_desc = nvdimm_bus->nd_desc;
return nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
- ND_CMD_GET_CONFIG_SIZE, cmd, sizeof(*cmd));
+ ND_CMD_GET_CONFIG_SIZE, cmd, sizeof(*cmd), NULL);
}
int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
@@ -120,7 +120,7 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
cmd->in_offset = offset;
rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
ND_CMD_GET_CONFIG_DATA, cmd,
- cmd->in_length + sizeof(*cmd));
+ cmd->in_length + sizeof(*cmd), NULL);
if (rc || cmd->status) {
rc = -ENXIO;
break;
@@ -171,7 +171,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
status = ((void *) cmd) + cmd_size - sizeof(u32);
rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
- ND_CMD_SET_CONFIG_DATA, cmd, cmd_size);
+ ND_CMD_SET_CONFIG_DATA, cmd, cmd_size, NULL);
if (rc || *status) {
rc = rc ? rc : -ENXIO;
break;
diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c
index b0045a505dc8..95825b38559a 100644
--- a/drivers/nvdimm/e820.c
+++ b/drivers/nvdimm/e820.c
@@ -55,7 +55,7 @@ static int e820_pmem_probe(struct platform_device *pdev)
for (p = iomem_resource.child; p ; p = p->sibling) {
struct nd_region_desc ndr_desc;
- if (strncmp(p->name, "Persistent Memory (legacy)", 26) != 0)
+ if (p->desc != IORES_DESC_PERSISTENT_MEMORY_LEGACY)
continue;
memset(&ndr_desc, 0, sizeof(ndr_desc));
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 9edf7eb7d17c..f5cb88601359 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -133,6 +133,7 @@ bool nd_is_uuid_unique(struct device *dev, u8 *uuid)
bool pmem_should_map_pages(struct device *dev)
{
struct nd_region *nd_region = to_nd_region(dev->parent);
+ struct nd_namespace_io *nsio;
if (!IS_ENABLED(CONFIG_ZONE_DEVICE))
return false;
@@ -143,6 +144,12 @@ bool pmem_should_map_pages(struct device *dev)
if (is_nd_pfn(dev) || is_nd_btt(dev))
return false;
+ nsio = to_nd_namespace_io(dev);
+ if (region_intersects(nsio->res.start, resource_size(&nsio->res),
+ IORESOURCE_SYSTEM_RAM,
+ IORES_DESC_NONE) == REGION_MIXED)
+ return false;
+
#ifdef ARCH_MEMREMAP_PMEM
return ARCH_MEMREMAP_PMEM == MEMREMAP_WB;
#else
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index ba1633b9da31..1799bd97a9ce 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -18,6 +18,7 @@
#include <linux/mutex.h>
#include <linux/ndctl.h>
#include <linux/types.h>
+#include <linux/nd.h>
#include "label.h"
enum {
@@ -168,6 +169,7 @@ int nd_integrity_init(struct gendisk *disk, unsigned long meta_size);
void wait_nvdimm_bus_probe_idle(struct device *dev);
void nd_device_register(struct device *dev);
void nd_device_unregister(struct device *dev, enum nd_async_mode mode);
+void nd_device_notify(struct device *dev, enum nvdimm_event event);
int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf,
size_t len);
ssize_t nd_sector_size_show(unsigned long current_lbasize,
@@ -184,6 +186,8 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd);
int nvdimm_init_config_data(struct nvdimm_drvdata *ndd);
int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
void *buf, size_t len);
+long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
+ unsigned int len);
struct nd_btt *to_nd_btt(struct device *dev);
struct nd_gen_sb {
diff --git a/drivers/nvdimm/pfn.h b/drivers/nvdimm/pfn.h
index cc243754acef..8e343a3ca873 100644
--- a/drivers/nvdimm/pfn.h
+++ b/drivers/nvdimm/pfn.h
@@ -15,6 +15,7 @@
#define __NVDIMM_PFN_H
#include <linux/types.h>
+#include <linux/mmzone.h>
#define PFN_SIG_LEN 16
#define PFN_SIG "NVDIMM_PFN_INFO\0"
@@ -26,10 +27,28 @@ struct nd_pfn_sb {
__le32 flags;
__le16 version_major;
__le16 version_minor;
- __le64 dataoff;
+ __le64 dataoff; /* relative to namespace_base + start_pad */
__le64 npfns;
__le32 mode;
- u8 padding[4012];
+ /* minor-version-1 additions for section alignment */
+ __le32 start_pad;
+ __le32 end_trunc;
+ u8 padding[4004];
__le64 checksum;
};
+
+#ifdef CONFIG_SPARSEMEM
+#define PFN_SECTION_ALIGN_DOWN(x) SECTION_ALIGN_DOWN(x)
+#define PFN_SECTION_ALIGN_UP(x) SECTION_ALIGN_UP(x)
+#else
+/*
+ * In this case ZONE_DEVICE=n and we will disable 'pfn' device support,
+ * but we still want pmem to compile.
+ */
+#define PFN_SECTION_ALIGN_DOWN(x) (x)
+#define PFN_SECTION_ALIGN_UP(x) (x)
+#endif
+
+#define PHYS_SECTION_ALIGN_DOWN(x) PFN_PHYS(PFN_SECTION_ALIGN_DOWN(PHYS_PFN(x)))
+#define PHYS_SECTION_ALIGN_UP(x) PFN_PHYS(PFN_SECTION_ALIGN_UP(PHYS_PFN(x)))
#endif /* __NVDIMM_PFN_H */
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index ae81a2f1da50..254d3bc13f70 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -205,11 +205,67 @@ static ssize_t namespace_store(struct device *dev,
}
static DEVICE_ATTR_RW(namespace);
+static ssize_t resource_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nd_pfn *nd_pfn = to_nd_pfn(dev);
+ ssize_t rc;
+
+ device_lock(dev);
+ if (dev->driver) {
+ struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+ u64 offset = __le64_to_cpu(pfn_sb->dataoff);
+ struct nd_namespace_common *ndns = nd_pfn->ndns;
+ u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
+ struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+
+ rc = sprintf(buf, "%#llx\n", (unsigned long long) nsio->res.start
+ + start_pad + offset);
+ } else {
+ /* no address to convey if the pfn instance is disabled */
+ rc = -ENXIO;
+ }
+ device_unlock(dev);
+
+ return rc;
+}
+static DEVICE_ATTR_RO(resource);
+
+static ssize_t size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nd_pfn *nd_pfn = to_nd_pfn(dev);
+ ssize_t rc;
+
+ device_lock(dev);
+ if (dev->driver) {
+ struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+ u64 offset = __le64_to_cpu(pfn_sb->dataoff);
+ struct nd_namespace_common *ndns = nd_pfn->ndns;
+ u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
+ u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
+ struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+
+ rc = sprintf(buf, "%llu\n", (unsigned long long)
+ resource_size(&nsio->res) - start_pad
+ - end_trunc - offset);
+ } else {
+ /* no size to convey if the pfn instance is disabled */
+ rc = -ENXIO;
+ }
+ device_unlock(dev);
+
+ return rc;
+}
+static DEVICE_ATTR_RO(size);
+
static struct attribute *nd_pfn_attributes[] = {
&dev_attr_mode.attr,
&dev_attr_namespace.attr,
&dev_attr_uuid.attr,
&dev_attr_align.attr,
+ &dev_attr_resource.attr,
+ &dev_attr_size.attr,
NULL,
};
@@ -299,6 +355,11 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
if (memcmp(pfn_sb->parent_uuid, parent_uuid, 16) != 0)
return -ENODEV;
+ if (__le16_to_cpu(pfn_sb->version_minor) < 1) {
+ pfn_sb->start_pad = 0;
+ pfn_sb->end_trunc = 0;
+ }
+
switch (le32_to_cpu(pfn_sb->mode)) {
case PFN_MODE_RAM:
case PFN_MODE_PMEM:
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 7edf31671dab..ca5721c306bb 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -41,14 +41,15 @@ struct pmem_device {
phys_addr_t phys_addr;
/* when non-zero this device is hosting a 'pfn' instance */
phys_addr_t data_offset;
- unsigned long pfn_flags;
+ u64 pfn_flags;
void __pmem *virt_addr;
+ /* immutable base size of the namespace */
size_t size;
+ /* trim size when namespace capacity has been section aligned */
+ u32 pfn_pad;
struct badblocks bb;
};
-static int pmem_major;
-
static bool is_bad_pmem(struct badblocks *bb, sector_t sector, unsigned int len)
{
if (bb->count) {
@@ -62,26 +63,56 @@ static bool is_bad_pmem(struct badblocks *bb, sector_t sector, unsigned int len)
return false;
}
+static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
+ unsigned int len)
+{
+ struct device *dev = disk_to_dev(pmem->pmem_disk);
+ sector_t sector;
+ long cleared;
+
+ sector = (offset - pmem->data_offset) / 512;
+ cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
+
+ if (cleared > 0 && cleared / 512) {
+ dev_dbg(dev, "%s: %llx clear %ld sector%s\n",
+ __func__, (unsigned long long) sector,
+ cleared / 512, cleared / 512 > 1 ? "s" : "");
+ badblocks_clear(&pmem->bb, sector, cleared / 512);
+ }
+ invalidate_pmem(pmem->virt_addr + offset, len);
+}
+
static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
unsigned int len, unsigned int off, int rw,
sector_t sector)
{
+ int rc = 0;
+ bool bad_pmem = false;
void *mem = kmap_atomic(page);
phys_addr_t pmem_off = sector * 512 + pmem->data_offset;
void __pmem *pmem_addr = pmem->virt_addr + pmem_off;
+ if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
+ bad_pmem = true;
+
if (rw == READ) {
- if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
- return -EIO;
- memcpy_from_pmem(mem + off, pmem_addr, len);
- flush_dcache_page(page);
+ if (unlikely(bad_pmem))
+ rc = -EIO;
+ else {
+ memcpy_from_pmem(mem + off, pmem_addr, len);
+ flush_dcache_page(page);
+ }
} else {
flush_dcache_page(page);
memcpy_to_pmem(pmem_addr, mem + off, len);
+ if (unlikely(bad_pmem)) {
+ pmem_clear_poison(pmem, pmem_off, len);
+ memcpy_to_pmem(pmem_addr, mem + off, len);
+ }
}
kunmap_atomic(mem);
- return 0;
+ return rc;
}
static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
@@ -145,7 +176,7 @@ static long pmem_direct_access(struct block_device *bdev, sector_t sector,
*kaddr = pmem->virt_addr + offset;
*pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags);
- return pmem->size - offset;
+ return pmem->size - pmem->pfn_pad - offset;
}
static const struct block_device_operations pmem_fops = {
@@ -228,15 +259,14 @@ static int pmem_attach_disk(struct device *dev,
return -ENOMEM;
}
- disk->major = pmem_major;
- disk->first_minor = 0;
disk->fops = &pmem_fops;
disk->private_data = pmem;
disk->queue = pmem->pmem_queue;
disk->flags = GENHD_FL_EXT_DEVT;
nvdimm_namespace_disk_name(ndns, disk->disk_name);
disk->driverfs_dev = dev;
- set_capacity(disk, (pmem->size - pmem->data_offset) / 512);
+ set_capacity(disk, (pmem->size - pmem->pfn_pad - pmem->data_offset)
+ / 512);
pmem->pmem_disk = disk;
devm_exit_badblocks(dev, &pmem->bb);
if (devm_init_badblocks(dev, &pmem->bb))
@@ -279,6 +309,9 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
struct nd_pfn_sb *pfn_sb = kzalloc(sizeof(*pfn_sb), GFP_KERNEL);
struct pmem_device *pmem = dev_get_drvdata(&nd_pfn->dev);
struct nd_namespace_common *ndns = nd_pfn->ndns;
+ u32 start_pad = 0, end_trunc = 0;
+ resource_size_t start, size;
+ struct nd_namespace_io *nsio;
struct nd_region *nd_region;
unsigned long npfns;
phys_addr_t offset;
@@ -304,21 +337,56 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
}
memset(pfn_sb, 0, sizeof(*pfn_sb));
- npfns = (pmem->size - SZ_8K) / SZ_4K;
+
+ /*
+ * Check if pmem collides with 'System RAM' when section aligned and
+ * trim it accordingly
+ */
+ nsio = to_nd_namespace_io(&ndns->dev);
+ start = PHYS_SECTION_ALIGN_DOWN(nsio->res.start);
+ size = resource_size(&nsio->res);
+ if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
+ IORES_DESC_NONE) == REGION_MIXED) {
+
+ start = nsio->res.start;
+ start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
+ }
+
+ start = nsio->res.start;
+ size = PHYS_SECTION_ALIGN_UP(start + size) - start;
+ if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
+ IORES_DESC_NONE) == REGION_MIXED) {
+ size = resource_size(&nsio->res);
+ end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size);
+ }
+
+ if (start_pad + end_trunc)
+ dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n",
+ dev_name(&ndns->dev), start_pad + end_trunc);
+
/*
* Note, we use 64 here for the standard size of struct page,
* debugging options may cause it to be larger in which case the
* implementation will limit the pfns advertised through
* ->direct_access() to those that are included in the memmap.
*/
+ start += start_pad;
+ npfns = (pmem->size - start_pad - end_trunc - SZ_8K) / SZ_4K;
if (nd_pfn->mode == PFN_MODE_PMEM)
- offset = ALIGN(SZ_8K + 64 * npfns, nd_pfn->align);
+ offset = ALIGN(start + SZ_8K + 64 * npfns, nd_pfn->align)
+ - start;
else if (nd_pfn->mode == PFN_MODE_RAM)
- offset = ALIGN(SZ_8K, nd_pfn->align);
+ offset = ALIGN(start + SZ_8K, nd_pfn->align) - start;
else
goto err;
- npfns = (pmem->size - offset) / SZ_4K;
+ if (offset + start_pad + end_trunc >= pmem->size) {
+ dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
+ dev_name(&ndns->dev));
+ goto err;
+ }
+
+ npfns = (pmem->size - offset - start_pad - end_trunc) / SZ_4K;
pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
pfn_sb->dataoff = cpu_to_le64(offset);
pfn_sb->npfns = cpu_to_le64(npfns);
@@ -326,6 +394,9 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
pfn_sb->version_major = cpu_to_le16(1);
+ pfn_sb->version_minor = cpu_to_le16(1);
+ pfn_sb->start_pad = cpu_to_le32(start_pad);
+ pfn_sb->end_trunc = cpu_to_le32(end_trunc);
checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
pfn_sb->checksum = cpu_to_le64(checksum);
@@ -356,41 +427,56 @@ static int nvdimm_namespace_detach_pfn(struct nd_namespace_common *ndns)
return 0;
}
-static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
+/*
+ * We hotplug memory at section granularity, pad the reserved area from
+ * the previous section base to the namespace base address.
+ */
+static unsigned long init_altmap_base(resource_size_t base)
+{
+ unsigned long base_pfn = PHYS_PFN(base);
+
+ return PFN_SECTION_ALIGN_DOWN(base_pfn);
+}
+
+static unsigned long init_altmap_reserve(resource_size_t base)
+{
+ unsigned long reserve = PHYS_PFN(SZ_8K);
+ unsigned long base_pfn = PHYS_PFN(base);
+
+ reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
+ return reserve;
+}
+
+static int __nvdimm_namespace_attach_pfn(struct nd_pfn *nd_pfn)
{
- struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
- struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim);
- struct device *dev = &nd_pfn->dev;
- struct nd_region *nd_region;
- struct vmem_altmap *altmap;
- struct nd_pfn_sb *pfn_sb;
- struct pmem_device *pmem;
- struct request_queue *q;
- phys_addr_t offset;
int rc;
+ struct resource res;
+ struct request_queue *q;
+ struct pmem_device *pmem;
+ struct vmem_altmap *altmap;
+ struct device *dev = &nd_pfn->dev;
+ struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+ struct nd_namespace_common *ndns = nd_pfn->ndns;
+ u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
+ u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
+ struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+ resource_size_t base = nsio->res.start + start_pad;
struct vmem_altmap __altmap = {
- .base_pfn = __phys_to_pfn(nsio->res.start),
- .reserve = __phys_to_pfn(SZ_8K),
+ .base_pfn = init_altmap_base(base),
+ .reserve = init_altmap_reserve(base),
};
- if (!nd_pfn->uuid || !nd_pfn->ndns)
- return -ENODEV;
-
- nd_region = to_nd_region(dev->parent);
- rc = nd_pfn_init(nd_pfn);
- if (rc)
- return rc;
-
- pfn_sb = nd_pfn->pfn_sb;
- offset = le64_to_cpu(pfn_sb->dataoff);
+ pmem = dev_get_drvdata(dev);
+ pmem->data_offset = le64_to_cpu(pfn_sb->dataoff);
+ pmem->pfn_pad = start_pad + end_trunc;
nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
if (nd_pfn->mode == PFN_MODE_RAM) {
- if (offset < SZ_8K)
+ if (pmem->data_offset < SZ_8K)
return -EINVAL;
nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
altmap = NULL;
} else if (nd_pfn->mode == PFN_MODE_PMEM) {
- nd_pfn->npfns = (resource_size(&nsio->res) - offset)
+ nd_pfn->npfns = (pmem->size - pmem->pfn_pad - pmem->data_offset)
/ PAGE_SIZE;
if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
dev_info(&nd_pfn->dev,
@@ -398,7 +484,7 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
le64_to_cpu(nd_pfn->pfn_sb->npfns),
nd_pfn->npfns);
altmap = & __altmap;
- altmap->free = __phys_to_pfn(offset - SZ_8K);
+ altmap->free = PHYS_PFN(pmem->data_offset - SZ_8K);
altmap->alloc = 0;
} else {
rc = -ENXIO;
@@ -406,10 +492,12 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
}
/* establish pfn range for lookup, and switch to direct map */
- pmem = dev_get_drvdata(dev);
q = pmem->pmem_queue;
+ memcpy(&res, &nsio->res, sizeof(res));
+ res.start += start_pad;
+ res.end -= end_trunc;
devm_memunmap(dev, (void __force *) pmem->virt_addr);
- pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &nsio->res,
+ pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &res,
&q->q_usage_counter, altmap);
pmem->pfn_flags |= PFN_MAP;
if (IS_ERR(pmem->virt_addr)) {
@@ -418,7 +506,6 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
}
/* attach pmem disk in "pfn-mode" */
- pmem->data_offset = offset;
rc = pmem_attach_disk(dev, ndns, pmem);
if (rc)
goto err;
@@ -427,6 +514,22 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
err:
nvdimm_namespace_detach_pfn(ndns);
return rc;
+
+}
+
+static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
+{
+ struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim);
+ int rc;
+
+ if (!nd_pfn->uuid || !nd_pfn->ndns)
+ return -ENODEV;
+
+ rc = nd_pfn_init(nd_pfn);
+ if (rc)
+ return rc;
+ /* we need a valid pfn_sb before we can init a vmem_altmap */
+ return __nvdimm_namespace_attach_pfn(nd_pfn);
}
static int nd_pmem_probe(struct device *dev)
@@ -488,12 +591,27 @@ static int nd_pmem_remove(struct device *dev)
return 0;
}
+static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
+{
+ struct pmem_device *pmem = dev_get_drvdata(dev);
+ struct nd_namespace_common *ndns = pmem->ndns;
+
+ if (event != NVDIMM_REVALIDATE_POISON)
+ return;
+
+ if (is_nd_btt(dev))
+ nvdimm_namespace_add_poison(ndns, &pmem->bb, 0);
+ else
+ nvdimm_namespace_add_poison(ndns, &pmem->bb, pmem->data_offset);
+}
+
MODULE_ALIAS("pmem");
MODULE_ALIAS_ND_DEVICE(ND_DEVICE_NAMESPACE_IO);
MODULE_ALIAS_ND_DEVICE(ND_DEVICE_NAMESPACE_PMEM);
static struct nd_device_driver nd_pmem_driver = {
.probe = nd_pmem_probe,
.remove = nd_pmem_remove,
+ .notify = nd_pmem_notify,
.drv = {
.name = "nd_pmem",
},
@@ -502,26 +620,13 @@ static struct nd_device_driver nd_pmem_driver = {
static int __init pmem_init(void)
{
- int error;
-
- pmem_major = register_blkdev(0, "pmem");
- if (pmem_major < 0)
- return pmem_major;
-
- error = nd_driver_register(&nd_pmem_driver);
- if (error) {
- unregister_blkdev(pmem_major, "pmem");
- return error;
- }
-
- return 0;
+ return nd_driver_register(&nd_pmem_driver);
}
module_init(pmem_init);
static void pmem_exit(void)
{
driver_unregister(&nd_pmem_driver.drv);
- unregister_blkdev(pmem_major, "pmem");
}
module_exit(pmem_exit);
diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c
index 7da63eac78ee..4b7715e29cff 100644
--- a/drivers/nvdimm/region.c
+++ b/drivers/nvdimm/region.c
@@ -93,9 +93,21 @@ static int nd_region_remove(struct device *dev)
return 0;
}
+static int child_notify(struct device *dev, void *data)
+{
+ nd_device_notify(dev, *(enum nvdimm_event *) data);
+ return 0;
+}
+
+static void nd_region_notify(struct device *dev, enum nvdimm_event event)
+{
+ device_for_each_child(dev, &event, child_notify);
+}
+
static struct nd_device_driver nd_region_driver = {
.probe = nd_region_probe,
.remove = nd_region_remove,
+ .notify = nd_region_notify,
.drv = {
.name = "nd_region",
},
diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig
index 5d6237391dcd..b586d84f2518 100644
--- a/drivers/nvme/host/Kconfig
+++ b/drivers/nvme/host/Kconfig
@@ -17,5 +17,6 @@ config BLK_DEV_NVME_SCSI
and block devices nodes, as well a a translation for a small
number of selected SCSI commands to NVMe commands to the NVMe
driver. If you don't know what this means you probably want
- to say N here, and if you know what it means you probably
- want to say N as well.
+ to say N here, unless you run a distro that abuses the SCSI
+ emulation to provide stable device names for mount by id, like
+ some OpenSuSE and SLES versions.
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index c5bf001af559..03c46412fff4 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -55,8 +55,9 @@ static void nvme_free_ns(struct kref *kref)
ns->disk->private_data = NULL;
spin_unlock(&dev_list_lock);
- nvme_put_ctrl(ns->ctrl);
put_disk(ns->disk);
+ ida_simple_remove(&ns->ctrl->ns_ida, ns->instance);
+ nvme_put_ctrl(ns->ctrl);
kfree(ns);
}
@@ -183,7 +184,7 @@ int __nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
goto out_unmap;
}
- if (meta_buffer) {
+ if (meta_buffer && meta_len) {
struct bio_integrity_payload *bip;
meta = kmalloc(meta_len, GFP_KERNEL);
@@ -373,6 +374,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
if (copy_from_user(&io, uio, sizeof(io)))
return -EFAULT;
+ if (io.flags)
+ return -EINVAL;
switch (io.opcode) {
case nvme_cmd_write:
@@ -424,6 +427,8 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
return -EACCES;
if (copy_from_user(&cmd, ucmd, sizeof(cmd)))
return -EFAULT;
+ if (cmd.flags)
+ return -EINVAL;
memset(&c, 0, sizeof(c));
c.common.opcode = cmd.opcode;
@@ -556,6 +561,10 @@ static int nvme_revalidate_disk(struct gendisk *disk)
u16 old_ms;
unsigned short bs;
+ if (test_bit(NVME_NS_DEAD, &ns->flags)) {
+ set_capacity(disk, 0);
+ return -ENODEV;
+ }
if (nvme_identify_ns(ns->ctrl, ns->ns_id, &id)) {
dev_warn(ns->ctrl->dev, "%s: Identify failure nvme%dn%d\n",
__func__, ns->ctrl->instance, ns->ns_id);
@@ -831,6 +840,23 @@ int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl)
return ret;
}
+static void nvme_set_queue_limits(struct nvme_ctrl *ctrl,
+ struct request_queue *q)
+{
+ if (ctrl->max_hw_sectors) {
+ u32 max_segments =
+ (ctrl->max_hw_sectors / (ctrl->page_size >> 9)) + 1;
+
+ blk_queue_max_hw_sectors(q, ctrl->max_hw_sectors);
+ blk_queue_max_segments(q, min_t(u32, max_segments, USHRT_MAX));
+ }
+ if (ctrl->stripe_size)
+ blk_queue_chunk_sectors(q, ctrl->stripe_size >> 9);
+ if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
+ blk_queue_flush(q, REQ_FLUSH | REQ_FUA);
+ blk_queue_virt_boundary(q, ctrl->page_size - 1);
+}
+
/*
* Initialize the cached copies of the Identify data and various controller
* register in our nvme_ctrl structure. This should be called as soon as
@@ -888,6 +914,8 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
}
}
+ nvme_set_queue_limits(ctrl, ctrl->admin_q);
+
kfree(id);
return 0;
}
@@ -1118,10 +1146,13 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
if (!ns)
return;
+ ns->instance = ida_simple_get(&ctrl->ns_ida, 1, 0, GFP_KERNEL);
+ if (ns->instance < 0)
+ goto out_free_ns;
+
ns->queue = blk_mq_init_queue(ctrl->tagset);
if (IS_ERR(ns->queue))
- goto out_free_ns;
- queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, ns->queue);
+ goto out_release_instance;
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, ns->queue);
ns->queue->queuedata = ns;
ns->ctrl = ctrl;
@@ -1135,17 +1166,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
ns->disk = disk;
ns->lba_shift = 9; /* set to a default value for 512 until disk is validated */
+
blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
- if (ctrl->max_hw_sectors) {
- blk_queue_max_hw_sectors(ns->queue, ctrl->max_hw_sectors);
- blk_queue_max_segments(ns->queue,
- (ctrl->max_hw_sectors / (ctrl->page_size >> 9)) + 1);
- }
- if (ctrl->stripe_size)
- blk_queue_chunk_sectors(ns->queue, ctrl->stripe_size >> 9);
- if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
- blk_queue_flush(ns->queue, REQ_FLUSH | REQ_FUA);
- blk_queue_virt_boundary(ns->queue, ctrl->page_size - 1);
+ nvme_set_queue_limits(ctrl, ns->queue);
disk->major = nvme_major;
disk->first_minor = 0;
@@ -1154,7 +1177,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
disk->queue = ns->queue;
disk->driverfs_dev = ctrl->device;
disk->flags = GENHD_FL_EXT_DEVT;
- sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance, nsid);
+ sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance, ns->instance);
if (nvme_revalidate_disk(ns->disk))
goto out_free_disk;
@@ -1174,40 +1197,29 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
kfree(disk);
out_free_queue:
blk_cleanup_queue(ns->queue);
+ out_release_instance:
+ ida_simple_remove(&ctrl->ns_ida, ns->instance);
out_free_ns:
kfree(ns);
}
static void nvme_ns_remove(struct nvme_ns *ns)
{
- bool kill = nvme_io_incapable(ns->ctrl) &&
- !blk_queue_dying(ns->queue);
-
- lockdep_assert_held(&ns->ctrl->namespaces_mutex);
-
- if (kill) {
- blk_set_queue_dying(ns->queue);
+ if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
+ return;
- /*
- * The controller was shutdown first if we got here through
- * device removal. The shutdown may requeue outstanding
- * requests. These need to be aborted immediately so
- * del_gendisk doesn't block indefinitely for their completion.
- */
- blk_mq_abort_requeue_list(ns->queue);
- }
if (ns->disk->flags & GENHD_FL_UP) {
if (blk_get_integrity(ns->disk))
blk_integrity_unregister(ns->disk);
sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
&nvme_ns_attr_group);
del_gendisk(ns->disk);
- }
- if (kill || !blk_queue_dying(ns->queue)) {
blk_mq_abort_requeue_list(ns->queue);
blk_cleanup_queue(ns->queue);
}
+ mutex_lock(&ns->ctrl->namespaces_mutex);
list_del_init(&ns->list);
+ mutex_unlock(&ns->ctrl->namespaces_mutex);
nvme_put_ns(ns);
}
@@ -1301,10 +1313,8 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
{
struct nvme_ns *ns, *next;
- mutex_lock(&ctrl->namespaces_mutex);
list_for_each_entry_safe(ns, next, &ctrl->namespaces, list)
nvme_ns_remove(ns);
- mutex_unlock(&ctrl->namespaces_mutex);
}
static DEFINE_IDA(nvme_instance_ida);
@@ -1351,6 +1361,7 @@ static void nvme_free_ctrl(struct kref *kref)
put_device(ctrl->device);
nvme_release_instance(ctrl);
+ ida_destroy(&ctrl->ns_ida);
ctrl->ops->free_ctrl(ctrl);
}
@@ -1391,6 +1402,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
}
get_device(ctrl->device);
dev_set_drvdata(ctrl->device, ctrl);
+ ida_init(&ctrl->ns_ida);
spin_lock(&dev_list_lock);
list_add_tail(&ctrl->node, &nvme_ctrl_list);
@@ -1403,6 +1415,38 @@ out:
return ret;
}
+/**
+ * nvme_kill_queues(): Ends all namespace queues
+ * @ctrl: the dead controller that needs to end
+ *
+ * Call this function when the driver determines it is unable to get the
+ * controller in a state capable of servicing IO.
+ */
+void nvme_kill_queues(struct nvme_ctrl *ctrl)
+{
+ struct nvme_ns *ns;
+
+ mutex_lock(&ctrl->namespaces_mutex);
+ list_for_each_entry(ns, &ctrl->namespaces, list) {
+ if (!kref_get_unless_zero(&ns->kref))
+ continue;
+
+ /*
+ * Revalidating a dead namespace sets capacity to 0. This will
+ * end buffered writers dirtying pages that can't be synced.
+ */
+ if (!test_and_set_bit(NVME_NS_DEAD, &ns->flags))
+ revalidate_disk(ns->disk);
+
+ blk_set_queue_dying(ns->queue);
+ blk_mq_abort_requeue_list(ns->queue);
+ blk_mq_start_stopped_hw_queues(ns->queue, true);
+
+ nvme_put_ns(ns);
+ }
+ mutex_unlock(&ctrl->namespaces_mutex);
+}
+
void nvme_stop_queues(struct nvme_ctrl *ctrl)
{
struct nvme_ns *ns;
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 5cd3725e2fa4..6bb15e4926dc 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -146,9 +146,10 @@ struct nvme_nvm_command {
};
};
+#define NVME_NVM_LP_MLC_PAIRS 886
struct nvme_nvm_lp_mlc {
__u16 num_pairs;
- __u8 pairs[886];
+ __u8 pairs[NVME_NVM_LP_MLC_PAIRS];
};
struct nvme_nvm_lp_tbl {
@@ -282,9 +283,14 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
memcpy(dst->lptbl.id, src->lptbl.id, 8);
dst->lptbl.mlc.num_pairs =
le16_to_cpu(src->lptbl.mlc.num_pairs);
- /* 4 bits per pair */
+
+ if (dst->lptbl.mlc.num_pairs > NVME_NVM_LP_MLC_PAIRS) {
+ pr_err("nvm: number of MLC pairs not supported\n");
+ return -EINVAL;
+ }
+
memcpy(dst->lptbl.mlc.pairs, src->lptbl.mlc.pairs,
- dst->lptbl.mlc.num_pairs >> 1);
+ dst->lptbl.mlc.num_pairs);
}
}
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 4fb5bb737868..fb15ba5f5d19 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -72,6 +72,7 @@ struct nvme_ctrl {
struct mutex namespaces_mutex;
struct device *device; /* char device */
struct list_head node;
+ struct ida ns_ida;
char name[12];
char serial[20];
@@ -102,6 +103,7 @@ struct nvme_ns {
struct request_queue *queue;
struct gendisk *disk;
struct kref kref;
+ int instance;
u8 eui[8];
u8 uuid[16];
@@ -112,6 +114,11 @@ struct nvme_ns {
bool ext;
u8 pi_type;
int type;
+ unsigned long flags;
+
+#define NVME_NS_REMOVING 0
+#define NVME_NS_DEAD 1
+
u64 mode_select_num_blocks;
u32 mode_select_block_len;
};
@@ -139,9 +146,9 @@ static inline bool nvme_io_incapable(struct nvme_ctrl *ctrl)
u32 val = 0;
if (ctrl->ops->io_incapable(ctrl))
- return false;
+ return true;
if (ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &val))
- return false;
+ return true;
return val & NVME_CSTS_CFS;
}
@@ -240,6 +247,7 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
void nvme_stop_queues(struct nvme_ctrl *ctrl);
void nvme_start_queues(struct nvme_ctrl *ctrl);
+void nvme_kill_queues(struct nvme_ctrl *ctrl);
struct request *nvme_alloc_request(struct request_queue *q,
struct nvme_command *cmd, unsigned int flags);
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 72ef8322d32a..680f5780750c 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -86,7 +86,6 @@ struct nvme_queue;
static int nvme_reset(struct nvme_dev *dev);
static void nvme_process_cq(struct nvme_queue *nvmeq);
-static void nvme_remove_dead_ctrl(struct nvme_dev *dev);
static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown);
/*
@@ -120,6 +119,7 @@ struct nvme_dev {
unsigned long flags;
#define NVME_CTRL_RESETTING 0
+#define NVME_CTRL_REMOVING 1
struct nvme_ctrl ctrl;
struct completion ioq_wait;
@@ -286,6 +286,17 @@ static int nvme_init_request(void *data, struct request *req,
return 0;
}
+static void nvme_queue_scan(struct nvme_dev *dev)
+{
+ /*
+ * Do not queue new scan work when a controller is reset during
+ * removal.
+ */
+ if (test_bit(NVME_CTRL_REMOVING, &dev->flags))
+ return;
+ queue_work(nvme_workq, &dev->scan_work);
+}
+
static void nvme_complete_async_event(struct nvme_dev *dev,
struct nvme_completion *cqe)
{
@@ -300,7 +311,7 @@ static void nvme_complete_async_event(struct nvme_dev *dev,
switch (result & 0xff07) {
case NVME_AER_NOTICE_NS_CHANGED:
dev_info(dev->dev, "rescanning\n");
- queue_work(nvme_workq, &dev->scan_work);
+ nvme_queue_scan(dev);
default:
dev_warn(dev->dev, "async event result %08x\n", result);
}
@@ -678,6 +689,14 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
blk_mq_start_request(req);
spin_lock_irq(&nvmeq->q_lock);
+ if (unlikely(nvmeq->cq_vector < 0)) {
+ if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
+ ret = BLK_MQ_RQ_QUEUE_BUSY;
+ else
+ ret = BLK_MQ_RQ_QUEUE_ERROR;
+ spin_unlock_irq(&nvmeq->q_lock);
+ goto out;
+ }
__nvme_submit_cmd(nvmeq, &cmnd);
nvme_process_cq(nvmeq);
spin_unlock_irq(&nvmeq->q_lock);
@@ -999,7 +1018,7 @@ static void nvme_cancel_queue_ios(struct request *req, void *data, bool reserved
if (!blk_mq_request_started(req))
return;
- dev_warn(nvmeq->q_dmadev,
+ dev_dbg_ratelimited(nvmeq->q_dmadev,
"Cancelling I/O %d QID %d\n", req->tag, nvmeq->qid);
status = NVME_SC_ABORT_REQ;
@@ -1245,6 +1264,12 @@ static struct blk_mq_ops nvme_mq_ops = {
static void nvme_dev_remove_admin(struct nvme_dev *dev)
{
if (dev->ctrl.admin_q && !blk_queue_dying(dev->ctrl.admin_q)) {
+ /*
+ * If the controller was reset during removal, it's possible
+ * user requests may be waiting on a stopped queue. Start the
+ * queue to flush these to completion.
+ */
+ blk_mq_start_stopped_hw_queues(dev->ctrl.admin_q, true);
blk_cleanup_queue(dev->ctrl.admin_q);
blk_mq_free_tag_set(&dev->admin_tagset);
}
@@ -1685,14 +1710,14 @@ static int nvme_dev_add(struct nvme_dev *dev)
return 0;
dev->ctrl.tagset = &dev->tagset;
}
- queue_work(nvme_workq, &dev->scan_work);
+ nvme_queue_scan(dev);
return 0;
}
-static int nvme_dev_map(struct nvme_dev *dev)
+static int nvme_pci_enable(struct nvme_dev *dev)
{
u64 cap;
- int bars, result = -ENOMEM;
+ int result = -ENOMEM;
struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pci_enable_device_mem(pdev))
@@ -1700,24 +1725,14 @@ static int nvme_dev_map(struct nvme_dev *dev)
dev->entry[0].vector = pdev->irq;
pci_set_master(pdev);
- bars = pci_select_bars(pdev, IORESOURCE_MEM);
- if (!bars)
- goto disable_pci;
-
- if (pci_request_selected_regions(pdev, bars, "nvme"))
- goto disable_pci;
if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)) &&
dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(32)))
goto disable;
- dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
- if (!dev->bar)
- goto disable;
-
if (readl(dev->bar + NVME_REG_CSTS) == -1) {
result = -ENODEV;
- goto unmap;
+ goto disable;
}
/*
@@ -1727,7 +1742,7 @@ static int nvme_dev_map(struct nvme_dev *dev)
if (!pdev->irq) {
result = pci_enable_msix(pdev, dev->entry, 1);
if (result < 0)
- goto unmap;
+ goto disable;
}
cap = lo_hi_readq(dev->bar + NVME_REG_CAP);
@@ -1754,18 +1769,20 @@ static int nvme_dev_map(struct nvme_dev *dev)
pci_save_state(pdev);
return 0;
- unmap:
- iounmap(dev->bar);
- dev->bar = NULL;
disable:
- pci_release_regions(pdev);
- disable_pci:
pci_disable_device(pdev);
return result;
}
static void nvme_dev_unmap(struct nvme_dev *dev)
{
+ if (dev->bar)
+ iounmap(dev->bar);
+ pci_release_regions(to_pci_dev(dev->dev));
+}
+
+static void nvme_pci_disable(struct nvme_dev *dev)
+{
struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pdev->msi_enabled)
@@ -1773,12 +1790,6 @@ static void nvme_dev_unmap(struct nvme_dev *dev)
else if (pdev->msix_enabled)
pci_disable_msix(pdev);
- if (dev->bar) {
- iounmap(dev->bar);
- dev->bar = NULL;
- pci_release_regions(pdev);
- }
-
if (pci_is_enabled(pdev)) {
pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
@@ -1837,7 +1848,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
nvme_dev_list_remove(dev);
mutex_lock(&dev->shutdown_lock);
- if (dev->bar) {
+ if (pci_is_enabled(to_pci_dev(dev->dev))) {
nvme_stop_queues(&dev->ctrl);
csts = readl(dev->bar + NVME_REG_CSTS);
}
@@ -1850,7 +1861,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
nvme_disable_io_queues(dev);
nvme_disable_admin_queue(dev, shutdown);
}
- nvme_dev_unmap(dev);
+ nvme_pci_disable(dev);
for (i = dev->queue_count - 1; i >= 0; i--)
nvme_clear_queue(dev->queues[i]);
@@ -1894,10 +1905,20 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
kfree(dev);
}
+static void nvme_remove_dead_ctrl(struct nvme_dev *dev, int status)
+{
+ dev_warn(dev->dev, "Removing after probe failure status: %d\n", status);
+
+ kref_get(&dev->ctrl.kref);
+ nvme_dev_disable(dev, false);
+ if (!schedule_work(&dev->remove_work))
+ nvme_put_ctrl(&dev->ctrl);
+}
+
static void nvme_reset_work(struct work_struct *work)
{
struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
- int result;
+ int result = -ENODEV;
if (WARN_ON(test_bit(NVME_CTRL_RESETTING, &dev->flags)))
goto out;
@@ -1906,37 +1927,37 @@ static void nvme_reset_work(struct work_struct *work)
* If we're called to reset a live controller first shut it down before
* moving on.
*/
- if (dev->bar)
+ if (dev->ctrl.ctrl_config & NVME_CC_ENABLE)
nvme_dev_disable(dev, false);
set_bit(NVME_CTRL_RESETTING, &dev->flags);
- result = nvme_dev_map(dev);
+ result = nvme_pci_enable(dev);
if (result)
goto out;
result = nvme_configure_admin_queue(dev);
if (result)
- goto unmap;
+ goto out;
nvme_init_queue(dev->queues[0], 0);
result = nvme_alloc_admin_tags(dev);
if (result)
- goto disable;
+ goto out;
result = nvme_init_identify(&dev->ctrl);
if (result)
- goto free_tags;
+ goto out;
result = nvme_setup_io_queues(dev);
if (result)
- goto free_tags;
+ goto out;
dev->ctrl.event_limit = NVME_NR_AEN_COMMANDS;
result = nvme_dev_list_add(dev);
if (result)
- goto remove;
+ goto out;
/*
* Keep the controller around but remove all namespaces if we don't have
@@ -1953,19 +1974,8 @@ static void nvme_reset_work(struct work_struct *work)
clear_bit(NVME_CTRL_RESETTING, &dev->flags);
return;
- remove:
- nvme_dev_list_remove(dev);
- free_tags:
- nvme_dev_remove_admin(dev);
- blk_put_queue(dev->ctrl.admin_q);
- dev->ctrl.admin_q = NULL;
- dev->queues[0]->tags = NULL;
- disable:
- nvme_disable_admin_queue(dev, false);
- unmap:
- nvme_dev_unmap(dev);
out:
- nvme_remove_dead_ctrl(dev);
+ nvme_remove_dead_ctrl(dev, result);
}
static void nvme_remove_dead_ctrl_work(struct work_struct *work)
@@ -1973,19 +1983,12 @@ static void nvme_remove_dead_ctrl_work(struct work_struct *work)
struct nvme_dev *dev = container_of(work, struct nvme_dev, remove_work);
struct pci_dev *pdev = to_pci_dev(dev->dev);
+ nvme_kill_queues(&dev->ctrl);
if (pci_get_drvdata(pdev))
pci_stop_and_remove_bus_device_locked(pdev);
nvme_put_ctrl(&dev->ctrl);
}
-static void nvme_remove_dead_ctrl(struct nvme_dev *dev)
-{
- dev_warn(dev->dev, "Removing after probe failure\n");
- kref_get(&dev->ctrl.kref);
- if (!schedule_work(&dev->remove_work))
- nvme_put_ctrl(&dev->ctrl);
-}
-
static int nvme_reset(struct nvme_dev *dev)
{
if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q))
@@ -2037,6 +2040,27 @@ static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
.free_ctrl = nvme_pci_free_ctrl,
};
+static int nvme_dev_map(struct nvme_dev *dev)
+{
+ int bars;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+ bars = pci_select_bars(pdev, IORESOURCE_MEM);
+ if (!bars)
+ return -ENODEV;
+ if (pci_request_selected_regions(pdev, bars, "nvme"))
+ return -ENODEV;
+
+ dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
+ if (!dev->bar)
+ goto release;
+
+ return 0;
+ release:
+ pci_release_regions(pdev);
+ return -ENODEV;
+}
+
static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int node, result = -ENOMEM;
@@ -2061,6 +2085,10 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev->dev = get_device(&pdev->dev);
pci_set_drvdata(pdev, dev);
+ result = nvme_dev_map(dev);
+ if (result)
+ goto free;
+
INIT_LIST_HEAD(&dev->node);
INIT_WORK(&dev->scan_work, nvme_dev_scan);
INIT_WORK(&dev->reset_work, nvme_reset_work);
@@ -2084,6 +2112,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
nvme_release_prp_pools(dev);
put_pci:
put_device(dev->dev);
+ nvme_dev_unmap(dev);
free:
kfree(dev->queues);
kfree(dev->entry);
@@ -2107,24 +2136,27 @@ static void nvme_shutdown(struct pci_dev *pdev)
nvme_dev_disable(dev, true);
}
+/*
+ * The driver's remove may be called on a device in a partially initialized
+ * state. This function must not have any dependencies on the device state in
+ * order to proceed.
+ */
static void nvme_remove(struct pci_dev *pdev)
{
struct nvme_dev *dev = pci_get_drvdata(pdev);
- spin_lock(&dev_list_lock);
- list_del_init(&dev->node);
- spin_unlock(&dev_list_lock);
-
+ set_bit(NVME_CTRL_REMOVING, &dev->flags);
pci_set_drvdata(pdev, NULL);
- flush_work(&dev->reset_work);
flush_work(&dev->scan_work);
nvme_remove_namespaces(&dev->ctrl);
nvme_uninit_ctrl(&dev->ctrl);
nvme_dev_disable(dev, true);
+ flush_work(&dev->reset_work);
nvme_dev_remove_admin(dev);
nvme_free_queues(dev, 0);
nvme_release_cmb(dev);
nvme_release_prp_pools(dev);
+ nvme_dev_unmap(dev);
nvme_put_ctrl(&dev->ctrl);
}
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index bc4ea585b42e..ca52952d850f 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -25,9 +25,19 @@ config NVMEM_IMX_OCOTP
This driver can also be built as a module. If so, the module
will be called nvmem-imx-ocotp.
+config NVMEM_LPC18XX_EEPROM
+ tristate "NXP LPC18XX EEPROM Memory Support"
+ depends on ARCH_LPC18XX || COMPILE_TEST
+ help
+ Say Y here to include support for NXP LPC18xx EEPROM memory found in
+ NXP LPC185x/3x and LPC435x/3x/2x/1x devices.
+ To compile this driver as a module, choose M here: the module
+ will be called nvmem_lpc18xx_eeprom.
+
config NVMEM_MXS_OCOTP
tristate "Freescale MXS On-Chip OTP Memory Support"
depends on ARCH_MXS || COMPILE_TEST
+ depends on HAS_IOMEM
help
If you say Y here, you will get readonly access to the
One Time Programmable memory pages that are stored
@@ -36,9 +46,21 @@ config NVMEM_MXS_OCOTP
This driver can also be built as a module. If so, the module
will be called nvmem-mxs-ocotp.
+config MTK_EFUSE
+ tristate "Mediatek SoCs EFUSE support"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ This is a driver to access hardware related data like sensor
+ calibration, HDMI impedance etc.
+
+ This driver can also be built as a module. If so, the module
+ will be called efuse-mtk.
+
config QCOM_QFPROM
tristate "QCOM QFPROM Support"
depends on ARCH_QCOM || COMPILE_TEST
+ depends on HAS_IOMEM
select REGMAP_MMIO
help
Say y here to enable QFPROM support. The QFPROM provides access
@@ -50,6 +72,7 @@ config QCOM_QFPROM
config ROCKCHIP_EFUSE
tristate "Rockchip eFuse Support"
depends on ARCH_ROCKCHIP || COMPILE_TEST
+ depends on HAS_IOMEM
help
This is a simple drive to dump specified values of Rockchip SoC
from eFuse, such as cpu-leakage.
@@ -71,6 +94,7 @@ config NVMEM_SUNXI_SID
config NVMEM_VF610_OCOTP
tristate "VF610 SoC OCOTP support"
depends on SOC_VF610 || COMPILE_TEST
+ depends on HAS_IOMEM
help
This is a driver for the 'OCOTP' peripheral available on Vybrid
devices like VF5xx and VF6xx.
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 95dde3f8f085..45ab1ae08fa9 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -8,8 +8,12 @@ nvmem_core-y := core.o
# Devices
obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o
nvmem-imx-ocotp-y := imx-ocotp.o
+obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o
+nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o
obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o
nvmem-mxs-ocotp-y := mxs-ocotp.o
+obj-$(CONFIG_MTK_EFUSE) += nvmem_mtk-efuse.o
+nvmem_mtk-efuse-y := mtk-efuse.o
obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
nvmem_qfprom-y := qfprom.o
obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 9d11d9837312..0de3d878c439 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -38,8 +38,13 @@ struct nvmem_device {
int users;
size_t size;
bool read_only;
+ int flags;
+ struct bin_attribute eeprom;
+ struct device *base_dev;
};
+#define FLAG_COMPAT BIT(0)
+
struct nvmem_cell {
const char *name;
int offset;
@@ -56,16 +61,26 @@ static DEFINE_IDA(nvmem_ida);
static LIST_HEAD(nvmem_cells);
static DEFINE_MUTEX(nvmem_cells_mutex);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key eeprom_lock_key;
+#endif
+
#define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t pos, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct nvmem_device *nvmem = to_nvmem_device(dev);
+ struct device *dev;
+ struct nvmem_device *nvmem;
int rc;
+ if (attr->private)
+ dev = attr->private;
+ else
+ dev = container_of(kobj, struct device, kobj);
+ nvmem = to_nvmem_device(dev);
+
/* Stop the user from reading */
if (pos >= nvmem->size)
return 0;
@@ -90,10 +105,16 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t pos, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct nvmem_device *nvmem = to_nvmem_device(dev);
+ struct device *dev;
+ struct nvmem_device *nvmem;
int rc;
+ if (attr->private)
+ dev = attr->private;
+ else
+ dev = container_of(kobj, struct device, kobj);
+ nvmem = to_nvmem_device(dev);
+
/* Stop the user from writing */
if (pos >= nvmem->size)
return 0;
@@ -161,6 +182,53 @@ static const struct attribute_group *nvmem_ro_dev_groups[] = {
NULL,
};
+/* default read/write permissions, root only */
+static struct bin_attribute bin_attr_rw_root_nvmem = {
+ .attr = {
+ .name = "nvmem",
+ .mode = S_IWUSR | S_IRUSR,
+ },
+ .read = bin_attr_nvmem_read,
+ .write = bin_attr_nvmem_write,
+};
+
+static struct bin_attribute *nvmem_bin_rw_root_attributes[] = {
+ &bin_attr_rw_root_nvmem,
+ NULL,
+};
+
+static const struct attribute_group nvmem_bin_rw_root_group = {
+ .bin_attrs = nvmem_bin_rw_root_attributes,
+};
+
+static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
+ &nvmem_bin_rw_root_group,
+ NULL,
+};
+
+/* read only permission, root only */
+static struct bin_attribute bin_attr_ro_root_nvmem = {
+ .attr = {
+ .name = "nvmem",
+ .mode = S_IRUSR,
+ },
+ .read = bin_attr_nvmem_read,
+};
+
+static struct bin_attribute *nvmem_bin_ro_root_attributes[] = {
+ &bin_attr_ro_root_nvmem,
+ NULL,
+};
+
+static const struct attribute_group nvmem_bin_ro_root_group = {
+ .bin_attrs = nvmem_bin_ro_root_attributes,
+};
+
+static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
+ &nvmem_bin_ro_root_group,
+ NULL,
+};
+
static void nvmem_release(struct device *dev)
{
struct nvmem_device *nvmem = to_nvmem_device(dev);
@@ -294,12 +362,51 @@ static int nvmem_add_cells(struct nvmem_device *nvmem,
return 0;
err:
- while (--i)
+ while (i--)
nvmem_cell_drop(cells[i]);
+ kfree(cells);
+
return rval;
}
+/*
+ * nvmem_setup_compat() - Create an additional binary entry in
+ * drivers sys directory, to be backwards compatible with the older
+ * drivers/misc/eeprom drivers.
+ */
+static int nvmem_setup_compat(struct nvmem_device *nvmem,
+ const struct nvmem_config *config)
+{
+ int rval;
+
+ if (!config->base_dev)
+ return -EINVAL;
+
+ if (nvmem->read_only)
+ nvmem->eeprom = bin_attr_ro_root_nvmem;
+ else
+ nvmem->eeprom = bin_attr_rw_root_nvmem;
+ nvmem->eeprom.attr.name = "eeprom";
+ nvmem->eeprom.size = nvmem->size;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ nvmem->eeprom.attr.key = &eeprom_lock_key;
+#endif
+ nvmem->eeprom.private = &nvmem->dev;
+ nvmem->base_dev = config->base_dev;
+
+ rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
+ if (rval) {
+ dev_err(&nvmem->dev,
+ "Failed to create eeprom binary file %d\n", rval);
+ return rval;
+ }
+
+ nvmem->flags |= FLAG_COMPAT;
+
+ return 0;
+}
+
/**
* nvmem_register() - Register a nvmem device for given nvmem_config.
* Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
@@ -353,24 +460,37 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->read_only = of_property_read_bool(np, "read-only") |
config->read_only;
- nvmem->dev.groups = nvmem->read_only ? nvmem_ro_dev_groups :
- nvmem_rw_dev_groups;
+ if (config->root_only)
+ nvmem->dev.groups = nvmem->read_only ?
+ nvmem_ro_root_dev_groups :
+ nvmem_rw_root_dev_groups;
+ else
+ nvmem->dev.groups = nvmem->read_only ?
+ nvmem_ro_dev_groups :
+ nvmem_rw_dev_groups;
device_initialize(&nvmem->dev);
dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
rval = device_add(&nvmem->dev);
- if (rval) {
- ida_simple_remove(&nvmem_ida, nvmem->id);
- kfree(nvmem);
- return ERR_PTR(rval);
+ if (rval)
+ goto out;
+
+ if (config->compat) {
+ rval = nvmem_setup_compat(nvmem, config);
+ if (rval)
+ goto out;
}
if (config->cells)
nvmem_add_cells(nvmem, config);
return nvmem;
+out:
+ ida_simple_remove(&nvmem_ida, nvmem->id);
+ kfree(nvmem);
+ return ERR_PTR(rval);
}
EXPORT_SYMBOL_GPL(nvmem_register);
@@ -390,6 +510,9 @@ int nvmem_unregister(struct nvmem_device *nvmem)
}
mutex_unlock(&nvmem_mutex);
+ if (nvmem->flags & FLAG_COMPAT)
+ device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
+
nvmem_device_remove_all_cells(nvmem);
device_del(&nvmem->dev);
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index b7971d410b60..d7796eb5421f 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -51,7 +51,7 @@ static int imx_ocotp_read(void *context, const void *reg, size_t reg_size,
val += 4;
}
- return (i - index) * 4;
+ return 0;
}
static int imx_ocotp_write(void *context, const void *data, size_t count)
diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c
new file mode 100644
index 000000000000..878fce789341
--- /dev/null
+++ b/drivers/nvmem/lpc18xx_eeprom.c
@@ -0,0 +1,330 @@
+/*
+ * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver
+ *
+ * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com>
+ *
+ * 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 published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+/* Registers */
+#define LPC18XX_EEPROM_AUTOPROG 0x00c
+#define LPC18XX_EEPROM_AUTOPROG_WORD 0x1
+
+#define LPC18XX_EEPROM_CLKDIV 0x014
+
+#define LPC18XX_EEPROM_PWRDWN 0x018
+#define LPC18XX_EEPROM_PWRDWN_NO 0x0
+#define LPC18XX_EEPROM_PWRDWN_YES 0x1
+
+#define LPC18XX_EEPROM_INTSTAT 0xfe0
+#define LPC18XX_EEPROM_INTSTAT_END_OF_PROG BIT(2)
+
+#define LPC18XX_EEPROM_INTSTATCLR 0xfe8
+#define LPC18XX_EEPROM_INTSTATCLR_PROG_CLR_ST BIT(2)
+
+/* Fixed page size (bytes) */
+#define LPC18XX_EEPROM_PAGE_SIZE 0x80
+
+/* EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) */
+#define LPC18XX_EEPROM_CLOCK_HZ 1500000
+
+/* EEPROM requires 3 ms of erase/program time between each writing */
+#define LPC18XX_EEPROM_PROGRAM_TIME 3
+
+struct lpc18xx_eeprom_dev {
+ struct clk *clk;
+ void __iomem *reg_base;
+ void __iomem *mem_base;
+ struct nvmem_device *nvmem;
+ unsigned reg_bytes;
+ unsigned val_bytes;
+};
+
+static struct regmap_config lpc18xx_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+};
+
+static inline void lpc18xx_eeprom_writel(struct lpc18xx_eeprom_dev *eeprom,
+ u32 reg, u32 val)
+{
+ writel(val, eeprom->reg_base + reg);
+}
+
+static inline u32 lpc18xx_eeprom_readl(struct lpc18xx_eeprom_dev *eeprom,
+ u32 reg)
+{
+ return readl(eeprom->reg_base + reg);
+}
+
+static int lpc18xx_eeprom_busywait_until_prog(struct lpc18xx_eeprom_dev *eeprom)
+{
+ unsigned long end;
+ u32 val;
+
+ /* Wait until EEPROM program operation has finished */
+ end = jiffies + msecs_to_jiffies(LPC18XX_EEPROM_PROGRAM_TIME * 10);
+
+ while (time_is_after_jiffies(end)) {
+ val = lpc18xx_eeprom_readl(eeprom, LPC18XX_EEPROM_INTSTAT);
+
+ if (val & LPC18XX_EEPROM_INTSTAT_END_OF_PROG) {
+ lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_INTSTATCLR,
+ LPC18XX_EEPROM_INTSTATCLR_PROG_CLR_ST);
+ return 0;
+ }
+
+ usleep_range(LPC18XX_EEPROM_PROGRAM_TIME * USEC_PER_MSEC,
+ (LPC18XX_EEPROM_PROGRAM_TIME + 1) * USEC_PER_MSEC);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int lpc18xx_eeprom_gather_write(void *context, const void *reg,
+ size_t reg_size, const void *val,
+ size_t val_size)
+{
+ struct lpc18xx_eeprom_dev *eeprom = context;
+ unsigned int offset = *(u32 *)reg;
+ int ret;
+
+ if (offset % lpc18xx_regmap_config.reg_stride)
+ return -EINVAL;
+
+ lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
+ LPC18XX_EEPROM_PWRDWN_NO);
+
+ /* Wait 100 us while the EEPROM wakes up */
+ usleep_range(100, 200);
+
+ while (val_size) {
+ writel(*(u32 *)val, eeprom->mem_base + offset);
+ ret = lpc18xx_eeprom_busywait_until_prog(eeprom);
+ if (ret < 0)
+ return ret;
+
+ val_size -= eeprom->val_bytes;
+ val += eeprom->val_bytes;
+ offset += eeprom->val_bytes;
+ }
+
+ lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
+ LPC18XX_EEPROM_PWRDWN_YES);
+
+ return 0;
+}
+
+static int lpc18xx_eeprom_write(void *context, const void *data, size_t count)
+{
+ struct lpc18xx_eeprom_dev *eeprom = context;
+ unsigned int offset = eeprom->reg_bytes;
+
+ if (count <= offset)
+ return -EINVAL;
+
+ return lpc18xx_eeprom_gather_write(context, data, eeprom->reg_bytes,
+ data + offset, count - offset);
+}
+
+static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct lpc18xx_eeprom_dev *eeprom = context;
+ unsigned int offset = *(u32 *)reg;
+
+ lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
+ LPC18XX_EEPROM_PWRDWN_NO);
+
+ /* Wait 100 us while the EEPROM wakes up */
+ usleep_range(100, 200);
+
+ while (val_size) {
+ *(u32 *)val = readl(eeprom->mem_base + offset);
+ val_size -= eeprom->val_bytes;
+ val += eeprom->val_bytes;
+ offset += eeprom->val_bytes;
+ }
+
+ lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
+ LPC18XX_EEPROM_PWRDWN_YES);
+
+ return 0;
+}
+
+static struct regmap_bus lpc18xx_eeprom_bus = {
+ .write = lpc18xx_eeprom_write,
+ .gather_write = lpc18xx_eeprom_gather_write,
+ .read = lpc18xx_eeprom_read,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+static bool lpc18xx_eeprom_writeable_reg(struct device *dev, unsigned int reg)
+{
+ /*
+ * The last page contains the EEPROM initialization data and is not
+ * writable.
+ */
+ return reg <= lpc18xx_regmap_config.max_register -
+ LPC18XX_EEPROM_PAGE_SIZE;
+}
+
+static bool lpc18xx_eeprom_readable_reg(struct device *dev, unsigned int reg)
+{
+ return reg <= lpc18xx_regmap_config.max_register;
+}
+
+static struct nvmem_config lpc18xx_nvmem_config = {
+ .name = "lpc18xx-eeprom",
+ .owner = THIS_MODULE,
+};
+
+static int lpc18xx_eeprom_probe(struct platform_device *pdev)
+{
+ struct lpc18xx_eeprom_dev *eeprom;
+ struct device *dev = &pdev->dev;
+ struct reset_control *rst;
+ unsigned long clk_rate;
+ struct regmap *regmap;
+ struct resource *res;
+ int ret;
+
+ eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
+ if (!eeprom)
+ return -ENOMEM;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
+ eeprom->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(eeprom->reg_base))
+ return PTR_ERR(eeprom->reg_base);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
+ eeprom->mem_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(eeprom->mem_base))
+ return PTR_ERR(eeprom->mem_base);
+
+ eeprom->clk = devm_clk_get(&pdev->dev, "eeprom");
+ if (IS_ERR(eeprom->clk)) {
+ dev_err(&pdev->dev, "failed to get eeprom clock\n");
+ return PTR_ERR(eeprom->clk);
+ }
+
+ ret = clk_prepare_enable(eeprom->clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to prepare/enable eeprom clk: %d\n", ret);
+ return ret;
+ }
+
+ rst = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(rst)) {
+ dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst));
+ ret = PTR_ERR(rst);
+ goto err_clk;
+ }
+
+ ret = reset_control_assert(rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to assert reset: %d\n", ret);
+ goto err_clk;
+ }
+
+ eeprom->val_bytes = lpc18xx_regmap_config.val_bits / BITS_PER_BYTE;
+ eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / BITS_PER_BYTE;
+
+ /*
+ * Clock rate is generated by dividing the system bus clock by the
+ * division factor, contained in the divider register (minus 1 encoded).
+ */
+ clk_rate = clk_get_rate(eeprom->clk);
+ clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1;
+ lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate);
+
+ /*
+ * Writing a single word to the page will start the erase/program cycle
+ * automatically
+ */
+ lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG,
+ LPC18XX_EEPROM_AUTOPROG_WORD);
+
+ lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
+ LPC18XX_EEPROM_PWRDWN_YES);
+
+ lpc18xx_regmap_config.max_register = resource_size(res) - 1;
+ lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg;
+ lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg;
+
+ regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom,
+ &lpc18xx_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap));
+ ret = PTR_ERR(regmap);
+ goto err_clk;
+ }
+
+ lpc18xx_nvmem_config.dev = dev;
+
+ eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config);
+ if (IS_ERR(eeprom->nvmem)) {
+ ret = PTR_ERR(eeprom->nvmem);
+ goto err_clk;
+ }
+
+ platform_set_drvdata(pdev, eeprom);
+
+ return 0;
+
+err_clk:
+ clk_disable_unprepare(eeprom->clk);
+
+ return ret;
+}
+
+static int lpc18xx_eeprom_remove(struct platform_device *pdev)
+{
+ struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = nvmem_unregister(eeprom->nvmem);
+ if (ret < 0)
+ return ret;
+
+ clk_disable_unprepare(eeprom->clk);
+
+ return 0;
+}
+
+static const struct of_device_id lpc18xx_eeprom_of_match[] = {
+ { .compatible = "nxp,lpc1857-eeprom" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match);
+
+static struct platform_driver lpc18xx_eeprom_driver = {
+ .probe = lpc18xx_eeprom_probe,
+ .remove = lpc18xx_eeprom_remove,
+ .driver = {
+ .name = "lpc18xx-eeprom",
+ .of_match_table = lpc18xx_eeprom_of_match,
+ },
+};
+
+module_platform_driver(lpc18xx_eeprom_driver);
+
+MODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>");
+MODULE_DESCRIPTION("NXP LPC18xx EEPROM memory Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c
new file mode 100644
index 000000000000..9c49369beea5
--- /dev/null
+++ b/drivers/nvmem/mtk-efuse.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
+ *
+ * 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
+ * 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/device.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+static struct regmap_config mtk_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int mtk_efuse_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct nvmem_device *nvmem;
+ struct nvmem_config *econfig;
+ struct regmap *regmap;
+ void __iomem *base;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ econfig = devm_kzalloc(dev, sizeof(*econfig), GFP_KERNEL);
+ if (!econfig)
+ return -ENOMEM;
+
+ mtk_regmap_config.max_register = resource_size(res) - 1;
+
+ regmap = devm_regmap_init_mmio(dev, base, &mtk_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "regmap init failed\n");
+ return PTR_ERR(regmap);
+ }
+
+ econfig->dev = dev;
+ econfig->owner = THIS_MODULE;
+ nvmem = nvmem_register(econfig);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+
+ platform_set_drvdata(pdev, nvmem);
+
+ return 0;
+}
+
+static int mtk_efuse_remove(struct platform_device *pdev)
+{
+ struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+
+ return nvmem_unregister(nvmem);
+}
+
+static const struct of_device_id mtk_efuse_of_match[] = {
+ { .compatible = "mediatek,mt8173-efuse",},
+ { .compatible = "mediatek,efuse",},
+ {/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, mtk_efuse_of_match);
+
+static struct platform_driver mtk_efuse_driver = {
+ .probe = mtk_efuse_probe,
+ .remove = mtk_efuse_remove,
+ .driver = {
+ .name = "mediatek,efuse",
+ .of_match_table = mtk_efuse_of_match,
+ },
+};
+
+static int __init mtk_efuse_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&mtk_efuse_driver);
+ if (ret) {
+ pr_err("Failed to register efuse driver\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit mtk_efuse_exit(void)
+{
+ return platform_driver_unregister(&mtk_efuse_driver);
+}
+
+subsys_initcall(mtk_efuse_init);
+module_exit(mtk_efuse_exit);
+
+MODULE_AUTHOR("Andrew-CT Chen <andrew-ct.chen@mediatek.com>");
+MODULE_DESCRIPTION("Mediatek EFUSE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c
index f55213424222..a009795111e9 100644
--- a/drivers/nvmem/rockchip-efuse.c
+++ b/drivers/nvmem/rockchip-efuse.c
@@ -14,16 +14,16 @@
* more details.
*/
-#include <linux/platform_device.h>
-#include <linux/nvmem-provider.h>
-#include <linux/slab.h>
-#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/delay.h>
+#include <linux/nvmem-provider.h>
+#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
#define EFUSE_A_SHIFT 6
#define EFUSE_A_MASK 0x3ff
@@ -35,10 +35,10 @@
#define REG_EFUSE_CTRL 0x0000
#define REG_EFUSE_DOUT 0x0004
-struct rockchip_efuse_context {
+struct rockchip_efuse_chip {
struct device *dev;
void __iomem *base;
- struct clk *efuse_clk;
+ struct clk *clk;
};
static int rockchip_efuse_write(void *context, const void *data, size_t count)
@@ -52,34 +52,32 @@ static int rockchip_efuse_read(void *context,
void *val, size_t val_size)
{
unsigned int offset = *(u32 *)reg;
- struct rockchip_efuse_context *_context = context;
- void __iomem *base = _context->base;
- struct clk *clk = _context->efuse_clk;
+ struct rockchip_efuse_chip *efuse = context;
u8 *buf = val;
int ret;
- ret = clk_prepare_enable(clk);
+ ret = clk_prepare_enable(efuse->clk);
if (ret < 0) {
- dev_err(_context->dev, "failed to prepare/enable efuse clk\n");
+ dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
return ret;
}
- writel(EFUSE_LOAD | EFUSE_PGENB, base + REG_EFUSE_CTRL);
+ writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + REG_EFUSE_CTRL);
udelay(1);
while (val_size) {
- writel(readl(base + REG_EFUSE_CTRL) &
+ writel(readl(efuse->base + REG_EFUSE_CTRL) &
(~(EFUSE_A_MASK << EFUSE_A_SHIFT)),
- base + REG_EFUSE_CTRL);
- writel(readl(base + REG_EFUSE_CTRL) |
+ efuse->base + REG_EFUSE_CTRL);
+ writel(readl(efuse->base + REG_EFUSE_CTRL) |
((offset & EFUSE_A_MASK) << EFUSE_A_SHIFT),
- base + REG_EFUSE_CTRL);
+ efuse->base + REG_EFUSE_CTRL);
udelay(1);
- writel(readl(base + REG_EFUSE_CTRL) |
- EFUSE_STROBE, base + REG_EFUSE_CTRL);
+ writel(readl(efuse->base + REG_EFUSE_CTRL) |
+ EFUSE_STROBE, efuse->base + REG_EFUSE_CTRL);
udelay(1);
- *buf++ = readb(base + REG_EFUSE_DOUT);
- writel(readl(base + REG_EFUSE_CTRL) &
- (~EFUSE_STROBE), base + REG_EFUSE_CTRL);
+ *buf++ = readb(efuse->base + REG_EFUSE_DOUT);
+ writel(readl(efuse->base + REG_EFUSE_CTRL) &
+ (~EFUSE_STROBE), efuse->base + REG_EFUSE_CTRL);
udelay(1);
val_size -= 1;
@@ -87,9 +85,9 @@ static int rockchip_efuse_read(void *context,
}
/* Switch to standby mode */
- writel(EFUSE_PGENB | EFUSE_CSB, base + REG_EFUSE_CTRL);
+ writel(EFUSE_PGENB | EFUSE_CSB, efuse->base + REG_EFUSE_CTRL);
- clk_disable_unprepare(clk);
+ clk_disable_unprepare(efuse->clk);
return 0;
}
@@ -114,48 +112,44 @@ static struct nvmem_config econfig = {
};
static const struct of_device_id rockchip_efuse_match[] = {
- { .compatible = "rockchip,rockchip-efuse",},
+ { .compatible = "rockchip,rockchip-efuse", },
{ /* sentinel */},
};
MODULE_DEVICE_TABLE(of, rockchip_efuse_match);
static int rockchip_efuse_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
struct resource *res;
struct nvmem_device *nvmem;
struct regmap *regmap;
- void __iomem *base;
- struct clk *clk;
- struct rockchip_efuse_context *context;
+ struct rockchip_efuse_chip *efuse;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
+ efuse = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_efuse_chip),
+ GFP_KERNEL);
+ if (!efuse)
+ return -ENOMEM;
- context = devm_kzalloc(dev, sizeof(struct rockchip_efuse_context),
- GFP_KERNEL);
- if (IS_ERR(context))
- return PTR_ERR(context);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ efuse->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(efuse->base))
+ return PTR_ERR(efuse->base);
- clk = devm_clk_get(dev, "pclk_efuse");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ efuse->clk = devm_clk_get(&pdev->dev, "pclk_efuse");
+ if (IS_ERR(efuse->clk))
+ return PTR_ERR(efuse->clk);
- context->dev = dev;
- context->base = base;
- context->efuse_clk = clk;
+ efuse->dev = &pdev->dev;
rockchip_efuse_regmap_config.max_register = resource_size(res) - 1;
- regmap = devm_regmap_init(dev, &rockchip_efuse_bus,
- context, &rockchip_efuse_regmap_config);
+ regmap = devm_regmap_init(efuse->dev, &rockchip_efuse_bus,
+ efuse, &rockchip_efuse_regmap_config);
if (IS_ERR(regmap)) {
- dev_err(dev, "regmap init failed\n");
+ dev_err(efuse->dev, "regmap init failed\n");
return PTR_ERR(regmap);
}
- econfig.dev = dev;
+
+ econfig.dev = efuse->dev;
nvmem = nvmem_register(&econfig);
if (IS_ERR(nvmem))
return PTR_ERR(nvmem);
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index cfa3b85064dd..bc88b4084055 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -13,10 +13,8 @@
* 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/device.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -27,7 +25,6 @@
#include <linux/slab.h>
#include <linux/random.h>
-
static struct nvmem_config econfig = {
.name = "sunxi-sid",
.read_only = true,
@@ -55,8 +52,8 @@ static u8 sunxi_sid_read_byte(const struct sunxi_sid *sid,
}
static int sunxi_sid_read(void *context,
- const void *reg, size_t reg_size,
- void *val, size_t val_size)
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
{
struct sunxi_sid *sid = context;
unsigned int offset = *(u32 *)reg;
@@ -130,7 +127,7 @@ static int sunxi_sid_probe(struct platform_device *pdev)
if (IS_ERR(nvmem))
return PTR_ERR(nvmem);
- randomness = kzalloc(sizeof(u8) * size, GFP_KERNEL);
+ randomness = kzalloc(sizeof(u8) * (size), GFP_KERNEL);
if (!randomness) {
ret = -EINVAL;
goto err_unreg_nvmem;
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 3e90bce70545..3349d2aa6634 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -804,14 +804,13 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
#endif /* CONFIG_BLK_DEV_INITRD */
#ifdef CONFIG_SERIAL_EARLYCON
-extern struct of_device_id __earlycon_of_table[];
static int __init early_init_dt_scan_chosen_serial(void)
{
int offset;
- const char *p;
+ const char *p, *q, *options = NULL;
int l;
- const struct of_device_id *match = __earlycon_of_table;
+ const struct earlycon_id *match;
const void *fdt = initial_boot_params;
offset = fdt_path_offset(fdt, "/chosen");
@@ -826,27 +825,26 @@ static int __init early_init_dt_scan_chosen_serial(void)
if (!p || !l)
return -ENOENT;
- /* Remove console options if present */
- l = strchrnul(p, ':') - p;
+ q = strchrnul(p, ':');
+ if (*q != '\0')
+ options = q + 1;
+ l = q - p;
/* Get the node specified by stdout-path */
offset = fdt_path_offset_namelen(fdt, p, l);
- if (offset < 0)
- return -ENODEV;
-
- while (match->compatible[0]) {
- u64 addr;
+ if (offset < 0) {
+ pr_warn("earlycon: stdout-path %.*s not found\n", l, p);
+ return 0;
+ }
- if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
- match++;
+ for (match = __earlycon_table; match < __earlycon_table_end; match++) {
+ if (!match->compatible[0])
continue;
- }
- addr = fdt_translate_address(fdt, offset);
- if (addr == OF_BAD_ADDR)
- return -ENXIO;
+ if (fdt_node_check_compatible(fdt, offset, match->compatible))
+ continue;
- of_setup_earlycon(addr, match->data);
+ of_setup_earlycon(match, offset, options);
return 0;
}
return -ENODEV;
diff --git a/drivers/of/fdt_address.c b/drivers/of/fdt_address.c
index 8d3dc6fbdb7a..dca8f9b93745 100644
--- a/drivers/of/fdt_address.c
+++ b/drivers/of/fdt_address.c
@@ -161,7 +161,7 @@ static int __init fdt_translate_one(const void *blob, int parent,
* that can be mapped to a cpu physical address). This is not really specified
* that way, but this is traditionally the way IBM at least do things
*/
-u64 __init fdt_translate_address(const void *blob, int node_offset)
+static u64 __init fdt_translate_address(const void *blob, int node_offset)
{
int parent, len;
const struct of_bus *bus, *pbus;
@@ -239,3 +239,12 @@ u64 __init fdt_translate_address(const void *blob, int node_offset)
bail:
return result;
}
+
+/**
+ * of_flat_dt_translate_address - translate DT addr into CPU phys addr
+ * @node: node in the flat blob
+ */
+u64 __init of_flat_dt_translate_address(unsigned long node)
+{
+ return fdt_translate_address(initial_boot_params, node);
+}
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 7ee21ae305ae..e7bfc175b8e1 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -635,6 +635,13 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np,
msi_base = be32_to_cpup(msi_map + 2);
rid_len = be32_to_cpup(msi_map + 3);
+ if (rid_base & ~map_mask) {
+ dev_err(parent_dev,
+ "Invalid msi-map translation - msi-map-mask (0x%x) ignores rid-base (0x%x)\n",
+ map_mask, rid_base);
+ return rid_out;
+ }
+
msi_controller_node = of_find_node_by_phandle(phandle);
matched = (masked_rid >= rid_base &&
@@ -654,7 +661,7 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np,
if (!matched)
return rid_out;
- rid_out = masked_rid + msi_base;
+ rid_out = masked_rid - rid_base + msi_base;
dev_dbg(dev,
"msi-map at: %s, using mask %08x, rid-base: %08x, msi-base: %08x, length: %08x, rid: %08x -> %08x\n",
dev_name(parent_dev), map_mask, rid_base, msi_base,
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 39c4be41ef83..365dc7e83ab4 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -305,6 +305,7 @@ EXPORT_SYMBOL(of_phy_find_device);
* @dev: pointer to net_device claiming the phy
* @phy_np: Pointer to device tree node for the PHY
* @hndlr: Link state callback for the network device
+ * @flags: flags to pass to the PHY
* @iface: PHY data interface type
*
* If successful, returns a pointer to the phy_device with the embedded
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index b1449f71601c..13f4fed38048 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -5,7 +5,6 @@
#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/slab.h>
-#include <asm-generic/pci-bridge.h>
static inline int __of_pci_pci_compare(struct device_node *node,
unsigned int data)
diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig
index 592de566e72f..3a102a84d637 100644
--- a/drivers/parisc/Kconfig
+++ b/drivers/parisc/Kconfig
@@ -110,8 +110,6 @@ config IOMMU_HELPER
source "drivers/pcmcia/Kconfig"
-source "drivers/pci/hotplug/Kconfig"
-
endmenu
menu "PA-RISC specific drivers"
diff --git a/drivers/parisc/eisa_enumerator.c b/drivers/parisc/eisa_enumerator.c
index a656d9e83343..21905fef2cbf 100644
--- a/drivers/parisc/eisa_enumerator.c
+++ b/drivers/parisc/eisa_enumerator.c
@@ -91,7 +91,7 @@ static int configure_memory(const unsigned char *buf,
for (i=0;i<HPEE_MEMORY_MAX_ENT;i++) {
c = get_8(buf+len);
- if (NULL != (res = kmalloc(sizeof(struct resource), GFP_KERNEL))) {
+ if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
int result;
res->name = name;
@@ -183,7 +183,7 @@ static int configure_port(const unsigned char *buf, struct resource *io_parent,
for (i=0;i<HPEE_PORT_MAX_ENT;i++) {
c = get_8(buf+len);
- if (NULL != (res = kmalloc(sizeof(struct resource), GFP_KERNEL))) {
+ if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
res->name = board;
res->start = get_16(buf+len+1);
res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 73de4efcbe6e..a1f37db745ab 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -1,6 +1,9 @@
#
# PCI configuration
#
+
+source "drivers/pci/pcie/Kconfig"
+
config PCI_BUS_ADDR_T_64BIT
def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT)
depends on PCI
@@ -118,4 +121,11 @@ config PCI_LABEL
def_bool y if (DMI || ACPI)
select NLS
+config PCI_HYPERV
+ tristate "Hyper-V PCI Frontend"
+ depends on PCI && X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64
+ help
+ The PCI device frontend driver allows the kernel to import arbitrary
+ PCI devices from a PCI backend to support PCI driver domains.
+
source "drivers/pci/host/Kconfig"
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index be3f631c3f75..2154092ddee8 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_PCI_IOV) += iov.o
# Some architectures use the generic PCI setup functions
#
obj-$(CONFIG_ALPHA) += setup-irq.o
+obj-$(CONFIG_ARC) += setup-irq.o
obj-$(CONFIG_ARM) += setup-irq.o
obj-$(CONFIG_ARM64) += setup-irq.o
obj-$(CONFIG_UNICORE32) += setup-irq.o
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 8c05b5ceeaec..01b9d0a00abc 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -174,38 +174,6 @@ struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops)
}
EXPORT_SYMBOL(pci_bus_set_ops);
-/**
- * pci_read_vpd - Read one entry from Vital Product Data
- * @dev: pci device struct
- * @pos: offset in vpd space
- * @count: number of bytes to read
- * @buf: pointer to where to store result
- *
- */
-ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
-{
- if (!dev->vpd || !dev->vpd->ops)
- return -ENODEV;
- return dev->vpd->ops->read(dev, pos, count, buf);
-}
-EXPORT_SYMBOL(pci_read_vpd);
-
-/**
- * pci_write_vpd - Write entry to Vital Product Data
- * @dev: pci device struct
- * @pos: offset in vpd space
- * @count: number of bytes to write
- * @buf: buffer containing write data
- *
- */
-ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
-{
- if (!dev->vpd || !dev->vpd->ops)
- return -ENODEV;
- return dev->vpd->ops->write(dev, pos, count, buf);
-}
-EXPORT_SYMBOL(pci_write_vpd);
-
/*
* The following routines are to prevent the user from accessing PCI config
* space when it's unsafe to do so. Some devices require this during BIST and
@@ -277,15 +245,91 @@ PCI_USER_WRITE_CONFIG(dword, u32)
/* VPD access through PCI 2.2+ VPD capability */
-#define PCI_VPD_PCI22_SIZE (PCI_VPD_ADDR_MASK + 1)
+/**
+ * pci_read_vpd - Read one entry from Vital Product Data
+ * @dev: pci device struct
+ * @pos: offset in vpd space
+ * @count: number of bytes to read
+ * @buf: pointer to where to store result
+ */
+ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
+{
+ if (!dev->vpd || !dev->vpd->ops)
+ return -ENODEV;
+ return dev->vpd->ops->read(dev, pos, count, buf);
+}
+EXPORT_SYMBOL(pci_read_vpd);
-struct pci_vpd_pci22 {
- struct pci_vpd base;
- struct mutex lock;
- u16 flag;
- bool busy;
- u8 cap;
-};
+/**
+ * pci_write_vpd - Write entry to Vital Product Data
+ * @dev: pci device struct
+ * @pos: offset in vpd space
+ * @count: number of bytes to write
+ * @buf: buffer containing write data
+ */
+ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
+{
+ if (!dev->vpd || !dev->vpd->ops)
+ return -ENODEV;
+ return dev->vpd->ops->write(dev, pos, count, buf);
+}
+EXPORT_SYMBOL(pci_write_vpd);
+
+#define PCI_VPD_MAX_SIZE (PCI_VPD_ADDR_MASK + 1)
+
+/**
+ * pci_vpd_size - determine actual size of Vital Product Data
+ * @dev: pci device struct
+ * @old_size: current assumed size, also maximum allowed size
+ */
+static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size)
+{
+ size_t off = 0;
+ unsigned char header[1+2]; /* 1 byte tag, 2 bytes length */
+
+ while (off < old_size &&
+ pci_read_vpd(dev, off, 1, header) == 1) {
+ unsigned char tag;
+
+ if (header[0] & PCI_VPD_LRDT) {
+ /* Large Resource Data Type Tag */
+ tag = pci_vpd_lrdt_tag(header);
+ /* Only read length from known tag items */
+ if ((tag == PCI_VPD_LTIN_ID_STRING) ||
+ (tag == PCI_VPD_LTIN_RO_DATA) ||
+ (tag == PCI_VPD_LTIN_RW_DATA)) {
+ if (pci_read_vpd(dev, off+1, 2,
+ &header[1]) != 2) {
+ dev_warn(&dev->dev,
+ "invalid large VPD tag %02x size at offset %zu",
+ tag, off + 1);
+ return 0;
+ }
+ off += PCI_VPD_LRDT_TAG_SIZE +
+ pci_vpd_lrdt_size(header);
+ }
+ } else {
+ /* Short Resource Data Type Tag */
+ off += PCI_VPD_SRDT_TAG_SIZE +
+ pci_vpd_srdt_size(header);
+ tag = pci_vpd_srdt_tag(header);
+ }
+
+ if (tag == PCI_VPD_STIN_END) /* End tag descriptor */
+ return off;
+
+ if ((tag != PCI_VPD_LTIN_ID_STRING) &&
+ (tag != PCI_VPD_LTIN_RO_DATA) &&
+ (tag != PCI_VPD_LTIN_RW_DATA)) {
+ dev_warn(&dev->dev,
+ "invalid %s VPD tag %02x at offset %zu",
+ (header[0] & PCI_VPD_LRDT) ? "large" : "short",
+ tag, off);
+ return 0;
+ }
+ }
+ return 0;
+}
/*
* Wait for last operation to complete.
@@ -295,55 +339,71 @@ struct pci_vpd_pci22 {
*
* Returns 0 on success, negative values indicate error.
*/
-static int pci_vpd_pci22_wait(struct pci_dev *dev)
+static int pci_vpd_wait(struct pci_dev *dev)
{
- struct pci_vpd_pci22 *vpd =
- container_of(dev->vpd, struct pci_vpd_pci22, base);
- unsigned long timeout = jiffies + HZ/20 + 2;
+ struct pci_vpd *vpd = dev->vpd;
+ unsigned long timeout = jiffies + msecs_to_jiffies(50);
+ unsigned long max_sleep = 16;
u16 status;
int ret;
if (!vpd->busy)
return 0;
- for (;;) {
+ while (time_before(jiffies, timeout)) {
ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR,
&status);
if (ret < 0)
return ret;
if ((status & PCI_VPD_ADDR_F) == vpd->flag) {
- vpd->busy = false;
+ vpd->busy = 0;
return 0;
}
- if (time_after(jiffies, timeout)) {
- dev_printk(KERN_DEBUG, &dev->dev, "vpd r/w failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n");
- return -ETIMEDOUT;
- }
if (fatal_signal_pending(current))
return -EINTR;
- if (!cond_resched())
- udelay(10);
+
+ usleep_range(10, max_sleep);
+ if (max_sleep < 1024)
+ max_sleep *= 2;
}
+
+ dev_warn(&dev->dev, "VPD access failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n");
+ return -ETIMEDOUT;
}
-static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count,
- void *arg)
+static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
+ void *arg)
{
- struct pci_vpd_pci22 *vpd =
- container_of(dev->vpd, struct pci_vpd_pci22, base);
+ struct pci_vpd *vpd = dev->vpd;
int ret;
loff_t end = pos + count;
u8 *buf = arg;
- if (pos < 0 || pos > vpd->base.len || end > vpd->base.len)
+ if (pos < 0)
return -EINVAL;
+ if (!vpd->valid) {
+ vpd->valid = 1;
+ vpd->len = pci_vpd_size(dev, vpd->len);
+ }
+
+ if (vpd->len == 0)
+ return -EIO;
+
+ if (pos > vpd->len)
+ return 0;
+
+ if (end > vpd->len) {
+ end = vpd->len;
+ count = end - pos;
+ }
+
if (mutex_lock_killable(&vpd->lock))
return -EINTR;
- ret = pci_vpd_pci22_wait(dev);
+ ret = pci_vpd_wait(dev);
if (ret < 0)
goto out;
@@ -355,9 +415,9 @@ static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count,
pos & ~3);
if (ret < 0)
break;
- vpd->busy = true;
+ vpd->busy = 1;
vpd->flag = PCI_VPD_ADDR_F;
- ret = pci_vpd_pci22_wait(dev);
+ ret = pci_vpd_wait(dev);
if (ret < 0)
break;
@@ -380,22 +440,32 @@ out:
return ret ? ret : count;
}
-static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count,
- const void *arg)
+static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
+ const void *arg)
{
- struct pci_vpd_pci22 *vpd =
- container_of(dev->vpd, struct pci_vpd_pci22, base);
+ struct pci_vpd *vpd = dev->vpd;
const u8 *buf = arg;
loff_t end = pos + count;
int ret = 0;
- if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len)
+ if (pos < 0 || (pos & 3) || (count & 3))
+ return -EINVAL;
+
+ if (!vpd->valid) {
+ vpd->valid = 1;
+ vpd->len = pci_vpd_size(dev, vpd->len);
+ }
+
+ if (vpd->len == 0)
+ return -EIO;
+
+ if (end > vpd->len)
return -EINVAL;
if (mutex_lock_killable(&vpd->lock))
return -EINTR;
- ret = pci_vpd_pci22_wait(dev);
+ ret = pci_vpd_wait(dev);
if (ret < 0)
goto out;
@@ -415,9 +485,9 @@ static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count
if (ret < 0)
break;
- vpd->busy = true;
+ vpd->busy = 1;
vpd->flag = 0;
- ret = pci_vpd_pci22_wait(dev);
+ ret = pci_vpd_wait(dev);
if (ret < 0)
break;
@@ -428,15 +498,9 @@ out:
return ret ? ret : count;
}
-static void pci_vpd_pci22_release(struct pci_dev *dev)
-{
- kfree(container_of(dev->vpd, struct pci_vpd_pci22, base));
-}
-
-static const struct pci_vpd_ops pci_vpd_pci22_ops = {
- .read = pci_vpd_pci22_read,
- .write = pci_vpd_pci22_write,
- .release = pci_vpd_pci22_release,
+static const struct pci_vpd_ops pci_vpd_ops = {
+ .read = pci_vpd_read,
+ .write = pci_vpd_write,
};
static ssize_t pci_vpd_f0_read(struct pci_dev *dev, loff_t pos, size_t count,
@@ -472,12 +536,11 @@ static ssize_t pci_vpd_f0_write(struct pci_dev *dev, loff_t pos, size_t count,
static const struct pci_vpd_ops pci_vpd_f0_ops = {
.read = pci_vpd_f0_read,
.write = pci_vpd_f0_write,
- .release = pci_vpd_pci22_release,
};
-int pci_vpd_pci22_init(struct pci_dev *dev)
+int pci_vpd_init(struct pci_dev *dev)
{
- struct pci_vpd_pci22 *vpd;
+ struct pci_vpd *vpd;
u8 cap;
cap = pci_find_capability(dev, PCI_CAP_ID_VPD);
@@ -488,18 +551,24 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
if (!vpd)
return -ENOMEM;
- vpd->base.len = PCI_VPD_PCI22_SIZE;
+ vpd->len = PCI_VPD_MAX_SIZE;
if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0)
- vpd->base.ops = &pci_vpd_f0_ops;
+ vpd->ops = &pci_vpd_f0_ops;
else
- vpd->base.ops = &pci_vpd_pci22_ops;
+ vpd->ops = &pci_vpd_ops;
mutex_init(&vpd->lock);
vpd->cap = cap;
- vpd->busy = false;
- dev->vpd = &vpd->base;
+ vpd->busy = 0;
+ vpd->valid = 0;
+ dev->vpd = vpd;
return 0;
}
+void pci_vpd_release(struct pci_dev *dev)
+{
+ kfree(dev->vpd);
+}
+
/**
* pci_cfg_access_lock - Lock PCI config reads/writes
* @dev: pci device struct
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 89b3befc7155..f2187d491475 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -291,7 +291,12 @@ void pci_bus_add_device(struct pci_dev *dev)
dev->match_driver = true;
retval = device_attach(&dev->dev);
- WARN_ON(retval < 0);
+ if (retval < 0) {
+ dev_warn(&dev->dev, "device attach failed (%d)\n", retval);
+ pci_proc_detach_device(dev);
+ pci_remove_sysfs_dev_files(dev);
+ return;
+ }
dev->is_added = 1;
}
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 75a605426538..c5014bf95a20 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -14,8 +14,31 @@ config PCI_DRA7XX
config PCI_MVEBU
bool "Marvell EBU PCIe controller"
depends on ARCH_MVEBU || ARCH_DOVE
+ depends on ARM
depends on OF
+
+config PCIE_XILINX_NWL
+ bool "NWL PCIe Core"
+ depends on ARCH_ZYNQMP
+ select PCI_MSI_IRQ_DOMAIN if PCI_MSI
+ help
+ Say 'Y' here if you want kernel support for Xilinx
+ NWL PCIe controller. The controller can act as Root Port
+ or End Point. The current option selection will only
+ support root port enabling.
+
+config PCIE_DW_PLAT
+ bool "Platform bus based DesignWare PCIe Controller"
+ select PCIE_DW
+ ---help---
+ This selects the DesignWare PCIe controller support. Select this if
+ you have a PCIe controller on Platform bus.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
config PCIE_DW
bool
@@ -41,7 +64,7 @@ config PCI_TEGRA
config PCI_RCAR_GEN2
bool "Renesas R-Car Gen2 Internal PCI controller"
depends on ARM
- depends on ARCH_SHMOBILE || COMPILE_TEST
+ depends on ARCH_RENESAS || COMPILE_TEST
help
Say Y here if you want internal PCI support on R-Car Gen2 SoC.
There are 3 internal PCI controllers available with a single
@@ -49,13 +72,17 @@ config PCI_RCAR_GEN2
config PCI_RCAR_GEN2_PCIE
bool "Renesas R-Car PCIe controller"
- depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
+ depends on ARCH_RENESAS || (ARM && COMPILE_TEST)
help
Say Y here if you want PCIe controller support on R-Car Gen2 SoCs.
+config PCI_HOST_COMMON
+ bool
+
config PCI_HOST_GENERIC
bool "Generic PCI host controller"
depends on (ARM || ARM64) && OF
+ select PCI_HOST_COMMON
help
Say Y here if you want to support a simple generic PCI host
controller, such as the one emulated by kvmtool.
@@ -81,7 +108,7 @@ config PCI_KEYSTONE
config PCIE_XILINX
bool "Xilinx AXI PCIe host bridge support"
- depends on ARCH_ZYNQ
+ depends on ARCH_ZYNQ || MICROBLAZE
help
Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
Host Bridge driver.
@@ -191,4 +218,18 @@ config PCIE_QCOM
PCIe controller uses the Designware core plus Qualcomm-specific
hardware wrappers.
+config PCI_HOST_THUNDER_PEM
+ bool "Cavium Thunder PCIe controller to off-chip devices"
+ depends on OF && ARM64
+ select PCI_HOST_COMMON
+ help
+ Say Y here if you want PCIe support for CN88XX Cavium Thunder SoCs.
+
+config PCI_HOST_THUNDER_ECAM
+ bool "Cavium Thunder ECAM controller to on-chip devices on pass-1.x silicon"
+ depends on OF && ARM64
+ select PCI_HOST_COMMON
+ help
+ Say Y here if you want ECAM support for CN88XX-Pass-1.x Cavium Thunder SoCs.
+
endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 7b2f20c6ccc6..d85b5faf9bbc 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -1,15 +1,19 @@
obj-$(CONFIG_PCIE_DW) += pcie-designware.o
+obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
+obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
+obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
+obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o
obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
@@ -22,3 +26,5 @@ obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
+obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
+obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c
index 923607bdabc5..2ca3a1f30ebf 100644
--- a/drivers/pci/host/pci-dra7xx.c
+++ b/drivers/pci/host/pci-dra7xx.c
@@ -10,7 +10,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -108,7 +107,6 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp)
{
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
u32 reg;
- unsigned int retries;
if (dw_pcie_link_up(pp)) {
dev_err(pp->dev, "link is already up\n");
@@ -119,14 +117,7 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp)
reg |= LTSSM_EN;
dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
- for (retries = 0; retries < 1000; retries++) {
- if (dw_pcie_link_up(pp))
- return 0;
- usleep_range(10, 20);
- }
-
- dev_err(pp->dev, "link is not up\n");
- return -EINVAL;
+ return dw_pcie_wait_for_link(pp);
}
static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index d997d22d4231..219976103efc 100644
--- a/drivers/pci/host/pci-exynos.c
+++ b/drivers/pci/host/pci-exynos.c
@@ -318,7 +318,6 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
{
struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
u32 val;
- unsigned int retries;
if (dw_pcie_link_up(pp)) {
dev_err(pp->dev, "Link already up\n");
@@ -357,13 +356,8 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
PCIE_APP_LTSSM_ENABLE);
/* check if the link is up or not */
- for (retries = 0; retries < 10; retries++) {
- if (dw_pcie_link_up(pp)) {
- dev_info(pp->dev, "Link up\n");
- return 0;
- }
- mdelay(100);
- }
+ if (!dw_pcie_wait_for_link(pp))
+ return 0;
while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) {
val = exynos_blk_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED);
@@ -372,8 +366,7 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
/* power off phy */
exynos_pcie_power_off_phy(pp);
- dev_err(pp->dev, "PCIe Link Fail\n");
- return -EINVAL;
+ return -ETIMEDOUT;
}
static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp)
diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
new file mode 100644
index 000000000000..e9f850f07968
--- /dev/null
+++ b/drivers/pci/host/pci-host-common.c
@@ -0,0 +1,194 @@
+/*
+ * 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
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2014 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+
+#include "pci-host-common.h"
+
+static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
+{
+ pci_free_resource_list(&pci->resources);
+}
+
+static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
+{
+ int err, res_valid = 0;
+ struct device *dev = pci->host.dev.parent;
+ struct device_node *np = dev->of_node;
+ resource_size_t iobase;
+ struct resource_entry *win;
+
+ err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
+ &iobase);
+ if (err)
+ return err;
+
+ resource_list_for_each_entry(win, &pci->resources) {
+ struct resource *parent, *res = win->res;
+
+ switch (resource_type(res)) {
+ case IORESOURCE_IO:
+ parent = &ioport_resource;
+ err = pci_remap_iospace(res, iobase);
+ if (err) {
+ dev_warn(dev, "error %d: failed to map resource %pR\n",
+ err, res);
+ continue;
+ }
+ break;
+ case IORESOURCE_MEM:
+ parent = &iomem_resource;
+ res_valid |= !(res->flags & IORESOURCE_PREFETCH);
+ break;
+ case IORESOURCE_BUS:
+ pci->cfg.bus_range = res;
+ default:
+ continue;
+ }
+
+ err = devm_request_resource(dev, parent, res);
+ if (err)
+ goto out_release_res;
+ }
+
+ if (!res_valid) {
+ dev_err(dev, "non-prefetchable memory resource required\n");
+ err = -EINVAL;
+ goto out_release_res;
+ }
+
+ return 0;
+
+out_release_res:
+ gen_pci_release_of_pci_ranges(pci);
+ return err;
+}
+
+static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
+{
+ int err;
+ u8 bus_max;
+ resource_size_t busn;
+ struct resource *bus_range;
+ struct device *dev = pci->host.dev.parent;
+ struct device_node *np = dev->of_node;
+ u32 sz = 1 << pci->cfg.ops->bus_shift;
+
+ err = of_address_to_resource(np, 0, &pci->cfg.res);
+ if (err) {
+ dev_err(dev, "missing \"reg\" property\n");
+ return err;
+ }
+
+ /* Limit the bus-range to fit within reg */
+ bus_max = pci->cfg.bus_range->start +
+ (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
+ pci->cfg.bus_range->end = min_t(resource_size_t,
+ pci->cfg.bus_range->end, bus_max);
+
+ pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
+ sizeof(*pci->cfg.win), GFP_KERNEL);
+ if (!pci->cfg.win)
+ return -ENOMEM;
+
+ /* Map our Configuration Space windows */
+ if (!devm_request_mem_region(dev, pci->cfg.res.start,
+ resource_size(&pci->cfg.res),
+ "Configuration Space"))
+ return -ENOMEM;
+
+ bus_range = pci->cfg.bus_range;
+ for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
+ u32 idx = busn - bus_range->start;
+
+ pci->cfg.win[idx] = devm_ioremap(dev,
+ pci->cfg.res.start + idx * sz,
+ sz);
+ if (!pci->cfg.win[idx])
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int pci_host_common_probe(struct platform_device *pdev,
+ struct gen_pci *pci)
+{
+ int err;
+ const char *type;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct pci_bus *bus, *child;
+
+ type = of_get_property(np, "device_type", NULL);
+ if (!type || strcmp(type, "pci")) {
+ dev_err(dev, "invalid \"device_type\" %s\n", type);
+ return -EINVAL;
+ }
+
+ of_pci_check_probe_only();
+
+ pci->host.dev.parent = dev;
+ INIT_LIST_HEAD(&pci->host.windows);
+ INIT_LIST_HEAD(&pci->resources);
+
+ /* Parse our PCI ranges and request their resources */
+ err = gen_pci_parse_request_of_pci_ranges(pci);
+ if (err)
+ return err;
+
+ /* Parse and map our Configuration Space windows */
+ err = gen_pci_parse_map_cfg_windows(pci);
+ if (err) {
+ gen_pci_release_of_pci_ranges(pci);
+ return err;
+ }
+
+ /* Do not reassign resources if probe only */
+ if (!pci_has_flag(PCI_PROBE_ONLY))
+ pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
+
+
+ bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start,
+ &pci->cfg.ops->ops, pci, &pci->resources);
+ if (!bus) {
+ dev_err(dev, "Scanning rootbus failed");
+ return -ENODEV;
+ }
+
+ pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
+
+ if (!pci_has_flag(PCI_PROBE_ONLY)) {
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
+
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
+ }
+
+ pci_bus_add_devices(bus);
+ return 0;
+}
+
+MODULE_DESCRIPTION("Generic PCI host driver common code");
+MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-host-common.h b/drivers/pci/host/pci-host-common.h
new file mode 100644
index 000000000000..09f3fa0a55d7
--- /dev/null
+++ b/drivers/pci/host/pci-host-common.h
@@ -0,0 +1,47 @@
+/*
+ * 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
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2014 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#ifndef _PCI_HOST_COMMON_H
+#define _PCI_HOST_COMMON_H
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+struct gen_pci_cfg_bus_ops {
+ u32 bus_shift;
+ struct pci_ops ops;
+};
+
+struct gen_pci_cfg_windows {
+ struct resource res;
+ struct resource *bus_range;
+ void __iomem **win;
+
+ struct gen_pci_cfg_bus_ops *ops;
+};
+
+struct gen_pci {
+ struct pci_host_bridge host;
+ struct gen_pci_cfg_windows cfg;
+ struct list_head resources;
+};
+
+int pci_host_common_probe(struct platform_device *pdev,
+ struct gen_pci *pci);
+
+#endif /* _PCI_HOST_COMMON_H */
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
index 1652bc70b145..e8aa78faa16d 100644
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -25,24 +25,7 @@
#include <linux/of_pci.h>
#include <linux/platform_device.h>
-struct gen_pci_cfg_bus_ops {
- u32 bus_shift;
- struct pci_ops ops;
-};
-
-struct gen_pci_cfg_windows {
- struct resource res;
- struct resource *bus_range;
- void __iomem **win;
-
- struct gen_pci_cfg_bus_ops *ops;
-};
-
-struct gen_pci {
- struct pci_host_bridge host;
- struct gen_pci_cfg_windows cfg;
- struct list_head resources;
-};
+#include "pci-host-common.h"
static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
unsigned int devfn,
@@ -93,175 +76,19 @@ static const struct of_device_id gen_pci_of_match[] = {
};
MODULE_DEVICE_TABLE(of, gen_pci_of_match);
-static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
-{
- pci_free_resource_list(&pci->resources);
-}
-
-static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
-{
- int err, res_valid = 0;
- struct device *dev = pci->host.dev.parent;
- struct device_node *np = dev->of_node;
- resource_size_t iobase;
- struct resource_entry *win;
-
- err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
- &iobase);
- if (err)
- return err;
-
- resource_list_for_each_entry(win, &pci->resources) {
- struct resource *parent, *res = win->res;
-
- switch (resource_type(res)) {
- case IORESOURCE_IO:
- parent = &ioport_resource;
- err = pci_remap_iospace(res, iobase);
- if (err) {
- dev_warn(dev, "error %d: failed to map resource %pR\n",
- err, res);
- continue;
- }
- break;
- case IORESOURCE_MEM:
- parent = &iomem_resource;
- res_valid |= !(res->flags & IORESOURCE_PREFETCH);
- break;
- case IORESOURCE_BUS:
- pci->cfg.bus_range = res;
- default:
- continue;
- }
-
- err = devm_request_resource(dev, parent, res);
- if (err)
- goto out_release_res;
- }
-
- if (!res_valid) {
- dev_err(dev, "non-prefetchable memory resource required\n");
- err = -EINVAL;
- goto out_release_res;
- }
-
- return 0;
-
-out_release_res:
- gen_pci_release_of_pci_ranges(pci);
- return err;
-}
-
-static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
-{
- int err;
- u8 bus_max;
- resource_size_t busn;
- struct resource *bus_range;
- struct device *dev = pci->host.dev.parent;
- struct device_node *np = dev->of_node;
- u32 sz = 1 << pci->cfg.ops->bus_shift;
-
- err = of_address_to_resource(np, 0, &pci->cfg.res);
- if (err) {
- dev_err(dev, "missing \"reg\" property\n");
- return err;
- }
-
- /* Limit the bus-range to fit within reg */
- bus_max = pci->cfg.bus_range->start +
- (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
- pci->cfg.bus_range->end = min_t(resource_size_t,
- pci->cfg.bus_range->end, bus_max);
-
- pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
- sizeof(*pci->cfg.win), GFP_KERNEL);
- if (!pci->cfg.win)
- return -ENOMEM;
-
- /* Map our Configuration Space windows */
- if (!devm_request_mem_region(dev, pci->cfg.res.start,
- resource_size(&pci->cfg.res),
- "Configuration Space"))
- return -ENOMEM;
-
- bus_range = pci->cfg.bus_range;
- for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
- u32 idx = busn - bus_range->start;
-
- pci->cfg.win[idx] = devm_ioremap(dev,
- pci->cfg.res.start + idx * sz,
- sz);
- if (!pci->cfg.win[idx])
- return -ENOMEM;
- }
-
- return 0;
-}
-
static int gen_pci_probe(struct platform_device *pdev)
{
- int err;
- const char *type;
- const struct of_device_id *of_id;
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
+ const struct of_device_id *of_id;
struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
- struct pci_bus *bus, *child;
if (!pci)
return -ENOMEM;
- type = of_get_property(np, "device_type", NULL);
- if (!type || strcmp(type, "pci")) {
- dev_err(dev, "invalid \"device_type\" %s\n", type);
- return -EINVAL;
- }
-
- of_pci_check_probe_only();
-
- of_id = of_match_node(gen_pci_of_match, np);
+ of_id = of_match_node(gen_pci_of_match, dev->of_node);
pci->cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data;
- pci->host.dev.parent = dev;
- INIT_LIST_HEAD(&pci->host.windows);
- INIT_LIST_HEAD(&pci->resources);
-
- /* Parse our PCI ranges and request their resources */
- err = gen_pci_parse_request_of_pci_ranges(pci);
- if (err)
- return err;
-
- /* Parse and map our Configuration Space windows */
- err = gen_pci_parse_map_cfg_windows(pci);
- if (err) {
- gen_pci_release_of_pci_ranges(pci);
- return err;
- }
-
- /* Do not reassign resources if probe only */
- if (!pci_has_flag(PCI_PROBE_ONLY))
- pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
-
-
- bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start,
- &pci->cfg.ops->ops, pci, &pci->resources);
- if (!bus) {
- dev_err(dev, "Scanning rootbus failed");
- return -ENODEV;
- }
-
- pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
-
- if (!pci_has_flag(PCI_PROBE_ONLY)) {
- pci_bus_size_bridges(bus);
- pci_bus_assign_resources(bus);
-
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child);
- }
- pci_bus_add_devices(bus);
- return 0;
+ return pci_host_common_probe(pdev, pci);
}
static struct platform_driver gen_pci_driver = {
diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c
new file mode 100644
index 000000000000..ed651baa7c50
--- /dev/null
+++ b/drivers/pci/host/pci-hyperv.c
@@ -0,0 +1,2346 @@
+/*
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Author:
+ * Jake Oshins <jakeo@microsoft.com>
+ *
+ * This driver acts as a paravirtual front-end for PCI Express root buses.
+ * When a PCI Express function (either an entire device or an SR-IOV
+ * Virtual Function) is being passed through to the VM, this driver exposes
+ * a new bus to the guest VM. This is modeled as a root PCI bus because
+ * no bridges are being exposed to the VM. In fact, with a "Generation 2"
+ * VM within Hyper-V, there may seem to be no PCI bus at all in the VM
+ * until a device as been exposed using this driver.
+ *
+ * Each root PCI bus has its own PCI domain, which is called "Segment" in
+ * the PCI Firmware Specifications. Thus while each device passed through
+ * to the VM using this front-end will appear at "device 0", the domain will
+ * be unique. Typically, each bus will have one PCI function on it, though
+ * this driver does support more than one.
+ *
+ * In order to map the interrupts from the device through to the guest VM,
+ * this driver also implements an IRQ Domain, which handles interrupts (either
+ * MSI or MSI-X) associated with the functions on the bus. As interrupts are
+ * set up, torn down, or reaffined, this driver communicates with the
+ * underlying hypervisor to adjust the mappings in the I/O MMU so that each
+ * interrupt will be delivered to the correct virtual processor at the right
+ * vector. This driver does not support level-triggered (line-based)
+ * interrupts, and will report that the Interrupt Line register in the
+ * function's configuration space is zero.
+ *
+ * The rest of this driver mostly maps PCI concepts onto underlying Hyper-V
+ * facilities. For instance, the configuration space of a function exposed
+ * by Hyper-V is mapped into a single page of memory space, and the
+ * read and write handlers for config space must be aware of this mechanism.
+ * Similarly, device setup and teardown involves messages sent to and from
+ * the PCI back-end driver in Hyper-V.
+ *
+ * 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 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/semaphore.h>
+#include <linux/irqdomain.h>
+#include <asm/irqdomain.h>
+#include <asm/apic.h>
+#include <linux/msi.h>
+#include <linux/hyperv.h>
+#include <asm/mshyperv.h>
+
+/*
+ * Protocol versions. The low word is the minor version, the high word the
+ * major version.
+ */
+
+#define PCI_MAKE_VERSION(major, minor) ((u32)(((major) << 16) | (major)))
+#define PCI_MAJOR_VERSION(version) ((u32)(version) >> 16)
+#define PCI_MINOR_VERSION(version) ((u32)(version) & 0xff)
+
+enum {
+ PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1),
+ PCI_PROTOCOL_VERSION_CURRENT = PCI_PROTOCOL_VERSION_1_1
+};
+
+#define PCI_CONFIG_MMIO_LENGTH 0x2000
+#define CFG_PAGE_OFFSET 0x1000
+#define CFG_PAGE_SIZE (PCI_CONFIG_MMIO_LENGTH - CFG_PAGE_OFFSET)
+
+#define MAX_SUPPORTED_MSI_MESSAGES 0x400
+
+/*
+ * Message Types
+ */
+
+enum pci_message_type {
+ /*
+ * Version 1.1
+ */
+ PCI_MESSAGE_BASE = 0x42490000,
+ PCI_BUS_RELATIONS = PCI_MESSAGE_BASE + 0,
+ PCI_QUERY_BUS_RELATIONS = PCI_MESSAGE_BASE + 1,
+ PCI_POWER_STATE_CHANGE = PCI_MESSAGE_BASE + 4,
+ PCI_QUERY_RESOURCE_REQUIREMENTS = PCI_MESSAGE_BASE + 5,
+ PCI_QUERY_RESOURCE_RESOURCES = PCI_MESSAGE_BASE + 6,
+ PCI_BUS_D0ENTRY = PCI_MESSAGE_BASE + 7,
+ PCI_BUS_D0EXIT = PCI_MESSAGE_BASE + 8,
+ PCI_READ_BLOCK = PCI_MESSAGE_BASE + 9,
+ PCI_WRITE_BLOCK = PCI_MESSAGE_BASE + 0xA,
+ PCI_EJECT = PCI_MESSAGE_BASE + 0xB,
+ PCI_QUERY_STOP = PCI_MESSAGE_BASE + 0xC,
+ PCI_REENABLE = PCI_MESSAGE_BASE + 0xD,
+ PCI_QUERY_STOP_FAILED = PCI_MESSAGE_BASE + 0xE,
+ PCI_EJECTION_COMPLETE = PCI_MESSAGE_BASE + 0xF,
+ PCI_RESOURCES_ASSIGNED = PCI_MESSAGE_BASE + 0x10,
+ PCI_RESOURCES_RELEASED = PCI_MESSAGE_BASE + 0x11,
+ PCI_INVALIDATE_BLOCK = PCI_MESSAGE_BASE + 0x12,
+ PCI_QUERY_PROTOCOL_VERSION = PCI_MESSAGE_BASE + 0x13,
+ PCI_CREATE_INTERRUPT_MESSAGE = PCI_MESSAGE_BASE + 0x14,
+ PCI_DELETE_INTERRUPT_MESSAGE = PCI_MESSAGE_BASE + 0x15,
+ PCI_MESSAGE_MAXIMUM
+};
+
+/*
+ * Structures defining the virtual PCI Express protocol.
+ */
+
+union pci_version {
+ struct {
+ u16 minor_version;
+ u16 major_version;
+ } parts;
+ u32 version;
+} __packed;
+
+/*
+ * Function numbers are 8-bits wide on Express, as interpreted through ARI,
+ * which is all this driver does. This representation is the one used in
+ * Windows, which is what is expected when sending this back and forth with
+ * the Hyper-V parent partition.
+ */
+union win_slot_encoding {
+ struct {
+ u32 func:8;
+ u32 reserved:24;
+ } bits;
+ u32 slot;
+} __packed;
+
+/*
+ * Pretty much as defined in the PCI Specifications.
+ */
+struct pci_function_description {
+ u16 v_id; /* vendor ID */
+ u16 d_id; /* device ID */
+ u8 rev;
+ u8 prog_intf;
+ u8 subclass;
+ u8 base_class;
+ u32 subsystem_id;
+ union win_slot_encoding win_slot;
+ u32 ser; /* serial number */
+} __packed;
+
+/**
+ * struct hv_msi_desc
+ * @vector: IDT entry
+ * @delivery_mode: As defined in Intel's Programmer's
+ * Reference Manual, Volume 3, Chapter 8.
+ * @vector_count: Number of contiguous entries in the
+ * Interrupt Descriptor Table that are
+ * occupied by this Message-Signaled
+ * Interrupt. For "MSI", as first defined
+ * in PCI 2.2, this can be between 1 and
+ * 32. For "MSI-X," as first defined in PCI
+ * 3.0, this must be 1, as each MSI-X table
+ * entry would have its own descriptor.
+ * @reserved: Empty space
+ * @cpu_mask: All the target virtual processors.
+ */
+struct hv_msi_desc {
+ u8 vector;
+ u8 delivery_mode;
+ u16 vector_count;
+ u32 reserved;
+ u64 cpu_mask;
+} __packed;
+
+/**
+ * struct tran_int_desc
+ * @reserved: unused, padding
+ * @vector_count: same as in hv_msi_desc
+ * @data: This is the "data payload" value that is
+ * written by the device when it generates
+ * a message-signaled interrupt, either MSI
+ * or MSI-X.
+ * @address: This is the address to which the data
+ * payload is written on interrupt
+ * generation.
+ */
+struct tran_int_desc {
+ u16 reserved;
+ u16 vector_count;
+ u32 data;
+ u64 address;
+} __packed;
+
+/*
+ * A generic message format for virtual PCI.
+ * Specific message formats are defined later in the file.
+ */
+
+struct pci_message {
+ u32 message_type;
+} __packed;
+
+struct pci_child_message {
+ u32 message_type;
+ union win_slot_encoding wslot;
+} __packed;
+
+struct pci_incoming_message {
+ struct vmpacket_descriptor hdr;
+ struct pci_message message_type;
+} __packed;
+
+struct pci_response {
+ struct vmpacket_descriptor hdr;
+ s32 status; /* negative values are failures */
+} __packed;
+
+struct pci_packet {
+ void (*completion_func)(void *context, struct pci_response *resp,
+ int resp_packet_size);
+ void *compl_ctxt;
+ struct pci_message message;
+};
+
+/*
+ * Specific message types supporting the PCI protocol.
+ */
+
+/*
+ * Version negotiation message. Sent from the guest to the host.
+ * The guest is free to try different versions until the host
+ * accepts the version.
+ *
+ * pci_version: The protocol version requested.
+ * is_last_attempt: If TRUE, this is the last version guest will request.
+ * reservedz: Reserved field, set to zero.
+ */
+
+struct pci_version_request {
+ struct pci_message message_type;
+ enum pci_message_type protocol_version;
+} __packed;
+
+/*
+ * Bus D0 Entry. This is sent from the guest to the host when the virtual
+ * bus (PCI Express port) is ready for action.
+ */
+
+struct pci_bus_d0_entry {
+ struct pci_message message_type;
+ u32 reserved;
+ u64 mmio_base;
+} __packed;
+
+struct pci_bus_relations {
+ struct pci_incoming_message incoming;
+ u32 device_count;
+ struct pci_function_description func[1];
+} __packed;
+
+struct pci_q_res_req_response {
+ struct vmpacket_descriptor hdr;
+ s32 status; /* negative values are failures */
+ u32 probed_bar[6];
+} __packed;
+
+struct pci_set_power {
+ struct pci_message message_type;
+ union win_slot_encoding wslot;
+ u32 power_state; /* In Windows terms */
+ u32 reserved;
+} __packed;
+
+struct pci_set_power_response {
+ struct vmpacket_descriptor hdr;
+ s32 status; /* negative values are failures */
+ union win_slot_encoding wslot;
+ u32 resultant_state; /* In Windows terms */
+ u32 reserved;
+} __packed;
+
+struct pci_resources_assigned {
+ struct pci_message message_type;
+ union win_slot_encoding wslot;
+ u8 memory_range[0x14][6]; /* not used here */
+ u32 msi_descriptors;
+ u32 reserved[4];
+} __packed;
+
+struct pci_create_interrupt {
+ struct pci_message message_type;
+ union win_slot_encoding wslot;
+ struct hv_msi_desc int_desc;
+} __packed;
+
+struct pci_create_int_response {
+ struct pci_response response;
+ u32 reserved;
+ struct tran_int_desc int_desc;
+} __packed;
+
+struct pci_delete_interrupt {
+ struct pci_message message_type;
+ union win_slot_encoding wslot;
+ struct tran_int_desc int_desc;
+} __packed;
+
+struct pci_dev_incoming {
+ struct pci_incoming_message incoming;
+ union win_slot_encoding wslot;
+} __packed;
+
+struct pci_eject_response {
+ u32 message_type;
+ union win_slot_encoding wslot;
+ u32 status;
+} __packed;
+
+static int pci_ring_size = (4 * PAGE_SIZE);
+
+/*
+ * Definitions or interrupt steering hypercall.
+ */
+#define HV_PARTITION_ID_SELF ((u64)-1)
+#define HVCALL_RETARGET_INTERRUPT 0x7e
+
+struct retarget_msi_interrupt {
+ u64 partition_id; /* use "self" */
+ u64 device_id;
+ u32 source; /* 1 for MSI(-X) */
+ u32 reserved1;
+ u32 address;
+ u32 data;
+ u64 reserved2;
+ u32 vector;
+ u32 flags;
+ u64 vp_mask;
+} __packed;
+
+/*
+ * Driver specific state.
+ */
+
+enum hv_pcibus_state {
+ hv_pcibus_init = 0,
+ hv_pcibus_probed,
+ hv_pcibus_installed,
+ hv_pcibus_maximum
+};
+
+struct hv_pcibus_device {
+ struct pci_sysdata sysdata;
+ enum hv_pcibus_state state;
+ atomic_t remove_lock;
+ struct hv_device *hdev;
+ resource_size_t low_mmio_space;
+ resource_size_t high_mmio_space;
+ struct resource *mem_config;
+ struct resource *low_mmio_res;
+ struct resource *high_mmio_res;
+ struct completion *survey_event;
+ struct completion remove_event;
+ struct pci_bus *pci_bus;
+ spinlock_t config_lock; /* Avoid two threads writing index page */
+ spinlock_t device_list_lock; /* Protect lists below */
+ void __iomem *cfg_addr;
+
+ struct semaphore enum_sem;
+ struct list_head resources_for_children;
+
+ struct list_head children;
+ struct list_head dr_list;
+ struct work_struct wrk;
+
+ struct msi_domain_info msi_info;
+ struct msi_controller msi_chip;
+ struct irq_domain *irq_domain;
+};
+
+/*
+ * Tracks "Device Relations" messages from the host, which must be both
+ * processed in order and deferred so that they don't run in the context
+ * of the incoming packet callback.
+ */
+struct hv_dr_work {
+ struct work_struct wrk;
+ struct hv_pcibus_device *bus;
+};
+
+struct hv_dr_state {
+ struct list_head list_entry;
+ u32 device_count;
+ struct pci_function_description func[1];
+};
+
+enum hv_pcichild_state {
+ hv_pcichild_init = 0,
+ hv_pcichild_requirements,
+ hv_pcichild_resourced,
+ hv_pcichild_ejecting,
+ hv_pcichild_maximum
+};
+
+enum hv_pcidev_ref_reason {
+ hv_pcidev_ref_invalid = 0,
+ hv_pcidev_ref_initial,
+ hv_pcidev_ref_by_slot,
+ hv_pcidev_ref_packet,
+ hv_pcidev_ref_pnp,
+ hv_pcidev_ref_childlist,
+ hv_pcidev_irqdata,
+ hv_pcidev_ref_max
+};
+
+struct hv_pci_dev {
+ /* List protected by pci_rescan_remove_lock */
+ struct list_head list_entry;
+ atomic_t refs;
+ enum hv_pcichild_state state;
+ struct pci_function_description desc;
+ bool reported_missing;
+ struct hv_pcibus_device *hbus;
+ struct work_struct wrk;
+
+ /*
+ * What would be observed if one wrote 0xFFFFFFFF to a BAR and then
+ * read it back, for each of the BAR offsets within config space.
+ */
+ u32 probed_bar[6];
+};
+
+struct hv_pci_compl {
+ struct completion host_event;
+ s32 completion_status;
+};
+
+/**
+ * hv_pci_generic_compl() - Invoked for a completion packet
+ * @context: Set up by the sender of the packet.
+ * @resp: The response packet
+ * @resp_packet_size: Size in bytes of the packet
+ *
+ * This function is used to trigger an event and report status
+ * for any message for which the completion packet contains a
+ * status and nothing else.
+ */
+static
+void
+hv_pci_generic_compl(void *context, struct pci_response *resp,
+ int resp_packet_size)
+{
+ struct hv_pci_compl *comp_pkt = context;
+
+ if (resp_packet_size >= offsetofend(struct pci_response, status))
+ comp_pkt->completion_status = resp->status;
+ complete(&comp_pkt->host_event);
+}
+
+static struct hv_pci_dev *get_pcichild_wslot(struct hv_pcibus_device *hbus,
+ u32 wslot);
+static void get_pcichild(struct hv_pci_dev *hv_pcidev,
+ enum hv_pcidev_ref_reason reason);
+static void put_pcichild(struct hv_pci_dev *hv_pcidev,
+ enum hv_pcidev_ref_reason reason);
+
+static void get_hvpcibus(struct hv_pcibus_device *hv_pcibus);
+static void put_hvpcibus(struct hv_pcibus_device *hv_pcibus);
+
+/**
+ * devfn_to_wslot() - Convert from Linux PCI slot to Windows
+ * @devfn: The Linux representation of PCI slot
+ *
+ * Windows uses a slightly different representation of PCI slot.
+ *
+ * Return: The Windows representation
+ */
+static u32 devfn_to_wslot(int devfn)
+{
+ union win_slot_encoding wslot;
+
+ wslot.slot = 0;
+ wslot.bits.func = PCI_SLOT(devfn) | (PCI_FUNC(devfn) << 5);
+
+ return wslot.slot;
+}
+
+/**
+ * wslot_to_devfn() - Convert from Windows PCI slot to Linux
+ * @wslot: The Windows representation of PCI slot
+ *
+ * Windows uses a slightly different representation of PCI slot.
+ *
+ * Return: The Linux representation
+ */
+static int wslot_to_devfn(u32 wslot)
+{
+ union win_slot_encoding slot_no;
+
+ slot_no.slot = wslot;
+ return PCI_DEVFN(0, slot_no.bits.func);
+}
+
+/*
+ * PCI Configuration Space for these root PCI buses is implemented as a pair
+ * of pages in memory-mapped I/O space. Writing to the first page chooses
+ * the PCI function being written or read. Once the first page has been
+ * written to, the following page maps in the entire configuration space of
+ * the function.
+ */
+
+/**
+ * _hv_pcifront_read_config() - Internal PCI config read
+ * @hpdev: The PCI driver's representation of the device
+ * @where: Offset within config space
+ * @size: Size of the transfer
+ * @val: Pointer to the buffer receiving the data
+ */
+static void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where,
+ int size, u32 *val)
+{
+ unsigned long flags;
+ void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where;
+
+ /*
+ * If the attempt is to read the IDs or the ROM BAR, simulate that.
+ */
+ if (where + size <= PCI_COMMAND) {
+ memcpy(val, ((u8 *)&hpdev->desc.v_id) + where, size);
+ } else if (where >= PCI_CLASS_REVISION && where + size <=
+ PCI_CACHE_LINE_SIZE) {
+ memcpy(val, ((u8 *)&hpdev->desc.rev) + where -
+ PCI_CLASS_REVISION, size);
+ } else if (where >= PCI_SUBSYSTEM_VENDOR_ID && where + size <=
+ PCI_ROM_ADDRESS) {
+ memcpy(val, (u8 *)&hpdev->desc.subsystem_id + where -
+ PCI_SUBSYSTEM_VENDOR_ID, size);
+ } else if (where >= PCI_ROM_ADDRESS && where + size <=
+ PCI_CAPABILITY_LIST) {
+ /* ROM BARs are unimplemented */
+ *val = 0;
+ } else if (where >= PCI_INTERRUPT_LINE && where + size <=
+ PCI_INTERRUPT_PIN) {
+ /*
+ * Interrupt Line and Interrupt PIN are hard-wired to zero
+ * because this front-end only supports message-signaled
+ * interrupts.
+ */
+ *val = 0;
+ } else if (where + size <= CFG_PAGE_SIZE) {
+ spin_lock_irqsave(&hpdev->hbus->config_lock, flags);
+ /* Choose the function to be read. (See comment above) */
+ writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr);
+ /* Read from that function's config space. */
+ switch (size) {
+ case 1:
+ *val = readb(addr);
+ break;
+ case 2:
+ *val = readw(addr);
+ break;
+ default:
+ *val = readl(addr);
+ break;
+ }
+ spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags);
+ } else {
+ dev_err(&hpdev->hbus->hdev->device,
+ "Attempt to read beyond a function's config space.\n");
+ }
+}
+
+/**
+ * _hv_pcifront_write_config() - Internal PCI config write
+ * @hpdev: The PCI driver's representation of the device
+ * @where: Offset within config space
+ * @size: Size of the transfer
+ * @val: The data being transferred
+ */
+static void _hv_pcifront_write_config(struct hv_pci_dev *hpdev, int where,
+ int size, u32 val)
+{
+ unsigned long flags;
+ void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where;
+
+ if (where >= PCI_SUBSYSTEM_VENDOR_ID &&
+ where + size <= PCI_CAPABILITY_LIST) {
+ /* SSIDs and ROM BARs are read-only */
+ } else if (where >= PCI_COMMAND && where + size <= CFG_PAGE_SIZE) {
+ spin_lock_irqsave(&hpdev->hbus->config_lock, flags);
+ /* Choose the function to be written. (See comment above) */
+ writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr);
+ /* Write to that function's config space. */
+ switch (size) {
+ case 1:
+ writeb(val, addr);
+ break;
+ case 2:
+ writew(val, addr);
+ break;
+ default:
+ writel(val, addr);
+ break;
+ }
+ spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags);
+ } else {
+ dev_err(&hpdev->hbus->hdev->device,
+ "Attempt to write beyond a function's config space.\n");
+ }
+}
+
+/**
+ * hv_pcifront_read_config() - Read configuration space
+ * @bus: PCI Bus structure
+ * @devfn: Device/function
+ * @where: Offset from base
+ * @size: Byte/word/dword
+ * @val: Value to be read
+ *
+ * Return: PCIBIOS_SUCCESSFUL on success
+ * PCIBIOS_DEVICE_NOT_FOUND on failure
+ */
+static int hv_pcifront_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ struct hv_pcibus_device *hbus =
+ container_of(bus->sysdata, struct hv_pcibus_device, sysdata);
+ struct hv_pci_dev *hpdev;
+
+ hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(devfn));
+ if (!hpdev)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ _hv_pcifront_read_config(hpdev, where, size, val);
+
+ put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/**
+ * hv_pcifront_write_config() - Write configuration space
+ * @bus: PCI Bus structure
+ * @devfn: Device/function
+ * @where: Offset from base
+ * @size: Byte/word/dword
+ * @val: Value to be written to device
+ *
+ * Return: PCIBIOS_SUCCESSFUL on success
+ * PCIBIOS_DEVICE_NOT_FOUND on failure
+ */
+static int hv_pcifront_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct hv_pcibus_device *hbus =
+ container_of(bus->sysdata, struct hv_pcibus_device, sysdata);
+ struct hv_pci_dev *hpdev;
+
+ hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(devfn));
+ if (!hpdev)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ _hv_pcifront_write_config(hpdev, where, size, val);
+
+ put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/* PCIe operations */
+static struct pci_ops hv_pcifront_ops = {
+ .read = hv_pcifront_read_config,
+ .write = hv_pcifront_write_config,
+};
+
+/* Interrupt management hooks */
+static void hv_int_desc_free(struct hv_pci_dev *hpdev,
+ struct tran_int_desc *int_desc)
+{
+ struct pci_delete_interrupt *int_pkt;
+ struct {
+ struct pci_packet pkt;
+ u8 buffer[sizeof(struct pci_delete_interrupt) -
+ sizeof(struct pci_message)];
+ } ctxt;
+
+ memset(&ctxt, 0, sizeof(ctxt));
+ int_pkt = (struct pci_delete_interrupt *)&ctxt.pkt.message;
+ int_pkt->message_type.message_type =
+ PCI_DELETE_INTERRUPT_MESSAGE;
+ int_pkt->wslot.slot = hpdev->desc.win_slot.slot;
+ int_pkt->int_desc = *int_desc;
+ vmbus_sendpacket(hpdev->hbus->hdev->channel, int_pkt, sizeof(*int_pkt),
+ (unsigned long)&ctxt.pkt, VM_PKT_DATA_INBAND, 0);
+ kfree(int_desc);
+}
+
+/**
+ * hv_msi_free() - Free the MSI.
+ * @domain: The interrupt domain pointer
+ * @info: Extra MSI-related context
+ * @irq: Identifies the IRQ.
+ *
+ * The Hyper-V parent partition and hypervisor are tracking the
+ * messages that are in use, keeping the interrupt redirection
+ * table up to date. This callback sends a message that frees
+ * the IRT entry and related tracking nonsense.
+ */
+static void hv_msi_free(struct irq_domain *domain, struct msi_domain_info *info,
+ unsigned int irq)
+{
+ struct hv_pcibus_device *hbus;
+ struct hv_pci_dev *hpdev;
+ struct pci_dev *pdev;
+ struct tran_int_desc *int_desc;
+ struct irq_data *irq_data = irq_domain_get_irq_data(domain, irq);
+ struct msi_desc *msi = irq_data_get_msi_desc(irq_data);
+
+ pdev = msi_desc_to_pci_dev(msi);
+ hbus = info->data;
+ hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
+ if (!hpdev)
+ return;
+
+ int_desc = irq_data_get_irq_chip_data(irq_data);
+ if (int_desc) {
+ irq_data->chip_data = NULL;
+ hv_int_desc_free(hpdev, int_desc);
+ }
+
+ put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+}
+
+static int hv_set_affinity(struct irq_data *data, const struct cpumask *dest,
+ bool force)
+{
+ struct irq_data *parent = data->parent_data;
+
+ return parent->chip->irq_set_affinity(parent, dest, force);
+}
+
+void hv_irq_mask(struct irq_data *data)
+{
+ pci_msi_mask_irq(data);
+}
+
+/**
+ * hv_irq_unmask() - "Unmask" the IRQ by setting its current
+ * affinity.
+ * @data: Describes the IRQ
+ *
+ * Build new a destination for the MSI and make a hypercall to
+ * update the Interrupt Redirection Table. "Device Logical ID"
+ * is built out of this PCI bus's instance GUID and the function
+ * number of the device.
+ */
+void hv_irq_unmask(struct irq_data *data)
+{
+ struct msi_desc *msi_desc = irq_data_get_msi_desc(data);
+ struct irq_cfg *cfg = irqd_cfg(data);
+ struct retarget_msi_interrupt params;
+ struct hv_pcibus_device *hbus;
+ struct cpumask *dest;
+ struct pci_bus *pbus;
+ struct pci_dev *pdev;
+ int cpu;
+
+ dest = irq_data_get_affinity_mask(data);
+ pdev = msi_desc_to_pci_dev(msi_desc);
+ pbus = pdev->bus;
+ hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
+
+ memset(&params, 0, sizeof(params));
+ params.partition_id = HV_PARTITION_ID_SELF;
+ params.source = 1; /* MSI(-X) */
+ params.address = msi_desc->msg.address_lo;
+ params.data = msi_desc->msg.data;
+ params.device_id = (hbus->hdev->dev_instance.b[5] << 24) |
+ (hbus->hdev->dev_instance.b[4] << 16) |
+ (hbus->hdev->dev_instance.b[7] << 8) |
+ (hbus->hdev->dev_instance.b[6] & 0xf8) |
+ PCI_FUNC(pdev->devfn);
+ params.vector = cfg->vector;
+
+ for_each_cpu_and(cpu, dest, cpu_online_mask)
+ params.vp_mask |= (1ULL << vmbus_cpu_number_to_vp_number(cpu));
+
+ hv_do_hypercall(HVCALL_RETARGET_INTERRUPT, &params, NULL);
+
+ pci_msi_unmask_irq(data);
+}
+
+struct compose_comp_ctxt {
+ struct hv_pci_compl comp_pkt;
+ struct tran_int_desc int_desc;
+};
+
+static void hv_pci_compose_compl(void *context, struct pci_response *resp,
+ int resp_packet_size)
+{
+ struct compose_comp_ctxt *comp_pkt = context;
+ struct pci_create_int_response *int_resp =
+ (struct pci_create_int_response *)resp;
+
+ comp_pkt->comp_pkt.completion_status = resp->status;
+ comp_pkt->int_desc = int_resp->int_desc;
+ complete(&comp_pkt->comp_pkt.host_event);
+}
+
+/**
+ * hv_compose_msi_msg() - Supplies a valid MSI address/data
+ * @data: Everything about this MSI
+ * @msg: Buffer that is filled in by this function
+ *
+ * This function unpacks the IRQ looking for target CPU set, IDT
+ * vector and mode and sends a message to the parent partition
+ * asking for a mapping for that tuple in this partition. The
+ * response supplies a data value and address to which that data
+ * should be written to trigger that interrupt.
+ */
+static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ struct irq_cfg *cfg = irqd_cfg(data);
+ struct hv_pcibus_device *hbus;
+ struct hv_pci_dev *hpdev;
+ struct pci_bus *pbus;
+ struct pci_dev *pdev;
+ struct pci_create_interrupt *int_pkt;
+ struct compose_comp_ctxt comp;
+ struct tran_int_desc *int_desc;
+ struct cpumask *affinity;
+ struct {
+ struct pci_packet pkt;
+ u8 buffer[sizeof(struct pci_create_interrupt) -
+ sizeof(struct pci_message)];
+ } ctxt;
+ int cpu;
+ int ret;
+
+ pdev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data));
+ pbus = pdev->bus;
+ hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
+ hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
+ if (!hpdev)
+ goto return_null_message;
+
+ /* Free any previous message that might have already been composed. */
+ if (data->chip_data) {
+ int_desc = data->chip_data;
+ data->chip_data = NULL;
+ hv_int_desc_free(hpdev, int_desc);
+ }
+
+ int_desc = kzalloc(sizeof(*int_desc), GFP_KERNEL);
+ if (!int_desc)
+ goto drop_reference;
+
+ memset(&ctxt, 0, sizeof(ctxt));
+ init_completion(&comp.comp_pkt.host_event);
+ ctxt.pkt.completion_func = hv_pci_compose_compl;
+ ctxt.pkt.compl_ctxt = &comp;
+ int_pkt = (struct pci_create_interrupt *)&ctxt.pkt.message;
+ int_pkt->message_type.message_type = PCI_CREATE_INTERRUPT_MESSAGE;
+ int_pkt->wslot.slot = hpdev->desc.win_slot.slot;
+ int_pkt->int_desc.vector = cfg->vector;
+ int_pkt->int_desc.vector_count = 1;
+ int_pkt->int_desc.delivery_mode =
+ (apic->irq_delivery_mode == dest_LowestPrio) ? 1 : 0;
+
+ /*
+ * This bit doesn't have to work on machines with more than 64
+ * processors because Hyper-V only supports 64 in a guest.
+ */
+ affinity = irq_data_get_affinity_mask(data);
+ for_each_cpu_and(cpu, affinity, cpu_online_mask) {
+ int_pkt->int_desc.cpu_mask |=
+ (1ULL << vmbus_cpu_number_to_vp_number(cpu));
+ }
+
+ ret = vmbus_sendpacket(hpdev->hbus->hdev->channel, int_pkt,
+ sizeof(*int_pkt), (unsigned long)&ctxt.pkt,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (!ret)
+ wait_for_completion(&comp.comp_pkt.host_event);
+
+ if (comp.comp_pkt.completion_status < 0) {
+ dev_err(&hbus->hdev->device,
+ "Request for interrupt failed: 0x%x",
+ comp.comp_pkt.completion_status);
+ goto free_int_desc;
+ }
+
+ /*
+ * Record the assignment so that this can be unwound later. Using
+ * irq_set_chip_data() here would be appropriate, but the lock it takes
+ * is already held.
+ */
+ *int_desc = comp.int_desc;
+ data->chip_data = int_desc;
+
+ /* Pass up the result. */
+ msg->address_hi = comp.int_desc.address >> 32;
+ msg->address_lo = comp.int_desc.address & 0xffffffff;
+ msg->data = comp.int_desc.data;
+
+ put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+ return;
+
+free_int_desc:
+ kfree(int_desc);
+drop_reference:
+ put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+return_null_message:
+ msg->address_hi = 0;
+ msg->address_lo = 0;
+ msg->data = 0;
+}
+
+/* HW Interrupt Chip Descriptor */
+static struct irq_chip hv_msi_irq_chip = {
+ .name = "Hyper-V PCIe MSI",
+ .irq_compose_msi_msg = hv_compose_msi_msg,
+ .irq_set_affinity = hv_set_affinity,
+ .irq_ack = irq_chip_ack_parent,
+ .irq_mask = hv_irq_mask,
+ .irq_unmask = hv_irq_unmask,
+};
+
+static irq_hw_number_t hv_msi_domain_ops_get_hwirq(struct msi_domain_info *info,
+ msi_alloc_info_t *arg)
+{
+ return arg->msi_hwirq;
+}
+
+static struct msi_domain_ops hv_msi_ops = {
+ .get_hwirq = hv_msi_domain_ops_get_hwirq,
+ .msi_prepare = pci_msi_prepare,
+ .set_desc = pci_msi_set_desc,
+ .msi_free = hv_msi_free,
+};
+
+/**
+ * hv_pcie_init_irq_domain() - Initialize IRQ domain
+ * @hbus: The root PCI bus
+ *
+ * This function creates an IRQ domain which will be used for
+ * interrupts from devices that have been passed through. These
+ * devices only support MSI and MSI-X, not line-based interrupts
+ * or simulations of line-based interrupts through PCIe's
+ * fabric-layer messages. Because interrupts are remapped, we
+ * can support multi-message MSI here.
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int hv_pcie_init_irq_domain(struct hv_pcibus_device *hbus)
+{
+ hbus->msi_info.chip = &hv_msi_irq_chip;
+ hbus->msi_info.ops = &hv_msi_ops;
+ hbus->msi_info.flags = (MSI_FLAG_USE_DEF_DOM_OPS |
+ MSI_FLAG_USE_DEF_CHIP_OPS | MSI_FLAG_MULTI_PCI_MSI |
+ MSI_FLAG_PCI_MSIX);
+ hbus->msi_info.handler = handle_edge_irq;
+ hbus->msi_info.handler_name = "edge";
+ hbus->msi_info.data = hbus;
+ hbus->irq_domain = pci_msi_create_irq_domain(hbus->sysdata.fwnode,
+ &hbus->msi_info,
+ x86_vector_domain);
+ if (!hbus->irq_domain) {
+ dev_err(&hbus->hdev->device,
+ "Failed to build an MSI IRQ domain\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * get_bar_size() - Get the address space consumed by a BAR
+ * @bar_val: Value that a BAR returned after -1 was written
+ * to it.
+ *
+ * This function returns the size of the BAR, rounded up to 1
+ * page. It has to be rounded up because the hypervisor's page
+ * table entry that maps the BAR into the VM can't specify an
+ * offset within a page. The invariant is that the hypervisor
+ * must place any BARs of smaller than page length at the
+ * beginning of a page.
+ *
+ * Return: Size in bytes of the consumed MMIO space.
+ */
+static u64 get_bar_size(u64 bar_val)
+{
+ return round_up((1 + ~(bar_val & PCI_BASE_ADDRESS_MEM_MASK)),
+ PAGE_SIZE);
+}
+
+/**
+ * survey_child_resources() - Total all MMIO requirements
+ * @hbus: Root PCI bus, as understood by this driver
+ */
+static void survey_child_resources(struct hv_pcibus_device *hbus)
+{
+ struct list_head *iter;
+ struct hv_pci_dev *hpdev;
+ resource_size_t bar_size = 0;
+ unsigned long flags;
+ struct completion *event;
+ u64 bar_val;
+ int i;
+
+ /* If nobody is waiting on the answer, don't compute it. */
+ event = xchg(&hbus->survey_event, NULL);
+ if (!event)
+ return;
+
+ /* If the answer has already been computed, go with it. */
+ if (hbus->low_mmio_space || hbus->high_mmio_space) {
+ complete(event);
+ return;
+ }
+
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+
+ /*
+ * Due to an interesting quirk of the PCI spec, all memory regions
+ * for a child device are a power of 2 in size and aligned in memory,
+ * so it's sufficient to just add them up without tracking alignment.
+ */
+ list_for_each(iter, &hbus->children) {
+ hpdev = container_of(iter, struct hv_pci_dev, list_entry);
+ for (i = 0; i < 6; i++) {
+ if (hpdev->probed_bar[i] & PCI_BASE_ADDRESS_SPACE_IO)
+ dev_err(&hbus->hdev->device,
+ "There's an I/O BAR in this list!\n");
+
+ if (hpdev->probed_bar[i] != 0) {
+ /*
+ * A probed BAR has all the upper bits set that
+ * can be changed.
+ */
+
+ bar_val = hpdev->probed_bar[i];
+ if (bar_val & PCI_BASE_ADDRESS_MEM_TYPE_64)
+ bar_val |=
+ ((u64)hpdev->probed_bar[++i] << 32);
+ else
+ bar_val |= 0xffffffff00000000ULL;
+
+ bar_size = get_bar_size(bar_val);
+
+ if (bar_val & PCI_BASE_ADDRESS_MEM_TYPE_64)
+ hbus->high_mmio_space += bar_size;
+ else
+ hbus->low_mmio_space += bar_size;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+ complete(event);
+}
+
+/**
+ * prepopulate_bars() - Fill in BARs with defaults
+ * @hbus: Root PCI bus, as understood by this driver
+ *
+ * The core PCI driver code seems much, much happier if the BARs
+ * for a device have values upon first scan. So fill them in.
+ * The algorithm below works down from large sizes to small,
+ * attempting to pack the assignments optimally. The assumption,
+ * enforced in other parts of the code, is that the beginning of
+ * the memory-mapped I/O space will be aligned on the largest
+ * BAR size.
+ */
+static void prepopulate_bars(struct hv_pcibus_device *hbus)
+{
+ resource_size_t high_size = 0;
+ resource_size_t low_size = 0;
+ resource_size_t high_base = 0;
+ resource_size_t low_base = 0;
+ resource_size_t bar_size;
+ struct hv_pci_dev *hpdev;
+ struct list_head *iter;
+ unsigned long flags;
+ u64 bar_val;
+ u32 command;
+ bool high;
+ int i;
+
+ if (hbus->low_mmio_space) {
+ low_size = 1ULL << (63 - __builtin_clzll(hbus->low_mmio_space));
+ low_base = hbus->low_mmio_res->start;
+ }
+
+ if (hbus->high_mmio_space) {
+ high_size = 1ULL <<
+ (63 - __builtin_clzll(hbus->high_mmio_space));
+ high_base = hbus->high_mmio_res->start;
+ }
+
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+
+ /* Pick addresses for the BARs. */
+ do {
+ list_for_each(iter, &hbus->children) {
+ hpdev = container_of(iter, struct hv_pci_dev,
+ list_entry);
+ for (i = 0; i < 6; i++) {
+ bar_val = hpdev->probed_bar[i];
+ if (bar_val == 0)
+ continue;
+ high = bar_val & PCI_BASE_ADDRESS_MEM_TYPE_64;
+ if (high) {
+ bar_val |=
+ ((u64)hpdev->probed_bar[i + 1]
+ << 32);
+ } else {
+ bar_val |= 0xffffffffULL << 32;
+ }
+ bar_size = get_bar_size(bar_val);
+ if (high) {
+ if (high_size != bar_size) {
+ i++;
+ continue;
+ }
+ _hv_pcifront_write_config(hpdev,
+ PCI_BASE_ADDRESS_0 + (4 * i),
+ 4,
+ (u32)(high_base & 0xffffff00));
+ i++;
+ _hv_pcifront_write_config(hpdev,
+ PCI_BASE_ADDRESS_0 + (4 * i),
+ 4, (u32)(high_base >> 32));
+ high_base += bar_size;
+ } else {
+ if (low_size != bar_size)
+ continue;
+ _hv_pcifront_write_config(hpdev,
+ PCI_BASE_ADDRESS_0 + (4 * i),
+ 4,
+ (u32)(low_base & 0xffffff00));
+ low_base += bar_size;
+ }
+ }
+ if (high_size <= 1 && low_size <= 1) {
+ /* Set the memory enable bit. */
+ _hv_pcifront_read_config(hpdev, PCI_COMMAND, 2,
+ &command);
+ command |= PCI_COMMAND_MEMORY;
+ _hv_pcifront_write_config(hpdev, PCI_COMMAND, 2,
+ command);
+ break;
+ }
+ }
+
+ high_size >>= 1;
+ low_size >>= 1;
+ } while (high_size || low_size);
+
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+}
+
+/**
+ * create_root_hv_pci_bus() - Expose a new root PCI bus
+ * @hbus: Root PCI bus, as understood by this driver
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus)
+{
+ /* Register the device */
+ hbus->pci_bus = pci_create_root_bus(&hbus->hdev->device,
+ 0, /* bus number is always zero */
+ &hv_pcifront_ops,
+ &hbus->sysdata,
+ &hbus->resources_for_children);
+ if (!hbus->pci_bus)
+ return -ENODEV;
+
+ hbus->pci_bus->msi = &hbus->msi_chip;
+ hbus->pci_bus->msi->dev = &hbus->hdev->device;
+
+ pci_scan_child_bus(hbus->pci_bus);
+ pci_bus_assign_resources(hbus->pci_bus);
+ pci_bus_add_devices(hbus->pci_bus);
+ hbus->state = hv_pcibus_installed;
+ return 0;
+}
+
+struct q_res_req_compl {
+ struct completion host_event;
+ struct hv_pci_dev *hpdev;
+};
+
+/**
+ * q_resource_requirements() - Query Resource Requirements
+ * @context: The completion context.
+ * @resp: The response that came from the host.
+ * @resp_packet_size: The size in bytes of resp.
+ *
+ * This function is invoked on completion of a Query Resource
+ * Requirements packet.
+ */
+static void q_resource_requirements(void *context, struct pci_response *resp,
+ int resp_packet_size)
+{
+ struct q_res_req_compl *completion = context;
+ struct pci_q_res_req_response *q_res_req =
+ (struct pci_q_res_req_response *)resp;
+ int i;
+
+ if (resp->status < 0) {
+ dev_err(&completion->hpdev->hbus->hdev->device,
+ "query resource requirements failed: %x\n",
+ resp->status);
+ } else {
+ for (i = 0; i < 6; i++) {
+ completion->hpdev->probed_bar[i] =
+ q_res_req->probed_bar[i];
+ }
+ }
+
+ complete(&completion->host_event);
+}
+
+static void get_pcichild(struct hv_pci_dev *hpdev,
+ enum hv_pcidev_ref_reason reason)
+{
+ atomic_inc(&hpdev->refs);
+}
+
+static void put_pcichild(struct hv_pci_dev *hpdev,
+ enum hv_pcidev_ref_reason reason)
+{
+ if (atomic_dec_and_test(&hpdev->refs))
+ kfree(hpdev);
+}
+
+/**
+ * new_pcichild_device() - Create a new child device
+ * @hbus: The internal struct tracking this root PCI bus.
+ * @desc: The information supplied so far from the host
+ * about the device.
+ *
+ * This function creates the tracking structure for a new child
+ * device and kicks off the process of figuring out what it is.
+ *
+ * Return: Pointer to the new tracking struct
+ */
+static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus,
+ struct pci_function_description *desc)
+{
+ struct hv_pci_dev *hpdev;
+ struct pci_child_message *res_req;
+ struct q_res_req_compl comp_pkt;
+ union {
+ struct pci_packet init_packet;
+ u8 buffer[0x100];
+ } pkt;
+ unsigned long flags;
+ int ret;
+
+ hpdev = kzalloc(sizeof(*hpdev), GFP_ATOMIC);
+ if (!hpdev)
+ return NULL;
+
+ hpdev->hbus = hbus;
+
+ memset(&pkt, 0, sizeof(pkt));
+ init_completion(&comp_pkt.host_event);
+ comp_pkt.hpdev = hpdev;
+ pkt.init_packet.compl_ctxt = &comp_pkt;
+ pkt.init_packet.completion_func = q_resource_requirements;
+ res_req = (struct pci_child_message *)&pkt.init_packet.message;
+ res_req->message_type = PCI_QUERY_RESOURCE_REQUIREMENTS;
+ res_req->wslot.slot = desc->win_slot.slot;
+
+ ret = vmbus_sendpacket(hbus->hdev->channel, res_req,
+ sizeof(struct pci_child_message),
+ (unsigned long)&pkt.init_packet,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (ret)
+ goto error;
+
+ wait_for_completion(&comp_pkt.host_event);
+
+ hpdev->desc = *desc;
+ get_pcichild(hpdev, hv_pcidev_ref_initial);
+ get_pcichild(hpdev, hv_pcidev_ref_childlist);
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+ list_add_tail(&hpdev->list_entry, &hbus->children);
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+ return hpdev;
+
+error:
+ kfree(hpdev);
+ return NULL;
+}
+
+/**
+ * get_pcichild_wslot() - Find device from slot
+ * @hbus: Root PCI bus, as understood by this driver
+ * @wslot: Location on the bus
+ *
+ * This function looks up a PCI device and returns the internal
+ * representation of it. It acquires a reference on it, so that
+ * the device won't be deleted while somebody is using it. The
+ * caller is responsible for calling put_pcichild() to release
+ * this reference.
+ *
+ * Return: Internal representation of a PCI device
+ */
+static struct hv_pci_dev *get_pcichild_wslot(struct hv_pcibus_device *hbus,
+ u32 wslot)
+{
+ unsigned long flags;
+ struct hv_pci_dev *iter, *hpdev = NULL;
+
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+ list_for_each_entry(iter, &hbus->children, list_entry) {
+ if (iter->desc.win_slot.slot == wslot) {
+ hpdev = iter;
+ get_pcichild(hpdev, hv_pcidev_ref_by_slot);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+ return hpdev;
+}
+
+/**
+ * pci_devices_present_work() - Handle new list of child devices
+ * @work: Work struct embedded in struct hv_dr_work
+ *
+ * "Bus Relations" is the Windows term for "children of this
+ * bus." The terminology is preserved here for people trying to
+ * debug the interaction between Hyper-V and Linux. This
+ * function is called when the parent partition reports a list
+ * of functions that should be observed under this PCI Express
+ * port (bus).
+ *
+ * This function updates the list, and must tolerate being
+ * called multiple times with the same information. The typical
+ * number of child devices is one, with very atypical cases
+ * involving three or four, so the algorithms used here can be
+ * simple and inefficient.
+ *
+ * It must also treat the omission of a previously observed device as
+ * notification that the device no longer exists.
+ *
+ * Note that this function is a work item, and it may not be
+ * invoked in the order that it was queued. Back to back
+ * updates of the list of present devices may involve queuing
+ * multiple work items, and this one may run before ones that
+ * were sent later. As such, this function only does something
+ * if is the last one in the queue.
+ */
+static void pci_devices_present_work(struct work_struct *work)
+{
+ u32 child_no;
+ bool found;
+ struct list_head *iter;
+ struct pci_function_description *new_desc;
+ struct hv_pci_dev *hpdev;
+ struct hv_pcibus_device *hbus;
+ struct list_head removed;
+ struct hv_dr_work *dr_wrk;
+ struct hv_dr_state *dr = NULL;
+ unsigned long flags;
+
+ dr_wrk = container_of(work, struct hv_dr_work, wrk);
+ hbus = dr_wrk->bus;
+ kfree(dr_wrk);
+
+ INIT_LIST_HEAD(&removed);
+
+ if (down_interruptible(&hbus->enum_sem)) {
+ put_hvpcibus(hbus);
+ return;
+ }
+
+ /* Pull this off the queue and process it if it was the last one. */
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+ while (!list_empty(&hbus->dr_list)) {
+ dr = list_first_entry(&hbus->dr_list, struct hv_dr_state,
+ list_entry);
+ list_del(&dr->list_entry);
+
+ /* Throw this away if the list still has stuff in it. */
+ if (!list_empty(&hbus->dr_list)) {
+ kfree(dr);
+ continue;
+ }
+ }
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+ if (!dr) {
+ up(&hbus->enum_sem);
+ put_hvpcibus(hbus);
+ return;
+ }
+
+ /* First, mark all existing children as reported missing. */
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+ list_for_each(iter, &hbus->children) {
+ hpdev = container_of(iter, struct hv_pci_dev,
+ list_entry);
+ hpdev->reported_missing = true;
+ }
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+ /* Next, add back any reported devices. */
+ for (child_no = 0; child_no < dr->device_count; child_no++) {
+ found = false;
+ new_desc = &dr->func[child_no];
+
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+ list_for_each(iter, &hbus->children) {
+ hpdev = container_of(iter, struct hv_pci_dev,
+ list_entry);
+ if ((hpdev->desc.win_slot.slot ==
+ new_desc->win_slot.slot) &&
+ (hpdev->desc.v_id == new_desc->v_id) &&
+ (hpdev->desc.d_id == new_desc->d_id) &&
+ (hpdev->desc.ser == new_desc->ser)) {
+ hpdev->reported_missing = false;
+ found = true;
+ }
+ }
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+ if (!found) {
+ hpdev = new_pcichild_device(hbus, new_desc);
+ if (!hpdev)
+ dev_err(&hbus->hdev->device,
+ "couldn't record a child device.\n");
+ }
+ }
+
+ /* Move missing children to a list on the stack. */
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+ do {
+ found = false;
+ list_for_each(iter, &hbus->children) {
+ hpdev = container_of(iter, struct hv_pci_dev,
+ list_entry);
+ if (hpdev->reported_missing) {
+ found = true;
+ put_pcichild(hpdev, hv_pcidev_ref_childlist);
+ list_del(&hpdev->list_entry);
+ list_add_tail(&hpdev->list_entry, &removed);
+ break;
+ }
+ }
+ } while (found);
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+ /* Delete everything that should no longer exist. */
+ while (!list_empty(&removed)) {
+ hpdev = list_first_entry(&removed, struct hv_pci_dev,
+ list_entry);
+ list_del(&hpdev->list_entry);
+ put_pcichild(hpdev, hv_pcidev_ref_initial);
+ }
+
+ /* Tell the core to rescan bus because there may have been changes. */
+ if (hbus->state == hv_pcibus_installed) {
+ pci_lock_rescan_remove();
+ pci_scan_child_bus(hbus->pci_bus);
+ pci_unlock_rescan_remove();
+ } else {
+ survey_child_resources(hbus);
+ }
+
+ up(&hbus->enum_sem);
+ put_hvpcibus(hbus);
+ kfree(dr);
+}
+
+/**
+ * hv_pci_devices_present() - Handles list of new children
+ * @hbus: Root PCI bus, as understood by this driver
+ * @relations: Packet from host listing children
+ *
+ * This function is invoked whenever a new list of devices for
+ * this bus appears.
+ */
+static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
+ struct pci_bus_relations *relations)
+{
+ struct hv_dr_state *dr;
+ struct hv_dr_work *dr_wrk;
+ unsigned long flags;
+
+ dr_wrk = kzalloc(sizeof(*dr_wrk), GFP_NOWAIT);
+ if (!dr_wrk)
+ return;
+
+ dr = kzalloc(offsetof(struct hv_dr_state, func) +
+ (sizeof(struct pci_function_description) *
+ (relations->device_count)), GFP_NOWAIT);
+ if (!dr) {
+ kfree(dr_wrk);
+ return;
+ }
+
+ INIT_WORK(&dr_wrk->wrk, pci_devices_present_work);
+ dr_wrk->bus = hbus;
+ dr->device_count = relations->device_count;
+ if (dr->device_count != 0) {
+ memcpy(dr->func, relations->func,
+ sizeof(struct pci_function_description) *
+ dr->device_count);
+ }
+
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+ list_add_tail(&dr->list_entry, &hbus->dr_list);
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+
+ get_hvpcibus(hbus);
+ schedule_work(&dr_wrk->wrk);
+}
+
+/**
+ * hv_eject_device_work() - Asynchronously handles ejection
+ * @work: Work struct embedded in internal device struct
+ *
+ * This function handles ejecting a device. Windows will
+ * attempt to gracefully eject a device, waiting 60 seconds to
+ * hear back from the guest OS that this completed successfully.
+ * If this timer expires, the device will be forcibly removed.
+ */
+static void hv_eject_device_work(struct work_struct *work)
+{
+ struct pci_eject_response *ejct_pkt;
+ struct hv_pci_dev *hpdev;
+ struct pci_dev *pdev;
+ unsigned long flags;
+ int wslot;
+ struct {
+ struct pci_packet pkt;
+ u8 buffer[sizeof(struct pci_eject_response) -
+ sizeof(struct pci_message)];
+ } ctxt;
+
+ hpdev = container_of(work, struct hv_pci_dev, wrk);
+
+ if (hpdev->state != hv_pcichild_ejecting) {
+ put_pcichild(hpdev, hv_pcidev_ref_pnp);
+ return;
+ }
+
+ /*
+ * Ejection can come before or after the PCI bus has been set up, so
+ * attempt to find it and tear down the bus state, if it exists. This
+ * must be done without constructs like pci_domain_nr(hbus->pci_bus)
+ * because hbus->pci_bus may not exist yet.
+ */
+ wslot = wslot_to_devfn(hpdev->desc.win_slot.slot);
+ pdev = pci_get_domain_bus_and_slot(hpdev->hbus->sysdata.domain, 0,
+ wslot);
+ if (pdev) {
+ pci_stop_and_remove_bus_device(pdev);
+ pci_dev_put(pdev);
+ }
+
+ memset(&ctxt, 0, sizeof(ctxt));
+ ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
+ ejct_pkt->message_type = PCI_EJECTION_COMPLETE;
+ ejct_pkt->wslot.slot = hpdev->desc.win_slot.slot;
+ vmbus_sendpacket(hpdev->hbus->hdev->channel, ejct_pkt,
+ sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
+ VM_PKT_DATA_INBAND, 0);
+
+ spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags);
+ list_del(&hpdev->list_entry);
+ spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags);
+
+ put_pcichild(hpdev, hv_pcidev_ref_childlist);
+ put_pcichild(hpdev, hv_pcidev_ref_pnp);
+ put_hvpcibus(hpdev->hbus);
+}
+
+/**
+ * hv_pci_eject_device() - Handles device ejection
+ * @hpdev: Internal device tracking struct
+ *
+ * This function is invoked when an ejection packet arrives. It
+ * just schedules work so that we don't re-enter the packet
+ * delivery code handling the ejection.
+ */
+static void hv_pci_eject_device(struct hv_pci_dev *hpdev)
+{
+ hpdev->state = hv_pcichild_ejecting;
+ get_pcichild(hpdev, hv_pcidev_ref_pnp);
+ INIT_WORK(&hpdev->wrk, hv_eject_device_work);
+ get_hvpcibus(hpdev->hbus);
+ schedule_work(&hpdev->wrk);
+}
+
+/**
+ * hv_pci_onchannelcallback() - Handles incoming packets
+ * @context: Internal bus tracking struct
+ *
+ * This function is invoked whenever the host sends a packet to
+ * this channel (which is private to this root PCI bus).
+ */
+static void hv_pci_onchannelcallback(void *context)
+{
+ const int packet_size = 0x100;
+ int ret;
+ struct hv_pcibus_device *hbus = context;
+ u32 bytes_recvd;
+ u64 req_id;
+ struct vmpacket_descriptor *desc;
+ unsigned char *buffer;
+ int bufferlen = packet_size;
+ struct pci_packet *comp_packet;
+ struct pci_response *response;
+ struct pci_incoming_message *new_message;
+ struct pci_bus_relations *bus_rel;
+ struct pci_dev_incoming *dev_message;
+ struct hv_pci_dev *hpdev;
+
+ buffer = kmalloc(bufferlen, GFP_ATOMIC);
+ if (!buffer)
+ return;
+
+ while (1) {
+ ret = vmbus_recvpacket_raw(hbus->hdev->channel, buffer,
+ bufferlen, &bytes_recvd, &req_id);
+
+ if (ret == -ENOBUFS) {
+ kfree(buffer);
+ /* Handle large packet */
+ bufferlen = bytes_recvd;
+ buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
+ if (!buffer)
+ return;
+ continue;
+ }
+
+ /*
+ * All incoming packets must be at least as large as a
+ * response.
+ */
+ if (bytes_recvd <= sizeof(struct pci_response)) {
+ kfree(buffer);
+ return;
+ }
+ desc = (struct vmpacket_descriptor *)buffer;
+
+ switch (desc->type) {
+ case VM_PKT_COMP:
+
+ /*
+ * The host is trusted, and thus it's safe to interpret
+ * this transaction ID as a pointer.
+ */
+ comp_packet = (struct pci_packet *)req_id;
+ response = (struct pci_response *)buffer;
+ comp_packet->completion_func(comp_packet->compl_ctxt,
+ response,
+ bytes_recvd);
+ kfree(buffer);
+ return;
+
+ case VM_PKT_DATA_INBAND:
+
+ new_message = (struct pci_incoming_message *)buffer;
+ switch (new_message->message_type.message_type) {
+ case PCI_BUS_RELATIONS:
+
+ bus_rel = (struct pci_bus_relations *)buffer;
+ if (bytes_recvd <
+ offsetof(struct pci_bus_relations, func) +
+ (sizeof(struct pci_function_description) *
+ (bus_rel->device_count))) {
+ dev_err(&hbus->hdev->device,
+ "bus relations too small\n");
+ break;
+ }
+
+ hv_pci_devices_present(hbus, bus_rel);
+ break;
+
+ case PCI_EJECT:
+
+ dev_message = (struct pci_dev_incoming *)buffer;
+ hpdev = get_pcichild_wslot(hbus,
+ dev_message->wslot.slot);
+ if (hpdev) {
+ hv_pci_eject_device(hpdev);
+ put_pcichild(hpdev,
+ hv_pcidev_ref_by_slot);
+ }
+ break;
+
+ default:
+ dev_warn(&hbus->hdev->device,
+ "Unimplemented protocol message %x\n",
+ new_message->message_type.message_type);
+ break;
+ }
+ break;
+
+ default:
+ dev_err(&hbus->hdev->device,
+ "unhandled packet type %d, tid %llx len %d\n",
+ desc->type, req_id, bytes_recvd);
+ break;
+ }
+ break;
+ }
+}
+
+/**
+ * hv_pci_protocol_negotiation() - Set up protocol
+ * @hdev: VMBus's tracking struct for this root PCI bus
+ *
+ * This driver is intended to support running on Windows 10
+ * (server) and later versions. It will not run on earlier
+ * versions, as they assume that many of the operations which
+ * Linux needs accomplished with a spinlock held were done via
+ * asynchronous messaging via VMBus. Windows 10 increases the
+ * surface area of PCI emulation so that these actions can take
+ * place by suspending a virtual processor for their duration.
+ *
+ * This function negotiates the channel protocol version,
+ * failing if the host doesn't support the necessary protocol
+ * level.
+ */
+static int hv_pci_protocol_negotiation(struct hv_device *hdev)
+{
+ struct pci_version_request *version_req;
+ struct hv_pci_compl comp_pkt;
+ struct pci_packet *pkt;
+ int ret;
+
+ /*
+ * Initiate the handshake with the host and negotiate
+ * a version that the host can support. We start with the
+ * highest version number and go down if the host cannot
+ * support it.
+ */
+ pkt = kzalloc(sizeof(*pkt) + sizeof(*version_req), GFP_KERNEL);
+ if (!pkt)
+ return -ENOMEM;
+
+ init_completion(&comp_pkt.host_event);
+ pkt->completion_func = hv_pci_generic_compl;
+ pkt->compl_ctxt = &comp_pkt;
+ version_req = (struct pci_version_request *)&pkt->message;
+ version_req->message_type.message_type = PCI_QUERY_PROTOCOL_VERSION;
+ version_req->protocol_version = PCI_PROTOCOL_VERSION_CURRENT;
+
+ ret = vmbus_sendpacket(hdev->channel, version_req,
+ sizeof(struct pci_version_request),
+ (unsigned long)pkt, VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (ret)
+ goto exit;
+
+ wait_for_completion(&comp_pkt.host_event);
+
+ if (comp_pkt.completion_status < 0) {
+ dev_err(&hdev->device,
+ "PCI Pass-through VSP failed version request %x\n",
+ comp_pkt.completion_status);
+ ret = -EPROTO;
+ goto exit;
+ }
+
+ ret = 0;
+
+exit:
+ kfree(pkt);
+ return ret;
+}
+
+/**
+ * hv_pci_free_bridge_windows() - Release memory regions for the
+ * bus
+ * @hbus: Root PCI bus, as understood by this driver
+ */
+static void hv_pci_free_bridge_windows(struct hv_pcibus_device *hbus)
+{
+ /*
+ * Set the resources back to the way they looked when they
+ * were allocated by setting IORESOURCE_BUSY again.
+ */
+
+ if (hbus->low_mmio_space && hbus->low_mmio_res) {
+ hbus->low_mmio_res->flags |= IORESOURCE_BUSY;
+ release_mem_region(hbus->low_mmio_res->start,
+ resource_size(hbus->low_mmio_res));
+ }
+
+ if (hbus->high_mmio_space && hbus->high_mmio_res) {
+ hbus->high_mmio_res->flags |= IORESOURCE_BUSY;
+ release_mem_region(hbus->high_mmio_res->start,
+ resource_size(hbus->high_mmio_res));
+ }
+}
+
+/**
+ * hv_pci_allocate_bridge_windows() - Allocate memory regions
+ * for the bus
+ * @hbus: Root PCI bus, as understood by this driver
+ *
+ * This function calls vmbus_allocate_mmio(), which is itself a
+ * bit of a compromise. Ideally, we might change the pnp layer
+ * in the kernel such that it comprehends either PCI devices
+ * which are "grandchildren of ACPI," with some intermediate bus
+ * node (in this case, VMBus) or change it such that it
+ * understands VMBus. The pnp layer, however, has been declared
+ * deprecated, and not subject to change.
+ *
+ * The workaround, implemented here, is to ask VMBus to allocate
+ * MMIO space for this bus. VMBus itself knows which ranges are
+ * appropriate by looking at its own ACPI objects. Then, after
+ * these ranges are claimed, they're modified to look like they
+ * would have looked if the ACPI and pnp code had allocated
+ * bridge windows. These descriptors have to exist in this form
+ * in order to satisfy the code which will get invoked when the
+ * endpoint PCI function driver calls request_mem_region() or
+ * request_mem_region_exclusive().
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_allocate_bridge_windows(struct hv_pcibus_device *hbus)
+{
+ resource_size_t align;
+ int ret;
+
+ if (hbus->low_mmio_space) {
+ align = 1ULL << (63 - __builtin_clzll(hbus->low_mmio_space));
+ ret = vmbus_allocate_mmio(&hbus->low_mmio_res, hbus->hdev, 0,
+ (u64)(u32)0xffffffff,
+ hbus->low_mmio_space,
+ align, false);
+ if (ret) {
+ dev_err(&hbus->hdev->device,
+ "Need %#llx of low MMIO space. Consider reconfiguring the VM.\n",
+ hbus->low_mmio_space);
+ return ret;
+ }
+
+ /* Modify this resource to become a bridge window. */
+ hbus->low_mmio_res->flags |= IORESOURCE_WINDOW;
+ hbus->low_mmio_res->flags &= ~IORESOURCE_BUSY;
+ pci_add_resource(&hbus->resources_for_children,
+ hbus->low_mmio_res);
+ }
+
+ if (hbus->high_mmio_space) {
+ align = 1ULL << (63 - __builtin_clzll(hbus->high_mmio_space));
+ ret = vmbus_allocate_mmio(&hbus->high_mmio_res, hbus->hdev,
+ 0x100000000, -1,
+ hbus->high_mmio_space, align,
+ false);
+ if (ret) {
+ dev_err(&hbus->hdev->device,
+ "Need %#llx of high MMIO space. Consider reconfiguring the VM.\n",
+ hbus->high_mmio_space);
+ goto release_low_mmio;
+ }
+
+ /* Modify this resource to become a bridge window. */
+ hbus->high_mmio_res->flags |= IORESOURCE_WINDOW;
+ hbus->high_mmio_res->flags &= ~IORESOURCE_BUSY;
+ pci_add_resource(&hbus->resources_for_children,
+ hbus->high_mmio_res);
+ }
+
+ return 0;
+
+release_low_mmio:
+ if (hbus->low_mmio_res) {
+ release_mem_region(hbus->low_mmio_res->start,
+ resource_size(hbus->low_mmio_res));
+ }
+
+ return ret;
+}
+
+/**
+ * hv_allocate_config_window() - Find MMIO space for PCI Config
+ * @hbus: Root PCI bus, as understood by this driver
+ *
+ * This function claims memory-mapped I/O space for accessing
+ * configuration space for the functions on this bus.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_allocate_config_window(struct hv_pcibus_device *hbus)
+{
+ int ret;
+
+ /*
+ * Set up a region of MMIO space to use for accessing configuration
+ * space.
+ */
+ ret = vmbus_allocate_mmio(&hbus->mem_config, hbus->hdev, 0, -1,
+ PCI_CONFIG_MMIO_LENGTH, 0x1000, false);
+ if (ret)
+ return ret;
+
+ /*
+ * vmbus_allocate_mmio() gets used for allocating both device endpoint
+ * resource claims (those which cannot be overlapped) and the ranges
+ * which are valid for the children of this bus, which are intended
+ * to be overlapped by those children. Set the flag on this claim
+ * meaning that this region can't be overlapped.
+ */
+
+ hbus->mem_config->flags |= IORESOURCE_BUSY;
+
+ return 0;
+}
+
+static void hv_free_config_window(struct hv_pcibus_device *hbus)
+{
+ release_mem_region(hbus->mem_config->start, PCI_CONFIG_MMIO_LENGTH);
+}
+
+/**
+ * hv_pci_enter_d0() - Bring the "bus" into the D0 power state
+ * @hdev: VMBus's tracking struct for this root PCI bus
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_enter_d0(struct hv_device *hdev)
+{
+ struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+ struct pci_bus_d0_entry *d0_entry;
+ struct hv_pci_compl comp_pkt;
+ struct pci_packet *pkt;
+ int ret;
+
+ /*
+ * Tell the host that the bus is ready to use, and moved into the
+ * powered-on state. This includes telling the host which region
+ * of memory-mapped I/O space has been chosen for configuration space
+ * access.
+ */
+ pkt = kzalloc(sizeof(*pkt) + sizeof(*d0_entry), GFP_KERNEL);
+ if (!pkt)
+ return -ENOMEM;
+
+ init_completion(&comp_pkt.host_event);
+ pkt->completion_func = hv_pci_generic_compl;
+ pkt->compl_ctxt = &comp_pkt;
+ d0_entry = (struct pci_bus_d0_entry *)&pkt->message;
+ d0_entry->message_type.message_type = PCI_BUS_D0ENTRY;
+ d0_entry->mmio_base = hbus->mem_config->start;
+
+ ret = vmbus_sendpacket(hdev->channel, d0_entry, sizeof(*d0_entry),
+ (unsigned long)pkt, VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (ret)
+ goto exit;
+
+ wait_for_completion(&comp_pkt.host_event);
+
+ if (comp_pkt.completion_status < 0) {
+ dev_err(&hdev->device,
+ "PCI Pass-through VSP failed D0 Entry with status %x\n",
+ comp_pkt.completion_status);
+ ret = -EPROTO;
+ goto exit;
+ }
+
+ ret = 0;
+
+exit:
+ kfree(pkt);
+ return ret;
+}
+
+/**
+ * hv_pci_query_relations() - Ask host to send list of child
+ * devices
+ * @hdev: VMBus's tracking struct for this root PCI bus
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_query_relations(struct hv_device *hdev)
+{
+ struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+ struct pci_message message;
+ struct completion comp;
+ int ret;
+
+ /* Ask the host to send along the list of child devices */
+ init_completion(&comp);
+ if (cmpxchg(&hbus->survey_event, NULL, &comp))
+ return -ENOTEMPTY;
+
+ memset(&message, 0, sizeof(message));
+ message.message_type = PCI_QUERY_BUS_RELATIONS;
+
+ ret = vmbus_sendpacket(hdev->channel, &message, sizeof(message),
+ 0, VM_PKT_DATA_INBAND, 0);
+ if (ret)
+ return ret;
+
+ wait_for_completion(&comp);
+ return 0;
+}
+
+/**
+ * hv_send_resources_allocated() - Report local resource choices
+ * @hdev: VMBus's tracking struct for this root PCI bus
+ *
+ * The host OS is expecting to be sent a request as a message
+ * which contains all the resources that the device will use.
+ * The response contains those same resources, "translated"
+ * which is to say, the values which should be used by the
+ * hardware, when it delivers an interrupt. (MMIO resources are
+ * used in local terms.) This is nice for Windows, and lines up
+ * with the FDO/PDO split, which doesn't exist in Linux. Linux
+ * is deeply expecting to scan an emulated PCI configuration
+ * space. So this message is sent here only to drive the state
+ * machine on the host forward.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_send_resources_allocated(struct hv_device *hdev)
+{
+ struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+ struct pci_resources_assigned *res_assigned;
+ struct hv_pci_compl comp_pkt;
+ struct hv_pci_dev *hpdev;
+ struct pci_packet *pkt;
+ u32 wslot;
+ int ret;
+
+ pkt = kmalloc(sizeof(*pkt) + sizeof(*res_assigned), GFP_KERNEL);
+ if (!pkt)
+ return -ENOMEM;
+
+ ret = 0;
+
+ for (wslot = 0; wslot < 256; wslot++) {
+ hpdev = get_pcichild_wslot(hbus, wslot);
+ if (!hpdev)
+ continue;
+
+ memset(pkt, 0, sizeof(*pkt) + sizeof(*res_assigned));
+ init_completion(&comp_pkt.host_event);
+ pkt->completion_func = hv_pci_generic_compl;
+ pkt->compl_ctxt = &comp_pkt;
+ pkt->message.message_type = PCI_RESOURCES_ASSIGNED;
+ res_assigned = (struct pci_resources_assigned *)&pkt->message;
+ res_assigned->wslot.slot = hpdev->desc.win_slot.slot;
+
+ put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+
+ ret = vmbus_sendpacket(
+ hdev->channel, &pkt->message,
+ sizeof(*res_assigned),
+ (unsigned long)pkt,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (ret)
+ break;
+
+ wait_for_completion(&comp_pkt.host_event);
+
+ if (comp_pkt.completion_status < 0) {
+ ret = -EPROTO;
+ dev_err(&hdev->device,
+ "resource allocated returned 0x%x",
+ comp_pkt.completion_status);
+ break;
+ }
+ }
+
+ kfree(pkt);
+ return ret;
+}
+
+/**
+ * hv_send_resources_released() - Report local resources
+ * released
+ * @hdev: VMBus's tracking struct for this root PCI bus
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_send_resources_released(struct hv_device *hdev)
+{
+ struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
+ struct pci_child_message pkt;
+ struct hv_pci_dev *hpdev;
+ u32 wslot;
+ int ret;
+
+ for (wslot = 0; wslot < 256; wslot++) {
+ hpdev = get_pcichild_wslot(hbus, wslot);
+ if (!hpdev)
+ continue;
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.message_type = PCI_RESOURCES_RELEASED;
+ pkt.wslot.slot = hpdev->desc.win_slot.slot;
+
+ put_pcichild(hpdev, hv_pcidev_ref_by_slot);
+
+ ret = vmbus_sendpacket(hdev->channel, &pkt, sizeof(pkt), 0,
+ VM_PKT_DATA_INBAND, 0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void get_hvpcibus(struct hv_pcibus_device *hbus)
+{
+ atomic_inc(&hbus->remove_lock);
+}
+
+static void put_hvpcibus(struct hv_pcibus_device *hbus)
+{
+ if (atomic_dec_and_test(&hbus->remove_lock))
+ complete(&hbus->remove_event);
+}
+
+/**
+ * hv_pci_probe() - New VMBus channel probe, for a root PCI bus
+ * @hdev: VMBus's tracking struct for this root PCI bus
+ * @dev_id: Identifies the device itself
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_probe(struct hv_device *hdev,
+ const struct hv_vmbus_device_id *dev_id)
+{
+ struct hv_pcibus_device *hbus;
+ int ret;
+
+ hbus = kzalloc(sizeof(*hbus), GFP_KERNEL);
+ if (!hbus)
+ return -ENOMEM;
+
+ /*
+ * The PCI bus "domain" is what is called "segment" in ACPI and
+ * other specs. Pull it from the instance ID, to get something
+ * unique. Bytes 8 and 9 are what is used in Windows guests, so
+ * do the same thing for consistency. Note that, since this code
+ * only runs in a Hyper-V VM, Hyper-V can (and does) guarantee
+ * that (1) the only domain in use for something that looks like
+ * a physical PCI bus (which is actually emulated by the
+ * hypervisor) is domain 0 and (2) there will be no overlap
+ * between domains derived from these instance IDs in the same
+ * VM.
+ */
+ hbus->sysdata.domain = hdev->dev_instance.b[9] |
+ hdev->dev_instance.b[8] << 8;
+
+ hbus->hdev = hdev;
+ atomic_inc(&hbus->remove_lock);
+ INIT_LIST_HEAD(&hbus->children);
+ INIT_LIST_HEAD(&hbus->dr_list);
+ INIT_LIST_HEAD(&hbus->resources_for_children);
+ spin_lock_init(&hbus->config_lock);
+ spin_lock_init(&hbus->device_list_lock);
+ sema_init(&hbus->enum_sem, 1);
+ init_completion(&hbus->remove_event);
+
+ ret = vmbus_open(hdev->channel, pci_ring_size, pci_ring_size, NULL, 0,
+ hv_pci_onchannelcallback, hbus);
+ if (ret)
+ goto free_bus;
+
+ hv_set_drvdata(hdev, hbus);
+
+ ret = hv_pci_protocol_negotiation(hdev);
+ if (ret)
+ goto close;
+
+ ret = hv_allocate_config_window(hbus);
+ if (ret)
+ goto close;
+
+ hbus->cfg_addr = ioremap(hbus->mem_config->start,
+ PCI_CONFIG_MMIO_LENGTH);
+ if (!hbus->cfg_addr) {
+ dev_err(&hdev->device,
+ "Unable to map a virtual address for config space\n");
+ ret = -ENOMEM;
+ goto free_config;
+ }
+
+ hbus->sysdata.fwnode = irq_domain_alloc_fwnode(hbus);
+ if (!hbus->sysdata.fwnode) {
+ ret = -ENOMEM;
+ goto unmap;
+ }
+
+ ret = hv_pcie_init_irq_domain(hbus);
+ if (ret)
+ goto free_fwnode;
+
+ ret = hv_pci_query_relations(hdev);
+ if (ret)
+ goto free_irq_domain;
+
+ ret = hv_pci_enter_d0(hdev);
+ if (ret)
+ goto free_irq_domain;
+
+ ret = hv_pci_allocate_bridge_windows(hbus);
+ if (ret)
+ goto free_irq_domain;
+
+ ret = hv_send_resources_allocated(hdev);
+ if (ret)
+ goto free_windows;
+
+ prepopulate_bars(hbus);
+
+ hbus->state = hv_pcibus_probed;
+
+ ret = create_root_hv_pci_bus(hbus);
+ if (ret)
+ goto free_windows;
+
+ return 0;
+
+free_windows:
+ hv_pci_free_bridge_windows(hbus);
+free_irq_domain:
+ irq_domain_remove(hbus->irq_domain);
+free_fwnode:
+ irq_domain_free_fwnode(hbus->sysdata.fwnode);
+unmap:
+ iounmap(hbus->cfg_addr);
+free_config:
+ hv_free_config_window(hbus);
+close:
+ vmbus_close(hdev->channel);
+free_bus:
+ kfree(hbus);
+ return ret;
+}
+
+/**
+ * hv_pci_remove() - Remove routine for this VMBus channel
+ * @hdev: VMBus's tracking struct for this root PCI bus
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int hv_pci_remove(struct hv_device *hdev)
+{
+ int ret;
+ struct hv_pcibus_device *hbus;
+ union {
+ struct pci_packet teardown_packet;
+ u8 buffer[0x100];
+ } pkt;
+ struct pci_bus_relations relations;
+ struct hv_pci_compl comp_pkt;
+
+ hbus = hv_get_drvdata(hdev);
+
+ ret = hv_send_resources_released(hdev);
+ if (ret)
+ dev_err(&hdev->device,
+ "Couldn't send resources released packet(s)\n");
+
+ memset(&pkt.teardown_packet, 0, sizeof(pkt.teardown_packet));
+ init_completion(&comp_pkt.host_event);
+ pkt.teardown_packet.completion_func = hv_pci_generic_compl;
+ pkt.teardown_packet.compl_ctxt = &comp_pkt;
+ pkt.teardown_packet.message.message_type = PCI_BUS_D0EXIT;
+
+ ret = vmbus_sendpacket(hdev->channel, &pkt.teardown_packet.message,
+ sizeof(struct pci_message),
+ (unsigned long)&pkt.teardown_packet,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (!ret)
+ wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ);
+
+ if (hbus->state == hv_pcibus_installed) {
+ /* Remove the bus from PCI's point of view. */
+ pci_lock_rescan_remove();
+ pci_stop_root_bus(hbus->pci_bus);
+ pci_remove_root_bus(hbus->pci_bus);
+ pci_unlock_rescan_remove();
+ }
+
+ vmbus_close(hdev->channel);
+
+ /* Delete any children which might still exist. */
+ memset(&relations, 0, sizeof(relations));
+ hv_pci_devices_present(hbus, &relations);
+
+ iounmap(hbus->cfg_addr);
+ hv_free_config_window(hbus);
+ pci_free_resource_list(&hbus->resources_for_children);
+ hv_pci_free_bridge_windows(hbus);
+ irq_domain_remove(hbus->irq_domain);
+ irq_domain_free_fwnode(hbus->sysdata.fwnode);
+ put_hvpcibus(hbus);
+ wait_for_completion(&hbus->remove_event);
+ kfree(hbus);
+ return 0;
+}
+
+static const struct hv_vmbus_device_id hv_pci_id_table[] = {
+ /* PCI Pass-through Class ID */
+ /* 44C4F61D-4444-4400-9D52-802E27EDE19F */
+ { HV_PCIE_GUID, },
+ { },
+};
+
+MODULE_DEVICE_TABLE(vmbus, hv_pci_id_table);
+
+static struct hv_driver hv_pci_drv = {
+ .name = "hv_pci",
+ .id_table = hv_pci_id_table,
+ .probe = hv_pci_probe,
+ .remove = hv_pci_remove,
+};
+
+static void __exit exit_hv_pci_drv(void)
+{
+ vmbus_driver_unregister(&hv_pci_drv);
+}
+
+static int __init init_hv_pci_drv(void)
+{
+ return vmbus_driver_register(&hv_pci_drv);
+}
+
+module_init(init_hv_pci_drv);
+module_exit(exit_hv_pci_drv);
+
+MODULE_DESCRIPTION("Hyper-V PCI");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index fe600964fa50..eb5a2755a164 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -39,6 +39,11 @@ struct imx6_pcie {
struct pcie_port pp;
struct regmap *iomuxc_gpr;
void __iomem *mem_base;
+ u32 tx_deemph_gen1;
+ u32 tx_deemph_gen2_3p5db;
+ u32 tx_deemph_gen2_6db;
+ u32 tx_swing_full;
+ u32 tx_swing_low;
};
/* PCIe Root Complex registers (memory-mapped) */
@@ -202,6 +207,23 @@ static int pcie_phy_write(void __iomem *dbi_base, int addr, int data)
return 0;
}
+static void imx6_pcie_reset_phy(struct pcie_port *pp)
+{
+ u32 tmp;
+
+ pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp);
+ tmp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
+ PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+ pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp);
+
+ usleep_range(2000, 3000);
+
+ pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp);
+ tmp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN |
+ PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+ pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp);
+}
+
/* Added for PCI abort handling */
static int imx6q_pcie_abort_handler(unsigned long addr,
unsigned int fsr, struct pt_regs *regs)
@@ -317,32 +339,32 @@ static void imx6_pcie_init_phy(struct pcie_port *pp)
IMX6Q_GPR12_LOS_LEVEL, 9 << 4);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_DEEMPH_GEN1, 0 << 0);
+ IMX6Q_GPR8_TX_DEEMPH_GEN1,
+ imx6_pcie->tx_deemph_gen1 << 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, 0 << 6);
+ IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB,
+ imx6_pcie->tx_deemph_gen2_3p5db << 6);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, 20 << 12);
+ IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB,
+ imx6_pcie->tx_deemph_gen2_6db << 12);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_SWING_FULL, 127 << 18);
+ IMX6Q_GPR8_TX_SWING_FULL,
+ imx6_pcie->tx_swing_full << 18);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_SWING_LOW, 127 << 25);
+ IMX6Q_GPR8_TX_SWING_LOW,
+ imx6_pcie->tx_swing_low << 25);
}
static int imx6_pcie_wait_for_link(struct pcie_port *pp)
{
- unsigned int retries;
-
- for (retries = 0; retries < 200; retries++) {
- if (dw_pcie_link_up(pp))
- return 0;
- usleep_range(100, 1000);
- }
+ /* check if the link is up or not */
+ if (!dw_pcie_wait_for_link(pp))
+ return 0;
- dev_err(pp->dev, "phy link never came up\n");
dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
- return -EINVAL;
+ return -ETIMEDOUT;
}
static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp)
@@ -390,8 +412,10 @@ static int imx6_pcie_establish_link(struct pcie_port *pp)
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
ret = imx6_pcie_wait_for_link(pp);
- if (ret)
- return ret;
+ if (ret) {
+ dev_info(pp->dev, "Link never came up\n");
+ goto err_reset_phy;
+ }
/* Allow Gen2 mode after the link is up. */
tmp = readl(pp->dbi_base + PCIE_RC_LCR);
@@ -410,19 +434,28 @@ static int imx6_pcie_establish_link(struct pcie_port *pp)
ret = imx6_pcie_wait_for_speed_change(pp);
if (ret) {
dev_err(pp->dev, "Failed to bring link up!\n");
- return ret;
+ goto err_reset_phy;
}
/* Make sure link training is finished as well! */
ret = imx6_pcie_wait_for_link(pp);
if (ret) {
dev_err(pp->dev, "Failed to bring link up!\n");
- return ret;
+ goto err_reset_phy;
}
tmp = readl(pp->dbi_base + PCIE_RC_LCSR);
dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf);
+
return 0;
+
+err_reset_phy:
+ dev_dbg(pp->dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
+ readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
+ readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
+ imx6_pcie_reset_phy(pp);
+
+ return ret;
}
static void imx6_pcie_host_init(struct pcie_port *pp)
@@ -441,81 +474,10 @@ static void imx6_pcie_host_init(struct pcie_port *pp)
dw_pcie_msi_init(pp);
}
-static void imx6_pcie_reset_phy(struct pcie_port *pp)
-{
- u32 tmp;
-
- pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp);
- tmp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
- PHY_RX_OVRD_IN_LO_RX_PLL_EN);
- pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp);
-
- usleep_range(2000, 3000);
-
- pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp);
- tmp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN |
- PHY_RX_OVRD_IN_LO_RX_PLL_EN);
- pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp);
-}
-
static int imx6_pcie_link_up(struct pcie_port *pp)
{
- u32 rc, debug_r0, rx_valid;
- int count = 5;
-
- /*
- * Test if the PHY reports that the link is up and also that the LTSSM
- * training finished. There are three possible states of the link when
- * this code is called:
- * 1) The link is DOWN (unlikely)
- * The link didn't come up yet for some reason. This usually means
- * we have a real problem somewhere. Reset the PHY and exit. This
- * state calls for inspection of the DEBUG registers.
- * 2) The link is UP, but still in LTSSM training
- * Wait for the training to finish, which should take a very short
- * time. If the training does not finish, we have a problem and we
- * need to inspect the DEBUG registers. If the training does finish,
- * the link is up and operating correctly.
- * 3) The link is UP and no longer in LTSSM training
- * The link is up and operating correctly.
- */
- while (1) {
- rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
- if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP))
- break;
- if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
- return 1;
- if (!count--)
- break;
- dev_dbg(pp->dev, "Link is up, but still in training\n");
- /*
- * Wait a little bit, then re-check if the link finished
- * the training.
- */
- usleep_range(1000, 2000);
- }
- /*
- * From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
- * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
- * If (MAC/LTSSM.state == Recovery.RcvrLock)
- * && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition
- * to gen2 is stuck
- */
- pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
- debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0);
-
- if (rx_valid & PCIE_PHY_RX_ASIC_OUT_VALID)
- return 0;
-
- if ((debug_r0 & 0x3f) != 0x0d)
- return 0;
-
- dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n");
- dev_dbg(pp->dev, "debug_r0=%08x debug_r1=%08x\n", debug_r0, rc);
-
- imx6_pcie_reset_phy(pp);
-
- return 0;
+ return readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) &
+ PCIE_PHY_DEBUG_R1_XMLH_LINK_UP;
}
static struct pcie_host_ops imx6_pcie_host_ops = {
@@ -562,6 +524,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
struct imx6_pcie *imx6_pcie;
struct pcie_port *pp;
struct resource *dbi_base;
+ struct device_node *node = pdev->dev.of_node;
int ret;
imx6_pcie = devm_kzalloc(&pdev->dev, sizeof(*imx6_pcie), GFP_KERNEL);
@@ -614,6 +577,27 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
return PTR_ERR(imx6_pcie->iomuxc_gpr);
}
+ /* Grab PCIe PHY Tx Settings */
+ if (of_property_read_u32(node, "fsl,tx-deemph-gen1",
+ &imx6_pcie->tx_deemph_gen1))
+ imx6_pcie->tx_deemph_gen1 = 0;
+
+ if (of_property_read_u32(node, "fsl,tx-deemph-gen2-3p5db",
+ &imx6_pcie->tx_deemph_gen2_3p5db))
+ imx6_pcie->tx_deemph_gen2_3p5db = 0;
+
+ if (of_property_read_u32(node, "fsl,tx-deemph-gen2-6db",
+ &imx6_pcie->tx_deemph_gen2_6db))
+ imx6_pcie->tx_deemph_gen2_6db = 20;
+
+ if (of_property_read_u32(node, "fsl,tx-swing-full",
+ &imx6_pcie->tx_swing_full))
+ imx6_pcie->tx_swing_full = 127;
+
+ if (of_property_read_u32(node, "fsl,tx-swing-low",
+ &imx6_pcie->tx_swing_low))
+ imx6_pcie->tx_swing_low = 127;
+
ret = imx6_add_pcie_port(pp, pdev);
if (ret < 0)
return ret;
diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
index ed34c9520a02..6153853ca9c3 100644
--- a/drivers/pci/host/pci-keystone-dw.c
+++ b/drivers/pci/host/pci-keystone-dw.c
@@ -58,11 +58,6 @@
#define to_keystone_pcie(x) container_of(x, struct keystone_pcie, pp)
-static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
-{
- return sys->private_data;
-}
-
static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
u32 *bit_pos)
{
@@ -108,7 +103,7 @@ static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
struct pcie_port *pp;
msi = irq_data_get_msi_desc(d);
- pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+ pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
ks_pcie = to_keystone_pcie(pp);
offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
@@ -146,7 +141,7 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
u32 offset;
msi = irq_data_get_msi_desc(d);
- pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+ pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
ks_pcie = to_keystone_pcie(pp);
offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
@@ -167,7 +162,7 @@ static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
u32 offset;
msi = irq_data_get_msi_desc(d);
- pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+ pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
ks_pcie = to_keystone_pcie(pp);
offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
index 0aa81bd3de12..b71f55bb0315 100644
--- a/drivers/pci/host/pci-keystone.c
+++ b/drivers/pci/host/pci-keystone.c
@@ -97,17 +97,15 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
return 0;
}
- ks_dw_pcie_initiate_link_train(ks_pcie);
/* check if the link is up or not */
- for (retries = 0; retries < 200; retries++) {
- if (dw_pcie_link_up(pp))
- return 0;
- usleep_range(100, 1000);
+ for (retries = 0; retries < 5; retries++) {
ks_dw_pcie_initiate_link_train(ks_pcie);
+ if (!dw_pcie_wait_for_link(pp))
+ return 0;
}
dev_err(pp->dev, "phy link never came up\n");
- return -EINVAL;
+ return -ETIMEDOUT;
}
static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
@@ -359,6 +357,9 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
/* initialize SerDes Phy if present */
phy = devm_phy_get(dev, "pcie-phy");
+ if (PTR_ERR_OR_ZERO(phy) == -EPROBE_DEFER)
+ return PTR_ERR(phy);
+
if (!IS_ERR_OR_NULL(phy)) {
ret = phy_init(phy);
if (ret < 0)
diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c
index 3923bed93c7e..a21e229d95e0 100644
--- a/drivers/pci/host/pci-layerscape.c
+++ b/drivers/pci/host/pci-layerscape.c
@@ -77,6 +77,16 @@ static void ls_pcie_fix_class(struct ls_pcie *pcie)
iowrite16(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE);
}
+/* Drop MSG TLP except for Vendor MSG */
+static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
+{
+ u32 val;
+
+ val = ioread32(pcie->dbi + PCIE_STRFMR1);
+ val &= 0xDFFFFFFF;
+ iowrite32(val, pcie->dbi + PCIE_STRFMR1);
+}
+
static int ls1021_pcie_link_up(struct pcie_port *pp)
{
u32 state;
@@ -97,7 +107,7 @@ static int ls1021_pcie_link_up(struct pcie_port *pp)
static void ls1021_pcie_host_init(struct pcie_port *pp)
{
struct ls_pcie *pcie = to_ls_pcie(pp);
- u32 val, index[2];
+ u32 index[2];
pcie->scfg = syscon_regmap_lookup_by_phandle(pp->dev->of_node,
"fsl,pcie-scfg");
@@ -116,13 +126,7 @@ static void ls1021_pcie_host_init(struct pcie_port *pp)
dw_pcie_setup_rc(pp);
- /*
- * LS1021A Workaround for internal TKT228622
- * to fix the INTx hang issue
- */
- val = ioread32(pcie->dbi + PCIE_STRFMR1);
- val &= 0xffff;
- iowrite32(val, pcie->dbi + PCIE_STRFMR1);
+ ls_pcie_drop_msg_tlp(pcie);
}
static int ls_pcie_link_up(struct pcie_port *pp)
@@ -147,6 +151,7 @@ static void ls_pcie_host_init(struct pcie_port *pp)
iowrite32(1, pcie->dbi + PCIE_DBI_RO_WR_EN);
ls_pcie_fix_class(pcie);
ls_pcie_clear_multifunction(pcie);
+ ls_pcie_drop_msg_tlp(pcie);
iowrite32(0, pcie->dbi + PCIE_DBI_RO_WR_EN);
}
@@ -203,6 +208,7 @@ static const struct of_device_id ls_pcie_of_match[] = {
{ .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
{ .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
{ .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
+ { .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata },
{ },
};
MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 30323114c53c..68d1f41b3cbf 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -281,6 +281,11 @@ struct tegra_pcie {
struct resource prefetch;
struct resource busn;
+ struct {
+ resource_size_t mem;
+ resource_size_t io;
+ } offset;
+
struct clk *pex_clk;
struct clk *afi_clk;
struct clk *pll_e;
@@ -295,7 +300,6 @@ struct tegra_pcie {
struct tegra_msi msi;
struct list_head ports;
- unsigned int num_ports;
u32 xbar_config;
struct regulator_bulk_data *supplies;
@@ -426,31 +430,38 @@ free:
return ERR_PTR(err);
}
-/*
- * Look up a virtual address mapping for the specified bus number. If no such
- * mapping exists, try to create one.
- */
-static void __iomem *tegra_pcie_bus_map(struct tegra_pcie *pcie,
- unsigned int busnr)
+static int tegra_pcie_add_bus(struct pci_bus *bus)
{
- struct tegra_pcie_bus *bus;
+ struct tegra_pcie *pcie = sys_to_pcie(bus->sysdata);
+ struct tegra_pcie_bus *b;
- list_for_each_entry(bus, &pcie->buses, list)
- if (bus->nr == busnr)
- return (void __iomem *)bus->area->addr;
+ b = tegra_pcie_bus_alloc(pcie, bus->number);
+ if (IS_ERR(b))
+ return PTR_ERR(b);
- bus = tegra_pcie_bus_alloc(pcie, busnr);
- if (IS_ERR(bus))
- return NULL;
+ list_add_tail(&b->list, &pcie->buses);
- list_add_tail(&bus->list, &pcie->buses);
+ return 0;
+}
- return (void __iomem *)bus->area->addr;
+static void tegra_pcie_remove_bus(struct pci_bus *child)
+{
+ struct tegra_pcie *pcie = sys_to_pcie(child->sysdata);
+ struct tegra_pcie_bus *bus, *tmp;
+
+ list_for_each_entry_safe(bus, tmp, &pcie->buses, list) {
+ if (bus->nr == child->number) {
+ vunmap(bus->area->addr);
+ list_del(&bus->list);
+ kfree(bus);
+ break;
+ }
+ }
}
-static void __iomem *tegra_pcie_conf_address(struct pci_bus *bus,
- unsigned int devfn,
- int where)
+static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus,
+ unsigned int devfn,
+ int where)
{
struct tegra_pcie *pcie = sys_to_pcie(bus->sysdata);
void __iomem *addr = NULL;
@@ -466,7 +477,12 @@ static void __iomem *tegra_pcie_conf_address(struct pci_bus *bus,
}
}
} else {
- addr = tegra_pcie_bus_map(pcie, bus->number);
+ struct tegra_pcie_bus *b;
+
+ list_for_each_entry(b, &pcie->buses, list)
+ if (b->nr == bus->number)
+ addr = (void __iomem *)b->area->addr;
+
if (!addr) {
dev_err(pcie->dev,
"failed to map cfg. space for bus %u\n",
@@ -481,7 +497,9 @@ static void __iomem *tegra_pcie_conf_address(struct pci_bus *bus,
}
static struct pci_ops tegra_pcie_ops = {
- .map_bus = tegra_pcie_conf_address,
+ .add_bus = tegra_pcie_add_bus,
+ .remove_bus = tegra_pcie_remove_bus,
+ .map_bus = tegra_pcie_map_bus,
.read = pci_generic_config_read32,
.write = pci_generic_config_write32,
};
@@ -598,6 +616,17 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
struct tegra_pcie *pcie = sys_to_pcie(sys);
int err;
+ sys->mem_offset = pcie->offset.mem;
+ sys->io_offset = pcie->offset.io;
+
+ err = devm_request_resource(pcie->dev, &pcie->all, &pcie->io);
+ if (err < 0)
+ return err;
+
+ err = devm_request_resource(pcie->dev, &ioport_resource, &pcie->pio);
+ if (err < 0)
+ return err;
+
err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem);
if (err < 0)
return err;
@@ -606,6 +635,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
if (err)
return err;
+ pci_add_resource_offset(&sys->resources, &pcie->pio, sys->io_offset);
pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
pci_add_resource_offset(&sys->resources, &pcie->prefetch,
sys->mem_offset);
@@ -741,7 +771,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
afi_writel(pcie, 0, AFI_FPCI_BAR5);
/* map all upstream transactions as uncached */
- afi_writel(pcie, PHYS_OFFSET, AFI_CACHE_BAR0_ST);
+ afi_writel(pcie, 0, AFI_CACHE_BAR0_ST);
afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ);
afi_writel(pcie, 0, AFI_CACHE_BAR1_ST);
afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ);
@@ -1601,6 +1631,9 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
switch (res.flags & IORESOURCE_TYPE_BITS) {
case IORESOURCE_IO:
+ /* Track the bus -> CPU I/O mapping offset. */
+ pcie->offset.io = res.start - range.pci_addr;
+
memcpy(&pcie->pio, &res, sizeof(res));
pcie->pio.name = np->full_name;
@@ -1621,6 +1654,14 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
break;
case IORESOURCE_MEM:
+ /*
+ * Track the bus -> CPU memory mapping offset. This
+ * assumes that the prefetchable and non-prefetchable
+ * regions will be the last of type IORESOURCE_MEM in
+ * the ranges property.
+ * */
+ pcie->offset.mem = res.start - range.pci_addr;
+
if (res.flags & IORESOURCE_PREFETCH) {
memcpy(&pcie->prefetch, &res, sizeof(res));
pcie->prefetch.name = "prefetchable";
diff --git a/drivers/pci/host/pci-thunder-ecam.c b/drivers/pci/host/pci-thunder-ecam.c
new file mode 100644
index 000000000000..d71935cb2678
--- /dev/null
+++ b/drivers/pci/host/pci-thunder-ecam.c
@@ -0,0 +1,403 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2015, 2016 Cavium, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/of_pci.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pci-host-common.h"
+
+/* Mapping is standard ECAM */
+static void __iomem *thunder_ecam_map_bus(struct pci_bus *bus,
+ unsigned int devfn,
+ int where)
+{
+ struct gen_pci *pci = bus->sysdata;
+ resource_size_t idx = bus->number - pci->cfg.bus_range->start;
+
+ return pci->cfg.win[idx] + ((devfn << 12) | where);
+}
+
+static void set_val(u32 v, int where, int size, u32 *val)
+{
+ int shift = (where & 3) * 8;
+
+ pr_debug("set_val %04x: %08x\n", (unsigned)(where & ~3), v);
+ v >>= shift;
+ if (size == 1)
+ v &= 0xff;
+ else if (size == 2)
+ v &= 0xffff;
+ *val = v;
+}
+
+static int handle_ea_bar(u32 e0, int bar, struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 *val)
+{
+ void __iomem *addr;
+ u32 v;
+
+ /* Entries are 16-byte aligned; bits[2,3] select word in entry */
+ int where_a = where & 0xc;
+
+ if (where_a == 0) {
+ set_val(e0, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0x4) {
+ addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ v = readl(addr);
+ v &= ~0xf;
+ v |= 2; /* EA entry-1. Base-L */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0x8) {
+ u32 barl_orig;
+ u32 barl_rb;
+
+ addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ barl_orig = readl(addr + 0);
+ writel(0xffffffff, addr + 0);
+ barl_rb = readl(addr + 0);
+ writel(barl_orig, addr + 0);
+ /* zeros in unsettable bits */
+ v = ~barl_rb & ~3;
+ v |= 0xc; /* EA entry-2. Offset-L */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xc) {
+ addr = bus->ops->map_bus(bus, devfn, bar + 4); /* BAR 1 */
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ v = readl(addr); /* EA entry-3. Base-H */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static int thunder_ecam_p2_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ struct gen_pci *pci = bus->sysdata;
+ int where_a = where & ~3;
+ void __iomem *addr;
+ u32 node_bits;
+ u32 v;
+
+ /* EA Base[63:32] may be missing some bits ... */
+ switch (where_a) {
+ case 0xa8:
+ case 0xbc:
+ case 0xd0:
+ case 0xe4:
+ break;
+ default:
+ return pci_generic_config_read(bus, devfn, where, size, val);
+ }
+
+ addr = bus->ops->map_bus(bus, devfn, where_a);
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ v = readl(addr);
+
+ /*
+ * Bit 44 of the 64-bit Base must match the same bit in
+ * the config space access window. Since we are working with
+ * the high-order 32 bits, shift everything down by 32 bits.
+ */
+ node_bits = (pci->cfg.res.start >> 32) & (1 << 12);
+
+ v |= node_bits;
+ set_val(v, where, size, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ u32 v;
+ u32 vendor_device;
+ u32 class_rev;
+ void __iomem *addr;
+ int cfg_type;
+ int where_a = where & ~3;
+
+ addr = bus->ops->map_bus(bus, devfn, 0xc);
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ v = readl(addr);
+
+ /* Check for non type-00 header */
+ cfg_type = (v >> 16) & 0x7f;
+
+ addr = bus->ops->map_bus(bus, devfn, 8);
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ class_rev = readl(addr);
+ if (class_rev == 0xffffffff)
+ goto no_emulation;
+
+ if ((class_rev & 0xff) >= 8) {
+ /* Pass-2 handling */
+ if (cfg_type)
+ goto no_emulation;
+ return thunder_ecam_p2_config_read(bus, devfn, where,
+ size, val);
+ }
+
+ /*
+ * All BARs have fixed addresses specified by the EA
+ * capability; they must return zero on read.
+ */
+ if (cfg_type == 0 &&
+ ((where >= 0x10 && where < 0x2c) ||
+ (where >= 0x1a4 && where < 0x1bc))) {
+ /* BAR or SR-IOV BAR */
+ *val = 0;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ addr = bus->ops->map_bus(bus, devfn, 0);
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ vendor_device = readl(addr);
+ if (vendor_device == 0xffffffff)
+ goto no_emulation;
+
+ pr_debug("%04x:%04x - Fix pass#: %08x, where: %03x, devfn: %03x\n",
+ vendor_device & 0xffff, vendor_device >> 16, class_rev,
+ (unsigned) where, devfn);
+
+ /* Check for non type-00 header */
+ if (cfg_type == 0) {
+ bool has_msix;
+ bool is_nic = (vendor_device == 0xa01e177d);
+ bool is_tns = (vendor_device == 0xa01f177d);
+
+ addr = bus->ops->map_bus(bus, devfn, 0x70);
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ /* E_CAP */
+ v = readl(addr);
+ has_msix = (v & 0xff00) != 0;
+
+ if (!has_msix && where_a == 0x70) {
+ v |= 0xbc00; /* next capability is EA at 0xbc */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xb0) {
+ addr = bus->ops->map_bus(bus, devfn, where_a);
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ v = readl(addr);
+ if (v & 0xff00)
+ pr_err("Bad MSIX cap header: %08x\n", v);
+ v |= 0xbc00; /* next capability is EA at 0xbc */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xbc) {
+ if (is_nic)
+ v = 0x40014; /* EA last in chain, 4 entries */
+ else if (is_tns)
+ v = 0x30014; /* EA last in chain, 3 entries */
+ else if (has_msix)
+ v = 0x20014; /* EA last in chain, 2 entries */
+ else
+ v = 0x10014; /* EA last in chain, 1 entry */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a >= 0xc0 && where_a < 0xd0)
+ /* EA entry-0. PP=0, BAR0 Size:3 */
+ return handle_ea_bar(0x80ff0003,
+ 0x10, bus, devfn, where,
+ size, val);
+ if (where_a >= 0xd0 && where_a < 0xe0 && has_msix)
+ /* EA entry-1. PP=0, BAR4 Size:3 */
+ return handle_ea_bar(0x80ff0043,
+ 0x20, bus, devfn, where,
+ size, val);
+ if (where_a >= 0xe0 && where_a < 0xf0 && is_tns)
+ /* EA entry-2. PP=0, BAR2, Size:3 */
+ return handle_ea_bar(0x80ff0023,
+ 0x18, bus, devfn, where,
+ size, val);
+ if (where_a >= 0xe0 && where_a < 0xf0 && is_nic)
+ /* EA entry-2. PP=4, VF_BAR0 (9), Size:3 */
+ return handle_ea_bar(0x80ff0493,
+ 0x1a4, bus, devfn, where,
+ size, val);
+ if (where_a >= 0xf0 && where_a < 0x100 && is_nic)
+ /* EA entry-3. PP=4, VF_BAR4 (d), Size:3 */
+ return handle_ea_bar(0x80ff04d3,
+ 0x1b4, bus, devfn, where,
+ size, val);
+ } else if (cfg_type == 1) {
+ bool is_rsl_bridge = devfn == 0x08;
+ bool is_rad_bridge = devfn == 0xa0;
+ bool is_zip_bridge = devfn == 0xa8;
+ bool is_dfa_bridge = devfn == 0xb0;
+ bool is_nic_bridge = devfn == 0x10;
+
+ if (where_a == 0x70) {
+ addr = bus->ops->map_bus(bus, devfn, where_a);
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ v = readl(addr);
+ if (v & 0xff00)
+ pr_err("Bad PCIe cap header: %08x\n", v);
+ v |= 0xbc00; /* next capability is EA at 0xbc */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xbc) {
+ if (is_nic_bridge)
+ v = 0x10014; /* EA last in chain, 1 entry */
+ else
+ v = 0x00014; /* EA last in chain, no entries */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xc0) {
+ if (is_rsl_bridge || is_nic_bridge)
+ v = 0x0101; /* subordinate:secondary = 1:1 */
+ else if (is_rad_bridge)
+ v = 0x0202; /* subordinate:secondary = 2:2 */
+ else if (is_zip_bridge)
+ v = 0x0303; /* subordinate:secondary = 3:3 */
+ else if (is_dfa_bridge)
+ v = 0x0404; /* subordinate:secondary = 4:4 */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xc4 && is_nic_bridge) {
+ /* Enabled, not-Write, SP=ff, PP=05, BEI=6, ES=4 */
+ v = 0x80ff0564;
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xc8 && is_nic_bridge) {
+ v = 0x00000002; /* Base-L 64-bit */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xcc && is_nic_bridge) {
+ v = 0xfffffffe; /* MaxOffset-L 64-bit */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xd0 && is_nic_bridge) {
+ v = 0x00008430; /* NIC Base-H */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if (where_a == 0xd4 && is_nic_bridge) {
+ v = 0x0000000f; /* MaxOffset-H */
+ set_val(v, where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ }
+no_emulation:
+ return pci_generic_config_read(bus, devfn, where, size, val);
+}
+
+static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ /*
+ * All BARs have fixed addresses; ignore BAR writes so they
+ * don't get corrupted.
+ */
+ if ((where >= 0x10 && where < 0x2c) ||
+ (where >= 0x1a4 && where < 0x1bc))
+ /* BAR or SR-IOV BAR */
+ return PCIBIOS_SUCCESSFUL;
+
+ return pci_generic_config_write(bus, devfn, where, size, val);
+}
+
+static struct gen_pci_cfg_bus_ops thunder_ecam_bus_ops = {
+ .bus_shift = 20,
+ .ops = {
+ .map_bus = thunder_ecam_map_bus,
+ .read = thunder_ecam_config_read,
+ .write = thunder_ecam_config_write,
+ }
+};
+
+static const struct of_device_id thunder_ecam_of_match[] = {
+ { .compatible = "cavium,pci-host-thunder-ecam",
+ .data = &thunder_ecam_bus_ops },
+
+ { },
+};
+MODULE_DEVICE_TABLE(of, thunder_ecam_of_match);
+
+static int thunder_ecam_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id;
+ struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+
+ if (!pci)
+ return -ENOMEM;
+
+ of_id = of_match_node(thunder_ecam_of_match, dev->of_node);
+ pci->cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data;
+
+ return pci_host_common_probe(pdev, pci);
+}
+
+static struct platform_driver thunder_ecam_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = thunder_ecam_of_match,
+ },
+ .probe = thunder_ecam_probe,
+};
+module_platform_driver(thunder_ecam_driver);
+
+MODULE_DESCRIPTION("Thunder ECAM PCI host driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
new file mode 100644
index 000000000000..cabb92a514ac
--- /dev/null
+++ b/drivers/pci/host/pci-thunder-pem.c
@@ -0,0 +1,346 @@
+/*
+ * 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
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2015 - 2016 Cavium, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+
+#include "pci-host-common.h"
+
+#define PEM_CFG_WR 0x28
+#define PEM_CFG_RD 0x30
+
+struct thunder_pem_pci {
+ struct gen_pci gen_pci;
+ u32 ea_entry[3];
+ void __iomem *pem_reg_base;
+};
+
+static void __iomem *thunder_pem_map_bus(struct pci_bus *bus,
+ unsigned int devfn, int where)
+{
+ struct gen_pci *pci = bus->sysdata;
+ resource_size_t idx = bus->number - pci->cfg.bus_range->start;
+
+ return pci->cfg.win[idx] + ((devfn << 16) | where);
+}
+
+static int thunder_pem_bridge_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ u64 read_val;
+ struct thunder_pem_pci *pem_pci;
+ struct gen_pci *pci = bus->sysdata;
+
+ pem_pci = container_of(pci, struct thunder_pem_pci, gen_pci);
+
+ if (devfn != 0 || where >= 2048) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ /*
+ * 32-bit accesses only. Write the address to the low order
+ * bits of PEM_CFG_RD, then trigger the read by reading back.
+ * The config data lands in the upper 32-bits of PEM_CFG_RD.
+ */
+ read_val = where & ~3ull;
+ writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+ read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
+ read_val >>= 32;
+
+ /*
+ * The config space contains some garbage, fix it up. Also
+ * synthesize an EA capability for the BAR used by MSI-X.
+ */
+ switch (where & ~3) {
+ case 0x40:
+ read_val &= 0xffff00ff;
+ read_val |= 0x00007000; /* Skip MSI CAP */
+ break;
+ case 0x70: /* Express Cap */
+ /* PME interrupt on vector 2*/
+ read_val |= (2u << 25);
+ break;
+ case 0xb0: /* MSI-X Cap */
+ /* TableSize=4, Next Cap is EA */
+ read_val &= 0xc00000ff;
+ read_val |= 0x0003bc00;
+ break;
+ case 0xb4:
+ /* Table offset=0, BIR=0 */
+ read_val = 0x00000000;
+ break;
+ case 0xb8:
+ /* BPA offset=0xf0000, BIR=0 */
+ read_val = 0x000f0000;
+ break;
+ case 0xbc:
+ /* EA, 1 entry, no next Cap */
+ read_val = 0x00010014;
+ break;
+ case 0xc0:
+ /* DW2 for type-1 */
+ read_val = 0x00000000;
+ break;
+ case 0xc4:
+ /* Entry BEI=0, PP=0x00, SP=0xff, ES=3 */
+ read_val = 0x80ff0003;
+ break;
+ case 0xc8:
+ read_val = pem_pci->ea_entry[0];
+ break;
+ case 0xcc:
+ read_val = pem_pci->ea_entry[1];
+ break;
+ case 0xd0:
+ read_val = pem_pci->ea_entry[2];
+ break;
+ default:
+ break;
+ }
+ read_val >>= (8 * (where & 3));
+ switch (size) {
+ case 1:
+ read_val &= 0xff;
+ break;
+ case 2:
+ read_val &= 0xffff;
+ break;
+ default:
+ break;
+ }
+ *val = read_val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int thunder_pem_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ struct gen_pci *pci = bus->sysdata;
+
+ if (bus->number < pci->cfg.bus_range->start ||
+ bus->number > pci->cfg.bus_range->end)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * The first device on the bus is the PEM PCIe bridge.
+ * Special case its config access.
+ */
+ if (bus->number == pci->cfg.bus_range->start)
+ return thunder_pem_bridge_read(bus, devfn, where, size, val);
+
+ return pci_generic_config_read(bus, devfn, where, size, val);
+}
+
+/*
+ * Some of the w1c_bits below also include read-only or non-writable
+ * reserved bits, this makes the code simpler and is OK as the bits
+ * are not affected by writing zeros to them.
+ */
+static u32 thunder_pem_bridge_w1c_bits(int where)
+{
+ u32 w1c_bits = 0;
+
+ switch (where & ~3) {
+ case 0x04: /* Command/Status */
+ case 0x1c: /* Base and I/O Limit/Secondary Status */
+ w1c_bits = 0xff000000;
+ break;
+ case 0x44: /* Power Management Control and Status */
+ w1c_bits = 0xfffffe00;
+ break;
+ case 0x78: /* Device Control/Device Status */
+ case 0x80: /* Link Control/Link Status */
+ case 0x88: /* Slot Control/Slot Status */
+ case 0x90: /* Root Status */
+ case 0xa0: /* Link Control 2 Registers/Link Status 2 */
+ w1c_bits = 0xffff0000;
+ break;
+ case 0x104: /* Uncorrectable Error Status */
+ case 0x110: /* Correctable Error Status */
+ case 0x130: /* Error Status */
+ case 0x160: /* Link Control 4 */
+ w1c_bits = 0xffffffff;
+ break;
+ default:
+ break;
+ }
+ return w1c_bits;
+}
+
+static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct gen_pci *pci = bus->sysdata;
+ struct thunder_pem_pci *pem_pci;
+ u64 write_val, read_val;
+ u32 mask = 0;
+
+ pem_pci = container_of(pci, struct thunder_pem_pci, gen_pci);
+
+ if (devfn != 0 || where >= 2048)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * 32-bit accesses only. If the write is for a size smaller
+ * than 32-bits, we must first read the 32-bit value and merge
+ * in the desired bits and then write the whole 32-bits back
+ * out.
+ */
+ switch (size) {
+ case 1:
+ read_val = where & ~3ull;
+ writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+ read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
+ read_val >>= 32;
+ mask = ~(0xff << (8 * (where & 3)));
+ read_val &= mask;
+ val = (val & 0xff) << (8 * (where & 3));
+ val |= (u32)read_val;
+ break;
+ case 2:
+ read_val = where & ~3ull;
+ writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+ read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
+ read_val >>= 32;
+ mask = ~(0xffff << (8 * (where & 3)));
+ read_val &= mask;
+ val = (val & 0xffff) << (8 * (where & 3));
+ val |= (u32)read_val;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * By expanding the write width to 32 bits, we may
+ * inadvertently hit some W1C bits that were not intended to
+ * be written. Calculate the mask that must be applied to the
+ * data to be written to avoid these cases.
+ */
+ if (mask) {
+ u32 w1c_bits = thunder_pem_bridge_w1c_bits(where);
+
+ if (w1c_bits) {
+ mask &= w1c_bits;
+ val &= ~mask;
+ }
+ }
+
+ /*
+ * Low order bits are the config address, the high order 32
+ * bits are the data to be written.
+ */
+ write_val = where & ~3ull;
+ write_val |= (((u64)val) << 32);
+ writeq(write_val, pem_pci->pem_reg_base + PEM_CFG_WR);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct gen_pci *pci = bus->sysdata;
+
+ if (bus->number < pci->cfg.bus_range->start ||
+ bus->number > pci->cfg.bus_range->end)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * The first device on the bus is the PEM PCIe bridge.
+ * Special case its config access.
+ */
+ if (bus->number == pci->cfg.bus_range->start)
+ return thunder_pem_bridge_write(bus, devfn, where, size, val);
+
+
+ return pci_generic_config_write(bus, devfn, where, size, val);
+}
+
+static struct gen_pci_cfg_bus_ops thunder_pem_bus_ops = {
+ .bus_shift = 24,
+ .ops = {
+ .map_bus = thunder_pem_map_bus,
+ .read = thunder_pem_config_read,
+ .write = thunder_pem_config_write,
+ }
+};
+
+static const struct of_device_id thunder_pem_of_match[] = {
+ { .compatible = "cavium,pci-host-thunder-pem",
+ .data = &thunder_pem_bus_ops },
+
+ { },
+};
+MODULE_DEVICE_TABLE(of, thunder_pem_of_match);
+
+static int thunder_pem_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id;
+ resource_size_t bar4_start;
+ struct resource *res_pem;
+ struct thunder_pem_pci *pem_pci;
+
+ pem_pci = devm_kzalloc(dev, sizeof(*pem_pci), GFP_KERNEL);
+ if (!pem_pci)
+ return -ENOMEM;
+
+ of_id = of_match_node(thunder_pem_of_match, dev->of_node);
+ pem_pci->gen_pci.cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data;
+
+ /*
+ * The second register range is the PEM bridge to the PCIe
+ * bus. It has a different config access method than those
+ * devices behind the bridge.
+ */
+ res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_pem) {
+ dev_err(dev, "missing \"reg[1]\"property\n");
+ return -EINVAL;
+ }
+
+ pem_pci->pem_reg_base = devm_ioremap(dev, res_pem->start, 0x10000);
+ if (!pem_pci->pem_reg_base)
+ return -ENOMEM;
+
+ /*
+ * The MSI-X BAR for the PEM and AER interrupts is located at
+ * a fixed offset from the PEM register base. Generate a
+ * fragment of the synthesized Enhanced Allocation capability
+ * structure here for the BAR.
+ */
+ bar4_start = res_pem->start + 0xf00000;
+ pem_pci->ea_entry[0] = (u32)bar4_start | 2;
+ pem_pci->ea_entry[1] = (u32)(res_pem->end - bar4_start) & ~3u;
+ pem_pci->ea_entry[2] = (u32)(bar4_start >> 32);
+
+ return pci_host_common_probe(pdev, &pem_pci->gen_pci);
+}
+
+static struct platform_driver thunder_pem_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = thunder_pem_of_match,
+ },
+ .probe = thunder_pem_probe,
+};
+module_platform_driver(thunder_pem_driver);
+
+MODULE_DESCRIPTION("Thunder PEM PCIe host driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c
index 99da549d5d06..dbac6fb3f0bd 100644
--- a/drivers/pci/host/pcie-altera.c
+++ b/drivers/pci/host/pcie-altera.c
@@ -40,6 +40,7 @@
#define P2A_INT_ENABLE 0x3070
#define P2A_INT_ENA_ALL 0xf
#define RP_LTSSM 0x3c64
+#define RP_LTSSM_MASK 0x1f
#define LTSSM_L0 0xf
/* TLP configuration type 0 and 1 */
@@ -140,7 +141,7 @@ static void tlp_write_tx(struct altera_pcie *pcie,
static bool altera_pcie_link_is_up(struct altera_pcie *pcie)
{
- return !!(cra_readl(pcie, RP_LTSSM) & LTSSM_L0);
+ return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0);
}
static bool altera_pcie_valid_config(struct altera_pcie *pcie,
diff --git a/drivers/pci/host/pcie-designware-plat.c b/drivers/pci/host/pcie-designware-plat.c
new file mode 100644
index 000000000000..b3500994d08a
--- /dev/null
+++ b/drivers/pci/host/pcie-designware-plat.c
@@ -0,0 +1,138 @@
+/*
+ * PCIe RC driver for Synopsys DesignWare Core
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Joao Pinto <jpinto@synopsys.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+
+#include "pcie-designware.h"
+
+struct dw_plat_pcie {
+ void __iomem *mem_base;
+ struct pcie_port pp;
+};
+
+static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg)
+{
+ struct pcie_port *pp = arg;
+
+ return dw_handle_msi_irq(pp);
+}
+
+static void dw_plat_pcie_host_init(struct pcie_port *pp)
+{
+ dw_pcie_setup_rc(pp);
+ dw_pcie_wait_for_link(pp);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ dw_pcie_msi_init(pp);
+}
+
+static struct pcie_host_ops dw_plat_pcie_host_ops = {
+ .host_init = dw_plat_pcie_host_init,
+};
+
+static int dw_plat_add_pcie_port(struct pcie_port *pp,
+ struct platform_device *pdev)
+{
+ int ret;
+
+ pp->irq = platform_get_irq(pdev, 1);
+ if (pp->irq < 0)
+ return pp->irq;
+
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ pp->msi_irq = platform_get_irq(pdev, 0);
+ if (pp->msi_irq < 0)
+ return pp->msi_irq;
+
+ ret = devm_request_irq(&pdev->dev, pp->msi_irq,
+ dw_plat_pcie_msi_irq_handler,
+ IRQF_SHARED, "dw-plat-pcie-msi", pp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request MSI IRQ\n");
+ return ret;
+ }
+ }
+
+ pp->root_bus_nr = -1;
+ pp->ops = &dw_plat_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dw_plat_pcie_probe(struct platform_device *pdev)
+{
+ struct dw_plat_pcie *dw_plat_pcie;
+ struct pcie_port *pp;
+ struct resource *res; /* Resource from DT */
+ int ret;
+
+ dw_plat_pcie = devm_kzalloc(&pdev->dev, sizeof(*dw_plat_pcie),
+ GFP_KERNEL);
+ if (!dw_plat_pcie)
+ return -ENOMEM;
+
+ pp = &dw_plat_pcie->pp;
+ pp->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ dw_plat_pcie->mem_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dw_plat_pcie->mem_base))
+ return PTR_ERR(dw_plat_pcie->mem_base);
+
+ pp->dbi_base = dw_plat_pcie->mem_base;
+
+ ret = dw_plat_add_pcie_port(pp, pdev);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, dw_plat_pcie);
+ return 0;
+}
+
+static const struct of_device_id dw_plat_pcie_of_match[] = {
+ { .compatible = "snps,dw-pcie", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_plat_pcie_of_match);
+
+static struct platform_driver dw_plat_pcie_driver = {
+ .driver = {
+ .name = "dw-pcie",
+ .of_match_table = dw_plat_pcie_of_match,
+ },
+ .probe = dw_plat_pcie_probe,
+};
+
+module_platform_driver(dw_plat_pcie_driver);
+
+MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
+MODULE_DESCRIPTION("Synopsys PCIe host controller glue platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 21716827847a..a4cccd356304 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -22,6 +22,7 @@
#include <linux/pci_regs.h>
#include <linux/platform_device.h>
#include <linux/types.h>
+#include <linux/delay.h>
#include "pcie-designware.h"
@@ -69,6 +70,11 @@
#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
#define PCIE_ATU_UPPER_TARGET 0x91C
+/* PCIe Port Logic registers */
+#define PLR_OFFSET 0x700
+#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c)
+#define PCIE_PHY_DEBUG_R1_LINK_UP 0x00000010
+
static struct pci_ops dw_pcie_ops;
int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
@@ -380,12 +386,33 @@ static struct msi_controller dw_pcie_msi_chip = {
.teardown_irq = dw_msi_teardown_irq,
};
+int dw_pcie_wait_for_link(struct pcie_port *pp)
+{
+ int retries;
+
+ /* check if the link is up or not */
+ for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+ if (dw_pcie_link_up(pp)) {
+ dev_info(pp->dev, "link up\n");
+ return 0;
+ }
+ usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+ }
+
+ dev_err(pp->dev, "phy link never came up\n");
+
+ return -ETIMEDOUT;
+}
+
int dw_pcie_link_up(struct pcie_port *pp)
{
+ u32 val;
+
if (pp->ops->link_up)
return pp->ops->link_up(pp);
- return 0;
+ val = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
+ return val & PCIE_PHY_DEBUG_R1_LINK_UP;
}
static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
@@ -517,6 +544,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
if (pp->ops->host_init)
pp->ops->host_init(pp);
+ /*
+ * If the platform provides ->rd_other_conf, it means the platform
+ * uses its own address translation component rather than ATU, so
+ * we should not program the ATU here.
+ */
if (!pp->ops->rd_other_conf)
dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
PCIE_ATU_TYPE_MEM, pp->mem_base,
@@ -551,13 +583,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
#endif
- if (!pci_has_flag(PCI_PROBE_ONLY)) {
- pci_bus_size_bridges(bus);
- pci_bus_assign_resources(bus);
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child);
- }
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
pci_bus_add_devices(bus);
return 0;
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 2356d29e8527..f437f9b5be04 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -22,6 +22,11 @@
#define MAX_MSI_IRQS 32
#define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32)
+/* Parameters for the waiting for link up routine */
+#define LINK_WAIT_MAX_RETRIES 10
+#define LINK_WAIT_USLEEP_MIN 90000
+#define LINK_WAIT_USLEEP_MAX 100000
+
struct pcie_port {
struct device *dev;
u8 root_bus_nr;
@@ -76,6 +81,7 @@ int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val);
int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
void dw_pcie_msi_init(struct pcie_port *pp);
+int dw_pcie_wait_for_link(struct pcie_port *pp);
int dw_pcie_link_up(struct pcie_port *pp);
void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp);
diff --git a/drivers/pci/host/pcie-qcom.c b/drivers/pci/host/pcie-qcom.c
index e845fba19632..f2f90c50f75d 100644
--- a/drivers/pci/host/pcie-qcom.c
+++ b/drivers/pci/host/pcie-qcom.c
@@ -116,8 +116,6 @@ static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg)
static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
{
- struct device *dev = pcie->dev;
- unsigned int retries = 0;
u32 val;
if (dw_pcie_link_up(&pcie->pp))
@@ -128,15 +126,7 @@ static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE;
writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL);
- do {
- if (dw_pcie_link_up(&pcie->pp))
- return 0;
- usleep_range(250, 1000);
- } while (retries < 200);
-
- dev_warn(dev, "phy link never came up\n");
-
- return -ETIMEDOUT;
+ return dw_pcie_wait_for_link(&pcie->pp);
}
static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie)
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 4edb5181f4e2..35092188039b 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -390,9 +390,7 @@ static int rcar_pcie_enable(struct rcar_pcie *pcie)
rcar_pcie_setup(&res, pcie);
- /* Do not reassign resources if probe only */
- if (!pci_has_flag(PCI_PROBE_ONLY))
- pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
+ pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
if (IS_ENABLED(CONFIG_PCI_MSI))
bus = pci_scan_root_bus_msi(pcie->dev, pcie->root_bus_nr,
@@ -408,13 +406,11 @@ static int rcar_pcie_enable(struct rcar_pcie *pcie)
pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
- if (!pci_has_flag(PCI_PROBE_ONLY)) {
- pci_bus_size_bridges(bus);
- pci_bus_assign_resources(bus);
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child);
- }
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
pci_bus_add_devices(bus);
diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c
index a6cd8233e8c0..a4060b85ab23 100644
--- a/drivers/pci/host/pcie-spear13xx.c
+++ b/drivers/pci/host/pcie-spear13xx.c
@@ -13,7 +13,6 @@
*/
#include <linux/clk.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -149,7 +148,6 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp);
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
u32 exp_cap_off = EXP_CAP_ID_OFFSET;
- unsigned int retries;
if (dw_pcie_link_up(pp)) {
dev_err(pp->dev, "link already up\n");
@@ -200,17 +198,7 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
| ((u32)1 << REG_TRANSLATION_ENABLE),
&app_reg->app_ctrl_0);
- /* check if the link is up or not */
- for (retries = 0; retries < 10; retries++) {
- if (dw_pcie_link_up(pp)) {
- dev_info(pp->dev, "link up\n");
- return 0;
- }
- mdelay(100);
- }
-
- dev_err(pp->dev, "link Fail\n");
- return -EINVAL;
+ return dw_pcie_wait_for_link(pp);
}
static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
diff --git a/drivers/pci/host/pcie-xilinx-nwl.c b/drivers/pci/host/pcie-xilinx-nwl.c
new file mode 100644
index 000000000000..5139e6443bbd
--- /dev/null
+++ b/drivers/pci/host/pcie-xilinx-nwl.c
@@ -0,0 +1,881 @@
+/*
+ * PCIe host controller driver for NWL PCIe Bridge
+ * Based on pcie-xilinx.c, pci-tegra.c
+ *
+ * (C) Copyright 2014 - 2015, Xilinx, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/irqchip/chained_irq.h>
+
+/* Bridge core config registers */
+#define BRCFG_PCIE_RX0 0x00000000
+#define BRCFG_INTERRUPT 0x00000010
+#define BRCFG_PCIE_RX_MSG_FILTER 0x00000020
+
+/* Egress - Bridge translation registers */
+#define E_BREG_CAPABILITIES 0x00000200
+#define E_BREG_CONTROL 0x00000208
+#define E_BREG_BASE_LO 0x00000210
+#define E_BREG_BASE_HI 0x00000214
+#define E_ECAM_CAPABILITIES 0x00000220
+#define E_ECAM_CONTROL 0x00000228
+#define E_ECAM_BASE_LO 0x00000230
+#define E_ECAM_BASE_HI 0x00000234
+
+/* Ingress - address translations */
+#define I_MSII_CAPABILITIES 0x00000300
+#define I_MSII_CONTROL 0x00000308
+#define I_MSII_BASE_LO 0x00000310
+#define I_MSII_BASE_HI 0x00000314
+
+#define I_ISUB_CONTROL 0x000003E8
+#define SET_ISUB_CONTROL BIT(0)
+/* Rxed msg fifo - Interrupt status registers */
+#define MSGF_MISC_STATUS 0x00000400
+#define MSGF_MISC_MASK 0x00000404
+#define MSGF_LEG_STATUS 0x00000420
+#define MSGF_LEG_MASK 0x00000424
+#define MSGF_MSI_STATUS_LO 0x00000440
+#define MSGF_MSI_STATUS_HI 0x00000444
+#define MSGF_MSI_MASK_LO 0x00000448
+#define MSGF_MSI_MASK_HI 0x0000044C
+
+/* Msg filter mask bits */
+#define CFG_ENABLE_PM_MSG_FWD BIT(1)
+#define CFG_ENABLE_INT_MSG_FWD BIT(2)
+#define CFG_ENABLE_ERR_MSG_FWD BIT(3)
+#define CFG_ENABLE_SLT_MSG_FWD BIT(5)
+#define CFG_ENABLE_VEN_MSG_FWD BIT(7)
+#define CFG_ENABLE_OTH_MSG_FWD BIT(13)
+#define CFG_ENABLE_VEN_MSG_EN BIT(14)
+#define CFG_ENABLE_VEN_MSG_VEN_INV BIT(15)
+#define CFG_ENABLE_VEN_MSG_VEN_ID GENMASK(31, 16)
+#define CFG_ENABLE_MSG_FILTER_MASK (CFG_ENABLE_PM_MSG_FWD | \
+ CFG_ENABLE_INT_MSG_FWD | \
+ CFG_ENABLE_ERR_MSG_FWD | \
+ CFG_ENABLE_SLT_MSG_FWD | \
+ CFG_ENABLE_VEN_MSG_FWD | \
+ CFG_ENABLE_OTH_MSG_FWD | \
+ CFG_ENABLE_VEN_MSG_EN | \
+ CFG_ENABLE_VEN_MSG_VEN_INV | \
+ CFG_ENABLE_VEN_MSG_VEN_ID)
+
+/* Misc interrupt status mask bits */
+#define MSGF_MISC_SR_RXMSG_AVAIL BIT(0)
+#define MSGF_MISC_SR_RXMSG_OVER BIT(1)
+#define MSGF_MISC_SR_SLAVE_ERR BIT(4)
+#define MSGF_MISC_SR_MASTER_ERR BIT(5)
+#define MSGF_MISC_SR_I_ADDR_ERR BIT(6)
+#define MSGF_MISC_SR_E_ADDR_ERR BIT(7)
+#define MSGF_MISC_SR_UR_DETECT BIT(20)
+
+#define MSGF_MISC_SR_PCIE_CORE GENMASK(18, 16)
+#define MSGF_MISC_SR_PCIE_CORE_ERR GENMASK(31, 22)
+
+#define MSGF_MISC_SR_MASKALL (MSGF_MISC_SR_RXMSG_AVAIL | \
+ MSGF_MISC_SR_RXMSG_OVER | \
+ MSGF_MISC_SR_SLAVE_ERR | \
+ MSGF_MISC_SR_MASTER_ERR | \
+ MSGF_MISC_SR_I_ADDR_ERR | \
+ MSGF_MISC_SR_E_ADDR_ERR | \
+ MSGF_MISC_SR_UR_DETECT | \
+ MSGF_MISC_SR_PCIE_CORE | \
+ MSGF_MISC_SR_PCIE_CORE_ERR)
+
+/* Legacy interrupt status mask bits */
+#define MSGF_LEG_SR_INTA BIT(0)
+#define MSGF_LEG_SR_INTB BIT(1)
+#define MSGF_LEG_SR_INTC BIT(2)
+#define MSGF_LEG_SR_INTD BIT(3)
+#define MSGF_LEG_SR_MASKALL (MSGF_LEG_SR_INTA | MSGF_LEG_SR_INTB | \
+ MSGF_LEG_SR_INTC | MSGF_LEG_SR_INTD)
+
+/* MSI interrupt status mask bits */
+#define MSGF_MSI_SR_LO_MASK BIT(0)
+#define MSGF_MSI_SR_HI_MASK BIT(0)
+
+#define MSII_PRESENT BIT(0)
+#define MSII_ENABLE BIT(0)
+#define MSII_STATUS_ENABLE BIT(15)
+
+/* Bridge config interrupt mask */
+#define BRCFG_INTERRUPT_MASK BIT(0)
+#define BREG_PRESENT BIT(0)
+#define BREG_ENABLE BIT(0)
+#define BREG_ENABLE_FORCE BIT(1)
+
+/* E_ECAM status mask bits */
+#define E_ECAM_PRESENT BIT(0)
+#define E_ECAM_CR_ENABLE BIT(0)
+#define E_ECAM_SIZE_LOC GENMASK(20, 16)
+#define E_ECAM_SIZE_SHIFT 16
+#define ECAM_BUS_LOC_SHIFT 20
+#define ECAM_DEV_LOC_SHIFT 12
+#define NWL_ECAM_VALUE_DEFAULT 12
+
+#define CFG_DMA_REG_BAR GENMASK(2, 0)
+
+#define INT_PCI_MSI_NR (2 * 32)
+#define INTX_NUM 4
+
+/* Readin the PS_LINKUP */
+#define PS_LINKUP_OFFSET 0x00000238
+#define PCIE_PHY_LINKUP_BIT BIT(0)
+#define PHY_RDY_LINKUP_BIT BIT(1)
+
+/* Parameters for the waiting for link up routine */
+#define LINK_WAIT_MAX_RETRIES 10
+#define LINK_WAIT_USLEEP_MIN 90000
+#define LINK_WAIT_USLEEP_MAX 100000
+
+struct nwl_msi { /* MSI information */
+ struct irq_domain *msi_domain;
+ unsigned long *bitmap;
+ struct irq_domain *dev_domain;
+ struct mutex lock; /* protect bitmap variable */
+ int irq_msi0;
+ int irq_msi1;
+};
+
+struct nwl_pcie {
+ struct device *dev;
+ void __iomem *breg_base;
+ void __iomem *pcireg_base;
+ void __iomem *ecam_base;
+ phys_addr_t phys_breg_base; /* Physical Bridge Register Base */
+ phys_addr_t phys_pcie_reg_base; /* Physical PCIe Controller Base */
+ phys_addr_t phys_ecam_base; /* Physical Configuration Base */
+ u32 breg_size;
+ u32 pcie_reg_size;
+ u32 ecam_size;
+ int irq_intx;
+ int irq_misc;
+ u32 ecam_value;
+ u8 last_busno;
+ u8 root_busno;
+ struct nwl_msi msi;
+ struct irq_domain *legacy_irq_domain;
+};
+
+static inline u32 nwl_bridge_readl(struct nwl_pcie *pcie, u32 off)
+{
+ return readl(pcie->breg_base + off);
+}
+
+static inline void nwl_bridge_writel(struct nwl_pcie *pcie, u32 val, u32 off)
+{
+ writel(val, pcie->breg_base + off);
+}
+
+static bool nwl_pcie_link_up(struct nwl_pcie *pcie)
+{
+ if (readl(pcie->pcireg_base + PS_LINKUP_OFFSET) & PCIE_PHY_LINKUP_BIT)
+ return true;
+ return false;
+}
+
+static bool nwl_phy_link_up(struct nwl_pcie *pcie)
+{
+ if (readl(pcie->pcireg_base + PS_LINKUP_OFFSET) & PHY_RDY_LINKUP_BIT)
+ return true;
+ return false;
+}
+
+static int nwl_wait_for_link(struct nwl_pcie *pcie)
+{
+ int retries;
+
+ /* check if the link is up or not */
+ for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+ if (nwl_phy_link_up(pcie))
+ return 0;
+ usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+ }
+
+ dev_err(pcie->dev, "PHY link never came up\n");
+ return -ETIMEDOUT;
+}
+
+static bool nwl_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
+{
+ struct nwl_pcie *pcie = bus->sysdata;
+
+ /* Check link before accessing downstream ports */
+ if (bus->number != pcie->root_busno) {
+ if (!nwl_pcie_link_up(pcie))
+ return false;
+ }
+
+ /* Only one device down on each root port */
+ if (bus->number == pcie->root_busno && devfn > 0)
+ return false;
+
+ return true;
+}
+
+/**
+ * nwl_pcie_map_bus - Get configuration base
+ *
+ * @bus: Bus structure of current bus
+ * @devfn: Device/function
+ * @where: Offset from base
+ *
+ * Return: Base address of the configuration space needed to be
+ * accessed.
+ */
+static void __iomem *nwl_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where)
+{
+ struct nwl_pcie *pcie = bus->sysdata;
+ int relbus;
+
+ if (!nwl_pcie_valid_device(bus, devfn))
+ return NULL;
+
+ relbus = (bus->number << ECAM_BUS_LOC_SHIFT) |
+ (devfn << ECAM_DEV_LOC_SHIFT);
+
+ return pcie->ecam_base + relbus + where;
+}
+
+/* PCIe operations */
+static struct pci_ops nwl_pcie_ops = {
+ .map_bus = nwl_pcie_map_bus,
+ .read = pci_generic_config_read,
+ .write = pci_generic_config_write,
+};
+
+static irqreturn_t nwl_pcie_misc_handler(int irq, void *data)
+{
+ struct nwl_pcie *pcie = data;
+ u32 misc_stat;
+
+ /* Checking for misc interrupts */
+ misc_stat = nwl_bridge_readl(pcie, MSGF_MISC_STATUS) &
+ MSGF_MISC_SR_MASKALL;
+ if (!misc_stat)
+ return IRQ_NONE;
+
+ if (misc_stat & MSGF_MISC_SR_RXMSG_OVER)
+ dev_err(pcie->dev, "Received Message FIFO Overflow\n");
+
+ if (misc_stat & MSGF_MISC_SR_SLAVE_ERR)
+ dev_err(pcie->dev, "Slave error\n");
+
+ if (misc_stat & MSGF_MISC_SR_MASTER_ERR)
+ dev_err(pcie->dev, "Master error\n");
+
+ if (misc_stat & MSGF_MISC_SR_I_ADDR_ERR)
+ dev_err(pcie->dev,
+ "In Misc Ingress address translation error\n");
+
+ if (misc_stat & MSGF_MISC_SR_E_ADDR_ERR)
+ dev_err(pcie->dev,
+ "In Misc Egress address translation error\n");
+
+ if (misc_stat & MSGF_MISC_SR_PCIE_CORE_ERR)
+ dev_err(pcie->dev, "PCIe Core error\n");
+
+ /* Clear misc interrupt status */
+ nwl_bridge_writel(pcie, misc_stat, MSGF_MISC_STATUS);
+
+ return IRQ_HANDLED;
+}
+
+static void nwl_pcie_leg_handler(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct nwl_pcie *pcie;
+ unsigned long status;
+ u32 bit;
+ u32 virq;
+
+ chained_irq_enter(chip, desc);
+ pcie = irq_desc_get_handler_data(desc);
+
+ while ((status = nwl_bridge_readl(pcie, MSGF_LEG_STATUS) &
+ MSGF_LEG_SR_MASKALL) != 0) {
+ for_each_set_bit(bit, &status, INTX_NUM) {
+ virq = irq_find_mapping(pcie->legacy_irq_domain,
+ bit + 1);
+ if (virq)
+ generic_handle_irq(virq);
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void nwl_pcie_handle_msi_irq(struct nwl_pcie *pcie, u32 status_reg)
+{
+ struct nwl_msi *msi;
+ unsigned long status;
+ u32 bit;
+ u32 virq;
+
+ msi = &pcie->msi;
+
+ while ((status = nwl_bridge_readl(pcie, status_reg)) != 0) {
+ for_each_set_bit(bit, &status, 32) {
+ nwl_bridge_writel(pcie, 1 << bit, status_reg);
+ virq = irq_find_mapping(msi->dev_domain, bit);
+ if (virq)
+ generic_handle_irq(virq);
+ }
+ }
+}
+
+static void nwl_pcie_msi_handler_high(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct nwl_pcie *pcie = irq_desc_get_handler_data(desc);
+
+ chained_irq_enter(chip, desc);
+ nwl_pcie_handle_msi_irq(pcie, MSGF_MSI_STATUS_HI);
+ chained_irq_exit(chip, desc);
+}
+
+static void nwl_pcie_msi_handler_low(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct nwl_pcie *pcie = irq_desc_get_handler_data(desc);
+
+ chained_irq_enter(chip, desc);
+ nwl_pcie_handle_msi_irq(pcie, MSGF_MSI_STATUS_LO);
+ chained_irq_exit(chip, desc);
+}
+
+static int nwl_legacy_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
+ irq_set_chip_data(irq, domain->host_data);
+
+ return 0;
+}
+
+static const struct irq_domain_ops legacy_domain_ops = {
+ .map = nwl_legacy_map,
+};
+
+#ifdef CONFIG_PCI_MSI
+static struct irq_chip nwl_msi_irq_chip = {
+ .name = "nwl_pcie:msi",
+ .irq_enable = unmask_msi_irq,
+ .irq_disable = mask_msi_irq,
+ .irq_mask = mask_msi_irq,
+ .irq_unmask = unmask_msi_irq,
+
+};
+
+static struct msi_domain_info nwl_msi_domain_info = {
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_MULTI_PCI_MSI),
+ .chip = &nwl_msi_irq_chip,
+};
+#endif
+
+static void nwl_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ struct nwl_pcie *pcie = irq_data_get_irq_chip_data(data);
+ phys_addr_t msi_addr = pcie->phys_pcie_reg_base;
+
+ msg->address_lo = lower_32_bits(msi_addr);
+ msg->address_hi = upper_32_bits(msi_addr);
+ msg->data = data->hwirq;
+}
+
+static int nwl_msi_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
+{
+ return -EINVAL;
+}
+
+static struct irq_chip nwl_irq_chip = {
+ .name = "Xilinx MSI",
+ .irq_compose_msi_msg = nwl_compose_msi_msg,
+ .irq_set_affinity = nwl_msi_set_affinity,
+};
+
+static int nwl_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *args)
+{
+ struct nwl_pcie *pcie = domain->host_data;
+ struct nwl_msi *msi = &pcie->msi;
+ int bit;
+ int i;
+
+ mutex_lock(&msi->lock);
+ bit = bitmap_find_next_zero_area(msi->bitmap, INT_PCI_MSI_NR, 0,
+ nr_irqs, 0);
+ if (bit >= INT_PCI_MSI_NR) {
+ mutex_unlock(&msi->lock);
+ return -ENOSPC;
+ }
+
+ bitmap_set(msi->bitmap, bit, nr_irqs);
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_domain_set_info(domain, virq + i, bit + i, &nwl_irq_chip,
+ domain->host_data, handle_simple_irq,
+ NULL, NULL);
+ }
+ mutex_unlock(&msi->lock);
+ return 0;
+}
+
+static void nwl_irq_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *data = irq_domain_get_irq_data(domain, virq);
+ struct nwl_pcie *pcie = irq_data_get_irq_chip_data(data);
+ struct nwl_msi *msi = &pcie->msi;
+
+ mutex_lock(&msi->lock);
+ bitmap_clear(msi->bitmap, data->hwirq, nr_irqs);
+ mutex_unlock(&msi->lock);
+}
+
+static const struct irq_domain_ops dev_msi_domain_ops = {
+ .alloc = nwl_irq_domain_alloc,
+ .free = nwl_irq_domain_free,
+};
+
+static void nwl_msi_free_irq_domain(struct nwl_pcie *pcie)
+{
+ struct nwl_msi *msi = &pcie->msi;
+
+ if (msi->irq_msi0)
+ irq_set_chained_handler_and_data(msi->irq_msi0, NULL, NULL);
+ if (msi->irq_msi1)
+ irq_set_chained_handler_and_data(msi->irq_msi1, NULL, NULL);
+
+ if (msi->msi_domain)
+ irq_domain_remove(msi->msi_domain);
+ if (msi->dev_domain)
+ irq_domain_remove(msi->dev_domain);
+
+ kfree(msi->bitmap);
+ msi->bitmap = NULL;
+}
+
+static void nwl_pcie_free_irq_domain(struct nwl_pcie *pcie)
+{
+ int i;
+ u32 irq;
+
+ for (i = 0; i < INTX_NUM; i++) {
+ irq = irq_find_mapping(pcie->legacy_irq_domain, i + 1);
+ if (irq > 0)
+ irq_dispose_mapping(irq);
+ }
+ if (pcie->legacy_irq_domain)
+ irq_domain_remove(pcie->legacy_irq_domain);
+
+ nwl_msi_free_irq_domain(pcie);
+}
+
+static int nwl_pcie_init_msi_irq_domain(struct nwl_pcie *pcie)
+{
+#ifdef CONFIG_PCI_MSI
+ struct fwnode_handle *fwnode = of_node_to_fwnode(pcie->dev->of_node);
+ struct nwl_msi *msi = &pcie->msi;
+
+ msi->dev_domain = irq_domain_add_linear(NULL, INT_PCI_MSI_NR,
+ &dev_msi_domain_ops, pcie);
+ if (!msi->dev_domain) {
+ dev_err(pcie->dev, "failed to create dev IRQ domain\n");
+ return -ENOMEM;
+ }
+ msi->msi_domain = pci_msi_create_irq_domain(fwnode,
+ &nwl_msi_domain_info,
+ msi->dev_domain);
+ if (!msi->msi_domain) {
+ dev_err(pcie->dev, "failed to create msi IRQ domain\n");
+ irq_domain_remove(msi->dev_domain);
+ return -ENOMEM;
+ }
+#endif
+ return 0;
+}
+
+static int nwl_pcie_init_irq_domain(struct nwl_pcie *pcie)
+{
+ struct device_node *node = pcie->dev->of_node;
+ struct device_node *legacy_intc_node;
+
+ legacy_intc_node = of_get_next_child(node, NULL);
+ if (!legacy_intc_node) {
+ dev_err(pcie->dev, "No legacy intc node found\n");
+ return -EINVAL;
+ }
+
+ pcie->legacy_irq_domain = irq_domain_add_linear(legacy_intc_node,
+ INTX_NUM,
+ &legacy_domain_ops,
+ pcie);
+
+ if (!pcie->legacy_irq_domain) {
+ dev_err(pcie->dev, "failed to create IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ nwl_pcie_init_msi_irq_domain(pcie);
+ return 0;
+}
+
+static int nwl_pcie_enable_msi(struct nwl_pcie *pcie, struct pci_bus *bus)
+{
+ struct platform_device *pdev = to_platform_device(pcie->dev);
+ struct nwl_msi *msi = &pcie->msi;
+ unsigned long base;
+ int ret;
+ int size = BITS_TO_LONGS(INT_PCI_MSI_NR) * sizeof(long);
+
+ mutex_init(&msi->lock);
+
+ msi->bitmap = kzalloc(size, GFP_KERNEL);
+ if (!msi->bitmap)
+ return -ENOMEM;
+
+ /* Get msi_1 IRQ number */
+ msi->irq_msi1 = platform_get_irq_byname(pdev, "msi1");
+ if (msi->irq_msi1 < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ#%d\n", msi->irq_msi1);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ irq_set_chained_handler_and_data(msi->irq_msi1,
+ nwl_pcie_msi_handler_high, pcie);
+
+ /* Get msi_0 IRQ number */
+ msi->irq_msi0 = platform_get_irq_byname(pdev, "msi0");
+ if (msi->irq_msi0 < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ#%d\n", msi->irq_msi0);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ irq_set_chained_handler_and_data(msi->irq_msi0,
+ nwl_pcie_msi_handler_low, pcie);
+
+ /* Check for msii_present bit */
+ ret = nwl_bridge_readl(pcie, I_MSII_CAPABILITIES) & MSII_PRESENT;
+ if (!ret) {
+ dev_err(pcie->dev, "MSI not present\n");
+ ret = -EIO;
+ goto err;
+ }
+
+ /* Enable MSII */
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, I_MSII_CONTROL) |
+ MSII_ENABLE, I_MSII_CONTROL);
+
+ /* Enable MSII status */
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, I_MSII_CONTROL) |
+ MSII_STATUS_ENABLE, I_MSII_CONTROL);
+
+ /* setup AFI/FPCI range */
+ base = pcie->phys_pcie_reg_base;
+ nwl_bridge_writel(pcie, lower_32_bits(base), I_MSII_BASE_LO);
+ nwl_bridge_writel(pcie, upper_32_bits(base), I_MSII_BASE_HI);
+
+ /*
+ * For high range MSI interrupts: disable, clear any pending,
+ * and enable
+ */
+ nwl_bridge_writel(pcie, (u32)~MSGF_MSI_SR_HI_MASK, MSGF_MSI_MASK_HI);
+
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, MSGF_MSI_STATUS_HI) &
+ MSGF_MSI_SR_HI_MASK, MSGF_MSI_STATUS_HI);
+
+ nwl_bridge_writel(pcie, MSGF_MSI_SR_HI_MASK, MSGF_MSI_MASK_HI);
+
+ /*
+ * For low range MSI interrupts: disable, clear any pending,
+ * and enable
+ */
+ nwl_bridge_writel(pcie, (u32)~MSGF_MSI_SR_LO_MASK, MSGF_MSI_MASK_LO);
+
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, MSGF_MSI_STATUS_LO) &
+ MSGF_MSI_SR_LO_MASK, MSGF_MSI_STATUS_LO);
+
+ nwl_bridge_writel(pcie, MSGF_MSI_SR_LO_MASK, MSGF_MSI_MASK_LO);
+
+ return 0;
+err:
+ kfree(msi->bitmap);
+ msi->bitmap = NULL;
+ return ret;
+}
+
+static int nwl_pcie_bridge_init(struct nwl_pcie *pcie)
+{
+ struct platform_device *pdev = to_platform_device(pcie->dev);
+ u32 breg_val, ecam_val, first_busno = 0;
+ int err;
+
+ breg_val = nwl_bridge_readl(pcie, E_BREG_CAPABILITIES) & BREG_PRESENT;
+ if (!breg_val) {
+ dev_err(pcie->dev, "BREG is not present\n");
+ return breg_val;
+ }
+
+ /* Write bridge_off to breg base */
+ nwl_bridge_writel(pcie, lower_32_bits(pcie->phys_breg_base),
+ E_BREG_BASE_LO);
+ nwl_bridge_writel(pcie, upper_32_bits(pcie->phys_breg_base),
+ E_BREG_BASE_HI);
+
+ /* Enable BREG */
+ nwl_bridge_writel(pcie, ~BREG_ENABLE_FORCE & BREG_ENABLE,
+ E_BREG_CONTROL);
+
+ /* Disable DMA channel registers */
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, BRCFG_PCIE_RX0) |
+ CFG_DMA_REG_BAR, BRCFG_PCIE_RX0);
+
+ /* Enable Ingress subtractive decode translation */
+ nwl_bridge_writel(pcie, SET_ISUB_CONTROL, I_ISUB_CONTROL);
+
+ /* Enable msg filtering details */
+ nwl_bridge_writel(pcie, CFG_ENABLE_MSG_FILTER_MASK,
+ BRCFG_PCIE_RX_MSG_FILTER);
+
+ err = nwl_wait_for_link(pcie);
+ if (err)
+ return err;
+
+ ecam_val = nwl_bridge_readl(pcie, E_ECAM_CAPABILITIES) & E_ECAM_PRESENT;
+ if (!ecam_val) {
+ dev_err(pcie->dev, "ECAM is not present\n");
+ return ecam_val;
+ }
+
+ /* Enable ECAM */
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, E_ECAM_CONTROL) |
+ E_ECAM_CR_ENABLE, E_ECAM_CONTROL);
+
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, E_ECAM_CONTROL) |
+ (pcie->ecam_value << E_ECAM_SIZE_SHIFT),
+ E_ECAM_CONTROL);
+
+ nwl_bridge_writel(pcie, lower_32_bits(pcie->phys_ecam_base),
+ E_ECAM_BASE_LO);
+ nwl_bridge_writel(pcie, upper_32_bits(pcie->phys_ecam_base),
+ E_ECAM_BASE_HI);
+
+ /* Get bus range */
+ ecam_val = nwl_bridge_readl(pcie, E_ECAM_CONTROL);
+ pcie->last_busno = (ecam_val & E_ECAM_SIZE_LOC) >> E_ECAM_SIZE_SHIFT;
+ /* Write primary, secondary and subordinate bus numbers */
+ ecam_val = first_busno;
+ ecam_val |= (first_busno + 1) << 8;
+ ecam_val |= (pcie->last_busno << E_ECAM_SIZE_SHIFT);
+ writel(ecam_val, (pcie->ecam_base + PCI_PRIMARY_BUS));
+
+ if (nwl_pcie_link_up(pcie))
+ dev_info(pcie->dev, "Link is UP\n");
+ else
+ dev_info(pcie->dev, "Link is DOWN\n");
+
+ /* Get misc IRQ number */
+ pcie->irq_misc = platform_get_irq_byname(pdev, "misc");
+ if (pcie->irq_misc < 0) {
+ dev_err(&pdev->dev, "failed to get misc IRQ %d\n",
+ pcie->irq_misc);
+ return -EINVAL;
+ }
+
+ err = devm_request_irq(pcie->dev, pcie->irq_misc,
+ nwl_pcie_misc_handler, IRQF_SHARED,
+ "nwl_pcie:misc", pcie);
+ if (err) {
+ dev_err(pcie->dev, "fail to register misc IRQ#%d\n",
+ pcie->irq_misc);
+ return err;
+ }
+
+ /* Disable all misc interrupts */
+ nwl_bridge_writel(pcie, (u32)~MSGF_MISC_SR_MASKALL, MSGF_MISC_MASK);
+
+ /* Clear pending misc interrupts */
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, MSGF_MISC_STATUS) &
+ MSGF_MISC_SR_MASKALL, MSGF_MISC_STATUS);
+
+ /* Enable all misc interrupts */
+ nwl_bridge_writel(pcie, MSGF_MISC_SR_MASKALL, MSGF_MISC_MASK);
+
+
+ /* Disable all legacy interrupts */
+ nwl_bridge_writel(pcie, (u32)~MSGF_LEG_SR_MASKALL, MSGF_LEG_MASK);
+
+ /* Clear pending legacy interrupts */
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, MSGF_LEG_STATUS) &
+ MSGF_LEG_SR_MASKALL, MSGF_LEG_STATUS);
+
+ /* Enable all legacy interrupts */
+ nwl_bridge_writel(pcie, MSGF_LEG_SR_MASKALL, MSGF_LEG_MASK);
+
+ /* Enable the bridge config interrupt */
+ nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, BRCFG_INTERRUPT) |
+ BRCFG_INTERRUPT_MASK, BRCFG_INTERRUPT);
+
+ return 0;
+}
+
+static int nwl_pcie_parse_dt(struct nwl_pcie *pcie,
+ struct platform_device *pdev)
+{
+ struct device_node *node = pcie->dev->of_node;
+ struct resource *res;
+ const char *type;
+
+ /* Check for device type */
+ type = of_get_property(node, "device_type", NULL);
+ if (!type || strcmp(type, "pci")) {
+ dev_err(pcie->dev, "invalid \"device_type\" %s\n", type);
+ return -EINVAL;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "breg");
+ pcie->breg_base = devm_ioremap_resource(pcie->dev, res);
+ if (IS_ERR(pcie->breg_base))
+ return PTR_ERR(pcie->breg_base);
+ pcie->phys_breg_base = res->start;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcireg");
+ pcie->pcireg_base = devm_ioremap_resource(pcie->dev, res);
+ if (IS_ERR(pcie->pcireg_base))
+ return PTR_ERR(pcie->pcireg_base);
+ pcie->phys_pcie_reg_base = res->start;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+ pcie->ecam_base = devm_ioremap_resource(pcie->dev, res);
+ if (IS_ERR(pcie->ecam_base))
+ return PTR_ERR(pcie->ecam_base);
+ pcie->phys_ecam_base = res->start;
+
+ /* Get intx IRQ number */
+ pcie->irq_intx = platform_get_irq_byname(pdev, "intx");
+ if (pcie->irq_intx < 0) {
+ dev_err(&pdev->dev, "failed to get intx IRQ %d\n",
+ pcie->irq_intx);
+ return -EINVAL;
+ }
+
+ irq_set_chained_handler_and_data(pcie->irq_intx,
+ nwl_pcie_leg_handler, pcie);
+
+ return 0;
+}
+
+static const struct of_device_id nwl_pcie_of_match[] = {
+ { .compatible = "xlnx,nwl-pcie-2.11", },
+ {}
+};
+
+static int nwl_pcie_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct nwl_pcie *pcie;
+ struct pci_bus *bus;
+ struct pci_bus *child;
+ int err;
+ resource_size_t iobase = 0;
+ LIST_HEAD(res);
+
+ pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie->dev = &pdev->dev;
+ pcie->ecam_value = NWL_ECAM_VALUE_DEFAULT;
+
+ err = nwl_pcie_parse_dt(pcie, pdev);
+ if (err) {
+ dev_err(pcie->dev, "Parsing DT failed\n");
+ return err;
+ }
+
+ err = nwl_pcie_bridge_init(pcie);
+ if (err) {
+ dev_err(pcie->dev, "HW Initalization failed\n");
+ return err;
+ }
+
+ err = of_pci_get_host_bridge_resources(node, 0, 0xff, &res, &iobase);
+ if (err) {
+ pr_err("Getting bridge resources failed\n");
+ return err;
+ }
+
+ err = nwl_pcie_init_irq_domain(pcie);
+ if (err) {
+ dev_err(pcie->dev, "Failed creating IRQ Domain\n");
+ return err;
+ }
+
+ bus = pci_create_root_bus(&pdev->dev, pcie->root_busno,
+ &nwl_pcie_ops, pcie, &res);
+ if (!bus)
+ return -ENOMEM;
+
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ err = nwl_pcie_enable_msi(pcie, bus);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "failed to enable MSI support: %d\n", err);
+ return err;
+ }
+ }
+ pci_scan_child_bus(bus);
+ pci_assign_unassigned_bus_resources(bus);
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
+ pci_bus_add_devices(bus);
+ platform_set_drvdata(pdev, pcie);
+ return 0;
+}
+
+static int nwl_pcie_remove(struct platform_device *pdev)
+{
+ struct nwl_pcie *pcie = platform_get_drvdata(pdev);
+
+ nwl_pcie_free_irq_domain(pcie);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver nwl_pcie_driver = {
+ .driver = {
+ .name = "nwl-pcie",
+ .of_match_table = nwl_pcie_of_match,
+ },
+ .probe = nwl_pcie_probe,
+ .remove = nwl_pcie_remove,
+};
+module_platform_driver(nwl_pcie_driver);
+
+MODULE_AUTHOR("Xilinx, Inc");
+MODULE_DESCRIPTION("NWL PCIe driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c
index 4cfa46360d12..65f0fe0c2eaf 100644
--- a/drivers/pci/host/pcie-xilinx.c
+++ b/drivers/pci/host/pcie-xilinx.c
@@ -94,9 +94,6 @@
/* Number of MSI IRQs */
#define XILINX_NUM_MSI_IRQS 128
-/* Number of Memory Resources */
-#define XILINX_MAX_NUM_RESOURCES 3
-
/**
* struct xilinx_pcie_port - PCIe port information
* @reg_base: IO Mapped Register Base
@@ -105,7 +102,6 @@
* @root_busno: Root Bus number
* @dev: Device pointer
* @irq_domain: IRQ domain pointer
- * @bus_range: Bus range
* @resources: Bus Resources
*/
struct xilinx_pcie_port {
@@ -115,17 +111,11 @@ struct xilinx_pcie_port {
u8 root_busno;
struct device *dev;
struct irq_domain *irq_domain;
- struct resource bus_range;
struct list_head resources;
};
static DECLARE_BITMAP(msi_irq_in_use, XILINX_NUM_MSI_IRQS);
-static inline struct xilinx_pcie_port *sys_to_pcie(struct pci_sys_data *sys)
-{
- return sys->private_data;
-}
-
static inline u32 pcie_read(struct xilinx_pcie_port *port, u32 reg)
{
return readl(port->reg_base + reg);
@@ -167,7 +157,7 @@ static void xilinx_pcie_clear_err_interrupts(struct xilinx_pcie_port *port)
*/
static bool xilinx_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
{
- struct xilinx_pcie_port *port = sys_to_pcie(bus->sysdata);
+ struct xilinx_pcie_port *port = bus->sysdata;
/* Check if link is up when trying to access downstream ports */
if (bus->number != port->root_busno)
@@ -200,7 +190,7 @@ static bool xilinx_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
static void __iomem *xilinx_pcie_map_bus(struct pci_bus *bus,
unsigned int devfn, int where)
{
- struct xilinx_pcie_port *port = sys_to_pcie(bus->sysdata);
+ struct xilinx_pcie_port *port = bus->sysdata;
int relbus;
if (!xilinx_pcie_valid_device(bus, devfn))
@@ -232,7 +222,7 @@ static void xilinx_pcie_destroy_msi(unsigned int irq)
if (!test_bit(irq, msi_irq_in_use)) {
msi = irq_get_msi_desc(irq);
- port = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+ port = msi_desc_to_pci_sysdata(msi);
dev_err(port->dev, "Trying to free unused MSI#%d\n", irq);
} else {
clear_bit(irq, msi_irq_in_use);
@@ -281,7 +271,7 @@ static int xilinx_pcie_msi_setup_irq(struct msi_controller *chip,
struct pci_dev *pdev,
struct msi_desc *desc)
{
- struct xilinx_pcie_port *port = sys_to_pcie(pdev->bus->sysdata);
+ struct xilinx_pcie_port *port = pdev->bus->sysdata;
unsigned int irq;
int hwirq;
struct msi_msg msg;
@@ -618,138 +608,6 @@ static void xilinx_pcie_init_port(struct xilinx_pcie_port *port)
}
/**
- * xilinx_pcie_setup - Setup memory resources
- * @nr: Bus number
- * @sys: Per controller structure
- *
- * Return: '1' on success and error value on failure
- */
-static int xilinx_pcie_setup(int nr, struct pci_sys_data *sys)
-{
- struct xilinx_pcie_port *port = sys_to_pcie(sys);
-
- list_splice_init(&port->resources, &sys->resources);
-
- return 1;
-}
-
-/**
- * xilinx_pcie_scan_bus - Scan PCIe bus for devices
- * @nr: Bus number
- * @sys: Per controller structure
- *
- * Return: Valid Bus pointer on success and NULL on failure
- */
-static struct pci_bus *xilinx_pcie_scan_bus(int nr, struct pci_sys_data *sys)
-{
- struct xilinx_pcie_port *port = sys_to_pcie(sys);
- struct pci_bus *bus;
-
- port->root_busno = sys->busnr;
-
- if (IS_ENABLED(CONFIG_PCI_MSI))
- bus = pci_scan_root_bus_msi(port->dev, sys->busnr,
- &xilinx_pcie_ops, sys,
- &sys->resources,
- &xilinx_pcie_msi_chip);
- else
- bus = pci_scan_root_bus(port->dev, sys->busnr,
- &xilinx_pcie_ops, sys, &sys->resources);
- return bus;
-}
-
-/**
- * xilinx_pcie_parse_and_add_res - Add resources by parsing ranges
- * @port: PCIe port information
- *
- * Return: '0' on success and error value on failure
- */
-static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port)
-{
- struct device *dev = port->dev;
- struct device_node *node = dev->of_node;
- struct resource *mem;
- resource_size_t offset;
- struct of_pci_range_parser parser;
- struct of_pci_range range;
- struct resource_entry *win;
- int err = 0, mem_resno = 0;
-
- /* Get the ranges */
- if (of_pci_range_parser_init(&parser, node)) {
- dev_err(dev, "missing \"ranges\" property\n");
- return -EINVAL;
- }
-
- /* Parse the ranges and add the resources found to the list */
- for_each_of_pci_range(&parser, &range) {
-
- if (mem_resno >= XILINX_MAX_NUM_RESOURCES) {
- dev_err(dev, "Maximum memory resources exceeded\n");
- return -EINVAL;
- }
-
- mem = devm_kmalloc(dev, sizeof(*mem), GFP_KERNEL);
- if (!mem) {
- err = -ENOMEM;
- goto free_resources;
- }
-
- of_pci_range_to_resource(&range, node, mem);
-
- switch (mem->flags & IORESOURCE_TYPE_BITS) {
- case IORESOURCE_MEM:
- offset = range.cpu_addr - range.pci_addr;
- mem_resno++;
- break;
- default:
- err = -EINVAL;
- break;
- }
-
- if (err < 0) {
- dev_warn(dev, "Invalid resource found %pR\n", mem);
- continue;
- }
-
- err = request_resource(&iomem_resource, mem);
- if (err)
- goto free_resources;
-
- pci_add_resource_offset(&port->resources, mem, offset);
- }
-
- /* Get the bus range */
- if (of_pci_parse_bus_range(node, &port->bus_range)) {
- u32 val = pcie_read(port, XILINX_PCIE_REG_BIR);
- u8 last;
-
- last = (val & XILINX_PCIE_BIR_ECAM_SZ_MASK) >>
- XILINX_PCIE_BIR_ECAM_SZ_SHIFT;
-
- port->bus_range = (struct resource) {
- .name = node->name,
- .start = 0,
- .end = last,
- .flags = IORESOURCE_BUS,
- };
- }
-
- /* Register bus resource */
- pci_add_resource(&port->resources, &port->bus_range);
-
- return 0;
-
-free_resources:
- release_child_resources(&iomem_resource);
- resource_list_for_each_entry(win, &port->resources)
- devm_kfree(dev, win->res);
- pci_free_resource_list(&port->resources);
-
- return err;
-}
-
-/**
* xilinx_pcie_parse_dt - Parse Device tree
* @port: PCIe port information
*
@@ -800,9 +658,12 @@ static int xilinx_pcie_parse_dt(struct xilinx_pcie_port *port)
static int xilinx_pcie_probe(struct platform_device *pdev)
{
struct xilinx_pcie_port *port;
- struct hw_pci hw;
struct device *dev = &pdev->dev;
+ struct pci_bus *bus;
+
int err;
+ resource_size_t iobase = 0;
+ LIST_HEAD(res);
if (!dev->of_node)
return -ENODEV;
@@ -827,34 +688,28 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
return err;
}
- /*
- * Parse PCI ranges, configuration bus range and
- * request their resources
- */
- INIT_LIST_HEAD(&port->resources);
- err = xilinx_pcie_parse_and_add_res(port);
+ err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff, &res,
+ &iobase);
if (err) {
- dev_err(dev, "Failed adding resources\n");
+ dev_err(dev, "Getting bridge resources failed\n");
return err;
}
-
- platform_set_drvdata(pdev, port);
-
- /* Register the device */
- memset(&hw, 0, sizeof(hw));
- hw = (struct hw_pci) {
- .nr_controllers = 1,
- .private_data = (void **)&port,
- .setup = xilinx_pcie_setup,
- .map_irq = of_irq_parse_and_map_pci,
- .scan = xilinx_pcie_scan_bus,
- .ops = &xilinx_pcie_ops,
- };
+ bus = pci_create_root_bus(&pdev->dev, 0,
+ &xilinx_pcie_ops, port, &res);
+ if (!bus)
+ return -ENOMEM;
#ifdef CONFIG_PCI_MSI
xilinx_pcie_msi_chip.dev = port->dev;
+ bus->msi = &xilinx_pcie_msi_chip;
#endif
- pci_common_init_dev(dev, &hw);
+ pci_scan_child_bus(bus);
+ pci_assign_unassigned_bus_resources(bus);
+#ifndef CONFIG_MICROBLAZE
+ pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
+#endif
+ pci_bus_add_devices(bus);
+ platform_set_drvdata(pdev, port);
return 0;
}
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c
index eb5efaef06ea..50b8b7d54416 100644
--- a/drivers/pci/hotplug/s390_pci_hpc.c
+++ b/drivers/pci/hotplug/s390_pci_hpc.c
@@ -93,13 +93,17 @@ out_deconfigure:
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
+ struct pci_dev *pdev;
int rc;
if (!zpci_fn_configured(slot->zdev->state))
return -EIO;
- if (slot->zdev->pdev)
- pci_stop_and_remove_bus_device_locked(slot->zdev->pdev);
+ pdev = pci_get_slot(slot->zdev->bus, ZPCI_DEVFN);
+ if (pdev) {
+ pci_stop_and_remove_bus_device_locked(pdev);
+ pci_dev_put(pdev);
+ }
rc = zpci_disable_device(slot->zdev);
if (rc)
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 31f31d460fc9..fe4bd0aa91a6 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -387,10 +387,6 @@ static int sriov_init(struct pci_dev *dev, int pos)
struct resource *res;
struct pci_dev *pdev;
- if (pci_pcie_type(dev) != PCI_EXP_TYPE_RC_END &&
- pci_pcie_type(dev) != PCI_EXP_TYPE_ENDPOINT)
- return -ENODEV;
-
pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
if (ctrl & PCI_SRIOV_CTRL_VFE) {
pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0);
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
index 0ae74d96ed85..51357377efbc 100644
--- a/drivers/pci/pci-label.c
+++ b/drivers/pci/pci-label.c
@@ -16,7 +16,7 @@
* the instance number and string from the type 41 record and exports
* it to sysfs.
*
- * Please see http://linux.dell.com/wiki/index.php/Oss/libnetdevname for more
+ * Please see http://linux.dell.com/files/biosdevname/ for more
* information.
*/
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 95d9e7bd933b..e982010f0ed1 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -769,10 +769,12 @@ static ssize_t read_vpd_attr(struct file *filp, struct kobject *kobj,
{
struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
- if (off > bin_attr->size)
- count = 0;
- else if (count > bin_attr->size - off)
- count = bin_attr->size - off;
+ if (bin_attr->size > 0) {
+ if (off > bin_attr->size)
+ count = 0;
+ else if (count > bin_attr->size - off)
+ count = bin_attr->size - off;
+ }
return pci_read_vpd(dev, off, count, buf);
}
@@ -783,10 +785,12 @@ static ssize_t write_vpd_attr(struct file *filp, struct kobject *kobj,
{
struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
- if (off > bin_attr->size)
- count = 0;
- else if (count > bin_attr->size - off)
- count = bin_attr->size - off;
+ if (bin_attr->size > 0) {
+ if (off > bin_attr->size)
+ count = 0;
+ else if (count > bin_attr->size - off)
+ count = bin_attr->size - off;
+ }
return pci_write_vpd(dev, off, count, buf);
}
@@ -1134,33 +1138,36 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
/* allocate attribute structure, piggyback attribute name */
int name_len = write_combine ? 13 : 10;
struct bin_attribute *res_attr;
+ char *res_attr_name;
int retval;
res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC);
- if (res_attr) {
- char *res_attr_name = (char *)(res_attr + 1);
-
- sysfs_bin_attr_init(res_attr);
- if (write_combine) {
- pdev->res_attr_wc[num] = res_attr;
- sprintf(res_attr_name, "resource%d_wc", num);
- res_attr->mmap = pci_mmap_resource_wc;
- } else {
- pdev->res_attr[num] = res_attr;
- sprintf(res_attr_name, "resource%d", num);
- res_attr->mmap = pci_mmap_resource_uc;
- }
- if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
- res_attr->read = pci_read_resource_io;
- res_attr->write = pci_write_resource_io;
- }
- res_attr->attr.name = res_attr_name;
- res_attr->attr.mode = S_IRUSR | S_IWUSR;
- res_attr->size = pci_resource_len(pdev, num);
- res_attr->private = &pdev->resource[num];
- retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
- } else
- retval = -ENOMEM;
+ if (!res_attr)
+ return -ENOMEM;
+
+ res_attr_name = (char *)(res_attr + 1);
+
+ sysfs_bin_attr_init(res_attr);
+ if (write_combine) {
+ pdev->res_attr_wc[num] = res_attr;
+ sprintf(res_attr_name, "resource%d_wc", num);
+ res_attr->mmap = pci_mmap_resource_wc;
+ } else {
+ pdev->res_attr[num] = res_attr;
+ sprintf(res_attr_name, "resource%d", num);
+ res_attr->mmap = pci_mmap_resource_uc;
+ }
+ if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
+ res_attr->read = pci_read_resource_io;
+ res_attr->write = pci_write_resource_io;
+ }
+ res_attr->attr.name = res_attr_name;
+ res_attr->attr.mode = S_IRUSR | S_IWUSR;
+ res_attr->size = pci_resource_len(pdev, num);
+ res_attr->private = &pdev->resource[num];
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
+ if (retval)
+ kfree(res_attr);
return retval;
}
@@ -1319,7 +1326,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
return -ENOMEM;
sysfs_bin_attr_init(attr);
- attr->size = dev->vpd->len;
+ attr->size = 0;
attr->attr.name = "vpd";
attr->attr.mode = S_IRUSR | S_IWUSR;
attr->read = read_vpd_attr;
@@ -1356,7 +1363,7 @@ error:
int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
{
int retval;
- int rom_size = 0;
+ int rom_size;
struct bin_attribute *attr;
if (!sysfs_initialized)
@@ -1373,12 +1380,8 @@ int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
if (retval)
goto err_config_file;
- if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
- rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
- else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
- rom_size = 0x20000;
-
/* If the device has a ROM, try to expose it in sysfs. */
+ rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
if (rom_size) {
attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
if (!attr) {
@@ -1409,7 +1412,7 @@ int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
return 0;
err_rom_file:
- if (rom_size) {
+ if (pdev->rom_attr) {
sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
kfree(pdev->rom_attr);
pdev->rom_attr = NULL;
@@ -1447,8 +1450,6 @@ static void pci_remove_capabilities_sysfs(struct pci_dev *dev)
*/
void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
{
- int rom_size = 0;
-
if (!sysfs_initialized)
return;
@@ -1461,18 +1462,13 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
pci_remove_resource_files(pdev);
- if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
- rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
- else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
- rom_size = 0x20000;
-
- if (rom_size && pdev->rom_attr) {
+ if (pdev->rom_attr) {
sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
kfree(pdev->rom_attr);
+ pdev->rom_attr = NULL;
}
pci_remove_firmware_label_files(pdev);
-
}
static int __init pci_sysfs_init(void)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 602eb4223510..25e0327d4429 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -25,7 +25,6 @@
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/pci_hotplug.h>
-#include <asm-generic/pci-bridge.h>
#include <asm/setup.h>
#include <linux/aer.h>
#include "pci.h"
@@ -3386,18 +3385,6 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
-int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size)
-{
- return dma_set_max_seg_size(&dev->dev, size);
-}
-EXPORT_SYMBOL(pci_set_dma_max_seg_size);
-
-int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
-{
- return dma_set_seg_boundary(&dev->dev, mask);
-}
-EXPORT_SYMBOL(pci_set_dma_seg_boundary);
-
/**
* pci_wait_for_pending_transaction - waits for pending transaction
* @dev: the PCI device to operate on
@@ -3414,6 +3401,29 @@ int pci_wait_for_pending_transaction(struct pci_dev *dev)
}
EXPORT_SYMBOL(pci_wait_for_pending_transaction);
+/*
+ * We should only need to wait 100ms after FLR, but some devices take longer.
+ * Wait for up to 1000ms for config space to return something other than -1.
+ * Intel IGD requires this when an LCD panel is attached. We read the 2nd
+ * dword because VFs don't implement the 1st dword.
+ */
+static void pci_flr_wait(struct pci_dev *dev)
+{
+ int i = 0;
+ u32 id;
+
+ do {
+ msleep(100);
+ pci_read_config_dword(dev, PCI_COMMAND, &id);
+ } while (i++ < 10 && id == ~0);
+
+ if (id == ~0)
+ dev_warn(&dev->dev, "Failed to return from FLR\n");
+ else if (i > 1)
+ dev_info(&dev->dev, "Required additional %dms to return from FLR\n",
+ (i - 1) * 100);
+}
+
static int pcie_flr(struct pci_dev *dev, int probe)
{
u32 cap;
@@ -3429,7 +3439,7 @@ static int pcie_flr(struct pci_dev *dev, int probe)
dev_err(&dev->dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
- msleep(100);
+ pci_flr_wait(dev);
return 0;
}
@@ -3459,7 +3469,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
dev_err(&dev->dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
- msleep(100);
+ pci_flr_wait(dev);
return 0;
}
@@ -4772,8 +4782,10 @@ int pci_get_new_domain_nr(void)
void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
{
static int use_dt_domains = -1;
- int domain = of_get_pci_domain_nr(parent->of_node);
+ int domain = -1;
+ if (parent)
+ domain = of_get_pci_domain_nr(parent->of_node);
/*
* Check DT domain and use_dt_domains values.
*
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9a1660f592ef..d0fb93481573 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -97,21 +97,21 @@ static inline bool pci_has_subordinate(struct pci_dev *pci_dev)
struct pci_vpd_ops {
ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
- void (*release)(struct pci_dev *dev);
};
struct pci_vpd {
- unsigned int len;
const struct pci_vpd_ops *ops;
struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
+ struct mutex lock;
+ unsigned int len;
+ u16 flag;
+ u8 cap;
+ u8 busy:1;
+ u8 valid:1;
};
-int pci_vpd_pci22_init(struct pci_dev *dev);
-static inline void pci_vpd_release(struct pci_dev *dev)
-{
- if (dev->vpd)
- dev->vpd->ops->release(dev);
-}
+int pci_vpd_init(struct pci_dev *dev);
+void pci_vpd_release(struct pci_dev *dev);
/* PCI /proc functions */
#ifdef CONFIG_PROC_FS
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index e294713c8143..72db7f4209ca 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -44,6 +44,7 @@ config PCIEASPM
/sys/module/pcie_aspm/parameters/policy
When in doubt, say Y.
+
config PCIEASPM_DEBUG
bool "Debug PCI Express ASPM"
depends on PCIEASPM
@@ -58,20 +59,20 @@ choice
depends on PCIEASPM
config PCIEASPM_DEFAULT
- bool "BIOS default"
+ bool "BIOS default"
depends on PCIEASPM
help
Use the BIOS defaults for PCI Express ASPM.
config PCIEASPM_POWERSAVE
- bool "Powersave"
+ bool "Powersave"
depends on PCIEASPM
help
Enable PCI Express ASPM L0s and L1 where possible, even if the
BIOS did not.
config PCIEASPM_PERFORMANCE
- bool "Performance"
+ bool "Performance"
depends on PCIEASPM
help
Disable PCI Express ASPM L0s and L1, even if the BIOS enabled them.
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c
index 20db790465dd..db553dc22c8e 100644
--- a/drivers/pci/pcie/aer/aer_inject.c
+++ b/drivers/pci/pcie/aer/aer_inject.c
@@ -25,6 +25,7 @@
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/stddef.h>
+#include <linux/device.h>
#include "aerdrv.h"
/* Override the existing corrected and uncorrected error masks */
@@ -124,16 +125,13 @@ static struct pci_ops *__find_pci_bus_ops(struct pci_bus *bus)
static struct pci_bus_ops *pci_bus_ops_pop(void)
{
unsigned long flags;
- struct pci_bus_ops *bus_ops = NULL;
+ struct pci_bus_ops *bus_ops;
spin_lock_irqsave(&inject_lock, flags);
- if (list_empty(&pci_bus_ops_list))
- bus_ops = NULL;
- else {
- struct list_head *lh = pci_bus_ops_list.next;
- list_del(lh);
- bus_ops = list_entry(lh, struct pci_bus_ops, list);
- }
+ bus_ops = list_first_entry_or_null(&pci_bus_ops_list,
+ struct pci_bus_ops, list);
+ if (bus_ops)
+ list_del(&bus_ops->list);
spin_unlock_irqrestore(&inject_lock, flags);
return bus_ops;
}
@@ -181,14 +179,16 @@ static u32 *find_pci_config_dword(struct aer_error *err, int where,
return target;
}
-static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 *val)
+static int aer_inj_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
{
u32 *sim;
struct aer_error *err;
unsigned long flags;
struct pci_ops *ops;
+ struct pci_ops *my_ops;
int domain;
+ int rv;
spin_lock_irqsave(&inject_lock, flags);
if (size != sizeof(u32))
@@ -208,19 +208,32 @@ static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where,
}
out:
ops = __find_pci_bus_ops(bus);
+ /*
+ * pci_lock must already be held, so we can directly
+ * manipulate bus->ops. Many config access functions,
+ * including pci_generic_config_read() require the original
+ * bus->ops be installed to function, so temporarily put them
+ * back.
+ */
+ my_ops = bus->ops;
+ bus->ops = ops;
+ rv = ops->read(bus, devfn, where, size, val);
+ bus->ops = my_ops;
spin_unlock_irqrestore(&inject_lock, flags);
- return ops->read(bus, devfn, where, size, val);
+ return rv;
}
-static int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 val)
+static int aer_inj_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
{
u32 *sim;
struct aer_error *err;
unsigned long flags;
int rw1cs;
struct pci_ops *ops;
+ struct pci_ops *my_ops;
int domain;
+ int rv;
spin_lock_irqsave(&inject_lock, flags);
if (size != sizeof(u32))
@@ -243,13 +256,24 @@ static int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where,
}
out:
ops = __find_pci_bus_ops(bus);
+ /*
+ * pci_lock must already be held, so we can directly
+ * manipulate bus->ops. Many config access functions,
+ * including pci_generic_config_write() require the original
+ * bus->ops be installed to function, so temporarily put them
+ * back.
+ */
+ my_ops = bus->ops;
+ bus->ops = ops;
+ rv = ops->write(bus, devfn, where, size, val);
+ bus->ops = my_ops;
spin_unlock_irqrestore(&inject_lock, flags);
- return ops->write(bus, devfn, where, size, val);
+ return rv;
}
-static struct pci_ops pci_ops_aer = {
- .read = pci_read_aer,
- .write = pci_write_aer,
+static struct pci_ops aer_inj_pci_ops = {
+ .read = aer_inj_read_config,
+ .write = aer_inj_write_config,
};
static void pci_bus_ops_init(struct pci_bus_ops *bus_ops,
@@ -270,9 +294,9 @@ static int pci_bus_set_aer_ops(struct pci_bus *bus)
bus_ops = kmalloc(sizeof(*bus_ops), GFP_KERNEL);
if (!bus_ops)
return -ENOMEM;
- ops = pci_bus_set_ops(bus, &pci_ops_aer);
+ ops = pci_bus_set_ops(bus, &aer_inj_pci_ops);
spin_lock_irqsave(&inject_lock, flags);
- if (ops == &pci_ops_aer)
+ if (ops == &aer_inj_pci_ops)
goto out;
pci_bus_ops_init(bus_ops, bus, ops);
list_add(&bus_ops->list, &pci_bus_ops_list);
@@ -334,13 +358,15 @@ static int aer_inject(struct aer_error_inj *einj)
return -ENODEV;
rpdev = pcie_find_root_port(dev);
if (!rpdev) {
+ dev_err(&dev->dev, "aer_inject: Root port not found\n");
ret = -ENODEV;
goto out_put;
}
pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos_cap_err) {
- ret = -EPERM;
+ dev_err(&dev->dev, "aer_inject: Device doesn't support AER\n");
+ ret = -EPROTONOSUPPORT;
goto out_put;
}
pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
@@ -350,7 +376,9 @@ static int aer_inject(struct aer_error_inj *einj)
rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
if (!rp_pos_cap_err) {
- ret = -EPERM;
+ dev_err(&rpdev->dev,
+ "aer_inject: Root port doesn't support AER\n");
+ ret = -EPROTONOSUPPORT;
goto out_put;
}
@@ -397,14 +425,16 @@ static int aer_inject(struct aer_error_inj *einj)
if (!aer_mask_override && einj->cor_status &&
!(einj->cor_status & ~cor_mask)) {
ret = -EINVAL;
- printk(KERN_WARNING "The correctable error(s) is masked by device\n");
+ dev_warn(&dev->dev,
+ "aer_inject: The correctable error(s) is masked by device\n");
spin_unlock_irqrestore(&inject_lock, flags);
goto out_put;
}
if (!aer_mask_override && einj->uncor_status &&
!(einj->uncor_status & ~uncor_mask)) {
ret = -EINVAL;
- printk(KERN_WARNING "The uncorrectable error(s) is masked by device\n");
+ dev_warn(&dev->dev,
+ "aer_inject: The uncorrectable error(s) is masked by device\n");
spin_unlock_irqrestore(&inject_lock, flags);
goto out_put;
}
@@ -457,13 +487,19 @@ static int aer_inject(struct aer_error_inj *einj)
if (find_aer_device(rpdev, &edev)) {
if (!get_service_data(edev)) {
- printk(KERN_WARNING "AER service is not initialized\n");
- ret = -EINVAL;
+ dev_warn(&edev->device,
+ "aer_inject: AER service is not initialized\n");
+ ret = -EPROTONOSUPPORT;
goto out_put;
}
+ dev_info(&edev->device,
+ "aer_inject: Injecting errors %08x/%08x into device %s\n",
+ einj->cor_status, einj->uncor_status, pci_name(dev));
aer_irq(-1, edev);
- } else
- ret = -EINVAL;
+ } else {
+ dev_err(&rpdev->dev, "aer_inject: AER device not found\n");
+ ret = -ENODEV;
+ }
out_put:
kfree(err_alloc);
kfree(rperr_alloc);
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 63fc63911295..1ae4c73e7a3c 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -396,7 +396,7 @@ static int pcie_pme_suspend(struct pcie_device *srv)
{
struct pcie_pme_service_data *data = get_service_data(srv);
struct pci_dev *port = srv->port;
- bool wakeup;
+ bool wakeup, wake_irq_enabled = false;
int ret;
if (device_may_wakeup(&port->dev)) {
@@ -409,11 +409,12 @@ static int pcie_pme_suspend(struct pcie_device *srv)
spin_lock_irq(&data->lock);
if (wakeup) {
ret = enable_irq_wake(srv->irq);
- data->suspend_level = PME_SUSPEND_WAKEUP;
+ if (ret == 0) {
+ data->suspend_level = PME_SUSPEND_WAKEUP;
+ wake_irq_enabled = true;
+ }
}
- if (!wakeup || ret) {
- struct pci_dev *port = srv->port;
-
+ if (!wake_irq_enabled) {
pcie_pme_interrupt_enable(port, false);
pcie_clear_root_pme_status(port);
data->suspend_level = PME_SUSPEND_NOIRQ;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6d7ab9bb0d5a..8004f67c57ec 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -15,7 +15,7 @@
#include <linux/pci-aspm.h>
#include <linux/aer.h>
#include <linux/acpi.h>
-#include <asm-generic/pci-bridge.h>
+#include <linux/irqdomain.h>
#include "pci.h"
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
@@ -179,6 +179,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
u16 orig_cmd;
struct pci_bus_region region, inverted_region;
+ if (dev->non_compliant_bars)
+ return 0;
+
mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
/* No printks while decoding is disabled! */
@@ -675,6 +678,20 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
if (!d)
d = pci_host_bridge_acpi_msi_domain(bus);
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+ /*
+ * If no IRQ domain was found via the OF tree, try looking it up
+ * directly through the fwnode_handle.
+ */
+ if (!d) {
+ struct fwnode_handle *fwnode = pci_root_bus_fwnode(bus);
+
+ if (fwnode)
+ d = irq_find_matching_fwnode(fwnode,
+ DOMAIN_BUS_PCI_MSI);
+ }
+#endif
+
return d;
}
@@ -758,6 +775,12 @@ add_dev:
pcibios_add_bus(child);
+ if (child->ops->add_bus) {
+ ret = child->ops->add_bus(child);
+ if (WARN_ON(ret < 0))
+ dev_err(&child->dev, "failed to add bus: %d\n", ret);
+ }
+
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(child);
@@ -1171,6 +1194,7 @@ static void pci_msi_setup_pci_dev(struct pci_dev *dev)
int pci_setup_device(struct pci_dev *dev)
{
u32 class;
+ u16 cmd;
u8 hdr_type;
int pos = 0;
struct pci_bus_region region;
@@ -1214,6 +1238,16 @@ int pci_setup_device(struct pci_dev *dev)
/* device class may be changed after fixup */
class = dev->class >> 8;
+ if (dev->non_compliant_bars) {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+ dev_info(&dev->dev, "device has non-compliant BARs; disabling IO/MEM decoding\n");
+ cmd &= ~PCI_COMMAND_IO;
+ cmd &= ~PCI_COMMAND_MEMORY;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ }
+
switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI)
@@ -1608,7 +1642,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_pm_init(dev);
/* Vital Product Data */
- pci_vpd_pci22_init(dev);
+ pci_vpd_init(dev);
/* Alternative Routing-ID Forwarding */
pci_configure_ari(dev);
@@ -1803,6 +1837,13 @@ static int only_one_child(struct pci_bus *bus)
return 0;
if (pci_pcie_type(parent) == PCI_EXP_TYPE_ROOT_PORT)
return 1;
+
+ /*
+ * PCIe downstream ports are bridges that normally lead to only a
+ * device 0, but if PCI_SCAN_ALL_PCIE_DEVS is set, scan all
+ * possible devices, not just device 0. See PCIe spec r3.0,
+ * sec 7.3.1.
+ */
if (parent->has_secondary_link &&
!pci_has_flag(PCI_SCAN_ALL_PCIE_DEVS))
return 1;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 0575a1e026b4..8e678027b900 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -438,7 +438,7 @@ static void quirk_amd_nl_class(struct pci_dev *pdev)
u32 class = pdev->class;
/* Use "USB Device (not host controller)" class */
- pdev->class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe;
+ pdev->class = PCI_CLASS_SERIAL_USB_DEVICE;
dev_info(&pdev->dev, "PCI class overridden (%#08x -> %#08x) so dwc3 driver can claim this instead of xhci\n",
class, pdev->class);
}
@@ -2135,6 +2135,35 @@ static void quirk_via_cx700_pci_parking_caching(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching);
/*
+ * If a device follows the VPD format spec, the PCI core will not read or
+ * write past the VPD End Tag. But some vendors do not follow the VPD
+ * format spec, so we can't tell how much data is safe to access. Devices
+ * may behave unpredictably if we access too much. Blacklist these devices
+ * so we don't touch VPD at all.
+ */
+static void quirk_blacklist_vpd(struct pci_dev *dev)
+{
+ if (dev->vpd) {
+ dev->vpd->len = 0;
+ dev_warn(&dev->dev, FW_BUG "VPD access disabled\n");
+ }
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0060, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x007c, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0413, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0078, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0079, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0073, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0071, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005b, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x002f, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005d, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, quirk_blacklist_vpd);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, PCI_ANY_ID,
+ quirk_blacklist_vpd);
+
+/*
* For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the
* VPD end tag will hang the device. This problem was initially
* observed when a vpd entry was created in sysfs
@@ -3832,6 +3861,19 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
#endif
}
+static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)
+{
+ /*
+ * Cavium devices matching this quirk do not perform peer-to-peer
+ * with other functions, allowing masking out these bits as if they
+ * were unimplemented in the ACS capability.
+ */
+ acs_flags &= ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
+ PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);
+
+ return acs_flags ? 0 : 1;
+}
+
/*
* Many Intel PCH root ports do provide ACS-like features to disable peer
* transactions and validate bus numbers in requests, but do not provide an
@@ -3984,6 +4026,8 @@ static const struct pci_dev_acs_enabled {
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
{ 0x19a2, 0x710, pci_quirk_mf_endpoint_acs }, /* Emulex BE3-R */
{ 0x10df, 0x720, pci_quirk_mf_endpoint_acs }, /* Emulex Skyhawk-R */
+ /* Cavium ThunderX */
+ { PCI_VENDOR_ID_CAVIUM, PCI_ANY_ID, pci_quirk_cavium_acs },
{ 0 }
};
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 8a280e9c2ad1..8982026637d5 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -7,7 +7,6 @@ static void pci_free_resources(struct pci_dev *dev)
{
int i;
- pci_cleanup_rom(dev);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = dev->resource + i;
if (res->parent)
@@ -54,6 +53,10 @@ void pci_remove_bus(struct pci_bus *bus)
pci_bus_release_busn_res(bus);
up_write(&pci_bus_sem);
pci_remove_legacy_files(bus);
+
+ if (bus->ops->remove_bus)
+ bus->ops->remove_bus(bus);
+
pcibios_remove_bus(bus);
device_unregister(&bus->dev);
}
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 9eaca39ef38d..06663d391b39 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -24,13 +24,17 @@
*/
int pci_enable_rom(struct pci_dev *pdev)
{
- struct resource *res = pdev->resource + PCI_ROM_RESOURCE;
+ struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
struct pci_bus_region region;
u32 rom_addr;
if (!res->flags)
return -1;
+ /* Nothing to enable if we're using a shadow copy in RAM */
+ if (res->flags & IORESOURCE_ROM_SHADOW)
+ return 0;
+
pcibios_resource_to_bus(pdev->bus, &region, res);
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
rom_addr &= ~PCI_ROM_ADDRESS_MASK;
@@ -49,7 +53,12 @@ EXPORT_SYMBOL_GPL(pci_enable_rom);
*/
void pci_disable_rom(struct pci_dev *pdev)
{
+ struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
u32 rom_addr;
+
+ if (res->flags & IORESOURCE_ROM_SHADOW)
+ return;
+
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
rom_addr &= ~PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
@@ -119,43 +128,23 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
loff_t start;
void __iomem *rom;
- /*
- * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy
- * memory map if the VGA enable bit of the Bridge Control register is
- * set for embedded VGA.
- */
- if (res->flags & IORESOURCE_ROM_SHADOW) {
- /* primary video rom always starts here */
- start = (loff_t)0xC0000;
- *size = 0x20000; /* cover C000:0 through E000:0 */
- } else {
- if (res->flags &
- (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) {
- *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
- return (void __iomem *)(unsigned long)
- pci_resource_start(pdev, PCI_ROM_RESOURCE);
- } else {
- /* assign the ROM an address if it doesn't have one */
- if (res->parent == NULL &&
- pci_assign_resource(pdev, PCI_ROM_RESOURCE))
- return NULL;
- start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
- *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
- if (*size == 0)
- return NULL;
-
- /* Enable ROM space decodes */
- if (pci_enable_rom(pdev))
- return NULL;
- }
- }
+ /* assign the ROM an address if it doesn't have one */
+ if (res->parent == NULL && pci_assign_resource(pdev, PCI_ROM_RESOURCE))
+ return NULL;
+
+ start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
+ *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+ if (*size == 0)
+ return NULL;
+
+ /* Enable ROM space decodes */
+ if (pci_enable_rom(pdev))
+ return NULL;
rom = ioremap(start, *size);
if (!rom) {
/* restore enable if ioremap fails */
- if (!(res->flags & (IORESOURCE_ROM_ENABLE |
- IORESOURCE_ROM_SHADOW |
- IORESOURCE_ROM_COPY)))
+ if (!(res->flags & IORESOURCE_ROM_ENABLE))
pci_disable_rom(pdev);
return NULL;
}
@@ -181,37 +170,15 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
- if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
- return;
-
iounmap(rom);
- /* Disable again before continuing, leave enabled if pci=rom */
- if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
+ /* Disable again before continuing */
+ if (!(res->flags & IORESOURCE_ROM_ENABLE))
pci_disable_rom(pdev);
}
EXPORT_SYMBOL(pci_unmap_rom);
/**
- * pci_cleanup_rom - free the ROM copy created by pci_map_rom_copy
- * @pdev: pointer to pci device struct
- *
- * Free the copied ROM if we allocated one.
- */
-void pci_cleanup_rom(struct pci_dev *pdev)
-{
- struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
-
- if (res->flags & IORESOURCE_ROM_COPY) {
- kfree((void *)(unsigned long)res->start);
- res->flags |= IORESOURCE_UNSET;
- res->flags &= ~IORESOURCE_ROM_COPY;
- res->start = 0;
- res->end = 0;
- }
-}
-
-/**
* pci_platform_rom - provides a pointer to any ROM image provided by the
* platform
* @pdev: pointer to pci device struct
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 7796d0a5befa..55641a39a3e9 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -25,7 +25,6 @@
#include <linux/ioport.h>
#include <linux/cache.h>
#include <linux/slab.h>
-#include <asm-generic/pci-bridge.h>
#include "pci.h"
unsigned int pci_flags;
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 604011e047d6..66c4d8f42233 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -276,6 +276,9 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
resource_size_t align, size;
int ret;
+ if (res->flags & IORESOURCE_PCI_FIXED)
+ return 0;
+
res->flags |= IORESOURCE_UNSET;
align = pci_resource_alignment(dev, res);
if (!align) {
@@ -321,6 +324,9 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
resource_size_t new_size;
int ret;
+ if (res->flags & IORESOURCE_PCI_FIXED)
+ return 0;
+
flags = res->flags;
res->flags |= IORESOURCE_UNSET;
if (!res->parent) {
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index c777b97207d5..5f70fee59a94 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -53,7 +53,7 @@ struct pcifront_device {
};
struct pcifront_sd {
- int domain;
+ struct pci_sysdata sd;
struct pcifront_device *pdev;
};
@@ -67,7 +67,9 @@ static inline void pcifront_init_sd(struct pcifront_sd *sd,
unsigned int domain, unsigned int bus,
struct pcifront_device *pdev)
{
- sd->domain = domain;
+ /* Because we do not expose that information via XenBus. */
+ sd->sd.node = first_online_node;
+ sd->sd.domain = domain;
sd->pdev = pdev;
}
@@ -468,8 +470,8 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
domain, bus);
- bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
- sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+ bus_entry = kzalloc(sizeof(*bus_entry), GFP_KERNEL);
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
if (!bus_entry || !sd) {
err = -ENOMEM;
goto err_out;
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 0124d17bd9fe..26566db09de0 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -32,7 +32,7 @@ config PHY_BERLIN_SATA
config ARMADA375_USBCLUSTER_PHY
def_bool y
depends on MACH_ARMADA_375 || COMPILE_TEST
- depends on OF
+ depends on OF && HAS_IOMEM
select GENERIC_PHY
config PHY_DM816X_USB
@@ -337,6 +337,20 @@ config PHY_ROCKCHIP_USB
help
Enable this to support the Rockchip USB 2.0 PHY.
+config PHY_ROCKCHIP_EMMC
+ tristate "Rockchip EMMC PHY Driver"
+ depends on ARCH_ROCKCHIP && OF
+ select GENERIC_PHY
+ help
+ Enable this to support the Rockchip EMMC PHY.
+
+config PHY_ROCKCHIP_DP
+ tristate "Rockchip Display Port PHY Driver"
+ depends on ARCH_ROCKCHIP && OF
+ select GENERIC_PHY
+ help
+ Enable this to support the Rockchip Display Port PHY.
+
config PHY_ST_SPEAR1310_MIPHY
tristate "ST SPEAR1310-MIPHY driver"
select GENERIC_PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index c80f09df3bb8..24596a96a887 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -37,6 +37,8 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o
obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
+obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
+obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
diff --git a/drivers/phy/phy-dm816x-usb.c b/drivers/phy/phy-dm816x-usb.c
index b4bbef664d20..cbcce7cf0028 100644
--- a/drivers/phy/phy-dm816x-usb.c
+++ b/drivers/phy/phy-dm816x-usb.c
@@ -118,7 +118,7 @@ static const struct phy_ops ops = {
.owner = THIS_MODULE,
};
-static int dm816x_usb_phy_runtime_suspend(struct device *dev)
+static int __maybe_unused dm816x_usb_phy_runtime_suspend(struct device *dev)
{
struct dm816x_usb_phy *phy = dev_get_drvdata(dev);
unsigned int mask, val;
@@ -136,7 +136,7 @@ static int dm816x_usb_phy_runtime_suspend(struct device *dev)
return 0;
}
-static int dm816x_usb_phy_runtime_resume(struct device *dev)
+static int __maybe_unused dm816x_usb_phy_runtime_resume(struct device *dev)
{
struct dm816x_usb_phy *phy = dev_get_drvdata(dev);
unsigned int mask, val;
diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c
index ef332ef4abc7..bc4f7dd821aa 100644
--- a/drivers/phy/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/phy-rcar-gen3-usb2.c
@@ -74,20 +74,6 @@
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
#define USB2_ADPCTRL_DRVVBUS BIT(4)
-/******* HSUSB registers (original offset is +0x100) *******/
-#define HSUSB_LPSTS 0x02
-#define HSUSB_UGCTRL2 0x84
-
-/* Low Power Status register (LPSTS) */
-#define HSUSB_LPSTS_SUSPM 0x4000
-
-/* USB General control register 2 (UGCTRL2) */
-#define HSUSB_UGCTRL2_MASK 0x00000031 /* bit[31:6] should be 0 */
-#define HSUSB_UGCTRL2_USB0SEL 0x00000030
-#define HSUSB_UGCTRL2_USB0SEL_HOST 0x00000010
-#define HSUSB_UGCTRL2_USB0SEL_HS_USB 0x00000020
-#define HSUSB_UGCTRL2_USB0SEL_OTG 0x00000030
-
struct rcar_gen3_data {
void __iomem *base;
struct clk *clk;
@@ -95,8 +81,8 @@ struct rcar_gen3_data {
struct rcar_gen3_chan {
struct rcar_gen3_data usb2;
- struct rcar_gen3_data hsusb;
struct phy *phy;
+ bool has_otg;
};
static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
@@ -202,24 +188,15 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
void __iomem *usb2_base = channel->usb2.base;
- void __iomem *hsusb_base = channel->hsusb.base;
- u32 val;
/* Initialize USB2 part */
writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE);
writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
- /* Initialize HSUSB part */
- if (hsusb_base) {
- val = readl(hsusb_base + HSUSB_UGCTRL2);
- val = (val & ~HSUSB_UGCTRL2_USB0SEL) |
- HSUSB_UGCTRL2_USB0SEL_OTG;
- writel(val & HSUSB_UGCTRL2_MASK, hsusb_base + HSUSB_UGCTRL2);
-
- /* Initialize otg part */
+ /* Initialize otg part */
+ if (channel->has_otg)
rcar_gen3_init_otg(channel);
- }
return 0;
}
@@ -237,7 +214,6 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
void __iomem *usb2_base = channel->usb2.base;
- void __iomem *hsusb_base = channel->hsusb.base;
u32 val;
val = readl(usb2_base + USB2_USBCTR);
@@ -246,33 +222,6 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
val &= ~USB2_USBCTR_PLL_RST;
writel(val, usb2_base + USB2_USBCTR);
- /*
- * TODO: To reduce power consuming, this driver should set the SUSPM
- * after the PHY detects ID pin as peripheral.
- */
- if (hsusb_base) {
- /* Power on HSUSB PHY */
- val = readw(hsusb_base + HSUSB_LPSTS);
- val |= HSUSB_LPSTS_SUSPM;
- writew(val, hsusb_base + HSUSB_LPSTS);
- }
-
- return 0;
-}
-
-static int rcar_gen3_phy_usb2_power_off(struct phy *p)
-{
- struct rcar_gen3_chan *channel = phy_get_drvdata(p);
- void __iomem *hsusb_base = channel->hsusb.base;
- u32 val;
-
- if (hsusb_base) {
- /* Power off HSUSB PHY */
- val = readw(hsusb_base + HSUSB_LPSTS);
- val &= ~HSUSB_LPSTS_SUSPM;
- writew(val, hsusb_base + HSUSB_LPSTS);
- }
-
return 0;
}
@@ -280,7 +229,6 @@ static struct phy_ops rcar_gen3_phy_usb2_ops = {
.init = rcar_gen3_phy_usb2_init,
.exit = rcar_gen3_phy_usb2_exit,
.power_on = rcar_gen3_phy_usb2_power_on,
- .power_off = rcar_gen3_phy_usb2_power_off,
.owner = THIS_MODULE,
};
@@ -313,6 +261,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
struct rcar_gen3_chan *channel;
struct phy_provider *provider;
struct resource *res;
+ int irq;
if (!dev->of_node) {
dev_err(dev, "This driver needs device tree\n");
@@ -323,29 +272,19 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
if (!channel)
return -ENOMEM;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "usb2_host");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
channel->usb2.base = devm_ioremap_resource(dev, res);
if (IS_ERR(channel->usb2.base))
return PTR_ERR(channel->usb2.base);
- /* "hsusb" memory resource is optional */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsusb");
-
- /* To avoid error message by devm_ioremap_resource() */
- if (res) {
- int irq;
-
- channel->hsusb.base = devm_ioremap_resource(dev, res);
- if (IS_ERR(channel->hsusb.base))
- channel->hsusb.base = NULL;
- /* call request_irq for OTG */
- irq = platform_get_irq(pdev, 0);
- if (irq >= 0)
- irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
- IRQF_SHARED, dev_name(dev),
- channel);
+ /* call request_irq for OTG */
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0) {
+ irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
+ IRQF_SHARED, dev_name(dev), channel);
if (irq < 0)
dev_err(dev, "No irq handler (%d)\n", irq);
+ channel->has_otg = true;
}
/* devm_phy_create() will call pm_runtime_enable(dev); */
diff --git a/drivers/phy/phy-rockchip-dp.c b/drivers/phy/phy-rockchip-dp.c
new file mode 100644
index 000000000000..77e2d02e6bee
--- /dev/null
+++ b/drivers/phy/phy-rockchip-dp.c
@@ -0,0 +1,151 @@
+/*
+ * Rockchip DP PHY driver
+ *
+ * Copyright (C) 2016 FuZhou Rockchip Co., Ltd.
+ * Author: Yakir Yang <ykk@@rock-chips.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define GRF_SOC_CON12 0x0274
+
+#define GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK BIT(20)
+#define GRF_EDP_REF_CLK_SEL_INTER BIT(4)
+
+#define GRF_EDP_PHY_SIDDQ_HIWORD_MASK BIT(21)
+#define GRF_EDP_PHY_SIDDQ_ON 0
+#define GRF_EDP_PHY_SIDDQ_OFF BIT(5)
+
+struct rockchip_dp_phy {
+ struct device *dev;
+ struct regmap *grf;
+ struct clk *phy_24m;
+};
+
+static int rockchip_set_phy_state(struct phy *phy, bool enable)
+{
+ struct rockchip_dp_phy *dp = phy_get_drvdata(phy);
+ int ret;
+
+ if (enable) {
+ ret = regmap_write(dp->grf, GRF_SOC_CON12,
+ GRF_EDP_PHY_SIDDQ_HIWORD_MASK |
+ GRF_EDP_PHY_SIDDQ_ON);
+ if (ret < 0) {
+ dev_err(dp->dev, "Can't enable PHY power %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(dp->phy_24m);
+ } else {
+ clk_disable_unprepare(dp->phy_24m);
+
+ ret = regmap_write(dp->grf, GRF_SOC_CON12,
+ GRF_EDP_PHY_SIDDQ_HIWORD_MASK |
+ GRF_EDP_PHY_SIDDQ_OFF);
+ }
+
+ return ret;
+}
+
+static int rockchip_dp_phy_power_on(struct phy *phy)
+{
+ return rockchip_set_phy_state(phy, true);
+}
+
+static int rockchip_dp_phy_power_off(struct phy *phy)
+{
+ return rockchip_set_phy_state(phy, false);
+}
+
+static const struct phy_ops rockchip_dp_phy_ops = {
+ .power_on = rockchip_dp_phy_power_on,
+ .power_off = rockchip_dp_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int rockchip_dp_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct phy_provider *phy_provider;
+ struct rockchip_dp_phy *dp;
+ struct phy *phy;
+ int ret;
+
+ if (!np)
+ return -ENODEV;
+
+ dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
+ if (IS_ERR(dp))
+ return -ENOMEM;
+
+ dp->dev = dev;
+
+ dp->phy_24m = devm_clk_get(dev, "24m");
+ if (IS_ERR(dp->phy_24m)) {
+ dev_err(dev, "cannot get clock 24m\n");
+ return PTR_ERR(dp->phy_24m);
+ }
+
+ ret = clk_set_rate(dp->phy_24m, 24000000);
+ if (ret < 0) {
+ dev_err(dp->dev, "cannot set clock phy_24m %d\n", ret);
+ return ret;
+ }
+
+ dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(dp->grf)) {
+ dev_err(dev, "rk3288-dp needs rockchip,grf property\n");
+ return PTR_ERR(dp->grf);
+ }
+
+ ret = regmap_write(dp->grf, GRF_SOC_CON12, GRF_EDP_REF_CLK_SEL_INTER |
+ GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK);
+ if (ret != 0) {
+ dev_err(dp->dev, "Could not config GRF edp ref clk: %d\n", ret);
+ return ret;
+ }
+
+ phy = devm_phy_create(dev, np, &rockchip_dp_phy_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create phy\n");
+ return PTR_ERR(phy);
+ }
+ phy_set_drvdata(phy, dp);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id rockchip_dp_phy_dt_ids[] = {
+ { .compatible = "rockchip,rk3288-dp-phy" },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_dp_phy_dt_ids);
+
+static struct platform_driver rockchip_dp_phy_driver = {
+ .probe = rockchip_dp_phy_probe,
+ .driver = {
+ .name = "rockchip-dp-phy",
+ .of_match_table = rockchip_dp_phy_dt_ids,
+ },
+};
+
+module_platform_driver(rockchip_dp_phy_driver);
+
+MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip DP PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
new file mode 100644
index 000000000000..887b4c27195f
--- /dev/null
+++ b/drivers/phy/phy-rockchip-emmc.c
@@ -0,0 +1,229 @@
+/*
+ * Rockchip emmc PHY driver
+ *
+ * Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * 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.
+ *
+ * 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/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/*
+ * The higher 16-bit of this register is used for write protection
+ * only if BIT(x + 16) set to 1 the BIT(x) can be written.
+ */
+#define HIWORD_UPDATE(val, mask, shift) \
+ ((val) << (shift) | (mask) << ((shift) + 16))
+
+/* Register definition */
+#define GRF_EMMCPHY_CON0 0x0
+#define GRF_EMMCPHY_CON1 0x4
+#define GRF_EMMCPHY_CON2 0x8
+#define GRF_EMMCPHY_CON3 0xc
+#define GRF_EMMCPHY_CON4 0x10
+#define GRF_EMMCPHY_CON5 0x14
+#define GRF_EMMCPHY_CON6 0x18
+#define GRF_EMMCPHY_STATUS 0x20
+
+#define PHYCTRL_PDB_MASK 0x1
+#define PHYCTRL_PDB_SHIFT 0x0
+#define PHYCTRL_PDB_PWR_ON 0x1
+#define PHYCTRL_PDB_PWR_OFF 0x0
+#define PHYCTRL_ENDLL_MASK 0x1
+#define PHYCTRL_ENDLL_SHIFT 0x1
+#define PHYCTRL_ENDLL_ENABLE 0x1
+#define PHYCTRL_ENDLL_DISABLE 0x0
+#define PHYCTRL_CALDONE_MASK 0x1
+#define PHYCTRL_CALDONE_SHIFT 0x6
+#define PHYCTRL_CALDONE_DONE 0x1
+#define PHYCTRL_CALDONE_GOING 0x0
+#define PHYCTRL_DLLRDY_MASK 0x1
+#define PHYCTRL_DLLRDY_SHIFT 0x5
+#define PHYCTRL_DLLRDY_DONE 0x1
+#define PHYCTRL_DLLRDY_GOING 0x0
+
+struct rockchip_emmc_phy {
+ unsigned int reg_offset;
+ struct regmap *reg_base;
+};
+
+static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
+ bool on_off)
+{
+ unsigned int caldone;
+ unsigned int dllrdy;
+
+ /*
+ * Keep phyctrl_pdb and phyctrl_endll low to allow
+ * initialization of CALIO state M/C DFFs
+ */
+ regmap_write(rk_phy->reg_base,
+ rk_phy->reg_offset + GRF_EMMCPHY_CON6,
+ HIWORD_UPDATE(PHYCTRL_PDB_PWR_OFF,
+ PHYCTRL_PDB_MASK,
+ PHYCTRL_PDB_SHIFT));
+ regmap_write(rk_phy->reg_base,
+ rk_phy->reg_offset + GRF_EMMCPHY_CON6,
+ HIWORD_UPDATE(PHYCTRL_ENDLL_DISABLE,
+ PHYCTRL_ENDLL_MASK,
+ PHYCTRL_ENDLL_SHIFT));
+
+ /* Already finish power_off above */
+ if (on_off == PHYCTRL_PDB_PWR_OFF)
+ return 0;
+
+ /*
+ * According to the user manual, calpad calibration
+ * cycle takes more than 2us without the minimal recommended
+ * value, so we may need a little margin here
+ */
+ udelay(3);
+ regmap_write(rk_phy->reg_base,
+ rk_phy->reg_offset + GRF_EMMCPHY_CON6,
+ HIWORD_UPDATE(PHYCTRL_PDB_PWR_ON,
+ PHYCTRL_PDB_MASK,
+ PHYCTRL_PDB_SHIFT));
+
+ /*
+ * According to the user manual, it asks driver to
+ * wait 5us for calpad busy trimming
+ */
+ udelay(5);
+ regmap_read(rk_phy->reg_base,
+ rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
+ &caldone);
+ caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK;
+ if (caldone != PHYCTRL_CALDONE_DONE) {
+ pr_err("rockchip_emmc_phy_power: caldone timeout.\n");
+ return -ETIMEDOUT;
+ }
+
+ regmap_write(rk_phy->reg_base,
+ rk_phy->reg_offset + GRF_EMMCPHY_CON6,
+ HIWORD_UPDATE(PHYCTRL_ENDLL_ENABLE,
+ PHYCTRL_ENDLL_MASK,
+ PHYCTRL_ENDLL_SHIFT));
+ /*
+ * After enable analog DLL circuits, we need extra 10.2us
+ * for dll to be ready for work.
+ */
+ udelay(11);
+ regmap_read(rk_phy->reg_base,
+ rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
+ &dllrdy);
+ dllrdy = (dllrdy >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK;
+ if (dllrdy != PHYCTRL_DLLRDY_DONE) {
+ pr_err("rockchip_emmc_phy_power: dllrdy timeout.\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int rockchip_emmc_phy_power_off(struct phy *phy)
+{
+ struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
+ int ret = 0;
+
+ /* Power down emmc phy analog blocks */
+ ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_OFF);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int rockchip_emmc_phy_power_on(struct phy *phy)
+{
+ struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
+ int ret = 0;
+
+ /* Power up emmc phy analog blocks */
+ ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_ON);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct phy_ops ops = {
+ .power_on = rockchip_emmc_phy_power_on,
+ .power_off = rockchip_emmc_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int rockchip_emmc_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rockchip_emmc_phy *rk_phy;
+ struct phy *generic_phy;
+ struct phy_provider *phy_provider;
+ struct regmap *grf;
+ unsigned int reg_offset;
+
+ grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
+ if (IS_ERR(grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return PTR_ERR(grf);
+ }
+
+ rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
+ if (!rk_phy)
+ return -ENOMEM;
+
+ if (of_property_read_u32(dev->of_node, "reg", &reg_offset)) {
+ dev_err(dev, "missing reg property in node %s\n",
+ dev->of_node->name);
+ return -EINVAL;
+ }
+
+ rk_phy->reg_offset = reg_offset;
+ rk_phy->reg_base = grf;
+
+ generic_phy = devm_phy_create(dev, dev->of_node, &ops);
+ if (IS_ERR(generic_phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(generic_phy);
+ }
+
+ phy_set_drvdata(generic_phy, rk_phy);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id rockchip_emmc_phy_dt_ids[] = {
+ { .compatible = "rockchip,rk3399-emmc-phy" },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_emmc_phy_dt_ids);
+
+static struct platform_driver rockchip_emmc_driver = {
+ .probe = rockchip_emmc_phy_probe,
+ .driver = {
+ .name = "rockchip-emmc-phy",
+ .of_match_table = rockchip_emmc_phy_dt_ids,
+ },
+};
+
+module_platform_driver(rockchip_emmc_driver);
+
+MODULE_AUTHOR("Shawn Lin <shawn.lin@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip EMMC PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c
index 33a80eba1cb4..f62d899063a3 100644
--- a/drivers/phy/phy-rockchip-usb.c
+++ b/drivers/phy/phy-rockchip-usb.c
@@ -30,21 +30,23 @@
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
-/*
- * The higher 16-bit of this register is used for write protection
- * only if BIT(13 + 16) set to 1 the BIT(13) can be written.
- */
-#define SIDDQ_WRITE_ENA BIT(29)
-#define SIDDQ_ON BIT(13)
-#define SIDDQ_OFF (0 << 13)
+static int enable_usb_uart;
+
+#define HIWORD_UPDATE(val, mask) \
+ ((val) | (mask) << 16)
+
+#define UOC_CON0_SIDDQ BIT(13)
struct rockchip_usb_phys {
int reg;
const char *pll_name;
};
+struct rockchip_usb_phy_base;
struct rockchip_usb_phy_pdata {
struct rockchip_usb_phys *phys;
+ int (*init_usb_uart)(struct regmap *grf);
+ int usb_uart_phy;
};
struct rockchip_usb_phy_base {
@@ -61,13 +63,15 @@ struct rockchip_usb_phy {
struct clk *clk480m;
struct clk_hw clk480m_hw;
struct phy *phy;
+ bool uart_enabled;
};
static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
bool siddq)
{
- return regmap_write(phy->base->reg_base, phy->reg_offset,
- SIDDQ_WRITE_ENA | (siddq ? SIDDQ_ON : SIDDQ_OFF));
+ u32 val = HIWORD_UPDATE(siddq ? UOC_CON0_SIDDQ : 0, UOC_CON0_SIDDQ);
+
+ return regmap_write(phy->base->reg_base, phy->reg_offset, val);
}
static unsigned long rockchip_usb_phy480m_recalc_rate(struct clk_hw *hw,
@@ -108,7 +112,7 @@ static int rockchip_usb_phy480m_is_enabled(struct clk_hw *hw)
if (ret < 0)
return ret;
- return (val & SIDDQ_ON) ? 0 : 1;
+ return (val & UOC_CON0_SIDDQ) ? 0 : 1;
}
static const struct clk_ops rockchip_usb_phy480m_ops = {
@@ -122,6 +126,9 @@ static int rockchip_usb_phy_power_off(struct phy *_phy)
{
struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
+ if (phy->uart_enabled)
+ return -EBUSY;
+
clk_disable_unprepare(phy->clk480m);
return 0;
@@ -131,6 +138,9 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
{
struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
+ if (phy->uart_enabled)
+ return -EBUSY;
+
return clk_prepare_enable(phy->clk480m);
}
@@ -144,8 +154,10 @@ static void rockchip_usb_phy_action(void *data)
{
struct rockchip_usb_phy *rk_phy = data;
- of_clk_del_provider(rk_phy->np);
- clk_unregister(rk_phy->clk480m);
+ if (!rk_phy->uart_enabled) {
+ of_clk_del_provider(rk_phy->np);
+ clk_unregister(rk_phy->clk480m);
+ }
if (rk_phy->clk)
clk_put(rk_phy->clk);
@@ -194,30 +206,35 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
return -EINVAL;
}
- if (rk_phy->clk) {
- clk_name = __clk_get_name(rk_phy->clk);
- init.flags = 0;
- init.parent_names = &clk_name;
- init.num_parents = 1;
+ if (enable_usb_uart && base->pdata->usb_uart_phy == i) {
+ dev_dbg(base->dev, "phy%d used as uart output\n", i);
+ rk_phy->uart_enabled = true;
} else {
- init.flags = CLK_IS_ROOT;
- init.parent_names = NULL;
- init.num_parents = 0;
- }
+ if (rk_phy->clk) {
+ clk_name = __clk_get_name(rk_phy->clk);
+ init.flags = 0;
+ init.parent_names = &clk_name;
+ init.num_parents = 1;
+ } else {
+ init.flags = CLK_IS_ROOT;
+ init.parent_names = NULL;
+ init.num_parents = 0;
+ }
- init.ops = &rockchip_usb_phy480m_ops;
- rk_phy->clk480m_hw.init = &init;
+ init.ops = &rockchip_usb_phy480m_ops;
+ rk_phy->clk480m_hw.init = &init;
- rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw);
- if (IS_ERR(rk_phy->clk480m)) {
- err = PTR_ERR(rk_phy->clk480m);
- goto err_clk;
- }
+ rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw);
+ if (IS_ERR(rk_phy->clk480m)) {
+ err = PTR_ERR(rk_phy->clk480m);
+ goto err_clk;
+ }
- err = of_clk_add_provider(child, of_clk_src_simple_get,
- rk_phy->clk480m);
- if (err < 0)
- goto err_clk_prov;
+ err = of_clk_add_provider(child, of_clk_src_simple_get,
+ rk_phy->clk480m);
+ if (err < 0)
+ goto err_clk_prov;
+ }
err = devm_add_action(base->dev, rockchip_usb_phy_action, rk_phy);
if (err)
@@ -230,13 +247,21 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
}
phy_set_drvdata(rk_phy->phy, rk_phy);
- /* only power up usb phy when it use, so disable it when init*/
- return rockchip_usb_phy_power(rk_phy, 1);
+ /*
+ * When acting as uart-pipe, just keep clock on otherwise
+ * only power up usb phy when it use, so disable it when init
+ */
+ if (rk_phy->uart_enabled)
+ return clk_prepare_enable(rk_phy->clk);
+ else
+ return rockchip_usb_phy_power(rk_phy, 1);
err_devm_action:
- of_clk_del_provider(child);
+ if (!rk_phy->uart_enabled)
+ of_clk_del_provider(child);
err_clk_prov:
- clk_unregister(rk_phy->clk480m);
+ if (!rk_phy->uart_enabled)
+ clk_unregister(rk_phy->clk480m);
err_clk:
if (rk_phy->clk)
clk_put(rk_phy->clk);
@@ -259,6 +284,86 @@ static const struct rockchip_usb_phy_pdata rk3188_pdata = {
},
};
+#define RK3288_UOC0_CON0 0x320
+#define RK3288_UOC0_CON0_COMMON_ON_N BIT(0)
+#define RK3288_UOC0_CON0_DISABLE BIT(4)
+
+#define RK3288_UOC0_CON2 0x328
+#define RK3288_UOC0_CON2_SOFT_CON_SEL BIT(2)
+
+#define RK3288_UOC0_CON3 0x32c
+#define RK3288_UOC0_CON3_UTMI_SUSPENDN BIT(0)
+#define RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING (1 << 1)
+#define RK3288_UOC0_CON3_UTMI_OPMODE_MASK (3 << 1)
+#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3)
+#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK (3 << 3)
+#define RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED BIT(5)
+#define RK3288_UOC0_CON3_BYPASSDMEN BIT(6)
+#define RK3288_UOC0_CON3_BYPASSSEL BIT(7)
+
+/*
+ * Enable the bypass of uart2 data through the otg usb phy.
+ * Original description in the TRM.
+ * 1. Disable the OTG block by setting OTGDISABLE0 to 1’b1.
+ * 2. Disable the pull-up resistance on the D+ line by setting
+ * OPMODE0[1:0] to 2’b01.
+ * 3. To ensure that the XO, Bias, and PLL blocks are powered down in Suspend
+ * mode, set COMMONONN to 1’b1.
+ * 4. Place the USB PHY in Suspend mode by setting SUSPENDM0 to 1’b0.
+ * 5. Set BYPASSSEL0 to 1’b1.
+ * 6. To transmit data, controls BYPASSDMEN0, and BYPASSDMDATA0.
+ * To receive data, monitor FSVPLUS0.
+ *
+ * The actual code in the vendor kernel does some things differently.
+ */
+static int __init rk3288_init_usb_uart(struct regmap *grf)
+{
+ u32 val;
+ int ret;
+
+ /*
+ * COMMON_ON and DISABLE settings are described in the TRM,
+ * but were not present in the original code.
+ * Also disable the analog phy components to save power.
+ */
+ val = HIWORD_UPDATE(RK3288_UOC0_CON0_COMMON_ON_N
+ | RK3288_UOC0_CON0_DISABLE
+ | UOC_CON0_SIDDQ,
+ RK3288_UOC0_CON0_COMMON_ON_N
+ | RK3288_UOC0_CON0_DISABLE
+ | UOC_CON0_SIDDQ);
+ ret = regmap_write(grf, RK3288_UOC0_CON0, val);
+ if (ret)
+ return ret;
+
+ val = HIWORD_UPDATE(RK3288_UOC0_CON2_SOFT_CON_SEL,
+ RK3288_UOC0_CON2_SOFT_CON_SEL);
+ ret = regmap_write(grf, RK3288_UOC0_CON2, val);
+ if (ret)
+ return ret;
+
+ val = HIWORD_UPDATE(RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING
+ | RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC
+ | RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED,
+ RK3288_UOC0_CON3_UTMI_SUSPENDN
+ | RK3288_UOC0_CON3_UTMI_OPMODE_MASK
+ | RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK
+ | RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED);
+ ret = regmap_write(grf, RK3288_UOC0_CON3, val);
+ if (ret)
+ return ret;
+
+ val = HIWORD_UPDATE(RK3288_UOC0_CON3_BYPASSSEL
+ | RK3288_UOC0_CON3_BYPASSDMEN,
+ RK3288_UOC0_CON3_BYPASSSEL
+ | RK3288_UOC0_CON3_BYPASSDMEN);
+ ret = regmap_write(grf, RK3288_UOC0_CON3, val);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static const struct rockchip_usb_phy_pdata rk3288_pdata = {
.phys = (struct rockchip_usb_phys[]){
{ .reg = 0x320, .pll_name = "sclk_otgphy0_480m" },
@@ -266,6 +371,8 @@ static const struct rockchip_usb_phy_pdata rk3288_pdata = {
{ .reg = 0x348, .pll_name = "sclk_otgphy2_480m" },
{ /* sentinel */ }
},
+ .init_usb_uart = rk3288_init_usb_uart,
+ .usb_uart_phy = 0,
};
static int rockchip_usb_phy_probe(struct platform_device *pdev)
@@ -328,6 +435,60 @@ static struct platform_driver rockchip_usb_driver = {
module_platform_driver(rockchip_usb_driver);
+#ifndef MODULE
+static int __init rockchip_init_usb_uart(void)
+{
+ const struct of_device_id *match;
+ const struct rockchip_usb_phy_pdata *data;
+ struct device_node *np;
+ struct regmap *grf;
+ int ret;
+
+ if (!enable_usb_uart)
+ return 0;
+
+ np = of_find_matching_node_and_match(NULL, rockchip_usb_phy_dt_ids,
+ &match);
+ if (!np) {
+ pr_err("%s: failed to find usbphy node\n", __func__);
+ return -ENOTSUPP;
+ }
+
+ pr_debug("%s: using settings for %s\n", __func__, match->compatible);
+ data = match->data;
+
+ if (!data->init_usb_uart) {
+ pr_err("%s: usb-uart not available on %s\n",
+ __func__, match->compatible);
+ return -ENOTSUPP;
+ }
+
+ grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(grf)) {
+ pr_err("%s: Missing rockchip,grf property, %lu\n",
+ __func__, PTR_ERR(grf));
+ return PTR_ERR(grf);
+ }
+
+ ret = data->init_usb_uart(grf);
+ if (ret) {
+ pr_err("%s: could not init usb_uart, %d\n", __func__, ret);
+ enable_usb_uart = 0;
+ return ret;
+ }
+
+ return 0;
+}
+early_initcall(rockchip_init_usb_uart);
+
+static int __init rockchip_usb_uart(char *buf)
+{
+ enable_usb_uart = true;
+ return 0;
+}
+early_param("rockchip.usb_uart", rockchip_usb_uart);
+#endif
+
MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 840f3eae428b..6b6af6cba454 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -391,7 +391,7 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
}
-static int twl4030_usb_runtime_suspend(struct device *dev)
+static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev)
{
struct twl4030_usb *twl = dev_get_drvdata(dev);
@@ -405,7 +405,7 @@ static int twl4030_usb_runtime_suspend(struct device *dev)
return 0;
}
-static int twl4030_usb_runtime_resume(struct device *dev)
+static int __maybe_unused twl4030_usb_runtime_resume(struct device *dev)
{
struct twl4030_usb *twl = dev_get_drvdata(dev);
int res;
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 99a4c10ed43f..fb8200b8e8ec 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -79,7 +79,7 @@ config PINCTRL_AT91PIO4
controller available on sama5d2 SoC.
config PINCTRL_AMD
- bool "AMD GPIO pin control"
+ tristate "AMD GPIO pin control"
depends on GPIOLIB
select GPIOLIB_IRQCHIP
select PINCONF
@@ -168,37 +168,6 @@ config PINCTRL_ST
select PINCONF
select GPIOLIB_IRQCHIP
-config PINCTRL_TEGRA
- bool
- select PINMUX
- select PINCONF
-
-config PINCTRL_TEGRA20
- bool
- select PINCTRL_TEGRA
-
-config PINCTRL_TEGRA30
- bool
- select PINCTRL_TEGRA
-
-config PINCTRL_TEGRA114
- bool
- select PINCTRL_TEGRA
-
-config PINCTRL_TEGRA124
- bool
- select PINCTRL_TEGRA
-
-config PINCTRL_TEGRA210
- bool
- select PINCTRL_TEGRA
-
-config PINCTRL_TEGRA_XUSB
- def_bool y if ARCH_TEGRA
- select GENERIC_PHY
- select PINCONF
- select PINMUX
-
config PINCTRL_TZ1090
bool "Toumaz Xenif TZ1090 pin control driver"
depends on SOC_TZ1090
@@ -238,6 +207,23 @@ config PINCTRL_PALMAS
open drain configuration for the Palmas series devices like
TPS65913, TPS80036 etc.
+config PINCTRL_PIC32
+ bool "Microchip PIC32 pin controller driver"
+ depends on OF
+ depends on MACH_PIC32
+ select PINMUX
+ select GENERIC_PINCONF
+ select GPIOLIB_IRQCHIP
+ select OF_GPIO
+ help
+ This is the pin controller and gpio driver for Microchip PIC32
+ microcontrollers. This option is selected automatically when specific
+ machine and arch are selected to build.
+
+config PINCTRL_PIC32MZDA
+ def_bool y if PIC32MZDA
+ select PINCTRL_PIC32
+
config PINCTRL_ZYNQ
bool "Pinctrl driver for Xilinx Zynq"
depends on ARCH_ZYNQ
@@ -257,7 +243,9 @@ source "drivers/pinctrl/qcom/Kconfig"
source "drivers/pinctrl/samsung/Kconfig"
source "drivers/pinctrl/sh-pfc/Kconfig"
source "drivers/pinctrl/spear/Kconfig"
+source "drivers/pinctrl/stm32/Kconfig"
source "drivers/pinctrl/sunxi/Kconfig"
+source "drivers/pinctrl/tegra/Kconfig"
source "drivers/pinctrl/uniphier/Kconfig"
source "drivers/pinctrl/vt8500/Kconfig"
source "drivers/pinctrl/mediatek/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index bf1b5ca5180b..e4bc1151e04f 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -18,17 +18,12 @@ obj-$(CONFIG_PINCTRL_DIGICOLOR) += pinctrl-digicolor.o
obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o
obj-$(CONFIG_PINCTRL_MESON) += meson/
obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o
+obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o
obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_SIRF) += sirf/
-obj-$(CONFIG_PINCTRL_TEGRA) += pinctrl-tegra.o
-obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
-obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
-obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o
-obj-$(CONFIG_PINCTRL_TEGRA124) += pinctrl-tegra124.o
-obj-$(CONFIG_PINCTRL_TEGRA210) += pinctrl-tegra210.o
-obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o
+obj-$(CONFIG_PINCTRL_TEGRA) += tegra/
obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o
obj-$(CONFIG_PINCTRL_TZ1090_PDC) += pinctrl-tz1090-pdc.o
obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
@@ -46,12 +41,13 @@ obj-y += freescale/
obj-$(CONFIG_X86) += intel/
obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/
obj-y += nomadik/
-obj-$(CONFIG_ARCH_PXA) += pxa/
+obj-$(CONFIG_PINCTRL_PXA) += pxa/
obj-$(CONFIG_ARCH_QCOM) += qcom/
obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/
obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc/
obj-$(CONFIG_PINCTRL_SPEAR) += spear/
-obj-$(CONFIG_ARCH_SUNXI) += sunxi/
+obj-$(CONFIG_PINCTRL_STM32) += stm32/
+obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
obj-$(CONFIG_ARCH_VT8500) += vt8500/
-obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
+obj-$(CONFIG_PINCTRL_MTK) += mediatek/
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index 0f5997ceb494..08b1d93da9fe 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -779,7 +779,7 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
}
if (num_pulls) {
err = of_property_read_u32_index(np, "brcm,pull",
- (num_funcs > 1) ? i : 0, &pull);
+ (num_pulls > 1) ? i : 0, &pull);
if (err)
goto out;
err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin,
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 2686a4450dfc..f67a8b7a4e18 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -481,18 +481,12 @@ int pinctrl_get_group_pins(struct pinctrl_dev *pctldev, const char *pin_group,
}
EXPORT_SYMBOL_GPL(pinctrl_get_group_pins);
-/**
- * pinctrl_find_gpio_range_from_pin() - locate the GPIO range for a pin
- * @pctldev: the pin controller device to look in
- * @pin: a controller-local number to find the range for
- */
struct pinctrl_gpio_range *
-pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
- unsigned int pin)
+pinctrl_find_gpio_range_from_pin_nolock(struct pinctrl_dev *pctldev,
+ unsigned int pin)
{
struct pinctrl_gpio_range *range;
- mutex_lock(&pctldev->mutex);
/* Loop over the ranges */
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
/* Check if we're in the valid range */
@@ -500,15 +494,32 @@ pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
int a;
for (a = 0; a < range->npins; a++) {
if (range->pins[a] == pin)
- goto out;
+ return range;
}
} else if (pin >= range->pin_base &&
pin < range->pin_base + range->npins)
- goto out;
+ return range;
}
- range = NULL;
-out:
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin_nolock);
+
+/**
+ * pinctrl_find_gpio_range_from_pin() - locate the GPIO range for a pin
+ * @pctldev: the pin controller device to look in
+ * @pin: a controller-local number to find the range for
+ */
+struct pinctrl_gpio_range *
+pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
+ unsigned int pin)
+{
+ struct pinctrl_gpio_range *range;
+
+ mutex_lock(&pctldev->mutex);
+ range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin);
mutex_unlock(&pctldev->mutex);
+
return range;
}
EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index b24ea846c867..ca08723b9ee1 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -182,6 +182,10 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
}
+extern struct pinctrl_gpio_range *
+pinctrl_find_gpio_range_from_pin_nolock(struct pinctrl_dev *pctldev,
+ unsigned int pin);
+
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
bool dup);
void pinctrl_unregister_map(struct pinctrl_map const *map);
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index a5bb93987378..46210512d8ec 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -24,6 +25,7 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/slab.h>
+#include <linux/regmap.h>
#include "../core.h"
#include "pinctrl-imx.h"
@@ -341,6 +343,31 @@ mux_pin:
return 0;
}
+static void imx_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg;
+ u32 reg;
+
+ /*
+ * Only Vybrid has the input/output buffer enable flags (IBE/OBE)
+ * They are part of the shared mux/conf register.
+ */
+ if (!(info->flags & SHARE_MUX_CONF_REG))
+ return;
+
+ pin_reg = &info->pin_regs[offset];
+ if (pin_reg->mux_reg == -1)
+ return;
+
+ /* Clear IBE/OBE/PUE to disable the pin (Hi-Z) */
+ reg = readl(ipctl->base + pin_reg->mux_reg);
+ reg &= ~0x7;
+ writel(reg, ipctl->base + pin_reg->mux_reg);
+}
+
static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range, unsigned offset, bool input)
{
@@ -377,6 +404,7 @@ static const struct pinmux_ops imx_pmx_ops = {
.get_function_groups = imx_pmx_get_groups,
.set_mux = imx_pmx_set,
.gpio_request_enable = imx_pmx_gpio_request_enable,
+ .gpio_disable_free = imx_pmx_gpio_disable_free,
.gpio_set_direction = imx_pmx_gpio_set_direction,
};
@@ -692,10 +720,12 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev,
int imx_pinctrl_probe(struct platform_device *pdev,
struct imx_pinctrl_soc_info *info)
{
+ struct regmap_config config = { .name = "gpr" };
struct device_node *dev_np = pdev->dev.of_node;
struct device_node *np;
struct imx_pinctrl *ipctl;
struct resource *res;
+ struct regmap *gpr;
int ret, i;
if (!info || !info->pins || !info->npins) {
@@ -704,6 +734,12 @@ int imx_pinctrl_probe(struct platform_device *pdev,
}
info->dev = &pdev->dev;
+ if (info->gpr_compatible) {
+ gpr = syscon_regmap_lookup_by_compatible(info->gpr_compatible);
+ if (!IS_ERR(gpr))
+ regmap_attach_dev(&pdev->dev, gpr, &config);
+ }
+
/* Create state holders etc for this driver */
ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
if (!ipctl)
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h
index 2a592f657c18..3b8bd81a39a4 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.h
+++ b/drivers/pinctrl/freescale/pinctrl-imx.h
@@ -82,6 +82,7 @@ struct imx_pinctrl_soc_info {
struct imx_pmx_func *functions;
unsigned int nfunctions;
unsigned int flags;
+ const char *gpr_compatible;
};
#define SHARE_MUX_CONF_REG 0x1
diff --git a/drivers/pinctrl/freescale/pinctrl-imx50.c b/drivers/pinctrl/freescale/pinctrl-imx50.c
index 51b31df96273..8acc4d960cfa 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx50.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx50.c
@@ -389,6 +389,7 @@ static const struct pinctrl_pin_desc imx50_pinctrl_pads[] = {
static struct imx_pinctrl_soc_info imx50_pinctrl_info = {
.pins = imx50_pinctrl_pads,
.npins = ARRAY_SIZE(imx50_pinctrl_pads),
+ .gpr_compatible = "fsl,imx50-iomuxc-gpr",
};
static const struct of_device_id imx50_pinctrl_of_match[] = {
diff --git a/drivers/pinctrl/freescale/pinctrl-imx53.c b/drivers/pinctrl/freescale/pinctrl-imx53.c
index 7344d340013c..d39dfd6a3a44 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx53.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx53.c
@@ -452,6 +452,7 @@ static const struct pinctrl_pin_desc imx53_pinctrl_pads[] = {
static struct imx_pinctrl_soc_info imx53_pinctrl_info = {
.pins = imx53_pinctrl_pads,
.npins = ARRAY_SIZE(imx53_pinctrl_pads),
+ .gpr_compatible = "fsl,imx53-iomuxc-gpr",
};
static const struct of_device_id imx53_pinctrl_of_match[] = {
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6dl.c b/drivers/pinctrl/freescale/pinctrl-imx6dl.c
index 6805c678c3b2..5a2cdb0549ce 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6dl.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6dl.c
@@ -458,6 +458,7 @@ static const struct pinctrl_pin_desc imx6dl_pinctrl_pads[] = {
static struct imx_pinctrl_soc_info imx6dl_pinctrl_info = {
.pins = imx6dl_pinctrl_pads,
.npins = ARRAY_SIZE(imx6dl_pinctrl_pads),
+ .gpr_compatible = "fsl,imx6q-iomuxc-gpr",
};
static const struct of_device_id imx6dl_pinctrl_of_match[] = {
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6q.c b/drivers/pinctrl/freescale/pinctrl-imx6q.c
index 4d1fcb861ac1..7d50a36b1086 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6q.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6q.c
@@ -464,6 +464,7 @@ static const struct pinctrl_pin_desc imx6q_pinctrl_pads[] = {
static struct imx_pinctrl_soc_info imx6q_pinctrl_info = {
.pins = imx6q_pinctrl_pads,
.npins = ARRAY_SIZE(imx6q_pinctrl_pads),
+ .gpr_compatible = "fsl,imx6q-iomuxc-gpr",
};
static const struct of_device_id imx6q_pinctrl_of_match[] = {
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sl.c b/drivers/pinctrl/freescale/pinctrl-imx6sl.c
index 83fa5f19ae89..e27d17fdc69d 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6sl.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6sl.c
@@ -364,6 +364,7 @@ static const struct pinctrl_pin_desc imx6sl_pinctrl_pads[] = {
static struct imx_pinctrl_soc_info imx6sl_pinctrl_info = {
.pins = imx6sl_pinctrl_pads,
.npins = ARRAY_SIZE(imx6sl_pinctrl_pads),
+ .gpr_compatible = "fsl,imx6sl-iomuxc-gpr",
};
static const struct of_device_id imx6sl_pinctrl_of_match[] = {
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sx.c b/drivers/pinctrl/freescale/pinctrl-imx6sx.c
index 0d78fe690818..117180c26c50 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6sx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6sx.c
@@ -368,6 +368,7 @@ static const struct pinctrl_pin_desc imx6sx_pinctrl_pads[] = {
static struct imx_pinctrl_soc_info imx6sx_pinctrl_info = {
.pins = imx6sx_pinctrl_pads,
.npins = ARRAY_SIZE(imx6sx_pinctrl_pads),
+ .gpr_compatible = "fsl,imx6sx-iomuxc-gpr",
};
static const struct of_device_id imx6sx_pinctrl_of_match[] = {
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6ul.c b/drivers/pinctrl/freescale/pinctrl-imx6ul.c
index 08e75764e7be..78627c70c6ba 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6ul.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6ul.c
@@ -284,6 +284,7 @@ static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = {
static struct imx_pinctrl_soc_info imx6ul_pinctrl_info = {
.pins = imx6ul_pinctrl_pads,
.npins = ARRAY_SIZE(imx6ul_pinctrl_pads),
+ .gpr_compatible = "fsl,imx6ul-iomuxc-gpr",
};
static struct of_device_id imx6ul_pinctrl_of_match[] = {
diff --git a/drivers/pinctrl/freescale/pinctrl-imx7d.c b/drivers/pinctrl/freescale/pinctrl-imx7d.c
index 16dc925117de..1c89613eb4b7 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx7d.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx7d.c
@@ -359,6 +359,7 @@ static const struct pinctrl_pin_desc imx7d_lpsr_pinctrl_pads[] = {
static struct imx_pinctrl_soc_info imx7d_pinctrl_info = {
.pins = imx7d_pinctrl_pads,
.npins = ARRAY_SIZE(imx7d_pinctrl_pads),
+ .gpr_compatible = "fsl,imx7d-iomuxc-gpr",
};
static struct imx_pinctrl_soc_info imx7d_lpsr_pinctrl_info = {
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index c0f5586218c4..85536b467c25 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -11,13 +11,9 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/acpi.h>
-#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
-#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 02f6f92df86c..4f0bc8a103f4 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -1,6 +1,6 @@
if ARCH_MEDIATEK || COMPILE_TEST
-config PINCTRL_MTK_COMMON
+config PINCTRL_MTK
bool
depends on OF
select PINMUX
@@ -9,17 +9,29 @@ config PINCTRL_MTK_COMMON
select OF_GPIO
# For ARMv7 SoCs
+config PINCTRL_MT2701
+ bool "Mediatek MT2701 pin control" if COMPILE_TEST && !MACH_MT2701
+ depends on OF
+ default MACH_MT2701
+ select PINCTRL_MTK
+
+config PINCTRL_MT7623
+ bool "Mediatek MT7623 pin control" if COMPILE_TEST && !MACH_MT7623
+ depends on OF
+ default MACH_MT7623
+ select PINCTRL_MTK_COMMON
+
config PINCTRL_MT8135
bool "Mediatek MT8135 pin control" if COMPILE_TEST && !MACH_MT8135
depends on OF
default MACH_MT8135
- select PINCTRL_MTK_COMMON
+ select PINCTRL_MTK
config PINCTRL_MT8127
bool "Mediatek MT8127 pin control" if COMPILE_TEST && !MACH_MT8127
depends on OF
default MACH_MT8127
- select PINCTRL_MTK_COMMON
+ select PINCTRL_MTK
# For ARMv8 SoCs
config PINCTRL_MT8173
@@ -27,13 +39,13 @@ config PINCTRL_MT8173
depends on OF
depends on ARM64 || COMPILE_TEST
default ARM64 && ARCH_MEDIATEK
- select PINCTRL_MTK_COMMON
+ select PINCTRL_MTK
# For PMIC
config PINCTRL_MT6397
bool "Mediatek MT6397 pin control" if COMPILE_TEST && !MFD_MT6397
depends on OF
default MFD_MT6397
- select PINCTRL_MTK_COMMON
+ select PINCTRL_MTK
endif
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
index eb923d64d387..3e3390a14716 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -1,8 +1,10 @@
# Core
-obj-$(CONFIG_PINCTRL_MTK_COMMON) += pinctrl-mtk-common.o
+obj-y += pinctrl-mtk-common.o
# SoC Drivers
-obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
-obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
-obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
-obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o
+obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o
+obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o
+obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
+obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
+obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
+obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
new file mode 100644
index 000000000000..8d802fa7decd
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Biao Huang <biao.huang@mediatek.com>
+ *
+ * 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
+ * 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 <dt-bindings/pinctrl/mt65xx.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/regmap.h>
+
+#include "pinctrl-mtk-common.h"
+#include "pinctrl-mtk-mt2701.h"
+
+/**
+ * struct mtk_spec_pinmux_set
+ * - For special pins' mode setting
+ * @pin: The pin number.
+ * @offset: The offset of extra setting register.
+ * @bit: The bit of extra setting register.
+ */
+struct mtk_spec_pinmux_set {
+ unsigned short pin;
+ unsigned short offset;
+ unsigned char bit;
+};
+
+#define MTK_PINMUX_SPEC(_pin, _offset, _bit) \
+ { \
+ .pin = _pin, \
+ .offset = _offset, \
+ .bit = _bit, \
+ }
+
+static const struct mtk_drv_group_desc mt2701_drv_grp[] = {
+ /* 0E4E8SR 4/8/12/16 */
+ MTK_DRV_GRP(4, 16, 1, 2, 4),
+ /* 0E2E4SR 2/4/6/8 */
+ MTK_DRV_GRP(2, 8, 1, 2, 2),
+ /* E8E4E2 2/4/6/8/10/12/14/16 */
+ MTK_DRV_GRP(2, 16, 0, 2, 2)
+};
+
+static const struct mtk_pin_drv_grp mt2701_pin_drv[] = {
+ MTK_PIN_DRV_GRP(0, 0xf50, 0, 1),
+ MTK_PIN_DRV_GRP(1, 0xf50, 0, 1),
+ MTK_PIN_DRV_GRP(2, 0xf50, 0, 1),
+ MTK_PIN_DRV_GRP(3, 0xf50, 0, 1),
+ MTK_PIN_DRV_GRP(4, 0xf50, 0, 1),
+ MTK_PIN_DRV_GRP(5, 0xf50, 0, 1),
+ MTK_PIN_DRV_GRP(6, 0xf50, 0, 1),
+ MTK_PIN_DRV_GRP(7, 0xf50, 4, 1),
+ MTK_PIN_DRV_GRP(8, 0xf50, 4, 1),
+ MTK_PIN_DRV_GRP(9, 0xf50, 4, 1),
+ MTK_PIN_DRV_GRP(10, 0xf50, 8, 1),
+ MTK_PIN_DRV_GRP(11, 0xf50, 8, 1),
+ MTK_PIN_DRV_GRP(12, 0xf50, 8, 1),
+ MTK_PIN_DRV_GRP(13, 0xf50, 8, 1),
+ MTK_PIN_DRV_GRP(14, 0xf50, 12, 0),
+ MTK_PIN_DRV_GRP(15, 0xf50, 12, 0),
+ MTK_PIN_DRV_GRP(16, 0xf60, 0, 0),
+ MTK_PIN_DRV_GRP(17, 0xf60, 0, 0),
+ MTK_PIN_DRV_GRP(18, 0xf60, 4, 0),
+ MTK_PIN_DRV_GRP(19, 0xf60, 4, 0),
+ MTK_PIN_DRV_GRP(20, 0xf60, 4, 0),
+ MTK_PIN_DRV_GRP(21, 0xf60, 4, 0),
+ MTK_PIN_DRV_GRP(22, 0xf60, 8, 0),
+ MTK_PIN_DRV_GRP(23, 0xf60, 8, 0),
+ MTK_PIN_DRV_GRP(24, 0xf60, 8, 0),
+ MTK_PIN_DRV_GRP(25, 0xf60, 8, 0),
+ MTK_PIN_DRV_GRP(26, 0xf60, 8, 0),
+ MTK_PIN_DRV_GRP(27, 0xf60, 12, 0),
+ MTK_PIN_DRV_GRP(28, 0xf60, 12, 0),
+ MTK_PIN_DRV_GRP(29, 0xf60, 12, 0),
+ MTK_PIN_DRV_GRP(30, 0xf60, 0, 0),
+ MTK_PIN_DRV_GRP(31, 0xf60, 0, 0),
+ MTK_PIN_DRV_GRP(32, 0xf60, 0, 0),
+ MTK_PIN_DRV_GRP(33, 0xf70, 0, 0),
+ MTK_PIN_DRV_GRP(34, 0xf70, 0, 0),
+ MTK_PIN_DRV_GRP(35, 0xf70, 0, 0),
+ MTK_PIN_DRV_GRP(36, 0xf70, 0, 0),
+ MTK_PIN_DRV_GRP(37, 0xf70, 0, 0),
+ MTK_PIN_DRV_GRP(38, 0xf70, 4, 0),
+ MTK_PIN_DRV_GRP(39, 0xf70, 8, 1),
+ MTK_PIN_DRV_GRP(40, 0xf70, 8, 1),
+ MTK_PIN_DRV_GRP(41, 0xf70, 8, 1),
+ MTK_PIN_DRV_GRP(42, 0xf70, 8, 1),
+ MTK_PIN_DRV_GRP(43, 0xf70, 12, 0),
+ MTK_PIN_DRV_GRP(44, 0xf70, 12, 0),
+ MTK_PIN_DRV_GRP(45, 0xf70, 12, 0),
+ MTK_PIN_DRV_GRP(47, 0xf80, 0, 0),
+ MTK_PIN_DRV_GRP(48, 0xf80, 0, 0),
+ MTK_PIN_DRV_GRP(49, 0xf80, 4, 0),
+ MTK_PIN_DRV_GRP(50, 0xf70, 4, 0),
+ MTK_PIN_DRV_GRP(51, 0xf70, 4, 0),
+ MTK_PIN_DRV_GRP(52, 0xf70, 4, 0),
+ MTK_PIN_DRV_GRP(53, 0xf80, 12, 0),
+ MTK_PIN_DRV_GRP(54, 0xf80, 12, 0),
+ MTK_PIN_DRV_GRP(55, 0xf80, 12, 0),
+ MTK_PIN_DRV_GRP(56, 0xf80, 12, 0),
+ MTK_PIN_DRV_GRP(60, 0xf90, 8, 1),
+ MTK_PIN_DRV_GRP(61, 0xf90, 8, 1),
+ MTK_PIN_DRV_GRP(62, 0xf90, 8, 1),
+ MTK_PIN_DRV_GRP(63, 0xf90, 12, 1),
+ MTK_PIN_DRV_GRP(64, 0xf90, 12, 1),
+ MTK_PIN_DRV_GRP(65, 0xf90, 12, 1),
+ MTK_PIN_DRV_GRP(66, 0xfa0, 0, 1),
+ MTK_PIN_DRV_GRP(67, 0xfa0, 0, 1),
+ MTK_PIN_DRV_GRP(68, 0xfa0, 0, 1),
+ MTK_PIN_DRV_GRP(69, 0xfa0, 0, 1),
+ MTK_PIN_DRV_GRP(70, 0xfa0, 0, 1),
+ MTK_PIN_DRV_GRP(71, 0xfa0, 0, 1),
+ MTK_PIN_DRV_GRP(72, 0xf80, 4, 0),
+ MTK_PIN_DRV_GRP(73, 0xf80, 4, 0),
+ MTK_PIN_DRV_GRP(74, 0xf80, 4, 0),
+ MTK_PIN_DRV_GRP(85, 0xda0, 0, 2),
+ MTK_PIN_DRV_GRP(86, 0xd90, 0, 2),
+ MTK_PIN_DRV_GRP(87, 0xdb0, 0, 2),
+ MTK_PIN_DRV_GRP(88, 0xdb0, 0, 2),
+ MTK_PIN_DRV_GRP(89, 0xdb0, 0, 2),
+ MTK_PIN_DRV_GRP(90, 0xdb0, 0, 2),
+ MTK_PIN_DRV_GRP(105, 0xd40, 0, 2),
+ MTK_PIN_DRV_GRP(106, 0xd30, 0, 2),
+ MTK_PIN_DRV_GRP(107, 0xd50, 0, 2),
+ MTK_PIN_DRV_GRP(108, 0xd50, 0, 2),
+ MTK_PIN_DRV_GRP(109, 0xd50, 0, 2),
+ MTK_PIN_DRV_GRP(110, 0xd50, 0, 2),
+ MTK_PIN_DRV_GRP(111, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(112, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(113, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(114, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(115, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(116, 0xcd0, 0, 2),
+ MTK_PIN_DRV_GRP(117, 0xcc0, 0, 2),
+ MTK_PIN_DRV_GRP(118, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(119, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(120, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(121, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(126, 0xf80, 4, 0),
+ MTK_PIN_DRV_GRP(188, 0xf70, 4, 0),
+ MTK_PIN_DRV_GRP(189, 0xfe0, 8, 0),
+ MTK_PIN_DRV_GRP(190, 0xfe0, 8, 0),
+ MTK_PIN_DRV_GRP(191, 0xfe0, 8, 0),
+ MTK_PIN_DRV_GRP(192, 0xfe0, 8, 0),
+ MTK_PIN_DRV_GRP(193, 0xfe0, 8, 0),
+ MTK_PIN_DRV_GRP(194, 0xfe0, 12, 0),
+ MTK_PIN_DRV_GRP(195, 0xfe0, 12, 0),
+ MTK_PIN_DRV_GRP(196, 0xfe0, 12, 0),
+ MTK_PIN_DRV_GRP(197, 0xfe0, 12, 0),
+ MTK_PIN_DRV_GRP(198, 0xfe0, 12, 0),
+ MTK_PIN_DRV_GRP(199, 0xf50, 4, 1),
+ MTK_PIN_DRV_GRP(200, 0xfd0, 0, 0),
+ MTK_PIN_DRV_GRP(201, 0xfd0, 0, 0),
+ MTK_PIN_DRV_GRP(202, 0xfd0, 0, 0),
+ MTK_PIN_DRV_GRP(203, 0xfd0, 4, 0),
+ MTK_PIN_DRV_GRP(204, 0xfd0, 4, 0),
+ MTK_PIN_DRV_GRP(205, 0xfd0, 4, 0),
+ MTK_PIN_DRV_GRP(206, 0xfd0, 4, 0),
+ MTK_PIN_DRV_GRP(207, 0xfd0, 4, 0),
+ MTK_PIN_DRV_GRP(208, 0xfd0, 8, 0),
+ MTK_PIN_DRV_GRP(209, 0xfd0, 8, 0),
+ MTK_PIN_DRV_GRP(210, 0xfd0, 12, 1),
+ MTK_PIN_DRV_GRP(211, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(212, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(213, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(214, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(215, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(216, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(217, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(218, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(219, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(220, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(221, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(222, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(223, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(224, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(225, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(226, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(227, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(228, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(229, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(230, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(231, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(232, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(233, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(234, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(235, 0xff0, 0, 1),
+ MTK_PIN_DRV_GRP(236, 0xff0, 4, 0),
+ MTK_PIN_DRV_GRP(237, 0xff0, 4, 0),
+ MTK_PIN_DRV_GRP(238, 0xff0, 4, 0),
+ MTK_PIN_DRV_GRP(239, 0xff0, 4, 0),
+ MTK_PIN_DRV_GRP(240, 0xff0, 4, 0),
+ MTK_PIN_DRV_GRP(241, 0xff0, 4, 0),
+ MTK_PIN_DRV_GRP(242, 0xff0, 8, 0),
+ MTK_PIN_DRV_GRP(243, 0xff0, 8, 0),
+ MTK_PIN_DRV_GRP(248, 0xf00, 0, 0),
+ MTK_PIN_DRV_GRP(249, 0xfc0, 0, 2),
+ MTK_PIN_DRV_GRP(250, 0xfc0, 0, 2),
+ MTK_PIN_DRV_GRP(251, 0xfc0, 0, 2),
+ MTK_PIN_DRV_GRP(252, 0xfc0, 0, 2),
+ MTK_PIN_DRV_GRP(253, 0xfc0, 0, 2),
+ MTK_PIN_DRV_GRP(254, 0xfc0, 0, 2),
+ MTK_PIN_DRV_GRP(255, 0xfc0, 0, 2),
+ MTK_PIN_DRV_GRP(256, 0xfc0, 0, 2),
+ MTK_PIN_DRV_GRP(257, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(258, 0xcb0, 0, 2),
+ MTK_PIN_DRV_GRP(259, 0xc90, 0, 2),
+ MTK_PIN_DRV_GRP(260, 0x3a0, 0, 2),
+ MTK_PIN_DRV_GRP(261, 0xd50, 0, 2),
+ MTK_PIN_DRV_GRP(262, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(263, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(264, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(265, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(266, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(267, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(268, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(269, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(270, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(271, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(272, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(273, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(274, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(275, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(276, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(277, 0xf00, 8, 0),
+ MTK_PIN_DRV_GRP(278, 0xf70, 8, 1),
+};
+
+static const struct mtk_pin_spec_pupd_set_samereg mt2701_spec_pupd[] = {
+ MTK_PIN_PUPD_SPEC_SR(111, 0xd00, 12, 13, 14), /* ms0 data7 */
+ MTK_PIN_PUPD_SPEC_SR(112, 0xd00, 8, 9, 10), /* ms0 data6 */
+ MTK_PIN_PUPD_SPEC_SR(113, 0xd00, 4, 5, 6), /* ms0 data5 */
+ MTK_PIN_PUPD_SPEC_SR(114, 0xd00, 0, 1, 2), /* ms0 data4 */
+ MTK_PIN_PUPD_SPEC_SR(115, 0xd10, 0, 1, 2), /* ms0 rstb */
+ MTK_PIN_PUPD_SPEC_SR(116, 0xcd0, 8, 9, 10), /* ms0 cmd */
+ MTK_PIN_PUPD_SPEC_SR(117, 0xcc0, 8, 9, 10), /* ms0 clk */
+ MTK_PIN_PUPD_SPEC_SR(118, 0xcf0, 12, 13, 14), /* ms0 data3 */
+ MTK_PIN_PUPD_SPEC_SR(119, 0xcf0, 8, 9, 10), /* ms0 data2 */
+ MTK_PIN_PUPD_SPEC_SR(120, 0xcf0, 4, 5, 6), /* ms0 data1 */
+ MTK_PIN_PUPD_SPEC_SR(121, 0xcf0, 0, 1, 2), /* ms0 data0 */
+
+ MTK_PIN_PUPD_SPEC_SR(105, 0xd40, 8, 9, 10), /* ms1 cmd */
+ MTK_PIN_PUPD_SPEC_SR(106, 0xd30, 8, 9, 10), /* ms1 clk */
+ MTK_PIN_PUPD_SPEC_SR(107, 0xd60, 0, 1, 2), /* ms1 dat0 */
+ MTK_PIN_PUPD_SPEC_SR(108, 0xd60, 10, 9, 8), /* ms1 dat1 */
+ MTK_PIN_PUPD_SPEC_SR(109, 0xd60, 4, 5, 6), /* ms1 dat2 */
+ MTK_PIN_PUPD_SPEC_SR(110, 0xc60, 12, 13, 14), /* ms1 dat3 */
+
+ MTK_PIN_PUPD_SPEC_SR(85, 0xda0, 8, 9, 10), /* ms2 cmd */
+ MTK_PIN_PUPD_SPEC_SR(86, 0xd90, 8, 9, 10), /* ms2 clk */
+ MTK_PIN_PUPD_SPEC_SR(87, 0xdc0, 0, 1, 2), /* ms2 dat0 */
+ MTK_PIN_PUPD_SPEC_SR(88, 0xdc0, 10, 9, 8), /* ms2 dat1 */
+ MTK_PIN_PUPD_SPEC_SR(89, 0xdc0, 4, 5, 6), /* ms2 dat2 */
+ MTK_PIN_PUPD_SPEC_SR(90, 0xdc0, 12, 13, 14), /* ms2 dat3 */
+
+ MTK_PIN_PUPD_SPEC_SR(249, 0x140, 0, 1, 2), /* ms0e rstb */
+ MTK_PIN_PUPD_SPEC_SR(250, 0x130, 12, 13, 14), /* ms0e dat7 */
+ MTK_PIN_PUPD_SPEC_SR(251, 0x130, 8, 9, 10), /* ms0e dat6 */
+ MTK_PIN_PUPD_SPEC_SR(252, 0x130, 4, 5, 6), /* ms0e dat5 */
+ MTK_PIN_PUPD_SPEC_SR(253, 0x130, 0, 1, 2), /* ms0e dat4 */
+ MTK_PIN_PUPD_SPEC_SR(254, 0xf40, 12, 13, 14), /* ms0e dat3 */
+ MTK_PIN_PUPD_SPEC_SR(255, 0xf40, 8, 9, 10), /* ms0e dat2 */
+ MTK_PIN_PUPD_SPEC_SR(256, 0xf40, 4, 5, 6), /* ms0e dat1 */
+ MTK_PIN_PUPD_SPEC_SR(257, 0xf40, 0, 1, 2), /* ms0e dat0 */
+ MTK_PIN_PUPD_SPEC_SR(258, 0xcb0, 8, 9, 10), /* ms0e cmd */
+ MTK_PIN_PUPD_SPEC_SR(259, 0xc90, 8, 9, 10), /* ms0e clk */
+ MTK_PIN_PUPD_SPEC_SR(261, 0x140, 8, 9, 10), /* ms1 ins */
+};
+
+static int mt2701_spec_pull_set(struct regmap *regmap, unsigned int pin,
+ unsigned char align, bool isup, unsigned int r1r0)
+{
+ return mtk_pctrl_spec_pull_set_samereg(regmap, mt2701_spec_pupd,
+ ARRAY_SIZE(mt2701_spec_pupd), pin, align, isup, r1r0);
+}
+
+static const struct mtk_pin_ies_smt_set mt2701_ies_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 6, 0xb20, 0),
+ MTK_PIN_IES_SMT_SPEC(7, 9, 0xb20, 1),
+ MTK_PIN_IES_SMT_SPEC(10, 13, 0xb30, 3),
+ MTK_PIN_IES_SMT_SPEC(14, 15, 0xb30, 13),
+ MTK_PIN_IES_SMT_SPEC(16, 17, 0xb40, 7),
+ MTK_PIN_IES_SMT_SPEC(18, 21, 0xb40, 13),
+ MTK_PIN_IES_SMT_SPEC(22, 26, 0xb40, 13),
+ MTK_PIN_IES_SMT_SPEC(27, 29, 0xb40, 13),
+ MTK_PIN_IES_SMT_SPEC(30, 32, 0xb40, 7),
+ MTK_PIN_IES_SMT_SPEC(33, 37, 0xb40, 13),
+ MTK_PIN_IES_SMT_SPEC(38, 38, 0xb20, 13),
+ MTK_PIN_IES_SMT_SPEC(39, 42, 0xb40, 13),
+ MTK_PIN_IES_SMT_SPEC(43, 45, 0xb20, 10),
+ MTK_PIN_IES_SMT_SPEC(47, 48, 0xb20, 11),
+ MTK_PIN_IES_SMT_SPEC(49, 49, 0xb20, 12),
+ MTK_PIN_IES_SMT_SPEC(50, 52, 0xb20, 13),
+ MTK_PIN_IES_SMT_SPEC(53, 56, 0xb20, 14),
+ MTK_PIN_IES_SMT_SPEC(57, 58, 0xb20, 15),
+ MTK_PIN_IES_SMT_SPEC(59, 59, 0xb30, 10),
+ MTK_PIN_IES_SMT_SPEC(60, 62, 0xb30, 0),
+ MTK_PIN_IES_SMT_SPEC(63, 65, 0xb30, 1),
+ MTK_PIN_IES_SMT_SPEC(66, 71, 0xb30, 2),
+ MTK_PIN_IES_SMT_SPEC(72, 74, 0xb20, 12),
+ MTK_PIN_IES_SMT_SPEC(75, 76, 0xb30, 3),
+ MTK_PIN_IES_SMT_SPEC(77, 78, 0xb30, 4),
+ MTK_PIN_IES_SMT_SPEC(79, 82, 0xb30, 5),
+ MTK_PIN_IES_SMT_SPEC(83, 84, 0xb30, 2),
+ MTK_PIN_IES_SMT_SPEC(85, 85, 0xda0, 4),
+ MTK_PIN_IES_SMT_SPEC(86, 86, 0xd90, 4),
+ MTK_PIN_IES_SMT_SPEC(87, 90, 0xdb0, 4),
+ MTK_PIN_IES_SMT_SPEC(101, 104, 0xb30, 6),
+ MTK_PIN_IES_SMT_SPEC(105, 105, 0xd40, 4),
+ MTK_PIN_IES_SMT_SPEC(106, 106, 0xd30, 4),
+ MTK_PIN_IES_SMT_SPEC(107, 110, 0xd50, 4),
+ MTK_PIN_IES_SMT_SPEC(111, 115, 0xce0, 4),
+ MTK_PIN_IES_SMT_SPEC(116, 116, 0xcd0, 4),
+ MTK_PIN_IES_SMT_SPEC(117, 117, 0xcc0, 4),
+ MTK_PIN_IES_SMT_SPEC(118, 121, 0xce0, 4),
+ MTK_PIN_IES_SMT_SPEC(122, 125, 0xb30, 7),
+ MTK_PIN_IES_SMT_SPEC(126, 126, 0xb20, 12),
+ MTK_PIN_IES_SMT_SPEC(127, 142, 0xb30, 9),
+ MTK_PIN_IES_SMT_SPEC(143, 160, 0xb30, 10),
+ MTK_PIN_IES_SMT_SPEC(161, 168, 0xb30, 12),
+ MTK_PIN_IES_SMT_SPEC(169, 183, 0xb30, 10),
+ MTK_PIN_IES_SMT_SPEC(184, 186, 0xb30, 9),
+ MTK_PIN_IES_SMT_SPEC(187, 187, 0xb30, 14),
+ MTK_PIN_IES_SMT_SPEC(188, 188, 0xb20, 13),
+ MTK_PIN_IES_SMT_SPEC(189, 193, 0xb30, 15),
+ MTK_PIN_IES_SMT_SPEC(194, 198, 0xb40, 0),
+ MTK_PIN_IES_SMT_SPEC(199, 199, 0xb20, 1),
+ MTK_PIN_IES_SMT_SPEC(200, 202, 0xb40, 1),
+ MTK_PIN_IES_SMT_SPEC(203, 207, 0xb40, 2),
+ MTK_PIN_IES_SMT_SPEC(208, 209, 0xb40, 3),
+ MTK_PIN_IES_SMT_SPEC(210, 210, 0xb40, 4),
+ MTK_PIN_IES_SMT_SPEC(211, 235, 0xb40, 5),
+ MTK_PIN_IES_SMT_SPEC(236, 241, 0xb40, 6),
+ MTK_PIN_IES_SMT_SPEC(242, 243, 0xb40, 7),
+ MTK_PIN_IES_SMT_SPEC(244, 247, 0xb40, 8),
+ MTK_PIN_IES_SMT_SPEC(248, 248, 0xb40, 9),
+ MTK_PIN_IES_SMT_SPEC(249, 257, 0xfc0, 4),
+ MTK_PIN_IES_SMT_SPEC(258, 258, 0xcb0, 4),
+ MTK_PIN_IES_SMT_SPEC(259, 259, 0xc90, 4),
+ MTK_PIN_IES_SMT_SPEC(260, 260, 0x3a0, 4),
+ MTK_PIN_IES_SMT_SPEC(261, 261, 0xd50, 4),
+ MTK_PIN_IES_SMT_SPEC(262, 277, 0xb40, 12),
+ MTK_PIN_IES_SMT_SPEC(278, 278, 0xb40, 13),
+};
+
+static const struct mtk_pin_ies_smt_set mt2701_smt_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 6, 0xb50, 0),
+ MTK_PIN_IES_SMT_SPEC(7, 9, 0xb50, 1),
+ MTK_PIN_IES_SMT_SPEC(10, 13, 0xb60, 3),
+ MTK_PIN_IES_SMT_SPEC(14, 15, 0xb60, 13),
+ MTK_PIN_IES_SMT_SPEC(16, 17, 0xb70, 7),
+ MTK_PIN_IES_SMT_SPEC(18, 21, 0xb70, 13),
+ MTK_PIN_IES_SMT_SPEC(22, 26, 0xb70, 13),
+ MTK_PIN_IES_SMT_SPEC(27, 29, 0xb70, 13),
+ MTK_PIN_IES_SMT_SPEC(30, 32, 0xb70, 7),
+ MTK_PIN_IES_SMT_SPEC(33, 37, 0xb70, 13),
+ MTK_PIN_IES_SMT_SPEC(38, 38, 0xb50, 13),
+ MTK_PIN_IES_SMT_SPEC(39, 42, 0xb70, 13),
+ MTK_PIN_IES_SMT_SPEC(43, 45, 0xb50, 10),
+ MTK_PIN_IES_SMT_SPEC(47, 48, 0xb50, 11),
+ MTK_PIN_IES_SMT_SPEC(49, 49, 0xb50, 12),
+ MTK_PIN_IES_SMT_SPEC(50, 52, 0xb50, 13),
+ MTK_PIN_IES_SMT_SPEC(53, 56, 0xb50, 14),
+ MTK_PIN_IES_SMT_SPEC(57, 58, 0xb50, 15),
+ MTK_PIN_IES_SMT_SPEC(59, 59, 0xb60, 10),
+ MTK_PIN_IES_SMT_SPEC(60, 62, 0xb60, 0),
+ MTK_PIN_IES_SMT_SPEC(63, 65, 0xb60, 1),
+ MTK_PIN_IES_SMT_SPEC(66, 71, 0xb60, 2),
+ MTK_PIN_IES_SMT_SPEC(72, 74, 0xb50, 12),
+ MTK_PIN_IES_SMT_SPEC(75, 76, 0xb60, 3),
+ MTK_PIN_IES_SMT_SPEC(77, 78, 0xb60, 4),
+ MTK_PIN_IES_SMT_SPEC(79, 82, 0xb60, 5),
+ MTK_PIN_IES_SMT_SPEC(83, 84, 0xb60, 2),
+ MTK_PIN_IES_SMT_SPEC(85, 85, 0xda0, 11),
+ MTK_PIN_IES_SMT_SPEC(86, 86, 0xd90, 11),
+ MTK_PIN_IES_SMT_SPEC(87, 87, 0xdc0, 3),
+ MTK_PIN_IES_SMT_SPEC(88, 88, 0xdc0, 7),
+ MTK_PIN_IES_SMT_SPEC(89, 89, 0xdc0, 11),
+ MTK_PIN_IES_SMT_SPEC(90, 90, 0xdc0, 15),
+ MTK_PIN_IES_SMT_SPEC(101, 104, 0xb60, 6),
+ MTK_PIN_IES_SMT_SPEC(105, 105, 0xd40, 11),
+ MTK_PIN_IES_SMT_SPEC(106, 106, 0xd30, 11),
+ MTK_PIN_IES_SMT_SPEC(107, 107, 0xd60, 3),
+ MTK_PIN_IES_SMT_SPEC(108, 108, 0xd60, 7),
+ MTK_PIN_IES_SMT_SPEC(109, 109, 0xd60, 11),
+ MTK_PIN_IES_SMT_SPEC(110, 110, 0xd60, 15),
+ MTK_PIN_IES_SMT_SPEC(111, 111, 0xd00, 15),
+ MTK_PIN_IES_SMT_SPEC(112, 112, 0xd00, 11),
+ MTK_PIN_IES_SMT_SPEC(113, 113, 0xd00, 7),
+ MTK_PIN_IES_SMT_SPEC(114, 114, 0xd00, 3),
+ MTK_PIN_IES_SMT_SPEC(115, 115, 0xd10, 3),
+ MTK_PIN_IES_SMT_SPEC(116, 116, 0xcd0, 11),
+ MTK_PIN_IES_SMT_SPEC(117, 117, 0xcc0, 11),
+ MTK_PIN_IES_SMT_SPEC(118, 118, 0xcf0, 15),
+ MTK_PIN_IES_SMT_SPEC(119, 119, 0xcf0, 11),
+ MTK_PIN_IES_SMT_SPEC(120, 120, 0xcf0, 7),
+ MTK_PIN_IES_SMT_SPEC(121, 121, 0xcf0, 3),
+ MTK_PIN_IES_SMT_SPEC(122, 125, 0xb60, 7),
+ MTK_PIN_IES_SMT_SPEC(126, 126, 0xb50, 12),
+ MTK_PIN_IES_SMT_SPEC(127, 142, 0xb60, 9),
+ MTK_PIN_IES_SMT_SPEC(143, 160, 0xb60, 10),
+ MTK_PIN_IES_SMT_SPEC(161, 168, 0xb60, 12),
+ MTK_PIN_IES_SMT_SPEC(169, 183, 0xb60, 10),
+ MTK_PIN_IES_SMT_SPEC(184, 186, 0xb60, 9),
+ MTK_PIN_IES_SMT_SPEC(187, 187, 0xb60, 14),
+ MTK_PIN_IES_SMT_SPEC(188, 188, 0xb50, 13),
+ MTK_PIN_IES_SMT_SPEC(189, 193, 0xb60, 15),
+ MTK_PIN_IES_SMT_SPEC(194, 198, 0xb70, 0),
+ MTK_PIN_IES_SMT_SPEC(199, 199, 0xb50, 1),
+ MTK_PIN_IES_SMT_SPEC(200, 202, 0xb70, 1),
+ MTK_PIN_IES_SMT_SPEC(203, 207, 0xb70, 2),
+ MTK_PIN_IES_SMT_SPEC(208, 209, 0xb70, 3),
+ MTK_PIN_IES_SMT_SPEC(210, 210, 0xb70, 4),
+ MTK_PIN_IES_SMT_SPEC(211, 235, 0xb70, 5),
+ MTK_PIN_IES_SMT_SPEC(236, 241, 0xb70, 6),
+ MTK_PIN_IES_SMT_SPEC(242, 243, 0xb70, 7),
+ MTK_PIN_IES_SMT_SPEC(244, 247, 0xb70, 8),
+ MTK_PIN_IES_SMT_SPEC(248, 248, 0xb70, 9),
+ MTK_PIN_IES_SMT_SPEC(249, 249, 0x140, 3),
+ MTK_PIN_IES_SMT_SPEC(250, 250, 0x130, 15),
+ MTK_PIN_IES_SMT_SPEC(251, 251, 0x130, 11),
+ MTK_PIN_IES_SMT_SPEC(252, 252, 0x130, 7),
+ MTK_PIN_IES_SMT_SPEC(253, 253, 0x130, 3),
+ MTK_PIN_IES_SMT_SPEC(254, 254, 0xf40, 15),
+ MTK_PIN_IES_SMT_SPEC(255, 255, 0xf40, 11),
+ MTK_PIN_IES_SMT_SPEC(256, 256, 0xf40, 7),
+ MTK_PIN_IES_SMT_SPEC(257, 257, 0xf40, 3),
+ MTK_PIN_IES_SMT_SPEC(258, 258, 0xcb0, 11),
+ MTK_PIN_IES_SMT_SPEC(259, 259, 0xc90, 11),
+ MTK_PIN_IES_SMT_SPEC(260, 260, 0x3a0, 11),
+ MTK_PIN_IES_SMT_SPEC(261, 261, 0x0b0, 3),
+ MTK_PIN_IES_SMT_SPEC(262, 277, 0xb70, 12),
+ MTK_PIN_IES_SMT_SPEC(278, 278, 0xb70, 13),
+};
+
+static int mt2701_ies_smt_set(struct regmap *regmap, unsigned int pin,
+ unsigned char align, int value, enum pin_config_param arg)
+{
+ if (arg == PIN_CONFIG_INPUT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt2701_ies_set,
+ ARRAY_SIZE(mt2701_ies_set), pin, align, value);
+ else if (arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt2701_smt_set,
+ ARRAY_SIZE(mt2701_smt_set), pin, align, value);
+ return -EINVAL;
+}
+
+static const struct mtk_spec_pinmux_set mt2701_spec_pinmux[] = {
+ MTK_PINMUX_SPEC(22, 0xb10, 3),
+ MTK_PINMUX_SPEC(23, 0xb10, 4),
+ MTK_PINMUX_SPEC(24, 0xb10, 5),
+ MTK_PINMUX_SPEC(29, 0xb10, 9),
+ MTK_PINMUX_SPEC(208, 0xb10, 7),
+ MTK_PINMUX_SPEC(209, 0xb10, 8),
+ MTK_PINMUX_SPEC(203, 0xf20, 0),
+ MTK_PINMUX_SPEC(204, 0xf20, 1),
+ MTK_PINMUX_SPEC(249, 0xef0, 0),
+ MTK_PINMUX_SPEC(250, 0xef0, 0),
+ MTK_PINMUX_SPEC(251, 0xef0, 0),
+ MTK_PINMUX_SPEC(252, 0xef0, 0),
+ MTK_PINMUX_SPEC(253, 0xef0, 0),
+ MTK_PINMUX_SPEC(254, 0xef0, 0),
+ MTK_PINMUX_SPEC(255, 0xef0, 0),
+ MTK_PINMUX_SPEC(256, 0xef0, 0),
+ MTK_PINMUX_SPEC(257, 0xef0, 0),
+ MTK_PINMUX_SPEC(258, 0xef0, 0),
+ MTK_PINMUX_SPEC(259, 0xef0, 0),
+ MTK_PINMUX_SPEC(260, 0xef0, 0),
+};
+
+static void mt2701_spec_pinmux_set(struct regmap *reg, unsigned int pin,
+ unsigned int mode)
+{
+ unsigned int i, value, mask;
+ unsigned int info_num = ARRAY_SIZE(mt2701_spec_pinmux);
+ unsigned int spec_flag;
+
+ for (i = 0; i < info_num; i++) {
+ if (pin == mt2701_spec_pinmux[i].pin)
+ break;
+ }
+
+ if (i == info_num)
+ return;
+
+ spec_flag = (mode >> 3);
+ mask = BIT(mt2701_spec_pinmux[i].bit);
+ if (!spec_flag)
+ value = mask;
+ else
+ value = 0;
+ regmap_update_bits(reg, mt2701_spec_pinmux[i].offset, mask, value);
+}
+
+static void mt2701_spec_dir_set(unsigned int *reg_addr, unsigned int pin)
+{
+ if (pin > 175)
+ *reg_addr += 0x10;
+}
+
+static const struct mtk_pinctrl_devdata mt2701_pinctrl_data = {
+ .pins = mtk_pins_mt2701,
+ .npins = ARRAY_SIZE(mtk_pins_mt2701),
+ .grp_desc = mt2701_drv_grp,
+ .n_grp_cls = ARRAY_SIZE(mt2701_drv_grp),
+ .pin_drv_grp = mt2701_pin_drv,
+ .n_pin_drv_grps = ARRAY_SIZE(mt2701_pin_drv),
+ .spec_pull_set = mt2701_spec_pull_set,
+ .spec_ies_smt_set = mt2701_ies_smt_set,
+ .spec_pinmux_set = mt2701_spec_pinmux_set,
+ .spec_dir_set = mt2701_spec_dir_set,
+ .dir_offset = 0x0000,
+ .pullen_offset = 0x0150,
+ .pullsel_offset = 0x0280,
+ .dout_offset = 0x0500,
+ .din_offset = 0x0630,
+ .pinmux_offset = 0x0760,
+ .type1_start = 280,
+ .type1_end = 280,
+ .port_shf = 4,
+ .port_mask = 0x1f,
+ .port_align = 4,
+ .eint_offsets = {
+ .name = "mt2701_eint",
+ .stat = 0x000,
+ .ack = 0x040,
+ .mask = 0x080,
+ .mask_set = 0x0c0,
+ .mask_clr = 0x100,
+ .sens = 0x140,
+ .sens_set = 0x180,
+ .sens_clr = 0x1c0,
+ .soft = 0x200,
+ .soft_set = 0x240,
+ .soft_clr = 0x280,
+ .pol = 0x300,
+ .pol_set = 0x340,
+ .pol_clr = 0x380,
+ .dom_en = 0x400,
+ .dbnc_ctrl = 0x500,
+ .dbnc_set = 0x600,
+ .dbnc_clr = 0x700,
+ .port_mask = 6,
+ .ports = 6,
+ },
+ .ap_num = 169,
+ .db_cnt = 16,
+};
+
+static int mt2701_pinctrl_probe(struct platform_device *pdev)
+{
+ return mtk_pctrl_init(pdev, &mt2701_pinctrl_data, NULL);
+}
+
+static const struct of_device_id mt2701_pctrl_match[] = {
+ { .compatible = "mediatek,mt2701-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt2701_pctrl_match);
+
+static struct platform_driver mtk_pinctrl_driver = {
+ .probe = mt2701_pinctrl_probe,
+ .driver = {
+ .name = "mediatek-mt2701-pinctrl",
+ .of_match_table = mt2701_pctrl_match,
+ .pm = &mtk_eint_pm_ops,
+ },
+};
+
+static int __init mtk_pinctrl_init(void)
+{
+ return platform_driver_register(&mtk_pinctrl_driver);
+}
+arch_initcall(mtk_pinctrl_init);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6397.c b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
index f9751ae28e32..6eccb85c02cd 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6397.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
@@ -12,7 +12,7 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -55,7 +55,6 @@ static const struct of_device_id mt6397_pctrl_match[] = {
{ .compatible = "mediatek,mt6397-pinctrl", },
{ }
};
-MODULE_DEVICE_TABLE(of, mt6397_pctrl_match);
static struct platform_driver mtk_pinctrl_driver = {
.probe = mt6397_pinctrl_probe,
@@ -69,9 +68,4 @@ static int __init mtk_pinctrl_init(void)
{
return platform_driver_register(&mtk_pinctrl_driver);
}
-
-module_init(mtk_pinctrl_init);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MediaTek MT6397 Pinctrl Driver");
-MODULE_AUTHOR("Hongzhou Yang <hongzhou.yang@mediatek.com>");
+device_initcall(mtk_pinctrl_init);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
new file mode 100644
index 000000000000..67895f8234e3
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2016 John Crispin <blogic@openwrt.org>
+ *
+ * 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
+ * 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 <dt-bindings/pinctrl/mt65xx.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/regmap.h>
+
+#include "pinctrl-mtk-common.h"
+#include "pinctrl-mtk-mt7623.h"
+
+static const struct mtk_drv_group_desc mt7623_drv_grp[] = {
+ /* 0E4E8SR 4/8/12/16 */
+ MTK_DRV_GRP(4, 16, 1, 2, 4),
+ /* 0E2E4SR 2/4/6/8 */
+ MTK_DRV_GRP(2, 8, 1, 2, 2),
+ /* E8E4E2 2/4/6/8/10/12/14/16 */
+ MTK_DRV_GRP(2, 16, 0, 2, 2)
+};
+
+#define DRV_SEL0 0xf50
+#define DRV_SEL1 0xf60
+#define DRV_SEL2 0xf70
+#define DRV_SEL3 0xf80
+#define DRV_SEL4 0xf90
+#define DRV_SEL5 0xfa0
+#define DRV_SEL6 0xfb0
+#define DRV_SEL7 0xfe0
+#define DRV_SEL8 0xfd0
+#define DRV_SEL9 0xff0
+#define DRV_SEL10 0xf00
+
+#define MSDC0_CTRL0 0xcc0
+#define MSDC0_CTRL1 0xcd0
+#define MSDC0_CTRL2 0xce0
+#define MSDC0_CTRL3 0xcf0
+#define MSDC0_CTRL4 0xd00
+#define MSDC0_CTRL5 0xd10
+#define MSDC0_CTRL6 0xd20
+#define MSDC1_CTRL0 0xd30
+#define MSDC1_CTRL1 0xd40
+#define MSDC1_CTRL2 0xd50
+#define MSDC1_CTRL3 0xd60
+#define MSDC1_CTRL4 0xd70
+#define MSDC1_CTRL5 0xd80
+#define MSDC1_CTRL6 0xd90
+
+#define IES_EN0 0xb20
+#define IES_EN1 0xb30
+#define IES_EN2 0xb40
+
+#define SMT_EN0 0xb50
+#define SMT_EN1 0xb60
+#define SMT_EN2 0xb70
+
+static const struct mtk_pin_drv_grp mt7623_pin_drv[] = {
+ MTK_PIN_DRV_GRP(0, DRV_SEL0, 0, 1),
+ MTK_PIN_DRV_GRP(1, DRV_SEL0, 0, 1),
+ MTK_PIN_DRV_GRP(2, DRV_SEL0, 0, 1),
+ MTK_PIN_DRV_GRP(3, DRV_SEL0, 0, 1),
+ MTK_PIN_DRV_GRP(4, DRV_SEL0, 0, 1),
+ MTK_PIN_DRV_GRP(5, DRV_SEL0, 0, 1),
+ MTK_PIN_DRV_GRP(6, DRV_SEL0, 0, 1),
+ MTK_PIN_DRV_GRP(7, DRV_SEL0, 4, 1),
+ MTK_PIN_DRV_GRP(8, DRV_SEL0, 4, 1),
+ MTK_PIN_DRV_GRP(9, DRV_SEL0, 4, 1),
+ MTK_PIN_DRV_GRP(10, DRV_SEL0, 8, 1),
+ MTK_PIN_DRV_GRP(11, DRV_SEL0, 8, 1),
+ MTK_PIN_DRV_GRP(12, DRV_SEL0, 8, 1),
+ MTK_PIN_DRV_GRP(13, DRV_SEL0, 8, 1),
+ MTK_PIN_DRV_GRP(14, DRV_SEL0, 12, 0),
+ MTK_PIN_DRV_GRP(15, DRV_SEL0, 12, 0),
+ MTK_PIN_DRV_GRP(18, DRV_SEL1, 4, 0),
+ MTK_PIN_DRV_GRP(19, DRV_SEL1, 4, 0),
+ MTK_PIN_DRV_GRP(20, DRV_SEL1, 4, 0),
+ MTK_PIN_DRV_GRP(21, DRV_SEL1, 4, 0),
+ MTK_PIN_DRV_GRP(22, DRV_SEL1, 8, 0),
+ MTK_PIN_DRV_GRP(23, DRV_SEL1, 8, 0),
+ MTK_PIN_DRV_GRP(24, DRV_SEL1, 8, 0),
+ MTK_PIN_DRV_GRP(25, DRV_SEL1, 8, 0),
+ MTK_PIN_DRV_GRP(26, DRV_SEL1, 8, 0),
+ MTK_PIN_DRV_GRP(27, DRV_SEL1, 12, 0),
+ MTK_PIN_DRV_GRP(28, DRV_SEL1, 12, 0),
+ MTK_PIN_DRV_GRP(29, DRV_SEL1, 12, 0),
+ MTK_PIN_DRV_GRP(33, DRV_SEL2, 0, 0),
+ MTK_PIN_DRV_GRP(34, DRV_SEL2, 0, 0),
+ MTK_PIN_DRV_GRP(35, DRV_SEL2, 0, 0),
+ MTK_PIN_DRV_GRP(36, DRV_SEL2, 0, 0),
+ MTK_PIN_DRV_GRP(37, DRV_SEL2, 0, 0),
+ MTK_PIN_DRV_GRP(39, DRV_SEL2, 8, 1),
+ MTK_PIN_DRV_GRP(40, DRV_SEL2, 8, 1),
+ MTK_PIN_DRV_GRP(41, DRV_SEL2, 8, 1),
+ MTK_PIN_DRV_GRP(42, DRV_SEL2, 8, 1),
+ MTK_PIN_DRV_GRP(43, DRV_SEL2, 12, 0),
+ MTK_PIN_DRV_GRP(44, DRV_SEL2, 12, 0),
+ MTK_PIN_DRV_GRP(45, DRV_SEL2, 12, 0),
+ MTK_PIN_DRV_GRP(47, DRV_SEL3, 0, 0),
+ MTK_PIN_DRV_GRP(48, DRV_SEL3, 0, 0),
+ MTK_PIN_DRV_GRP(49, DRV_SEL3, 4, 0),
+ MTK_PIN_DRV_GRP(53, DRV_SEL3, 12, 0),
+ MTK_PIN_DRV_GRP(54, DRV_SEL3, 12, 0),
+ MTK_PIN_DRV_GRP(55, DRV_SEL3, 12, 0),
+ MTK_PIN_DRV_GRP(56, DRV_SEL3, 12, 0),
+ MTK_PIN_DRV_GRP(60, DRV_SEL4, 8, 1),
+ MTK_PIN_DRV_GRP(61, DRV_SEL4, 8, 1),
+ MTK_PIN_DRV_GRP(62, DRV_SEL4, 8, 1),
+ MTK_PIN_DRV_GRP(63, DRV_SEL4, 12, 1),
+ MTK_PIN_DRV_GRP(64, DRV_SEL4, 12, 1),
+ MTK_PIN_DRV_GRP(65, DRV_SEL4, 12, 1),
+ MTK_PIN_DRV_GRP(66, DRV_SEL5, 0, 1),
+ MTK_PIN_DRV_GRP(67, DRV_SEL5, 0, 1),
+ MTK_PIN_DRV_GRP(68, DRV_SEL5, 0, 1),
+ MTK_PIN_DRV_GRP(69, DRV_SEL5, 0, 1),
+ MTK_PIN_DRV_GRP(70, DRV_SEL5, 0, 1),
+ MTK_PIN_DRV_GRP(71, DRV_SEL5, 0, 1),
+ MTK_PIN_DRV_GRP(72, DRV_SEL3, 4, 0),
+ MTK_PIN_DRV_GRP(73, DRV_SEL3, 4, 0),
+ MTK_PIN_DRV_GRP(74, DRV_SEL3, 4, 0),
+ MTK_PIN_DRV_GRP(83, DRV_SEL5, 0, 1),
+ MTK_PIN_DRV_GRP(84, DRV_SEL5, 0, 1),
+ MTK_PIN_DRV_GRP(105, MSDC1_CTRL1, 0, 1),
+ MTK_PIN_DRV_GRP(106, MSDC1_CTRL0, 0, 1),
+ MTK_PIN_DRV_GRP(107, MSDC1_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(108, MSDC1_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(109, MSDC1_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(110, MSDC1_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(111, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(112, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(113, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(114, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(115, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(116, MSDC0_CTRL1, 0, 1),
+ MTK_PIN_DRV_GRP(117, MSDC0_CTRL0, 0, 1),
+ MTK_PIN_DRV_GRP(118, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(119, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(120, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(121, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(126, DRV_SEL3, 4, 0),
+ MTK_PIN_DRV_GRP(199, DRV_SEL0, 4, 1),
+ MTK_PIN_DRV_GRP(200, DRV_SEL8, 0, 0),
+ MTK_PIN_DRV_GRP(201, DRV_SEL8, 0, 0),
+ MTK_PIN_DRV_GRP(203, DRV_SEL8, 4, 0),
+ MTK_PIN_DRV_GRP(204, DRV_SEL8, 4, 0),
+ MTK_PIN_DRV_GRP(205, DRV_SEL8, 4, 0),
+ MTK_PIN_DRV_GRP(206, DRV_SEL8, 4, 0),
+ MTK_PIN_DRV_GRP(207, DRV_SEL8, 4, 0),
+ MTK_PIN_DRV_GRP(208, DRV_SEL8, 8, 0),
+ MTK_PIN_DRV_GRP(209, DRV_SEL8, 8, 0),
+ MTK_PIN_DRV_GRP(236, DRV_SEL9, 4, 0),
+ MTK_PIN_DRV_GRP(237, DRV_SEL9, 4, 0),
+ MTK_PIN_DRV_GRP(238, DRV_SEL9, 4, 0),
+ MTK_PIN_DRV_GRP(239, DRV_SEL9, 4, 0),
+ MTK_PIN_DRV_GRP(240, DRV_SEL9, 4, 0),
+ MTK_PIN_DRV_GRP(241, DRV_SEL9, 4, 0),
+ MTK_PIN_DRV_GRP(242, DRV_SEL9, 8, 0),
+ MTK_PIN_DRV_GRP(243, DRV_SEL9, 8, 0),
+ MTK_PIN_DRV_GRP(257, MSDC0_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(261, MSDC1_CTRL2, 0, 1),
+ MTK_PIN_DRV_GRP(262, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(263, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(264, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(265, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(266, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(267, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(268, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(269, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(270, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(271, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(272, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(274, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(275, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(276, DRV_SEL10, 8, 0),
+ MTK_PIN_DRV_GRP(278, DRV_SEL2, 8, 1),
+};
+
+static const struct mtk_pin_spec_pupd_set_samereg mt7623_spec_pupd[] = {
+ MTK_PIN_PUPD_SPEC_SR(105, MSDC1_CTRL1, 8, 9, 10),
+ MTK_PIN_PUPD_SPEC_SR(106, MSDC1_CTRL0, 8, 9, 10),
+ MTK_PIN_PUPD_SPEC_SR(107, MSDC1_CTRL3, 0, 1, 2),
+ MTK_PIN_PUPD_SPEC_SR(108, MSDC1_CTRL3, 4, 5, 6),
+ MTK_PIN_PUPD_SPEC_SR(109, MSDC1_CTRL3, 8, 9, 10),
+ MTK_PIN_PUPD_SPEC_SR(110, MSDC1_CTRL3, 12, 13, 14),
+ MTK_PIN_PUPD_SPEC_SR(111, MSDC0_CTRL4, 12, 13, 14),
+ MTK_PIN_PUPD_SPEC_SR(112, MSDC0_CTRL4, 8, 9, 10),
+ MTK_PIN_PUPD_SPEC_SR(113, MSDC0_CTRL4, 4, 5, 6),
+ MTK_PIN_PUPD_SPEC_SR(114, MSDC0_CTRL4, 0, 1, 2),
+ MTK_PIN_PUPD_SPEC_SR(115, MSDC0_CTRL5, 0, 1, 2),
+ MTK_PIN_PUPD_SPEC_SR(116, MSDC0_CTRL1, 8, 9, 10),
+ MTK_PIN_PUPD_SPEC_SR(117, MSDC0_CTRL0, 8, 9, 10),
+ MTK_PIN_PUPD_SPEC_SR(118, MSDC0_CTRL3, 12, 13, 14),
+ MTK_PIN_PUPD_SPEC_SR(119, MSDC0_CTRL3, 8, 9, 10),
+ MTK_PIN_PUPD_SPEC_SR(120, MSDC0_CTRL3, 4, 5, 6),
+ MTK_PIN_PUPD_SPEC_SR(121, MSDC0_CTRL3, 0, 1, 2),
+};
+
+static int mt7623_spec_pull_set(struct regmap *regmap, unsigned int pin,
+ unsigned char align, bool isup, unsigned int r1r0)
+{
+ return mtk_pctrl_spec_pull_set_samereg(regmap, mt7623_spec_pupd,
+ ARRAY_SIZE(mt7623_spec_pupd), pin, align, isup, r1r0);
+}
+
+static const struct mtk_pin_ies_smt_set mt7623_ies_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 6, IES_EN0, 0),
+ MTK_PIN_IES_SMT_SPEC(7, 9, IES_EN0, 1),
+ MTK_PIN_IES_SMT_SPEC(10, 13, IES_EN0, 2),
+ MTK_PIN_IES_SMT_SPEC(14, 15, IES_EN0, 3),
+ MTK_PIN_IES_SMT_SPEC(18, 21, IES_EN0, 5),
+ MTK_PIN_IES_SMT_SPEC(22, 26, IES_EN0, 6),
+ MTK_PIN_IES_SMT_SPEC(27, 29, IES_EN0, 7),
+ MTK_PIN_IES_SMT_SPEC(33, 37, IES_EN0, 8),
+ MTK_PIN_IES_SMT_SPEC(39, 42, IES_EN0, 9),
+ MTK_PIN_IES_SMT_SPEC(43, 45, IES_EN0, 10),
+ MTK_PIN_IES_SMT_SPEC(47, 48, IES_EN0, 11),
+ MTK_PIN_IES_SMT_SPEC(49, 49, IES_EN0, 12),
+ MTK_PIN_IES_SMT_SPEC(53, 56, IES_EN0, 14),
+ MTK_PIN_IES_SMT_SPEC(60, 62, IES_EN1, 0),
+ MTK_PIN_IES_SMT_SPEC(63, 65, IES_EN1, 1),
+ MTK_PIN_IES_SMT_SPEC(66, 71, IES_EN1, 2),
+ MTK_PIN_IES_SMT_SPEC(72, 74, IES_EN0, 12),
+ MTK_PIN_IES_SMT_SPEC(75, 76, IES_EN1, 3),
+ MTK_PIN_IES_SMT_SPEC(83, 84, IES_EN1, 2),
+ MTK_PIN_IES_SMT_SPEC(105, 121, MSDC1_CTRL1, 4),
+ MTK_PIN_IES_SMT_SPEC(122, 125, IES_EN1, 7),
+ MTK_PIN_IES_SMT_SPEC(126, 126, IES_EN0, 12),
+ MTK_PIN_IES_SMT_SPEC(199, 201, IES_EN0, 1),
+ MTK_PIN_IES_SMT_SPEC(203, 207, IES_EN2, 2),
+ MTK_PIN_IES_SMT_SPEC(208, 209, IES_EN2, 3),
+ MTK_PIN_IES_SMT_SPEC(236, 241, IES_EN2, 6),
+ MTK_PIN_IES_SMT_SPEC(242, 243, IES_EN2, 7),
+ MTK_PIN_IES_SMT_SPEC(261, 261, MSDC1_CTRL2, 4),
+ MTK_PIN_IES_SMT_SPEC(262, 272, IES_EN2, 12),
+ MTK_PIN_IES_SMT_SPEC(274, 276, IES_EN2, 12),
+ MTK_PIN_IES_SMT_SPEC(278, 278, IES_EN2, 13),
+};
+
+static const struct mtk_pin_ies_smt_set mt7623_smt_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 6, SMT_EN0, 0),
+ MTK_PIN_IES_SMT_SPEC(7, 9, SMT_EN0, 1),
+ MTK_PIN_IES_SMT_SPEC(10, 13, SMT_EN0, 2),
+ MTK_PIN_IES_SMT_SPEC(14, 15, SMT_EN0, 3),
+ MTK_PIN_IES_SMT_SPEC(18, 21, SMT_EN0, 5),
+ MTK_PIN_IES_SMT_SPEC(22, 26, SMT_EN0, 6),
+ MTK_PIN_IES_SMT_SPEC(27, 29, SMT_EN0, 7),
+ MTK_PIN_IES_SMT_SPEC(33, 37, SMT_EN0, 8),
+ MTK_PIN_IES_SMT_SPEC(39, 42, SMT_EN0, 9),
+ MTK_PIN_IES_SMT_SPEC(43, 45, SMT_EN0, 10),
+ MTK_PIN_IES_SMT_SPEC(47, 48, SMT_EN0, 11),
+ MTK_PIN_IES_SMT_SPEC(49, 49, SMT_EN0, 12),
+ MTK_PIN_IES_SMT_SPEC(53, 56, SMT_EN0, 14),
+ MTK_PIN_IES_SMT_SPEC(60, 62, SMT_EN1, 0),
+ MTK_PIN_IES_SMT_SPEC(63, 65, SMT_EN1, 1),
+ MTK_PIN_IES_SMT_SPEC(66, 71, SMT_EN1, 2),
+ MTK_PIN_IES_SMT_SPEC(72, 74, SMT_EN0, 12),
+ MTK_PIN_IES_SMT_SPEC(75, 76, SMT_EN1, 3),
+ MTK_PIN_IES_SMT_SPEC(83, 84, SMT_EN1, 2),
+ MTK_PIN_IES_SMT_SPEC(105, 106, MSDC1_CTRL1, 11),
+ MTK_PIN_IES_SMT_SPEC(107, 107, MSDC1_CTRL3, 3),
+ MTK_PIN_IES_SMT_SPEC(108, 108, MSDC1_CTRL3, 7),
+ MTK_PIN_IES_SMT_SPEC(109, 109, MSDC1_CTRL3, 11),
+ MTK_PIN_IES_SMT_SPEC(110, 111, MSDC1_CTRL3, 15),
+ MTK_PIN_IES_SMT_SPEC(112, 112, MSDC0_CTRL4, 11),
+ MTK_PIN_IES_SMT_SPEC(113, 113, MSDC0_CTRL4, 7),
+ MTK_PIN_IES_SMT_SPEC(114, 115, MSDC0_CTRL4, 3),
+ MTK_PIN_IES_SMT_SPEC(116, 117, MSDC0_CTRL1, 11),
+ MTK_PIN_IES_SMT_SPEC(118, 118, MSDC0_CTRL3, 15),
+ MTK_PIN_IES_SMT_SPEC(119, 119, MSDC0_CTRL3, 11),
+ MTK_PIN_IES_SMT_SPEC(120, 120, MSDC0_CTRL3, 7),
+ MTK_PIN_IES_SMT_SPEC(121, 121, MSDC0_CTRL3, 3),
+ MTK_PIN_IES_SMT_SPEC(122, 125, SMT_EN1, 7),
+ MTK_PIN_IES_SMT_SPEC(126, 126, SMT_EN0, 12),
+ MTK_PIN_IES_SMT_SPEC(199, 201, SMT_EN0, 1),
+ MTK_PIN_IES_SMT_SPEC(203, 207, SMT_EN2, 2),
+ MTK_PIN_IES_SMT_SPEC(208, 209, SMT_EN2, 3),
+ MTK_PIN_IES_SMT_SPEC(236, 241, SMT_EN2, 6),
+ MTK_PIN_IES_SMT_SPEC(242, 243, SMT_EN2, 7),
+ MTK_PIN_IES_SMT_SPEC(261, 261, MSDC1_CTRL6, 3),
+ MTK_PIN_IES_SMT_SPEC(262, 272, SMT_EN2, 12),
+ MTK_PIN_IES_SMT_SPEC(274, 276, SMT_EN2, 12),
+ MTK_PIN_IES_SMT_SPEC(278, 278, SMT_EN2, 13),
+};
+
+static int mt7623_ies_smt_set(struct regmap *regmap, unsigned int pin,
+ unsigned char align, int value, enum pin_config_param arg)
+{
+ if (arg == PIN_CONFIG_INPUT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt7623_ies_set,
+ ARRAY_SIZE(mt7623_ies_set), pin, align, value);
+ else if (arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt7623_smt_set,
+ ARRAY_SIZE(mt7623_smt_set), pin, align, value);
+ return -EINVAL;
+}
+
+static const struct mtk_pinctrl_devdata mt7623_pinctrl_data = {
+ .pins = mtk_pins_mt7623,
+ .npins = ARRAY_SIZE(mtk_pins_mt7623),
+ .grp_desc = mt7623_drv_grp,
+ .n_grp_cls = ARRAY_SIZE(mt7623_drv_grp),
+ .pin_drv_grp = mt7623_pin_drv,
+ .n_pin_drv_grps = ARRAY_SIZE(mt7623_pin_drv),
+ .spec_pull_set = mt7623_spec_pull_set,
+ .spec_ies_smt_set = mt7623_ies_smt_set,
+ .dir_offset = 0x0000,
+ .pullen_offset = 0x0150,
+ .pullsel_offset = 0x0280,
+ .dout_offset = 0x0500,
+ .din_offset = 0x0630,
+ .pinmux_offset = 0x0760,
+ .type1_start = 280,
+ .type1_end = 280,
+ .port_shf = 4,
+ .port_mask = 0x1f,
+ .port_align = 4,
+ .eint_offsets = {
+ .name = "mt7623_eint",
+ .stat = 0x000,
+ .ack = 0x040,
+ .mask = 0x080,
+ .mask_set = 0x0c0,
+ .mask_clr = 0x100,
+ .sens = 0x140,
+ .sens_set = 0x180,
+ .sens_clr = 0x1c0,
+ .soft = 0x200,
+ .soft_set = 0x240,
+ .soft_clr = 0x280,
+ .pol = 0x300,
+ .pol_set = 0x340,
+ .pol_clr = 0x380,
+ .dom_en = 0x400,
+ .dbnc_ctrl = 0x500,
+ .dbnc_set = 0x600,
+ .dbnc_clr = 0x700,
+ .port_mask = 6,
+ .ports = 6,
+ },
+ .ap_num = 169,
+ .db_cnt = 16,
+};
+
+static int mt7623_pinctrl_probe(struct platform_device *pdev)
+{
+ return mtk_pctrl_init(pdev, &mt7623_pinctrl_data, NULL);
+}
+
+static const struct of_device_id mt7623_pctrl_match[] = {
+ { .compatible = "mediatek,mt7623-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt7623_pctrl_match);
+
+static struct platform_driver mtk_pinctrl_driver = {
+ .probe = mt7623_pinctrl_probe,
+ .driver = {
+ .name = "mediatek-mt7623-pinctrl",
+ .of_match_table = mt7623_pctrl_match,
+ },
+};
+
+static int __init mtk_pinctrl_init(void)
+{
+ return platform_driver_register(&mtk_pinctrl_driver);
+}
+
+arch_initcall(mtk_pinctrl_init);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8127.c b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
index 98e0bebfdf92..d76491574841 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8127.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
@@ -13,7 +13,7 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -336,7 +336,6 @@ static const struct of_device_id mt8127_pctrl_match[] = {
{ .compatible = "mediatek,mt8127-pinctrl", },
{ }
};
-MODULE_DEVICE_TABLE(of, mt8127_pctrl_match);
static struct platform_driver mtk_pinctrl_driver = {
.probe = mt8127_pinctrl_probe,
@@ -350,9 +349,4 @@ static int __init mtk_pinctrl_init(void)
{
return platform_driver_register(&mtk_pinctrl_driver);
}
-
arch_initcall(mtk_pinctrl_init);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MediaTek MT8127 Pinctrl Driver");
-MODULE_AUTHOR("Yingjoe Chen <yingjoe.chen@mediatek.com>");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8135.c b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
index 1c153b860f36..d8c645f16f21 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8135.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
@@ -12,7 +12,7 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -351,7 +351,6 @@ static const struct of_device_id mt8135_pctrl_match[] = {
},
{ }
};
-MODULE_DEVICE_TABLE(of, mt8135_pctrl_match);
static struct platform_driver mtk_pinctrl_driver = {
.probe = mt8135_pinctrl_probe,
@@ -365,9 +364,4 @@ static int __init mtk_pinctrl_init(void)
{
return platform_driver_register(&mtk_pinctrl_driver);
}
-
arch_initcall(mtk_pinctrl_init);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MediaTek Pinctrl Driver");
-MODULE_AUTHOR("Hongzhou Yang <hongzhou.yang@mediatek.com>");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index a62514eb2129..8bfd427b9135 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -12,7 +12,7 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -378,7 +378,6 @@ static const struct of_device_id mt8173_pctrl_match[] = {
},
{ }
};
-MODULE_DEVICE_TABLE(of, mt8173_pctrl_match);
static struct platform_driver mtk_pinctrl_driver = {
.probe = mt8173_pinctrl_probe,
@@ -393,9 +392,4 @@ static int __init mtk_pinctrl_init(void)
{
return platform_driver_register(&mtk_pinctrl_driver);
}
-
arch_initcall(mtk_pinctrl_init);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MediaTek Pinctrl Driver");
-MODULE_AUTHOR("Hongzhou Yang <hongzhou.yang@mediatek.com>");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 16d48a4ed225..2bbe6f7964a7 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -43,10 +43,13 @@
#define MAX_GPIO_MODE_PER_REG 5
#define GPIO_MODE_BITS 3
+#define GPIO_MODE_PREFIX "GPIO"
static const char * const mtk_gpio_functions[] = {
"func0", "func1", "func2", "func3",
"func4", "func5", "func6", "func7",
+ "func8", "func9", "func10", "func11",
+ "func12", "func13", "func14", "func15",
};
/*
@@ -81,6 +84,9 @@ static int mtk_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
bit = BIT(offset & 0xf);
+ if (pctl->devdata->spec_dir_set)
+ pctl->devdata->spec_dir_set(&reg_addr, offset);
+
if (input)
/* Different SoC has different alignment offset. */
reg_addr = CLR_ADDR(reg_addr, pctl);
@@ -347,6 +353,7 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
ret = mtk_pconf_set_pull_select(pctl, pin, true, false, arg);
break;
case PIN_CONFIG_INPUT_ENABLE:
+ mtk_pmx_gpio_set_direction(pctldev, NULL, pin, true);
ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
break;
case PIN_CONFIG_OUTPUT:
@@ -354,6 +361,7 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
ret = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ mtk_pmx_gpio_set_direction(pctldev, NULL, pin, true);
ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
break;
case PIN_CONFIG_DRIVE_STRENGTH:
@@ -675,9 +683,14 @@ static int mtk_pmx_set_mode(struct pinctrl_dev *pctldev,
unsigned int mask = (1L << GPIO_MODE_BITS) - 1;
struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ if (pctl->devdata->spec_pinmux_set)
+ pctl->devdata->spec_pinmux_set(mtk_get_regmap(pctl, pin),
+ pin, mode);
+
reg_addr = ((pin / MAX_GPIO_MODE_PER_REG) << pctl->devdata->port_shf)
+ pctl->devdata->pinmux_offset;
+ mode &= mask;
bit = pin % MAX_GPIO_MODE_PER_REG;
mask <<= (GPIO_MODE_BITS * bit);
val = (mode << (GPIO_MODE_BITS * bit));
@@ -723,12 +736,48 @@ static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev,
return 0;
}
+static int mtk_pmx_find_gpio_mode(struct mtk_pinctrl *pctl,
+ unsigned offset)
+{
+ const struct mtk_desc_pin *pin = pctl->devdata->pins + offset;
+ const struct mtk_desc_function *func = pin->functions;
+
+ while (func && func->name) {
+ if (!strncmp(func->name, GPIO_MODE_PREFIX,
+ sizeof(GPIO_MODE_PREFIX)-1))
+ return func->muxval;
+ func++;
+ }
+ return -EINVAL;
+}
+
+static int mtk_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ int muxval;
+ struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ muxval = mtk_pmx_find_gpio_mode(pctl, offset);
+
+ if (muxval < 0) {
+ dev_err(pctl->dev, "invalid gpio pin %d.\n", offset);
+ return -EINVAL;
+ }
+
+ mtk_pmx_set_mode(pctldev, offset, muxval);
+ mtk_pconf_set_ies_smt(pctl, offset, 1, PIN_CONFIG_INPUT_ENABLE);
+
+ return 0;
+}
+
static const struct pinmux_ops mtk_pmx_ops = {
.get_functions_count = mtk_pmx_get_funcs_cnt,
.get_function_name = mtk_pmx_get_func_name,
.get_function_groups = mtk_pmx_get_func_groups,
.set_mux = mtk_pmx_set_mux,
.gpio_set_direction = mtk_pmx_gpio_set_direction,
+ .gpio_request_enable = mtk_pmx_gpio_request_enable,
};
static int mtk_gpio_direction_input(struct gpio_chip *chip,
@@ -754,6 +803,10 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
bit = BIT(offset & 0xf);
+
+ if (pctl->devdata->spec_dir_set)
+ pctl->devdata->spec_dir_set(&reg_addr, offset);
+
regmap_read(pctl->regmap1, reg_addr, &read_val);
return !(read_val & bit);
}
@@ -812,6 +865,10 @@ static int mtk_pinctrl_irq_request_resources(struct irq_data *d)
/* set mux to INT mode */
mtk_pmx_set_mode(pctl->pctl_dev, pin->pin.number, pin->eint.eintmux);
+ /* set gpio direction to input */
+ mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, pin->pin.number, true);
+ /* set input-enable */
+ mtk_pconf_set_ies_smt(pctl, pin->pin.number, 1, PIN_CONFIG_INPUT_ENABLE);
return 0;
}
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
index 55a534338931..8543bc478a1e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -209,7 +209,14 @@ struct mtk_eint_offsets {
* means when user set smt, input enable is set at the same time. So they
* also need special control. If special control is success, this should
* return 0, otherwise return non-zero value.
- *
+ * @spec_pinmux_set: In some cases, there are two pinmux functions share
+ * the same value in the same segment of pinmux control register. If user
+ * want to use one of the two functions, they need an extra bit setting to
+ * select the right one.
+ * @spec_dir_set: In very few SoCs, direction control registers are not
+ * arranged continuously, they may be cut to parts. So they need special
+ * dir setting.
+
* @dir_offset: The direction register offset.
* @pullen_offset: The pull-up/pull-down enable register offset.
* @pinmux_offset: The pinmux register offset.
@@ -234,6 +241,9 @@ struct mtk_pinctrl_devdata {
unsigned char align, bool isup, unsigned int arg);
int (*spec_ies_smt_set)(struct regmap *reg, unsigned int pin,
unsigned char align, int value, enum pin_config_param arg);
+ void (*spec_pinmux_set)(struct regmap *reg, unsigned int pin,
+ unsigned int mode);
+ void (*spec_dir_set)(unsigned int *reg_addr, unsigned int pin);
unsigned int dir_offset;
unsigned int ies_offset;
unsigned int smt_offset;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h
new file mode 100644
index 000000000000..f90642078c31
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h
@@ -0,0 +1,2323 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Biao Huang <biao.huang@mediatek.com>
+ *
+ * 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
+ * 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 __PINCTRL_MTK_MT2701_H
+#define __PINCTRL_MTK_MT2701_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-mtk-common.h"
+
+static const struct mtk_desc_pin mtk_pins_mt2701[] = {
+ MTK_PIN(
+ PINCTRL_PIN(0, "PWRAP_SPI0_MI"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 148),
+ MTK_FUNCTION(0, "GPIO0"),
+ MTK_FUNCTION(1, "PWRAP_SPIDO"),
+ MTK_FUNCTION(2, "PWRAP_SPIDI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(1, "PWRAP_SPI0_MO"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 149),
+ MTK_FUNCTION(0, "GPIO1"),
+ MTK_FUNCTION(1, "PWRAP_SPIDI"),
+ MTK_FUNCTION(2, "PWRAP_SPIDO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(2, "PWRAP_INT"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 150),
+ MTK_FUNCTION(0, "GPIO2"),
+ MTK_FUNCTION(1, "PWRAP_INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(3, "PWRAP_SPI0_CK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 151),
+ MTK_FUNCTION(0, "GPIO3"),
+ MTK_FUNCTION(1, "PWRAP_SPICK_I")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(4, "PWRAP_SPI0_CSN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 152),
+ MTK_FUNCTION(0, "GPIO4"),
+ MTK_FUNCTION(1, "PWRAP_SPICS_B_I")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(5, "PWRAP_SPI0_CK2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 153),
+ MTK_FUNCTION(0, "GPIO5"),
+ MTK_FUNCTION(1, "PWRAP_SPICK2_I"),
+ MTK_FUNCTION(5, "ANT_SEL1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(6, "PWRAP_SPI0_CSN2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 154),
+ MTK_FUNCTION(0, "GPIO6"),
+ MTK_FUNCTION(1, "PWRAP_SPICS2_B_I"),
+ MTK_FUNCTION(5, "ANT_SEL0"),
+ MTK_FUNCTION(7, "DBG_MON_A[0]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(7, "SPI1_CSN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 155),
+ MTK_FUNCTION(0, "GPIO7"),
+ MTK_FUNCTION(1, "SPI1_CS"),
+ MTK_FUNCTION(4, "KCOL0"),
+ MTK_FUNCTION(7, "DBG_MON_B[12]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(8, "SPI1_MI"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 156),
+ MTK_FUNCTION(0, "GPIO8"),
+ MTK_FUNCTION(1, "SPI1_MI"),
+ MTK_FUNCTION(2, "SPI1_MO"),
+ MTK_FUNCTION(4, "KCOL1"),
+ MTK_FUNCTION(7, "DBG_MON_B[13]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(9, "SPI1_MO"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 157),
+ MTK_FUNCTION(0, "GPIO9"),
+ MTK_FUNCTION(1, "SPI1_MO"),
+ MTK_FUNCTION(2, "SPI1_MI"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(4, "KCOL2"),
+ MTK_FUNCTION(7, "DBG_MON_B[14]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(10, "RTC32K_CK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 158),
+ MTK_FUNCTION(0, "GPIO10"),
+ MTK_FUNCTION(1, "RTC32K_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(11, "WATCHDOG"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 159),
+ MTK_FUNCTION(0, "GPIO11"),
+ MTK_FUNCTION(1, "WATCHDOG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(12, "SRCLKENA"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 160),
+ MTK_FUNCTION(0, "GPIO12"),
+ MTK_FUNCTION(1, "SRCLKENA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(13, "SRCLKENAI"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 161),
+ MTK_FUNCTION(0, "GPIO13"),
+ MTK_FUNCTION(1, "SRCLKENAI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(14, "URXD2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 162),
+ MTK_FUNCTION(0, "GPIO14"),
+ MTK_FUNCTION(1, "URXD2"),
+ MTK_FUNCTION(2, "UTXD2"),
+ MTK_FUNCTION(5, "SRCCLKENAI2"),
+ MTK_FUNCTION(7, "DBG_MON_B[30]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(15, "UTXD2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 163),
+ MTK_FUNCTION(0, "GPIO15"),
+ MTK_FUNCTION(1, "UTXD2"),
+ MTK_FUNCTION(2, "URXD2"),
+ MTK_FUNCTION(7, "DBG_MON_B[31]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(16, "I2S5_DATA_IN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 164),
+ MTK_FUNCTION(0, "GPIO16"),
+ MTK_FUNCTION(1, "I2S5_DATA_IN"),
+ MTK_FUNCTION(3, "PCM_RX"),
+ MTK_FUNCTION(4, "ANT_SEL4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(17, "I2S5_BCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 165),
+ MTK_FUNCTION(0, "GPIO17"),
+ MTK_FUNCTION(1, "I2S5_BCK"),
+ MTK_FUNCTION(3, "PCM_CLK0"),
+ MTK_FUNCTION(4, "ANT_SEL2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(18, "PCM_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 166),
+ MTK_FUNCTION(0, "GPIO18"),
+ MTK_FUNCTION(1, "PCM_CLK0"),
+ MTK_FUNCTION(2, "MRG_CLK"),
+ MTK_FUNCTION(4, "MM_TEST_CK"),
+ MTK_FUNCTION(5, "CONN_DSP_JCK"),
+ MTK_FUNCTION(6, "WCN_PCM_CLKO"),
+ MTK_FUNCTION(7, "DBG_MON_A[3]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(19, "PCM_SYNC"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 167),
+ MTK_FUNCTION(0, "GPIO19"),
+ MTK_FUNCTION(1, "PCM_SYNC"),
+ MTK_FUNCTION(2, "MRG_SYNC"),
+ MTK_FUNCTION(5, "CONN_DSP_JINTP"),
+ MTK_FUNCTION(6, "WCN_PCM_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_A[5]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(20, "PCM_RX"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO20"),
+ MTK_FUNCTION(1, "PCM_RX"),
+ MTK_FUNCTION(2, "MRG_RX"),
+ MTK_FUNCTION(3, "MRG_TX"),
+ MTK_FUNCTION(4, "PCM_TX"),
+ MTK_FUNCTION(5, "CONN_DSP_JDI"),
+ MTK_FUNCTION(6, "WCN_PCM_RX"),
+ MTK_FUNCTION(7, "DBG_MON_A[4]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(21, "PCM_TX"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO21"),
+ MTK_FUNCTION(1, "PCM_TX"),
+ MTK_FUNCTION(2, "MRG_TX"),
+ MTK_FUNCTION(3, "MRG_RX"),
+ MTK_FUNCTION(4, "PCM_RX"),
+ MTK_FUNCTION(5, "CONN_DSP_JMS"),
+ MTK_FUNCTION(6, "WCN_PCM_TX"),
+ MTK_FUNCTION(7, "DBG_MON_A[2]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(22, "EINT0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 0),
+ MTK_FUNCTION(0, "GPIO22"),
+ MTK_FUNCTION(1, "UCTS0"),
+ MTK_FUNCTION(3, "KCOL3"),
+ MTK_FUNCTION(4, "CONN_DSP_JDO"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_A[30]"),
+ MTK_FUNCTION(10, "PCIE0_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(23, "EINT1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 1),
+ MTK_FUNCTION(0, "GPIO23"),
+ MTK_FUNCTION(1, "URTS0"),
+ MTK_FUNCTION(3, "KCOL2"),
+ MTK_FUNCTION(4, "CONN_MCU_TDO"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_A[29]"),
+ MTK_FUNCTION(10, "PCIE1_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(24, "EINT2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 2),
+ MTK_FUNCTION(0, "GPIO24"),
+ MTK_FUNCTION(1, "UCTS1"),
+ MTK_FUNCTION(3, "KCOL1"),
+ MTK_FUNCTION(4, "CONN_MCU_DBGACK_N"),
+ MTK_FUNCTION(7, "DBG_MON_A[28]"),
+ MTK_FUNCTION(10, "PCIE2_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(25, "EINT3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 3),
+ MTK_FUNCTION(0, "GPIO25"),
+ MTK_FUNCTION(1, "URTS1"),
+ MTK_FUNCTION(3, "KCOL0"),
+ MTK_FUNCTION(4, "CONN_MCU_DBGI_N"),
+ MTK_FUNCTION(7, "DBG_MON_A[27]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(26, "EINT4"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 4),
+ MTK_FUNCTION(0, "GPIO26"),
+ MTK_FUNCTION(1, "UCTS3"),
+ MTK_FUNCTION(2, "DRV_VBUS_P1"),
+ MTK_FUNCTION(3, "KROW3"),
+ MTK_FUNCTION(4, "CONN_MCU_TCK0"),
+ MTK_FUNCTION(5, "CONN_MCU_AICE_JCKC"),
+ MTK_FUNCTION(6, "PCIE2_WAKE_N"),
+ MTK_FUNCTION(7, "DBG_MON_A[26]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(27, "EINT5"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 5),
+ MTK_FUNCTION(0, "GPIO27"),
+ MTK_FUNCTION(1, "URTS3"),
+ MTK_FUNCTION(2, "IDDIG_P1"),
+ MTK_FUNCTION(3, "KROW2"),
+ MTK_FUNCTION(4, "CONN_MCU_TDI"),
+ MTK_FUNCTION(6, "PCIE1_WAKE_N"),
+ MTK_FUNCTION(7, "DBG_MON_A[25]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(28, "EINT6"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 6),
+ MTK_FUNCTION(0, "GPIO28"),
+ MTK_FUNCTION(1, "DRV_VBUS"),
+ MTK_FUNCTION(3, "KROW1"),
+ MTK_FUNCTION(4, "CONN_MCU_TRST_B"),
+ MTK_FUNCTION(6, "PCIE0_WAKE_N"),
+ MTK_FUNCTION(7, "DBG_MON_A[24]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(29, "EINT7"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 7),
+ MTK_FUNCTION(0, "GPIO29"),
+ MTK_FUNCTION(1, "IDDIG"),
+ MTK_FUNCTION(2, "MSDC1_WP"),
+ MTK_FUNCTION(3, "KROW0"),
+ MTK_FUNCTION(4, "CONN_MCU_TMS"),
+ MTK_FUNCTION(5, "CONN_MCU_AICE_JMSC"),
+ MTK_FUNCTION(7, "DBG_MON_A[23]"),
+ MTK_FUNCTION(14, "PCIE2_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(30, "I2S5_LRCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 12),
+ MTK_FUNCTION(0, "GPIO30"),
+ MTK_FUNCTION(1, "I2S5_LRCK"),
+ MTK_FUNCTION(3, "PCM_SYNC"),
+ MTK_FUNCTION(4, "ANT_SEL1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(31, "I2S5_MCLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 13),
+ MTK_FUNCTION(0, "GPIO31"),
+ MTK_FUNCTION(1, "I2S5_MCLK"),
+ MTK_FUNCTION(4, "ANT_SEL0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(32, "I2S5_DATA"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 14),
+ MTK_FUNCTION(0, "GPIO32"),
+ MTK_FUNCTION(1, "I2S5_DATA"),
+ MTK_FUNCTION(2, "I2S5_DATA_BYPS"),
+ MTK_FUNCTION(3, "PCM_TX"),
+ MTK_FUNCTION(4, "ANT_SEL3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(33, "I2S1_DATA"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 15),
+ MTK_FUNCTION(0, "GPIO33"),
+ MTK_FUNCTION(1, "I2S1_DATA"),
+ MTK_FUNCTION(2, "I2S1_DATA_BYPS"),
+ MTK_FUNCTION(3, "PCM_TX"),
+ MTK_FUNCTION(4, "IMG_TEST_CK"),
+ MTK_FUNCTION(5, "G1_RXD0"),
+ MTK_FUNCTION(6, "WCN_PCM_TX"),
+ MTK_FUNCTION(7, "DBG_MON_B[8]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(34, "I2S1_DATA_IN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 16),
+ MTK_FUNCTION(0, "GPIO34"),
+ MTK_FUNCTION(1, "I2S1_DATA_IN"),
+ MTK_FUNCTION(3, "PCM_RX"),
+ MTK_FUNCTION(4, "VDEC_TEST_CK"),
+ MTK_FUNCTION(5, "G1_RXD1"),
+ MTK_FUNCTION(6, "WCN_PCM_RX"),
+ MTK_FUNCTION(7, "DBG_MON_B[7]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(35, "I2S1_BCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 17),
+ MTK_FUNCTION(0, "GPIO35"),
+ MTK_FUNCTION(1, "I2S1_BCK"),
+ MTK_FUNCTION(3, "PCM_CLK0"),
+ MTK_FUNCTION(5, "G1_RXD2"),
+ MTK_FUNCTION(6, "WCN_PCM_CLKO"),
+ MTK_FUNCTION(7, "DBG_MON_B[9]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(36, "I2S1_LRCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 18),
+ MTK_FUNCTION(0, "GPIO36"),
+ MTK_FUNCTION(1, "I2S1_LRCK"),
+ MTK_FUNCTION(3, "PCM_SYNC"),
+ MTK_FUNCTION(5, "G1_RXD3"),
+ MTK_FUNCTION(6, "WCN_PCM_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_B[10]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(37, "I2S1_MCLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 19),
+ MTK_FUNCTION(0, "GPIO37"),
+ MTK_FUNCTION(1, "I2S1_MCLK"),
+ MTK_FUNCTION(5, "G1_RXDV"),
+ MTK_FUNCTION(7, "DBG_MON_B[11]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(38, "I2S2_DATA"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 20),
+ MTK_FUNCTION(0, "GPIO38"),
+ MTK_FUNCTION(2, "I2S2_DATA_BYPS"),
+ MTK_FUNCTION(3, "PCM_TX"),
+ MTK_FUNCTION(4, "DMIC_DAT0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(39, "JTMS"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 21),
+ MTK_FUNCTION(0, "GPIO39"),
+ MTK_FUNCTION(1, "JTMS"),
+ MTK_FUNCTION(2, "CONN_MCU_TMS"),
+ MTK_FUNCTION(3, "CONN_MCU_AICE_JMSC"),
+ MTK_FUNCTION(4, "DFD_TMS_XI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(40, "JTCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 22),
+ MTK_FUNCTION(0, "GPIO40"),
+ MTK_FUNCTION(1, "JTCK"),
+ MTK_FUNCTION(2, "CONN_MCU_TCK1"),
+ MTK_FUNCTION(3, "CONN_MCU_AICE_JCKC"),
+ MTK_FUNCTION(4, "DFD_TCK_XI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(41, "JTDI"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 23),
+ MTK_FUNCTION(0, "GPIO41"),
+ MTK_FUNCTION(1, "JTDI"),
+ MTK_FUNCTION(2, "CONN_MCU_TDI"),
+ MTK_FUNCTION(4, "DFD_TDI_XI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(42, "JTDO"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 24),
+ MTK_FUNCTION(0, "GPIO42"),
+ MTK_FUNCTION(1, "JTDO"),
+ MTK_FUNCTION(2, "CONN_MCU_TDO"),
+ MTK_FUNCTION(4, "DFD_TDO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(43, "NCLE"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 25),
+ MTK_FUNCTION(0, "GPIO43"),
+ MTK_FUNCTION(1, "NCLE"),
+ MTK_FUNCTION(2, "EXT_XCS2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(44, "NCEB1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 26),
+ MTK_FUNCTION(0, "GPIO44"),
+ MTK_FUNCTION(1, "NCEB1"),
+ MTK_FUNCTION(2, "IDDIG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(45, "NCEB0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 27),
+ MTK_FUNCTION(0, "GPIO45"),
+ MTK_FUNCTION(1, "NCEB0"),
+ MTK_FUNCTION(2, "DRV_VBUS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(46, "IR"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 28),
+ MTK_FUNCTION(0, "GPIO46"),
+ MTK_FUNCTION(1, "IR")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(47, "NREB"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 29),
+ MTK_FUNCTION(0, "GPIO47"),
+ MTK_FUNCTION(1, "NREB"),
+ MTK_FUNCTION(2, "IDDIG_P1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(48, "NRNB"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 30),
+ MTK_FUNCTION(0, "GPIO48"),
+ MTK_FUNCTION(1, "NRNB"),
+ MTK_FUNCTION(2, "DRV_VBUS_P1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(49, "I2S0_DATA"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 31),
+ MTK_FUNCTION(0, "GPIO49"),
+ MTK_FUNCTION(1, "I2S0_DATA"),
+ MTK_FUNCTION(2, "I2S0_DATA_BYPS"),
+ MTK_FUNCTION(3, "PCM_TX"),
+ MTK_FUNCTION(6, "WCN_I2S_DO"),
+ MTK_FUNCTION(7, "DBG_MON_B[3]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(50, "I2S2_BCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 32),
+ MTK_FUNCTION(0, "GPIO50"),
+ MTK_FUNCTION(1, "I2S2_BCK"),
+ MTK_FUNCTION(3, "PCM_CLK0"),
+ MTK_FUNCTION(4, "DMIC_SCK1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(51, "I2S2_DATA_IN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 33),
+ MTK_FUNCTION(0, "GPIO51"),
+ MTK_FUNCTION(1, "I2S2_DATA_IN"),
+ MTK_FUNCTION(3, "PCM_RX"),
+ MTK_FUNCTION(4, "DMIC_SCK0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(52, "I2S2_LRCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 34),
+ MTK_FUNCTION(0, "GPIO52"),
+ MTK_FUNCTION(1, "I2S2_LRCK"),
+ MTK_FUNCTION(3, "PCM_SYNC"),
+ MTK_FUNCTION(4, "DMIC_DAT1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(53, "SPI0_CSN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 35),
+ MTK_FUNCTION(0, "GPIO53"),
+ MTK_FUNCTION(1, "SPI0_CS"),
+ MTK_FUNCTION(3, "SPDIF"),
+ MTK_FUNCTION(4, "ADC_CK"),
+ MTK_FUNCTION(5, "PWM1"),
+ MTK_FUNCTION(7, "DBG_MON_A[7]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(54, "SPI0_CK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 36),
+ MTK_FUNCTION(0, "GPIO54"),
+ MTK_FUNCTION(1, "SPI0_CK"),
+ MTK_FUNCTION(3, "SPDIF_IN1"),
+ MTK_FUNCTION(4, "ADC_DAT_IN"),
+ MTK_FUNCTION(7, "DBG_MON_A[10]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(55, "SPI0_MI"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 37),
+ MTK_FUNCTION(0, "GPIO55"),
+ MTK_FUNCTION(1, "SPI0_MI"),
+ MTK_FUNCTION(2, "SPI0_MO"),
+ MTK_FUNCTION(3, "MSDC1_WP"),
+ MTK_FUNCTION(4, "ADC_WS"),
+ MTK_FUNCTION(5, "PWM2"),
+ MTK_FUNCTION(7, "DBG_MON_A[8]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(56, "SPI0_MO"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 38),
+ MTK_FUNCTION(0, "GPIO56"),
+ MTK_FUNCTION(1, "SPI0_MO"),
+ MTK_FUNCTION(2, "SPI0_MI"),
+ MTK_FUNCTION(3, "SPDIF_IN0"),
+ MTK_FUNCTION(7, "DBG_MON_A[9]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(57, "SDA1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 39),
+ MTK_FUNCTION(0, "GPIO57"),
+ MTK_FUNCTION(1, "SDA1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(58, "SCL1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 40),
+ MTK_FUNCTION(0, "GPIO58"),
+ MTK_FUNCTION(1, "SCL1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(59, "RAMBUF_I_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO59"),
+ MTK_FUNCTION(1, "RAMBUF_I_CLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(60, "WB_RSTB"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 41),
+ MTK_FUNCTION(0, "GPIO60"),
+ MTK_FUNCTION(1, "WB_RSTB"),
+ MTK_FUNCTION(7, "DBG_MON_A[11]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(61, "F2W_DATA"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 42),
+ MTK_FUNCTION(0, "GPIO61"),
+ MTK_FUNCTION(1, "F2W_DATA"),
+ MTK_FUNCTION(7, "DBG_MON_A[16]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(62, "F2W_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 43),
+ MTK_FUNCTION(0, "GPIO62"),
+ MTK_FUNCTION(1, "F2W_CK"),
+ MTK_FUNCTION(7, "DBG_MON_A[15]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(63, "WB_SCLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 44),
+ MTK_FUNCTION(0, "GPIO63"),
+ MTK_FUNCTION(1, "WB_SCLK"),
+ MTK_FUNCTION(7, "DBG_MON_A[13]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(64, "WB_SDATA"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 45),
+ MTK_FUNCTION(0, "GPIO64"),
+ MTK_FUNCTION(1, "WB_SDATA"),
+ MTK_FUNCTION(7, "DBG_MON_A[12]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(65, "WB_SEN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 46),
+ MTK_FUNCTION(0, "GPIO65"),
+ MTK_FUNCTION(1, "WB_SEN"),
+ MTK_FUNCTION(7, "DBG_MON_A[14]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(66, "WB_CRTL0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 47),
+ MTK_FUNCTION(0, "GPIO66"),
+ MTK_FUNCTION(1, "WB_CRTL0"),
+ MTK_FUNCTION(5, "DFD_NTRST_XI"),
+ MTK_FUNCTION(7, "DBG_MON_A[17]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(67, "WB_CRTL1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 48),
+ MTK_FUNCTION(0, "GPIO67"),
+ MTK_FUNCTION(1, "WB_CRTL1"),
+ MTK_FUNCTION(5, "DFD_TMS_XI"),
+ MTK_FUNCTION(7, "DBG_MON_A[18]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(68, "WB_CRTL2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 49),
+ MTK_FUNCTION(0, "GPIO68"),
+ MTK_FUNCTION(1, "WB_CRTL2"),
+ MTK_FUNCTION(5, "DFD_TCK_XI"),
+ MTK_FUNCTION(7, "DBG_MON_A[19]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(69, "WB_CRTL3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 50),
+ MTK_FUNCTION(0, "GPIO69"),
+ MTK_FUNCTION(1, "WB_CRTL3"),
+ MTK_FUNCTION(5, "DFD_TDI_XI"),
+ MTK_FUNCTION(7, "DBG_MON_A[20]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(70, "WB_CRTL4"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 51),
+ MTK_FUNCTION(0, "GPIO70"),
+ MTK_FUNCTION(1, "WB_CRTL4"),
+ MTK_FUNCTION(5, "DFD_TDO"),
+ MTK_FUNCTION(7, "DBG_MON_A[21]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(71, "WB_CRTL5"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 52),
+ MTK_FUNCTION(0, "GPIO71"),
+ MTK_FUNCTION(1, "WB_CRTL5"),
+ MTK_FUNCTION(7, "DBG_MON_A[22]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(72, "I2S0_DATA_IN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 53),
+ MTK_FUNCTION(0, "GPIO72"),
+ MTK_FUNCTION(1, "I2S0_DATA_IN"),
+ MTK_FUNCTION(3, "PCM_RX"),
+ MTK_FUNCTION(4, "PWM0"),
+ MTK_FUNCTION(5, "DISP_PWM"),
+ MTK_FUNCTION(6, "WCN_I2S_DI"),
+ MTK_FUNCTION(7, "DBG_MON_B[2]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(73, "I2S0_LRCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 54),
+ MTK_FUNCTION(0, "GPIO73"),
+ MTK_FUNCTION(1, "I2S0_LRCK"),
+ MTK_FUNCTION(3, "PCM_SYNC"),
+ MTK_FUNCTION(6, "WCN_I2S_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B[5]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(74, "I2S0_BCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 55),
+ MTK_FUNCTION(0, "GPIO74"),
+ MTK_FUNCTION(1, "I2S0_BCK"),
+ MTK_FUNCTION(3, "PCM_CLK0"),
+ MTK_FUNCTION(6, "WCN_I2S_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B[4]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(75, "SDA0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 56),
+ MTK_FUNCTION(0, "GPIO75"),
+ MTK_FUNCTION(1, "SDA0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(76, "SCL0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 57),
+ MTK_FUNCTION(0, "GPIO76"),
+ MTK_FUNCTION(1, "SCL0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(77, "SDA2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 58),
+ MTK_FUNCTION(0, "GPIO77"),
+ MTK_FUNCTION(1, "SDA2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(78, "SCL2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 59),
+ MTK_FUNCTION(0, "GPIO78"),
+ MTK_FUNCTION(1, "SCL2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(79, "URXD0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 60),
+ MTK_FUNCTION(0, "GPIO79"),
+ MTK_FUNCTION(1, "URXD0"),
+ MTK_FUNCTION(2, "UTXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(80, "UTXD0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 61),
+ MTK_FUNCTION(0, "GPIO80"),
+ MTK_FUNCTION(1, "UTXD0"),
+ MTK_FUNCTION(2, "URXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(81, "URXD1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 62),
+ MTK_FUNCTION(0, "GPIO81"),
+ MTK_FUNCTION(1, "URXD1"),
+ MTK_FUNCTION(2, "UTXD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(82, "UTXD1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 63),
+ MTK_FUNCTION(0, "GPIO82"),
+ MTK_FUNCTION(1, "UTXD1"),
+ MTK_FUNCTION(2, "URXD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(83, "LCM_RST"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 64),
+ MTK_FUNCTION(0, "GPIO83"),
+ MTK_FUNCTION(1, "LCM_RST"),
+ MTK_FUNCTION(2, "VDAC_CK_XI"),
+ MTK_FUNCTION(7, "DBG_MON_B[1]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(84, "DSI_TE"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 65),
+ MTK_FUNCTION(0, "GPIO84"),
+ MTK_FUNCTION(1, "DSI_TE"),
+ MTK_FUNCTION(7, "DBG_MON_B[0]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(85, "MSDC2_CMD"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 66),
+ MTK_FUNCTION(0, "GPIO85"),
+ MTK_FUNCTION(1, "MSDC2_CMD"),
+ MTK_FUNCTION(2, "ANT_SEL0"),
+ MTK_FUNCTION(3, "SDA1"),
+ MTK_FUNCTION(6, "I2SOUT_BCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(86, "MSDC2_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 67),
+ MTK_FUNCTION(0, "GPIO86"),
+ MTK_FUNCTION(1, "MSDC2_CLK"),
+ MTK_FUNCTION(2, "ANT_SEL1"),
+ MTK_FUNCTION(3, "SCL1"),
+ MTK_FUNCTION(6, "I2SOUT_LRCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(87, "MSDC2_DAT0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 68),
+ MTK_FUNCTION(0, "GPIO87"),
+ MTK_FUNCTION(1, "MSDC2_DAT0"),
+ MTK_FUNCTION(2, "ANT_SEL2"),
+ MTK_FUNCTION(5, "UTXD0"),
+ MTK_FUNCTION(6, "I2SOUT_DATA_OUT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(88, "MSDC2_DAT1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 71),
+ MTK_FUNCTION(0, "GPIO88"),
+ MTK_FUNCTION(1, "MSDC2_DAT1"),
+ MTK_FUNCTION(2, "ANT_SEL3"),
+ MTK_FUNCTION(3, "PWM0"),
+ MTK_FUNCTION(5, "URXD0"),
+ MTK_FUNCTION(6, "PWM1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(89, "MSDC2_DAT2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 72),
+ MTK_FUNCTION(0, "GPIO89"),
+ MTK_FUNCTION(1, "MSDC2_DAT2"),
+ MTK_FUNCTION(2, "ANT_SEL4"),
+ MTK_FUNCTION(3, "SDA2"),
+ MTK_FUNCTION(5, "UTXD1"),
+ MTK_FUNCTION(6, "PWM2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(90, "MSDC2_DAT3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 73),
+ MTK_FUNCTION(0, "GPIO90"),
+ MTK_FUNCTION(1, "MSDC2_DAT3"),
+ MTK_FUNCTION(2, "ANT_SEL5"),
+ MTK_FUNCTION(3, "SCL2"),
+ MTK_FUNCTION(4, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(5, "URXD1"),
+ MTK_FUNCTION(6, "PWM3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(91, "TDN3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI91"),
+ MTK_FUNCTION(1, "TDN3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(92, "TDP3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI92"),
+ MTK_FUNCTION(1, "TDP3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(93, "TDN2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI93"),
+ MTK_FUNCTION(1, "TDN2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(94, "TDP2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI94"),
+ MTK_FUNCTION(1, "TDP2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(95, "TCN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI95"),
+ MTK_FUNCTION(1, "TCN")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(96, "TCP"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI96"),
+ MTK_FUNCTION(1, "TCP")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(97, "TDN1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI97"),
+ MTK_FUNCTION(1, "TDN1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(98, "TDP1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI98"),
+ MTK_FUNCTION(1, "TDP1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(99, "TDN0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI99"),
+ MTK_FUNCTION(1, "TDN0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(100, "TDP0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPI100"),
+ MTK_FUNCTION(1, "TDP0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(101, "SPI2_CSN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 74),
+ MTK_FUNCTION(0, "GPIO101"),
+ MTK_FUNCTION(1, "SPI2_CS"),
+ MTK_FUNCTION(3, "SCL3"),
+ MTK_FUNCTION(4, "KROW0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(102, "SPI2_MI"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 75),
+ MTK_FUNCTION(0, "GPIO102"),
+ MTK_FUNCTION(1, "SPI2_MI"),
+ MTK_FUNCTION(2, "SPI2_MO"),
+ MTK_FUNCTION(3, "SDA3"),
+ MTK_FUNCTION(4, "KROW1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(103, "SPI2_MO"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 76),
+ MTK_FUNCTION(0, "GPIO103"),
+ MTK_FUNCTION(1, "SPI2_MO"),
+ MTK_FUNCTION(2, "SPI2_MI"),
+ MTK_FUNCTION(3, "SCL3"),
+ MTK_FUNCTION(4, "KROW2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(104, "SPI2_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 77),
+ MTK_FUNCTION(0, "GPIO104"),
+ MTK_FUNCTION(1, "SPI2_CK"),
+ MTK_FUNCTION(3, "SDA3"),
+ MTK_FUNCTION(4, "KROW3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(105, "MSDC1_CMD"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 78),
+ MTK_FUNCTION(0, "GPIO105"),
+ MTK_FUNCTION(1, "MSDC1_CMD"),
+ MTK_FUNCTION(2, "ANT_SEL0"),
+ MTK_FUNCTION(3, "SDA1"),
+ MTK_FUNCTION(6, "I2SOUT_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B[27]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(106, "MSDC1_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 79),
+ MTK_FUNCTION(0, "GPIO106"),
+ MTK_FUNCTION(1, "MSDC1_CLK"),
+ MTK_FUNCTION(2, "ANT_SEL1"),
+ MTK_FUNCTION(3, "SCL1"),
+ MTK_FUNCTION(6, "I2SOUT_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B[28]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(107, "MSDC1_DAT0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 80),
+ MTK_FUNCTION(0, "GPIO107"),
+ MTK_FUNCTION(1, "MSDC1_DAT0"),
+ MTK_FUNCTION(2, "ANT_SEL2"),
+ MTK_FUNCTION(5, "UTXD0"),
+ MTK_FUNCTION(6, "I2SOUT_DATA_OUT"),
+ MTK_FUNCTION(7, "DBG_MON_B[26]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(108, "MSDC1_DAT1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 81),
+ MTK_FUNCTION(0, "GPIO108"),
+ MTK_FUNCTION(1, "MSDC1_DAT1"),
+ MTK_FUNCTION(2, "ANT_SEL3"),
+ MTK_FUNCTION(3, "PWM0"),
+ MTK_FUNCTION(5, "URXD0"),
+ MTK_FUNCTION(6, "PWM1"),
+ MTK_FUNCTION(7, "DBG_MON_B[25]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(109, "MSDC1_DAT2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 82),
+ MTK_FUNCTION(0, "GPIO109"),
+ MTK_FUNCTION(1, "MSDC1_DAT2"),
+ MTK_FUNCTION(2, "ANT_SEL4"),
+ MTK_FUNCTION(3, "SDA2"),
+ MTK_FUNCTION(5, "UTXD1"),
+ MTK_FUNCTION(6, "PWM2"),
+ MTK_FUNCTION(7, "DBG_MON_B[24]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(110, "MSDC1_DAT3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 83),
+ MTK_FUNCTION(0, "GPIO110"),
+ MTK_FUNCTION(1, "MSDC1_DAT3"),
+ MTK_FUNCTION(2, "ANT_SEL5"),
+ MTK_FUNCTION(3, "SCL2"),
+ MTK_FUNCTION(4, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(5, "URXD1"),
+ MTK_FUNCTION(6, "PWM3"),
+ MTK_FUNCTION(7, "DBG_MON_B[23]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(111, "MSDC0_DAT7"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 84),
+ MTK_FUNCTION(0, "GPIO111"),
+ MTK_FUNCTION(1, "MSDC0_DAT7"),
+ MTK_FUNCTION(4, "NLD7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(112, "MSDC0_DAT6"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 85),
+ MTK_FUNCTION(0, "GPIO112"),
+ MTK_FUNCTION(1, "MSDC0_DAT6"),
+ MTK_FUNCTION(4, "NLD6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(113, "MSDC0_DAT5"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 86),
+ MTK_FUNCTION(0, "GPIO113"),
+ MTK_FUNCTION(1, "MSDC0_DAT5"),
+ MTK_FUNCTION(4, "NLD5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(114, "MSDC0_DAT4"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 87),
+ MTK_FUNCTION(0, "GPIO114"),
+ MTK_FUNCTION(1, "MSDC0_DAT4"),
+ MTK_FUNCTION(4, "NLD4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(115, "MSDC0_RSTB"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 88),
+ MTK_FUNCTION(0, "GPIO115"),
+ MTK_FUNCTION(1, "MSDC0_RSTB"),
+ MTK_FUNCTION(4, "NLD8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(116, "MSDC0_CMD"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 89),
+ MTK_FUNCTION(0, "GPIO116"),
+ MTK_FUNCTION(1, "MSDC0_CMD"),
+ MTK_FUNCTION(4, "NALE")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(117, "MSDC0_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 90),
+ MTK_FUNCTION(0, "GPIO117"),
+ MTK_FUNCTION(1, "MSDC0_CLK"),
+ MTK_FUNCTION(4, "NWEB")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(118, "MSDC0_DAT3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 91),
+ MTK_FUNCTION(0, "GPIO118"),
+ MTK_FUNCTION(1, "MSDC0_DAT3"),
+ MTK_FUNCTION(4, "NLD3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(119, "MSDC0_DAT2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 92),
+ MTK_FUNCTION(0, "GPIO119"),
+ MTK_FUNCTION(1, "MSDC0_DAT2"),
+ MTK_FUNCTION(4, "NLD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(120, "MSDC0_DAT1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 93),
+ MTK_FUNCTION(0, "GPIO120"),
+ MTK_FUNCTION(1, "MSDC0_DAT1"),
+ MTK_FUNCTION(4, "NLD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(121, "MSDC0_DAT0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 94),
+ MTK_FUNCTION(0, "GPIO121"),
+ MTK_FUNCTION(1, "MSDC0_DAT0"),
+ MTK_FUNCTION(4, "NLD0"),
+ MTK_FUNCTION(5, "WATCHDOG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(122, "CEC"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 95),
+ MTK_FUNCTION(0, "GPIO122"),
+ MTK_FUNCTION(1, "CEC"),
+ MTK_FUNCTION(4, "SDA2"),
+ MTK_FUNCTION(5, "URXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(123, "HTPLG"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 96),
+ MTK_FUNCTION(0, "GPIO123"),
+ MTK_FUNCTION(1, "HTPLG"),
+ MTK_FUNCTION(4, "SCL2"),
+ MTK_FUNCTION(5, "UTXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(124, "HDMISCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 97),
+ MTK_FUNCTION(0, "GPIO124"),
+ MTK_FUNCTION(1, "HDMISCK"),
+ MTK_FUNCTION(4, "SDA1"),
+ MTK_FUNCTION(5, "PWM3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(125, "HDMISD"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 98),
+ MTK_FUNCTION(0, "GPIO125"),
+ MTK_FUNCTION(1, "HDMISD"),
+ MTK_FUNCTION(4, "SCL1"),
+ MTK_FUNCTION(5, "PWM4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(126, "I2S0_MCLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 99),
+ MTK_FUNCTION(0, "GPIO126"),
+ MTK_FUNCTION(1, "I2S0_MCLK"),
+ MTK_FUNCTION(6, "WCN_I2S_MCLK"),
+ MTK_FUNCTION(7, "DBG_MON_B[6]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(127, "RAMBUF_IDATA0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO127"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(128, "RAMBUF_IDATA1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO128"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(129, "RAMBUF_IDATA2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO129"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(130, "RAMBUF_IDATA3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO130"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(131, "RAMBUF_IDATA4"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO131"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(132, "RAMBUF_IDATA5"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO132"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(133, "RAMBUF_IDATA6"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO133"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(134, "RAMBUF_IDATA7"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO134"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(135, "RAMBUF_IDATA8"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO135"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(136, "RAMBUF_IDATA9"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO136"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA9")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(137, "RAMBUF_IDATA10"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO137"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA10")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(138, "RAMBUF_IDATA11"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO138"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA11")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(139, "RAMBUF_IDATA12"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO139"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA12")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(140, "RAMBUF_IDATA13"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO140"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA13")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(141, "RAMBUF_IDATA14"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO141"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA14")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(142, "RAMBUF_IDATA15"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO142"),
+ MTK_FUNCTION(1, "RAMBUF_IDATA15")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(143, "RAMBUF_ODATA0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO143"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(144, "RAMBUF_ODATA1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO144"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(145, "RAMBUF_ODATA2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO145"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(146, "RAMBUF_ODATA3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO146"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(147, "RAMBUF_ODATA4"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO147"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(148, "RAMBUF_ODATA5"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO148"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(149, "RAMBUF_ODATA6"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO149"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(150, "RAMBUF_ODATA7"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO150"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(151, "RAMBUF_ODATA8"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO151"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(152, "RAMBUF_ODATA9"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO152"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA9")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(153, "RAMBUF_ODATA10"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO153"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA10")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(154, "RAMBUF_ODATA11"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO154"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA11")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(155, "RAMBUF_ODATA12"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO155"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA12")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(156, "RAMBUF_ODATA13"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO156"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA13")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(157, "RAMBUF_ODATA14"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO157"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA14")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(158, "RAMBUF_ODATA15"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO158"),
+ MTK_FUNCTION(1, "RAMBUF_ODATA15")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(159, "RAMBUF_BE0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO159"),
+ MTK_FUNCTION(1, "RAMBUF_BE0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(160, "RAMBUF_BE1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO160"),
+ MTK_FUNCTION(1, "RAMBUF_BE1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(161, "AP2PT_INT"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO161"),
+ MTK_FUNCTION(1, "AP2PT_INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(162, "AP2PT_INT_CLR"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO162"),
+ MTK_FUNCTION(1, "AP2PT_INT_CLR")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(163, "PT2AP_INT"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO163"),
+ MTK_FUNCTION(1, "PT2AP_INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(164, "PT2AP_INT_CLR"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO164"),
+ MTK_FUNCTION(1, "PT2AP_INT_CLR")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(165, "AP2UP_INT"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO165"),
+ MTK_FUNCTION(1, "AP2UP_INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(166, "AP2UP_INT_CLR"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO166"),
+ MTK_FUNCTION(1, "AP2UP_INT_CLR")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(167, "UP2AP_INT"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO167"),
+ MTK_FUNCTION(1, "UP2AP_INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(168, "UP2AP_INT_CLR"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO168"),
+ MTK_FUNCTION(1, "UP2AP_INT_CLR")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(169, "RAMBUF_ADDR0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO169"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(170, "RAMBUF_ADDR1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO170"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(171, "RAMBUF_ADDR2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO171"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(172, "RAMBUF_ADDR3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO172"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(173, "RAMBUF_ADDR4"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO173"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(174, "RAMBUF_ADDR5"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO174"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(175, "RAMBUF_ADDR6"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO175"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(176, "RAMBUF_ADDR7"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO176"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(177, "RAMBUF_ADDR8"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO177"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(178, "RAMBUF_ADDR9"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO178"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR9")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(179, "RAMBUF_ADDR10"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO179"),
+ MTK_FUNCTION(1, "RAMBUF_ADDR10")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(180, "RAMBUF_RW"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO180"),
+ MTK_FUNCTION(1, "RAMBUF_RW")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(181, "RAMBUF_LAST"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO181"),
+ MTK_FUNCTION(1, "RAMBUF_LAST")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(182, "RAMBUF_HP"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO182"),
+ MTK_FUNCTION(1, "RAMBUF_HP")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(183, "RAMBUF_REQ"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO183"),
+ MTK_FUNCTION(1, "RAMBUF_REQ")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(184, "RAMBUF_ALE"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO184"),
+ MTK_FUNCTION(1, "RAMBUF_ALE")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(185, "RAMBUF_DLE"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO185"),
+ MTK_FUNCTION(1, "RAMBUF_DLE")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(186, "RAMBUF_WDLE"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO186"),
+ MTK_FUNCTION(1, "RAMBUF_WDLE")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(187, "RAMBUF_O_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO187"),
+ MTK_FUNCTION(1, "RAMBUF_O_CLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(188, "I2S2_MCLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 100),
+ MTK_FUNCTION(0, "GPIO188"),
+ MTK_FUNCTION(1, "I2S2_MCLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(189, "I2S3_DATA"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 101),
+ MTK_FUNCTION(0, "GPIO189"),
+ MTK_FUNCTION(2, "I2S3_DATA_BYPS"),
+ MTK_FUNCTION(3, "PCM_TX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(190, "I2S3_DATA_IN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 102),
+ MTK_FUNCTION(0, "GPIO190"),
+ MTK_FUNCTION(1, "I2S3_DATA_IN"),
+ MTK_FUNCTION(3, "PCM_RX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(191, "I2S3_BCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 103),
+ MTK_FUNCTION(0, "GPIO191"),
+ MTK_FUNCTION(1, "I2S3_BCK"),
+ MTK_FUNCTION(3, "PCM_CLK0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(192, "I2S3_LRCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 104),
+ MTK_FUNCTION(0, "GPIO192"),
+ MTK_FUNCTION(1, "I2S3_LRCK"),
+ MTK_FUNCTION(3, "PCM_SYNC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(193, "I2S3_MCLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 105),
+ MTK_FUNCTION(0, "GPIO193"),
+ MTK_FUNCTION(1, "I2S3_MCLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(194, "I2S4_DATA"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 106),
+ MTK_FUNCTION(0, "GPIO194"),
+ MTK_FUNCTION(1, "I2S4_DATA"),
+ MTK_FUNCTION(2, "I2S4_DATA_BYPS"),
+ MTK_FUNCTION(3, "PCM_TX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(195, "I2S4_DATA_IN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 107),
+ MTK_FUNCTION(0, "GPIO195"),
+ MTK_FUNCTION(1, "I2S4_DATA_IN"),
+ MTK_FUNCTION(3, "PCM_RX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(196, "I2S4_BCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 108),
+ MTK_FUNCTION(0, "GPIO196"),
+ MTK_FUNCTION(1, "I2S4_BCK"),
+ MTK_FUNCTION(3, "PCM_CLK0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(197, "I2S4_LRCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 109),
+ MTK_FUNCTION(0, "GPIO197"),
+ MTK_FUNCTION(1, "I2S4_LRCK"),
+ MTK_FUNCTION(3, "PCM_SYNC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(198, "I2S4_MCLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 110),
+ MTK_FUNCTION(0, "GPIO198"),
+ MTK_FUNCTION(1, "I2S4_MCLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(199, "SPI1_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 111),
+ MTK_FUNCTION(0, "GPIO199"),
+ MTK_FUNCTION(1, "SPI1_CK"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(4, "KCOL3"),
+ MTK_FUNCTION(7, "DBG_MON_B[15]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(200, "SPDIF_OUT"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 112),
+ MTK_FUNCTION(0, "GPIO200"),
+ MTK_FUNCTION(1, "SPDIF_OUT"),
+ MTK_FUNCTION(5, "G1_TXD3"),
+ MTK_FUNCTION(6, "URXD2"),
+ MTK_FUNCTION(7, "DBG_MON_B[16]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(201, "SPDIF_IN0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 113),
+ MTK_FUNCTION(0, "GPIO201"),
+ MTK_FUNCTION(1, "SPDIF_IN0"),
+ MTK_FUNCTION(5, "G1_TXEN"),
+ MTK_FUNCTION(6, "UTXD2"),
+ MTK_FUNCTION(7, "DBG_MON_B[17]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(202, "SPDIF_IN1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 114),
+ MTK_FUNCTION(0, "GPIO202"),
+ MTK_FUNCTION(1, "SPDIF_IN1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(203, "PWM0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 115),
+ MTK_FUNCTION(0, "GPIO203"),
+ MTK_FUNCTION(1, "PWM0"),
+ MTK_FUNCTION(2, "DISP_PWM"),
+ MTK_FUNCTION(5, "G1_TXD2"),
+ MTK_FUNCTION(7, "DBG_MON_B[18]"),
+ MTK_FUNCTION(9, "I2S2_DATA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(204, "PWM1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 116),
+ MTK_FUNCTION(0, "GPIO204"),
+ MTK_FUNCTION(1, "PWM1"),
+ MTK_FUNCTION(2, "CLKM3"),
+ MTK_FUNCTION(5, "G1_TXD1"),
+ MTK_FUNCTION(7, "DBG_MON_B[19]"),
+ MTK_FUNCTION(9, "I2S3_DATA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(205, "PWM2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 117),
+ MTK_FUNCTION(0, "GPIO205"),
+ MTK_FUNCTION(1, "PWM2"),
+ MTK_FUNCTION(2, "CLKM2"),
+ MTK_FUNCTION(5, "G1_TXD0"),
+ MTK_FUNCTION(7, "DBG_MON_B[20]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(206, "PWM3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 118),
+ MTK_FUNCTION(0, "GPIO206"),
+ MTK_FUNCTION(1, "PWM3"),
+ MTK_FUNCTION(2, "CLKM1"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(5, "G1_TXC"),
+ MTK_FUNCTION(7, "DBG_MON_B[21]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(207, "PWM4"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 119),
+ MTK_FUNCTION(0, "GPIO207"),
+ MTK_FUNCTION(1, "PWM4"),
+ MTK_FUNCTION(2, "CLKM0"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(5, "G1_RXC"),
+ MTK_FUNCTION(7, "DBG_MON_B[22]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(208, "AUD_EXT_CK1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 120),
+ MTK_FUNCTION(0, "GPIO208"),
+ MTK_FUNCTION(1, "AUD_EXT_CK1"),
+ MTK_FUNCTION(2, "PWM0"),
+ MTK_FUNCTION(4, "ANT_SEL5"),
+ MTK_FUNCTION(5, "DISP_PWM"),
+ MTK_FUNCTION(7, "DBG_MON_A[31]"),
+ MTK_FUNCTION(11, "PCIE0_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(209, "AUD_EXT_CK2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 121),
+ MTK_FUNCTION(0, "GPIO209"),
+ MTK_FUNCTION(1, "AUD_EXT_CK2"),
+ MTK_FUNCTION(2, "MSDC1_WP"),
+ MTK_FUNCTION(5, "PWM1"),
+ MTK_FUNCTION(7, "DBG_MON_A[32]"),
+ MTK_FUNCTION(11, "PCIE1_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(210, "AUD_CLOCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO210"),
+ MTK_FUNCTION(1, "AUD_CLOCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(211, "DVP_RESET"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO211"),
+ MTK_FUNCTION(1, "DVP_RESET")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(212, "DVP_CLOCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO212"),
+ MTK_FUNCTION(1, "DVP_CLOCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(213, "DVP_CS"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO213"),
+ MTK_FUNCTION(1, "DVP_CS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(214, "DVP_CK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO214"),
+ MTK_FUNCTION(1, "DVP_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(215, "DVP_DI"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO215"),
+ MTK_FUNCTION(1, "DVP_DI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(216, "DVP_DO"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO216"),
+ MTK_FUNCTION(1, "DVP_DO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(217, "AP_CS"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO217"),
+ MTK_FUNCTION(1, "AP_CS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(218, "AP_CK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO218"),
+ MTK_FUNCTION(1, "AP_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(219, "AP_DI"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO219"),
+ MTK_FUNCTION(1, "AP_DI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(220, "AP_DO"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO220"),
+ MTK_FUNCTION(1, "AP_DO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(221, "DVD_BCLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO221"),
+ MTK_FUNCTION(1, "DVD_BCLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(222, "T8032_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO222"),
+ MTK_FUNCTION(1, "T8032_CLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(223, "AP_BCLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO223"),
+ MTK_FUNCTION(1, "AP_BCLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(224, "HOST_CS"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO224"),
+ MTK_FUNCTION(1, "HOST_CS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(225, "HOST_CK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO225"),
+ MTK_FUNCTION(1, "HOST_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(226, "HOST_DO0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO226"),
+ MTK_FUNCTION(1, "HOST_DO0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(227, "HOST_DO1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO227"),
+ MTK_FUNCTION(1, "HOST_DO1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(228, "SLV_CS"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO228"),
+ MTK_FUNCTION(1, "SLV_CS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(229, "SLV_CK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO229"),
+ MTK_FUNCTION(1, "SLV_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(230, "SLV_DI0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO230"),
+ MTK_FUNCTION(1, "SLV_DI0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(231, "SLV_DI1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO231"),
+ MTK_FUNCTION(1, "SLV_DI1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(232, "AP2DSP_INT"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO232"),
+ MTK_FUNCTION(1, "AP2DSP_INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(233, "AP2DSP_INT_CLR"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO233"),
+ MTK_FUNCTION(1, "AP2DSP_INT_CLR")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(234, "DSP2AP_INT"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO234"),
+ MTK_FUNCTION(1, "DSP2AP_INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(235, "DSP2AP_INT_CLR"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO235"),
+ MTK_FUNCTION(1, "DSP2AP_INT_CLR")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(236, "EXT_SDIO3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 122),
+ MTK_FUNCTION(0, "GPIO236"),
+ MTK_FUNCTION(1, "EXT_SDIO3"),
+ MTK_FUNCTION(2, "IDDIG"),
+ MTK_FUNCTION(7, "DBG_MON_A[1]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(237, "EXT_SDIO2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 123),
+ MTK_FUNCTION(0, "GPIO237"),
+ MTK_FUNCTION(1, "EXT_SDIO2"),
+ MTK_FUNCTION(2, "DRV_VBUS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(238, "EXT_SDIO1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 124),
+ MTK_FUNCTION(0, "GPIO238"),
+ MTK_FUNCTION(1, "EXT_SDIO1"),
+ MTK_FUNCTION(2, "IDDIG_P1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(239, "EXT_SDIO0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 125),
+ MTK_FUNCTION(0, "GPIO239"),
+ MTK_FUNCTION(1, "EXT_SDIO0"),
+ MTK_FUNCTION(2, "DRV_VBUS_P1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(240, "EXT_XCS"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 126),
+ MTK_FUNCTION(0, "GPIO240"),
+ MTK_FUNCTION(1, "EXT_XCS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(241, "EXT_SCK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 127),
+ MTK_FUNCTION(0, "GPIO241"),
+ MTK_FUNCTION(1, "EXT_SCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(242, "URTS2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 128),
+ MTK_FUNCTION(0, "GPIO242"),
+ MTK_FUNCTION(1, "URTS2"),
+ MTK_FUNCTION(2, "UTXD3"),
+ MTK_FUNCTION(3, "URXD3"),
+ MTK_FUNCTION(4, "SCL1"),
+ MTK_FUNCTION(7, "DBG_MON_B[32]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(243, "UCTS2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 129),
+ MTK_FUNCTION(0, "GPIO243"),
+ MTK_FUNCTION(1, "UCTS2"),
+ MTK_FUNCTION(2, "URXD3"),
+ MTK_FUNCTION(3, "UTXD3"),
+ MTK_FUNCTION(4, "SDA1"),
+ MTK_FUNCTION(7, "DBG_MON_A[6]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(244, "HDMI_SDA_RX"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 130),
+ MTK_FUNCTION(0, "GPIO244"),
+ MTK_FUNCTION(1, "HDMI_SDA_RX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(245, "HDMI_SCL_RX"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 131),
+ MTK_FUNCTION(0, "GPIO245"),
+ MTK_FUNCTION(1, "HDMI_SCL_RX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(246, "MHL_SENCE"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 132),
+ MTK_FUNCTION(0, "GPIO246")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(247, "HDMI_HPD_CBUS_RX"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 69),
+ MTK_FUNCTION(0, "GPIO247"),
+ MTK_FUNCTION(1, "HDMI_HPD_RX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(248, "HDMI_TESTOUTP_RX"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 133),
+ MTK_FUNCTION(0, "GPIO248"),
+ MTK_FUNCTION(1, "HDMI_TESTOUTP_RX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(249, "MSDC0E_RSTB"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 134),
+ MTK_FUNCTION(0, "GPIO249"),
+ MTK_FUNCTION(1, "MSDC0E_RSTB")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(250, "MSDC0E_DAT7"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 135),
+ MTK_FUNCTION(0, "GPIO250"),
+ MTK_FUNCTION(1, "MSDC3_DAT7"),
+ MTK_FUNCTION(6, "PCIE0_CLKREQ_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(251, "MSDC0E_DAT6"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 136),
+ MTK_FUNCTION(0, "GPIO251"),
+ MTK_FUNCTION(1, "MSDC3_DAT6"),
+ MTK_FUNCTION(6, "PCIE0_WAKE_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(252, "MSDC0E_DAT5"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 137),
+ MTK_FUNCTION(0, "GPIO252"),
+ MTK_FUNCTION(1, "MSDC3_DAT5"),
+ MTK_FUNCTION(6, "PCIE1_CLKREQ_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(253, "MSDC0E_DAT4"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 138),
+ MTK_FUNCTION(0, "GPIO253"),
+ MTK_FUNCTION(1, "MSDC3_DAT4"),
+ MTK_FUNCTION(6, "PCIE1_WAKE_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(254, "MSDC0E_DAT3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 139),
+ MTK_FUNCTION(0, "GPIO254"),
+ MTK_FUNCTION(1, "MSDC3_DAT3"),
+ MTK_FUNCTION(6, "PCIE2_CLKREQ_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(255, "MSDC0E_DAT2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 140),
+ MTK_FUNCTION(0, "GPIO255"),
+ MTK_FUNCTION(1, "MSDC3_DAT2"),
+ MTK_FUNCTION(6, "PCIE2_WAKE_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(256, "MSDC0E_DAT1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 141),
+ MTK_FUNCTION(0, "GPIO256"),
+ MTK_FUNCTION(1, "MSDC3_DAT1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(257, "MSDC0E_DAT0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 142),
+ MTK_FUNCTION(0, "GPIO257"),
+ MTK_FUNCTION(1, "MSDC3_DAT0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(258, "MSDC0E_CMD"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 143),
+ MTK_FUNCTION(0, "GPIO258"),
+ MTK_FUNCTION(1, "MSDC3_CMD")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(259, "MSDC0E_CLK"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 144),
+ MTK_FUNCTION(0, "GPIO259"),
+ MTK_FUNCTION(1, "MSDC3_CLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(260, "MSDC0E_DSL"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 145),
+ MTK_FUNCTION(0, "GPIO260"),
+ MTK_FUNCTION(1, "MSDC3_DSL")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(261, "MSDC1_INS"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 146),
+ MTK_FUNCTION(0, "GPIO261"),
+ MTK_FUNCTION(1, "MSDC1_INS"),
+ MTK_FUNCTION(7, "DBG_MON_B[29]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(262, "G2_TXEN"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 8),
+ MTK_FUNCTION(0, "GPIO262"),
+ MTK_FUNCTION(1, "G2_TXEN")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(263, "G2_TXD3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 9),
+ MTK_FUNCTION(0, "GPIO263"),
+ MTK_FUNCTION(1, "G2_TXD3"),
+ MTK_FUNCTION(6, "ANT_SEL5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(264, "G2_TXD2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 10),
+ MTK_FUNCTION(0, "GPIO264"),
+ MTK_FUNCTION(1, "G2_TXD2"),
+ MTK_FUNCTION(6, "ANT_SEL4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(265, "G2_TXD1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 11),
+ MTK_FUNCTION(0, "GPIO265"),
+ MTK_FUNCTION(1, "G2_TXD1"),
+ MTK_FUNCTION(6, "ANT_SEL3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(266, "G2_TXD0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO266"),
+ MTK_FUNCTION(1, "G2_TXD0"),
+ MTK_FUNCTION(6, "ANT_SEL2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(267, "G2_TXC"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO267"),
+ MTK_FUNCTION(1, "G2_TXC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(268, "G2_RXC"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO268"),
+ MTK_FUNCTION(1, "G2_RXC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(269, "G2_RXD0"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO269"),
+ MTK_FUNCTION(1, "G2_RXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(270, "G2_RXD1"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO270"),
+ MTK_FUNCTION(1, "G2_RXD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(271, "G2_RXD2"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO271"),
+ MTK_FUNCTION(1, "G2_RXD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(272, "G2_RXD3"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO272"),
+ MTK_FUNCTION(1, "G2_RXD3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(273, "ESW_INT"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 168),
+ MTK_FUNCTION(0, "GPIO273"),
+ MTK_FUNCTION(1, "ESW_INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(274, "G2_RXDV"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO274"),
+ MTK_FUNCTION(1, "G2_RXDV")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(275, "MDC"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO275"),
+ MTK_FUNCTION(1, "MDC"),
+ MTK_FUNCTION(6, "ANT_SEL0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(276, "MDIO"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO276"),
+ MTK_FUNCTION(1, "MDIO"),
+ MTK_FUNCTION(6, "ANT_SEL1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(277, "ESW_RST"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO277"),
+ MTK_FUNCTION(1, "ESW_RST")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(278, "JTAG_RESET"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(0, 147),
+ MTK_FUNCTION(0, "GPIO278"),
+ MTK_FUNCTION(1, "JTAG_RESET")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(279, "USB3_RES_BOND"),
+ NULL, "mt2701",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO279"),
+ MTK_FUNCTION(1, "USB3_RES_BOND")
+ ),
+};
+
+#endif /* __PINCTRL_MTK_MT2701_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
new file mode 100644
index 000000000000..3472a76ad422
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
@@ -0,0 +1,1936 @@
+/*
+ * Copyright (c) 2016 John Crispin <blogic@openwrt.org>
+ *
+ * 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
+ * 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 __PINCTRL_MTK_MT7623_H
+#define __PINCTRL_MTK_MT7623_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-mtk-common.h"
+
+static const struct mtk_desc_pin mtk_pins_mt7623[] = {
+ MTK_PIN(
+ PINCTRL_PIN(0, "PWRAP_SPI0_MI"),
+ "J20", "mt7623",
+ MTK_EINT_FUNCTION(0, 148),
+ MTK_FUNCTION(0, "GPIO0"),
+ MTK_FUNCTION(1, "PWRAP_SPIDO"),
+ MTK_FUNCTION(2, "PWRAP_SPIDI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(1, "PWRAP_SPI0_MO"),
+ "D10", "mt7623",
+ MTK_EINT_FUNCTION(0, 149),
+ MTK_FUNCTION(0, "GPIO1"),
+ MTK_FUNCTION(1, "PWRAP_SPIDI"),
+ MTK_FUNCTION(2, "PWRAP_SPIDO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(2, "PWRAP_INT"),
+ "E11", "mt7623",
+ MTK_EINT_FUNCTION(0, 150),
+ MTK_FUNCTION(0, "GPIO2"),
+ MTK_FUNCTION(1, "PWRAP_INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(3, "PWRAP_SPI0_CK"),
+ "H12", "mt7623",
+ MTK_EINT_FUNCTION(0, 151),
+ MTK_FUNCTION(0, "GPIO3"),
+ MTK_FUNCTION(1, "PWRAP_SPICK_I")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(4, "PWRAP_SPI0_CSN"),
+ "E12", "mt7623",
+ MTK_EINT_FUNCTION(0, 152),
+ MTK_FUNCTION(0, "GPIO4"),
+ MTK_FUNCTION(1, "PWRAP_SPICS_B_I")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(5, "PWRAP_SPI0_CK2"),
+ "H11", "mt7623",
+ MTK_EINT_FUNCTION(0, 155),
+ MTK_FUNCTION(0, "GPIO5"),
+ MTK_FUNCTION(1, "PWRAP_SPICK2_I")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(6, "PWRAP_SPI0_CSN2"),
+ "G11", "mt7623",
+ MTK_EINT_FUNCTION(0, 156),
+ MTK_FUNCTION(0, "GPIO6"),
+ MTK_FUNCTION(1, "PWRAP_SPICS2_B_I")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(7, "SPI1_CSN"),
+ "G19", "mt7623",
+ MTK_EINT_FUNCTION(0, 153),
+ MTK_FUNCTION(0, "GPIO7"),
+ MTK_FUNCTION(1, "SPI1_CS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(8, "SPI1_MI"),
+ "F19", "mt7623",
+ MTK_EINT_FUNCTION(0, 154),
+ MTK_FUNCTION(0, "GPIO8"),
+ MTK_FUNCTION(1, "SPI1_MI"),
+ MTK_FUNCTION(2, "SPI1_MO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(9, "SPI1_MO"),
+ "G20", "mt7623",
+ MTK_EINT_FUNCTION(0, 157),
+ MTK_FUNCTION(0, "GPIO9"),
+ MTK_FUNCTION(1, "SPI1_MO"),
+ MTK_FUNCTION(2, "SPI1_MI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(10, "RTC32K_CK"),
+ "A13", "mt7623",
+ MTK_EINT_FUNCTION(0, 158),
+ MTK_FUNCTION(0, "GPIO10"),
+ MTK_FUNCTION(1, "RTC32K_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(11, "WATCHDOG"),
+ "D14", "mt7623",
+ MTK_EINT_FUNCTION(0, 159),
+ MTK_FUNCTION(0, "GPIO11"),
+ MTK_FUNCTION(1, "WATCHDOG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(12, "SRCLKENA"),
+ "C13", "mt7623",
+ MTK_EINT_FUNCTION(0, 169),
+ MTK_FUNCTION(0, "GPIO12"),
+ MTK_FUNCTION(1, "SRCLKENA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(13, "SRCLKENAI"),
+ "B13", "mt7623",
+ MTK_EINT_FUNCTION(0, 161),
+ MTK_FUNCTION(0, "GPIO13"),
+ MTK_FUNCTION(1, "SRCLKENAI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(14, "GPIO14"),
+ "E18", "mt7623",
+ MTK_EINT_FUNCTION(0, 162),
+ MTK_FUNCTION(0, "GPIO14"),
+ MTK_FUNCTION(1, "URXD2"),
+ MTK_FUNCTION(2, "UTXD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(15, "GPIO15"),
+ "E17", "mt7623",
+ MTK_EINT_FUNCTION(0, 163),
+ MTK_FUNCTION(0, "GPIO15"),
+ MTK_FUNCTION(1, "UTXD2"),
+ MTK_FUNCTION(2, "URXD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(16, "GPIO16"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO16")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(17, "GPIO17"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO17")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(18, "PCM_CLK"),
+ "C19", "mt7623",
+ MTK_EINT_FUNCTION(0, 166),
+ MTK_FUNCTION(0, "GPIO18"),
+ MTK_FUNCTION(1, "PCM_CLK0"),
+ MTK_FUNCTION(6, "AP_PCM_CLKO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(19, "PCM_SYNC"),
+ "D19", "mt7623",
+ MTK_EINT_FUNCTION(0, 167),
+ MTK_FUNCTION(0, "GPIO19"),
+ MTK_FUNCTION(1, "PCM_SYNC"),
+ MTK_FUNCTION(6, "AP_PCM_SYNC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(20, "PCM_RX"),
+ "D18", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO20"),
+ MTK_FUNCTION(1, "PCM_RX"),
+ MTK_FUNCTION(4, "PCM_TX"),
+ MTK_FUNCTION(6, "AP_PCM_RX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(21, "PCM_TX"),
+ "C18", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO21"),
+ MTK_FUNCTION(1, "PCM_TX"),
+ MTK_FUNCTION(4, "PCM_RX"),
+ MTK_FUNCTION(6, "AP_PCM_TX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(22, "EINT0"),
+ "H15", "mt7623",
+ MTK_EINT_FUNCTION(0, 0),
+ MTK_FUNCTION(0, "GPIO22"),
+ MTK_FUNCTION(1, "UCTS0"),
+ MTK_FUNCTION(2, "PCIE0_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(23, "EINT1"),
+ "J16", "mt7623",
+ MTK_EINT_FUNCTION(0, 1),
+ MTK_FUNCTION(0, "GPIO23"),
+ MTK_FUNCTION(1, "URTS0"),
+ MTK_FUNCTION(2, "PCIE1_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(24, "EINT2"),
+ "H16", "mt7623",
+ MTK_EINT_FUNCTION(0, 2),
+ MTK_FUNCTION(0, "GPIO24"),
+ MTK_FUNCTION(1, "UCTS1"),
+ MTK_FUNCTION(2, "PCIE2_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(25, "EINT3"),
+ "K15", "mt7623",
+ MTK_EINT_FUNCTION(0, 3),
+ MTK_FUNCTION(0, "GPIO25"),
+ MTK_FUNCTION(1, "URTS1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(26, "EINT4"),
+ "G15", "mt7623",
+ MTK_EINT_FUNCTION(0, 4),
+ MTK_FUNCTION(0, "GPIO26"),
+ MTK_FUNCTION(1, "UCTS3"),
+ MTK_FUNCTION(6, "PCIE2_WAKE_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(27, "EINT5"),
+ "F15", "mt7623",
+ MTK_EINT_FUNCTION(0, 5),
+ MTK_FUNCTION(0, "GPIO27"),
+ MTK_FUNCTION(1, "URTS3"),
+ MTK_FUNCTION(6, "PCIE1_WAKE_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(28, "EINT6"),
+ "J15", "mt7623",
+ MTK_EINT_FUNCTION(0, 6),
+ MTK_FUNCTION(0, "GPIO28"),
+ MTK_FUNCTION(1, "DRV_VBUS"),
+ MTK_FUNCTION(6, "PCIE0_WAKE_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(29, "EINT7"),
+ "E15", "mt7623",
+ MTK_EINT_FUNCTION(0, 7),
+ MTK_FUNCTION(0, "GPIO29"),
+ MTK_FUNCTION(1, "IDDIG"),
+ MTK_FUNCTION(2, "MSDC1_WP"),
+ MTK_FUNCTION(6, "PCIE2_PERST_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(30, "GPIO30"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO30")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(31, "GPIO31"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO31")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(32, "GPIO32"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO32")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(33, "I2S1_DATA"),
+ "Y18", "mt7623",
+ MTK_EINT_FUNCTION(0, 15),
+ MTK_FUNCTION(0, "GPIO33"),
+ MTK_FUNCTION(1, "I2S1_DATA"),
+ MTK_FUNCTION(3, "PCM_TX"),
+ MTK_FUNCTION(6, "AP_PCM_TX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(34, "I2S1_DATA_IN"),
+ "Y17", "mt7623",
+ MTK_EINT_FUNCTION(0, 16),
+ MTK_FUNCTION(0, "GPIO34"),
+ MTK_FUNCTION(1, "I2S1_DATA_IN"),
+ MTK_FUNCTION(3, "PCM_RX"),
+ MTK_FUNCTION(6, "AP_PCM_RX")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(35, "I2S1_BCK"),
+ "V17", "mt7623",
+ MTK_EINT_FUNCTION(0, 17),
+ MTK_FUNCTION(0, "GPIO35"),
+ MTK_FUNCTION(1, "I2S1_BCK"),
+ MTK_FUNCTION(3, "PCM_CLK0"),
+ MTK_FUNCTION(6, "AP_PCM_CLKO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(36, "I2S1_LRCK"),
+ "W17", "mt7623",
+ MTK_EINT_FUNCTION(0, 18),
+ MTK_FUNCTION(0, "GPIO36"),
+ MTK_FUNCTION(1, "I2S1_LRCK"),
+ MTK_FUNCTION(3, "PCM_SYNC"),
+ MTK_FUNCTION(6, "AP_PCM_SYNC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(37, "I2S1_MCLK"),
+ "AA18", "mt7623",
+ MTK_EINT_FUNCTION(0, 19),
+ MTK_FUNCTION(0, "GPIO37"),
+ MTK_FUNCTION(1, "I2S1_MCLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(38, "GPIO38"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO38")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(39, "JTMS"),
+ "G21", "mt7623",
+ MTK_EINT_FUNCTION(0, 21),
+ MTK_FUNCTION(0, "GPIO39"),
+ MTK_FUNCTION(1, "JTMS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(40, "GPIO40"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO40")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(41, "JTDI"),
+ "H22", "mt7623",
+ MTK_EINT_FUNCTION(0, 23),
+ MTK_FUNCTION(0, "GPIO41"),
+ MTK_FUNCTION(1, "JTDI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(42, "JTDO"),
+ "H21", "mt7623",
+ MTK_EINT_FUNCTION(0, 24),
+ MTK_FUNCTION(0, "GPIO42"),
+ MTK_FUNCTION(1, "JTDO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(43, "NCLE"),
+ "C7", "mt7623",
+ MTK_EINT_FUNCTION(0, 25),
+ MTK_FUNCTION(0, "GPIO43"),
+ MTK_FUNCTION(1, "NCLE"),
+ MTK_FUNCTION(2, "EXT_XCS2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(44, "NCEB1"),
+ "C6", "mt7623",
+ MTK_EINT_FUNCTION(0, 26),
+ MTK_FUNCTION(0, "GPIO44"),
+ MTK_FUNCTION(1, "NCEB1"),
+ MTK_FUNCTION(2, "IDDIG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(45, "NCEB0"),
+ "D7", "mt7623",
+ MTK_EINT_FUNCTION(0, 27),
+ MTK_FUNCTION(0, "GPIO45"),
+ MTK_FUNCTION(1, "NCEB0"),
+ MTK_FUNCTION(2, "DRV_VBUS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(46, "IR"),
+ "D15", "mt7623",
+ MTK_EINT_FUNCTION(0, 28),
+ MTK_FUNCTION(0, "GPIO46"),
+ MTK_FUNCTION(1, "IR")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(47, "NREB"),
+ "A6", "mt7623",
+ MTK_EINT_FUNCTION(0, 29),
+ MTK_FUNCTION(0, "GPIO47"),
+ MTK_FUNCTION(1, "NREB")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(48, "NRNB"),
+ "B6", "mt7623",
+ MTK_EINT_FUNCTION(0, 30),
+ MTK_FUNCTION(0, "GPIO48"),
+ MTK_FUNCTION(1, "NRNB")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(49, "I2S0_DATA"),
+ "AB18", "mt7623",
+ MTK_EINT_FUNCTION(0, 31),
+ MTK_FUNCTION(0, "GPIO49"),
+ MTK_FUNCTION(1, "I2S0_DATA"),
+ MTK_FUNCTION(3, "PCM_TX"),
+ MTK_FUNCTION(6, "AP_I2S_DO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(50, "GPIO50"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO50")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(51, "GPIO51"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO51")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(52, "GPIO52"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO52")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(53, "SPI0_CSN"),
+ "E7", "mt7623",
+ MTK_EINT_FUNCTION(0, 35),
+ MTK_FUNCTION(0, "GPIO53"),
+ MTK_FUNCTION(1, "SPI0_CS"),
+ MTK_FUNCTION(5, "PWM1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(54, "SPI0_CK"),
+ "F7", "mt7623",
+ MTK_EINT_FUNCTION(0, 36),
+ MTK_FUNCTION(0, "GPIO54"),
+ MTK_FUNCTION(1, "SPI0_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(55, "SPI0_MI"),
+ "E6", "mt7623",
+ MTK_EINT_FUNCTION(0, 37),
+ MTK_FUNCTION(0, "GPIO55"),
+ MTK_FUNCTION(1, "SPI0_MI"),
+ MTK_FUNCTION(2, "SPI0_MO"),
+ MTK_FUNCTION(3, "MSDC1_WP"),
+ MTK_FUNCTION(5, "PWM2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(56, "SPI0_MO"),
+ "G7", "mt7623",
+ MTK_EINT_FUNCTION(0, 38),
+ MTK_FUNCTION(0, "GPIO56"),
+ MTK_FUNCTION(1, "SPI0_MO"),
+ MTK_FUNCTION(2, "SPI0_MI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(57, "GPIO57"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO57")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(58, "GPIO58"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO58")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(59, "GPIO59"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO59")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(60, "WB_RSTB"),
+ "Y21", "mt7623",
+ MTK_EINT_FUNCTION(0, 41),
+ MTK_FUNCTION(0, "GPIO60"),
+ MTK_FUNCTION(1, "WB_RSTB")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(61, "GPIO61"),
+ "AA21", "mt7623",
+ MTK_EINT_FUNCTION(0, 42),
+ MTK_FUNCTION(0, "GPIO61"),
+ MTK_FUNCTION(1, "TEST_FD")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(62, "GPIO62"),
+ "AB22", "mt7623",
+ MTK_EINT_FUNCTION(0, 43),
+ MTK_FUNCTION(0, "GPIO62"),
+ MTK_FUNCTION(1, "TEST_FC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(63, "WB_SCLK"),
+ "AC23", "mt7623",
+ MTK_EINT_FUNCTION(0, 44),
+ MTK_FUNCTION(0, "GPIO63"),
+ MTK_FUNCTION(1, "WB_SCLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(64, "WB_SDATA"),
+ "AB21", "mt7623",
+ MTK_EINT_FUNCTION(0, 45),
+ MTK_FUNCTION(0, "GPIO64"),
+ MTK_FUNCTION(1, "WB_SDATA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(65, "WB_SEN"),
+ "AB24", "mt7623",
+ MTK_EINT_FUNCTION(0, 46),
+ MTK_FUNCTION(0, "GPIO65"),
+ MTK_FUNCTION(1, "WB_SEN")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(66, "WB_CRTL0"),
+ "AB20", "mt7623",
+ MTK_EINT_FUNCTION(0, 47),
+ MTK_FUNCTION(0, "GPIO66"),
+ MTK_FUNCTION(1, "WB_CRTL0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(67, "WB_CRTL1"),
+ "AC20", "mt7623",
+ MTK_EINT_FUNCTION(0, 48),
+ MTK_FUNCTION(0, "GPIO67"),
+ MTK_FUNCTION(1, "WB_CRTL1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(68, "WB_CRTL2"),
+ "AB19", "mt7623",
+ MTK_EINT_FUNCTION(0, 49),
+ MTK_FUNCTION(0, "GPIO68"),
+ MTK_FUNCTION(1, "WB_CRTL2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(69, "WB_CRTL3"),
+ "AC19", "mt7623",
+ MTK_EINT_FUNCTION(0, 50),
+ MTK_FUNCTION(0, "GPIO69"),
+ MTK_FUNCTION(1, "WB_CRTL3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(70, "WB_CRTL4"),
+ "AD19", "mt7623",
+ MTK_EINT_FUNCTION(0, 51),
+ MTK_FUNCTION(0, "GPIO70"),
+ MTK_FUNCTION(1, "WB_CRTL4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(71, "WB_CRTL5"),
+ "AE19", "mt7623",
+ MTK_EINT_FUNCTION(0, 52),
+ MTK_FUNCTION(0, "GPIO71"),
+ MTK_FUNCTION(1, "WB_CRTL5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(72, "I2S0_DATA_IN"),
+ "AA20", "mt7623",
+ MTK_EINT_FUNCTION(0, 53),
+ MTK_FUNCTION(0, "GPIO72"),
+ MTK_FUNCTION(1, "I2S0_DATA_IN"),
+ MTK_FUNCTION(3, "PCM_RX"),
+ MTK_FUNCTION(4, "PWM0"),
+ MTK_FUNCTION(5, "DISP_PWM"),
+ MTK_FUNCTION(6, "AP_I2S_DI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(73, "I2S0_LRCK"),
+ "Y20", "mt7623",
+ MTK_EINT_FUNCTION(0, 54),
+ MTK_FUNCTION(0, "GPIO73"),
+ MTK_FUNCTION(1, "I2S0_LRCK"),
+ MTK_FUNCTION(3, "PCM_SYNC"),
+ MTK_FUNCTION(6, "AP_I2S_LRCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(74, "I2S0_BCK"),
+ "Y19", "mt7623",
+ MTK_EINT_FUNCTION(0, 55),
+ MTK_FUNCTION(0, "GPIO74"),
+ MTK_FUNCTION(1, "I2S0_BCK"),
+ MTK_FUNCTION(3, "PCM_CLK0"),
+ MTK_FUNCTION(6, "AP_I2S_BCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(75, "SDA0"),
+ "K19", "mt7623",
+ MTK_EINT_FUNCTION(0, 56),
+ MTK_FUNCTION(0, "GPIO75"),
+ MTK_FUNCTION(1, "SDA0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(76, "SCL0"),
+ "K20", "mt7623",
+ MTK_EINT_FUNCTION(0, 57),
+ MTK_FUNCTION(0, "GPIO76"),
+ MTK_FUNCTION(1, "SCL0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(77, "GPIO77"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO77")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(78, "GPIO78"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO78")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(79, "GPIO79"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO79")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(80, "GPIO80"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO80")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(81, "GPIO81"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO81")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(82, "GPIO82"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO82")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(83, "LCM_RST"),
+ "V16", "mt7623",
+ MTK_EINT_FUNCTION(0, 64),
+ MTK_FUNCTION(0, "GPIO83"),
+ MTK_FUNCTION(1, "LCM_RST")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(84, "DSI_TE"),
+ "V14", "mt7623",
+ MTK_EINT_FUNCTION(0, 65),
+ MTK_FUNCTION(0, "GPIO84"),
+ MTK_FUNCTION(1, "DSI_TE")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(85, "GPIO85"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO85")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(86, "GPIO86"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO86")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(87, "GPIO87"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO87")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(88, "GPIO88"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO88")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(89, "GPIO89"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO89")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(90, "GPIO90"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO90")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(91, "GPIO91"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO91")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(92, "GPIO92"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO92")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(93, "GPIO93"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO93")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(94, "GPIO94"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO94")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(95, "MIPI_TCN"),
+ "AB14", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO95"),
+ MTK_FUNCTION(1, "TCN")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(96, "MIPI_TCP"),
+ "AC14", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO96"),
+ MTK_FUNCTION(1, "TCP")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(97, "MIPI_TDN1"),
+ "AE15", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO97"),
+ MTK_FUNCTION(1, "TDN1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(98, "MIPI_TDP1"),
+ "AD15", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO98"),
+ MTK_FUNCTION(1, "TDP1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(99, "MIPI_TDN0"),
+ "AB15", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO99"),
+ MTK_FUNCTION(1, "TDN0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(100, "MIPI_TDP0"),
+ "AC15", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO100"),
+ MTK_FUNCTION(1, "TDP0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(101, "GPIO101"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO101")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(102, "GPIO102"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO102")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(103, "GPIO103"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO103")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(104, "GPIO104"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO104")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(105, "MSDC1_CMD"),
+ "AD2", "mt7623",
+ MTK_EINT_FUNCTION(0, 78),
+ MTK_FUNCTION(0, "GPIO105"),
+ MTK_FUNCTION(1, "MSDC1_CMD"),
+ MTK_FUNCTION(3, "SDA1"),
+ MTK_FUNCTION(6, "I2SOUT_BCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(106, "MSDC1_CLK"),
+ "AD3", "mt7623",
+ MTK_EINT_FUNCTION(0, 79),
+ MTK_FUNCTION(0, "GPIO106"),
+ MTK_FUNCTION(1, "MSDC1_CLK"),
+ MTK_FUNCTION(3, "SCL1"),
+ MTK_FUNCTION(6, "I2SOUT_LRCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(107, "MSDC1_DAT0"),
+ "AE2", "mt7623",
+ MTK_EINT_FUNCTION(0, 80),
+ MTK_FUNCTION(0, "GPIO107"),
+ MTK_FUNCTION(1, "MSDC1_DAT0"),
+ MTK_FUNCTION(5, "UTXD0"),
+ MTK_FUNCTION(6, "I2SOUT_DATA_OUT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(108, "MSDC1_DAT1"),
+ "AC1", "mt7623",
+ MTK_EINT_FUNCTION(0, 81),
+ MTK_FUNCTION(0, "GPIO108"),
+ MTK_FUNCTION(1, "MSDC1_DAT1"),
+ MTK_FUNCTION(3, "PWM0"),
+ MTK_FUNCTION(5, "URXD0"),
+ MTK_FUNCTION(6, "PWM1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(109, "MSDC1_DAT2"),
+ "AC3", "mt7623",
+ MTK_EINT_FUNCTION(0, 82),
+ MTK_FUNCTION(0, "GPIO109"),
+ MTK_FUNCTION(1, "MSDC1_DAT2"),
+ MTK_FUNCTION(3, "SDA2"),
+ MTK_FUNCTION(5, "UTXD1"),
+ MTK_FUNCTION(6, "PWM2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(110, "MSDC1_DAT3"),
+ "AC4", "mt7623",
+ MTK_EINT_FUNCTION(0, 83),
+ MTK_FUNCTION(0, "GPIO110"),
+ MTK_FUNCTION(1, "MSDC1_DAT3"),
+ MTK_FUNCTION(3, "SCL2"),
+ MTK_FUNCTION(5, "URXD1"),
+ MTK_FUNCTION(6, "PWM3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(111, "MSDC0_DAT7"),
+ "A2", "mt7623",
+ MTK_EINT_FUNCTION(0, 84),
+ MTK_FUNCTION(0, "GPIO111"),
+ MTK_FUNCTION(1, "MSDC0_DAT7"),
+ MTK_FUNCTION(4, "NLD7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(112, "MSDC0_DAT6"),
+ "B3", "mt7623",
+ MTK_EINT_FUNCTION(0, 85),
+ MTK_FUNCTION(0, "GPIO112"),
+ MTK_FUNCTION(1, "MSDC0_DAT6"),
+ MTK_FUNCTION(4, "NLD6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(113, "MSDC0_DAT5"),
+ "C4", "mt7623",
+ MTK_EINT_FUNCTION(0, 86),
+ MTK_FUNCTION(0, "GPIO113"),
+ MTK_FUNCTION(1, "MSDC0_DAT5"),
+ MTK_FUNCTION(4, "NLD5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(114, "MSDC0_DAT4"),
+ "A4", "mt7623",
+ MTK_EINT_FUNCTION(0, 87),
+ MTK_FUNCTION(0, "GPIO114"),
+ MTK_FUNCTION(1, "MSDC0_DAT4"),
+ MTK_FUNCTION(4, "NLD4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(115, "MSDC0_RSTB"),
+ "C5", "mt7623",
+ MTK_EINT_FUNCTION(0, 88),
+ MTK_FUNCTION(0, "GPIO115"),
+ MTK_FUNCTION(1, "MSDC0_RSTB"),
+ MTK_FUNCTION(4, "NLD8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(116, "MSDC0_CMD"),
+ "D5", "mt7623",
+ MTK_EINT_FUNCTION(0, 89),
+ MTK_FUNCTION(0, "GPIO116"),
+ MTK_FUNCTION(1, "MSDC0_CMD"),
+ MTK_FUNCTION(4, "NALE")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(117, "MSDC0_CLK"),
+ "B1", "mt7623",
+ MTK_EINT_FUNCTION(0, 90),
+ MTK_FUNCTION(0, "GPIO117"),
+ MTK_FUNCTION(1, "MSDC0_CLK"),
+ MTK_FUNCTION(4, "NWEB")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(118, "MSDC0_DAT3"),
+ "D6", "mt7623",
+ MTK_EINT_FUNCTION(0, 91),
+ MTK_FUNCTION(0, "GPIO118"),
+ MTK_FUNCTION(1, "MSDC0_DAT3"),
+ MTK_FUNCTION(4, "NLD3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(119, "MSDC0_DAT2"),
+ "B2", "mt7623",
+ MTK_EINT_FUNCTION(0, 92),
+ MTK_FUNCTION(0, "GPIO119"),
+ MTK_FUNCTION(1, "MSDC0_DAT2"),
+ MTK_FUNCTION(4, "NLD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(120, "MSDC0_DAT1"),
+ "A3", "mt7623",
+ MTK_EINT_FUNCTION(0, 93),
+ MTK_FUNCTION(0, "GPIO120"),
+ MTK_FUNCTION(1, "MSDC0_DAT1"),
+ MTK_FUNCTION(4, "NLD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(121, "MSDC0_DAT0"),
+ "B4", "mt7623",
+ MTK_EINT_FUNCTION(0, 94),
+ MTK_FUNCTION(0, "GPIO121"),
+ MTK_FUNCTION(1, "MSDC0_DAT0"),
+ MTK_FUNCTION(4, "NLD0"),
+ MTK_FUNCTION(5, "WATCHDOG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(122, "GPIO122"),
+ "H17", "mt7623",
+ MTK_EINT_FUNCTION(0, 95),
+ MTK_FUNCTION(0, "GPIO122"),
+ MTK_FUNCTION(1, "TEST"),
+ MTK_FUNCTION(4, "SDA2"),
+ MTK_FUNCTION(5, "URXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(123, "GPIO123"),
+ "F17", "mt7623",
+ MTK_EINT_FUNCTION(0, 96),
+ MTK_FUNCTION(0, "GPIO123"),
+ MTK_FUNCTION(1, "TEST"),
+ MTK_FUNCTION(4, "SCL2"),
+ MTK_FUNCTION(5, "UTXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(124, "GPIO124"),
+ "H18", "mt7623",
+ MTK_EINT_FUNCTION(0, 97),
+ MTK_FUNCTION(0, "GPIO124"),
+ MTK_FUNCTION(1, "TEST"),
+ MTK_FUNCTION(4, "SDA1"),
+ MTK_FUNCTION(5, "PWM3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(125, "GPIO125"),
+ "G17", "mt7623",
+ MTK_EINT_FUNCTION(0, 98),
+ MTK_FUNCTION(0, "GPIO125"),
+ MTK_FUNCTION(1, "TEST"),
+ MTK_FUNCTION(4, "SCL1"),
+ MTK_FUNCTION(5, "PWM4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(126, "I2S0_MCLK"),
+ "AA19", "mt7623",
+ MTK_EINT_FUNCTION(0, 99),
+ MTK_FUNCTION(0, "GPIO126"),
+ MTK_FUNCTION(1, "I2S0_MCLK"),
+ MTK_FUNCTION(6, "AP_I2S_MCLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(127, "GPIO127"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO127")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(128, "GPIO128"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO128")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(129, "GPIO129"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO129")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(130, "GPIO130"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO130")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(131, "GPIO131"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO131")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(132, "GPIO132"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO132")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(133, "GPIO133"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO133")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(134, "GPIO134"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO134")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(135, "GPIO135"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO135")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(136, "GPIO136"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO136")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(137, "GPIO137"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO137")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(138, "GPIO138"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO138")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(139, "GPIO139"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO139")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(140, "GPIO140"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO140")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(141, "GPIO141"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO141")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(142, "GPIO142"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO142")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(143, "GPIO143"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO143")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(144, "GPIO144"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO144")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(145, "GPIO145"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO145")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(146, "GPIO146"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO146")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(147, "GPIO147"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO147")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(148, "GPIO148"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO148")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(149, "GPIO149"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO149")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(150, "GPIO150"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO150")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(151, "GPIO151"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO151")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(152, "GPIO152"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO152")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(153, "GPIO153"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO153")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(154, "GPIO154"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO154")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(155, "GPIO155"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO155")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(156, "GPIO156"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO156")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(157, "GPIO157"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO157")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(158, "GPIO158"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO158")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(159, "GPIO159"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO159")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(160, "GPIO160"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO160")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(161, "GPIO161"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO161")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(162, "GPIO162"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO162")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(163, "GPIO163"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO163")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(164, "GPIO164"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO164")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(165, "GPIO165"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO165")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(166, "GPIO166"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO166")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(167, "GPIO167"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO167")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(168, "GPIO168"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO168")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(169, "GPIO169"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO169")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(170, "GPIO170"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO170")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(171, "GPIO171"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO171")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(172, "GPIO172"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO172")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(173, "GPIO173"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO173")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(174, "GPIO174"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO174")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(175, "GPIO175"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO175")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(176, "GPIO176"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO176")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(177, "GPIO177"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO177")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(178, "GPIO178"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO178")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(179, "GPIO179"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO179")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(180, "GPIO180"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO180")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(181, "GPIO181"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO181")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(182, "GPIO182"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO182")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(183, "GPIO183"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO183")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(184, "GPIO184"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO184")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(185, "GPIO185"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO185")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(186, "GPIO186"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO186")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(187, "GPIO187"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO187")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(188, "GPIO188"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO188")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(189, "GPIO189"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO189")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(190, "GPIO190"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO190")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(191, "GPIO191"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO191")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(192, "GPIO192"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO192")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(193, "GPIO193"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO193")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(194, "GPIO194"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO194")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(195, "GPIO195"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO195")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(196, "GPIO196"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO196")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(197, "GPIO197"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO197")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(198, "GPIO198"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO198")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(199, "SPI1_CK"),
+ "E19", "mt7623",
+ MTK_EINT_FUNCTION(0, 111),
+ MTK_FUNCTION(0, "GPIO199"),
+ MTK_FUNCTION(1, "SPI1_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(200, "URXD2"),
+ "K18", "mt7623",
+ MTK_EINT_FUNCTION(0, 112),
+ MTK_FUNCTION(0, "GPIO200"),
+ MTK_FUNCTION(6, "URXD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(201, "UTXD2"),
+ "L18", "mt7623",
+ MTK_EINT_FUNCTION(0, 113),
+ MTK_FUNCTION(0, "GPIO201"),
+ MTK_FUNCTION(6, "UTXD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(202, "GPIO202"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO202")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(203, "PWM0"),
+ "AA16", "mt7623",
+ MTK_EINT_FUNCTION(0, 115),
+ MTK_FUNCTION(0, "GPIO203"),
+ MTK_FUNCTION(1, "PWM0"),
+ MTK_FUNCTION(2, "DISP_PWM")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(204, "PWM1"),
+ "Y16", "mt7623",
+ MTK_EINT_FUNCTION(0, 116),
+ MTK_FUNCTION(0, "GPIO204"),
+ MTK_FUNCTION(1, "PWM1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(205, "PWM2"),
+ "AA15", "mt7623",
+ MTK_EINT_FUNCTION(0, 117),
+ MTK_FUNCTION(0, "GPIO205"),
+ MTK_FUNCTION(1, "PWM2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(206, "PWM3"),
+ "AA17", "mt7623",
+ MTK_EINT_FUNCTION(0, 118),
+ MTK_FUNCTION(0, "GPIO206"),
+ MTK_FUNCTION(1, "PWM3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(207, "PWM4"),
+ "Y15", "mt7623",
+ MTK_EINT_FUNCTION(0, 119),
+ MTK_FUNCTION(0, "GPIO207"),
+ MTK_FUNCTION(1, "PWM4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(208, "AUD_EXT_CK1"),
+ "W14", "mt7623",
+ MTK_EINT_FUNCTION(0, 120),
+ MTK_FUNCTION(0, "GPIO208"),
+ MTK_FUNCTION(1, "AUD_EXT_CK1"),
+ MTK_FUNCTION(2, "PWM0"),
+ MTK_FUNCTION(3, "PCIE0_PERST_N"),
+ MTK_FUNCTION(5, "DISP_PWM")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(209, "AUD_EXT_CK2"),
+ "V15", "mt7623",
+ MTK_EINT_FUNCTION(0, 121),
+ MTK_FUNCTION(0, "GPIO209"),
+ MTK_FUNCTION(1, "AUD_EXT_CK2"),
+ MTK_FUNCTION(2, "MSDC1_WP"),
+ MTK_FUNCTION(3, "PCIE1_PERST_N"),
+ MTK_FUNCTION(5, "PWM1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(210, "GPIO210"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO210")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(211, "GPIO211"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO211")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(212, "GPIO212"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO212")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(213, "GPIO213"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO213")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(214, "GPIO214"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO214")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(215, "GPIO215"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO215")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(216, "GPIO216"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO216")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(217, "GPIO217"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO217")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(218, "GPIO218"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO218")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(219, "GPIO219"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO219")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(220, "GPIO220"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO220")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(221, "GPIO221"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO221")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(222, "GPIO222"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO222")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(223, "GPIO223"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO223")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(224, "GPIO224"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO224")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(225, "GPIO225"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO225")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(226, "GPIO226"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO226")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(227, "GPIO227"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO227")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(228, "GPIO228"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO228")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(229, "GPIO229"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO229")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(230, "GPIO230"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO230")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(231, "GPIO231"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO231")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(232, "GPIO232"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO232")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(233, "GPIO233"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO233")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(234, "GPIO234"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO234")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(235, "GPIO235"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO235")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(236, "EXT_SDIO3"),
+ "A8", "mt7623",
+ MTK_EINT_FUNCTION(0, 122),
+ MTK_FUNCTION(0, "GPIO236"),
+ MTK_FUNCTION(1, "EXT_SDIO3"),
+ MTK_FUNCTION(2, "IDDIG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(237, "EXT_SDIO2"),
+ "D8", "mt7623",
+ MTK_EINT_FUNCTION(0, 123),
+ MTK_FUNCTION(0, "GPIO237"),
+ MTK_FUNCTION(1, "EXT_SDIO2"),
+ MTK_FUNCTION(2, "DRV_VBUS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(238, "EXT_SDIO1"),
+ "D9", "mt7623",
+ MTK_EINT_FUNCTION(0, 124),
+ MTK_FUNCTION(0, "GPIO238"),
+ MTK_FUNCTION(1, "EXT_SDIO1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(239, "EXT_SDIO0"),
+ "B8", "mt7623",
+ MTK_EINT_FUNCTION(0, 125),
+ MTK_FUNCTION(0, "GPIO239"),
+ MTK_FUNCTION(1, "EXT_SDIO0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(240, "EXT_XCS"),
+ "C9", "mt7623",
+ MTK_EINT_FUNCTION(0, 126),
+ MTK_FUNCTION(0, "GPIO240"),
+ MTK_FUNCTION(1, "EXT_XCS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(241, "EXT_SCK"),
+ "C8", "mt7623",
+ MTK_EINT_FUNCTION(0, 127),
+ MTK_FUNCTION(0, "GPIO241"),
+ MTK_FUNCTION(1, "EXT_SCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(242, "URTS2"),
+ "G18", "mt7623",
+ MTK_EINT_FUNCTION(0, 128),
+ MTK_FUNCTION(0, "GPIO242"),
+ MTK_FUNCTION(1, "URTS2"),
+ MTK_FUNCTION(2, "UTXD3"),
+ MTK_FUNCTION(3, "URXD3"),
+ MTK_FUNCTION(4, "SCL1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(243, "UCTS2"),
+ "H19", "mt7623",
+ MTK_EINT_FUNCTION(0, 129),
+ MTK_FUNCTION(0, "GPIO243"),
+ MTK_FUNCTION(1, "UCTS2"),
+ MTK_FUNCTION(2, "URXD3"),
+ MTK_FUNCTION(3, "UTXD3"),
+ MTK_FUNCTION(4, "SDA1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(244, "GPIO244"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO244")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(245, "GPIO245"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO245")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(246, "GPIO246"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO246")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(247, "GPIO247"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO247")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(248, "GPIO248"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO248")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(249, "GPIO249"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO249")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(250, "GPIO250"),
+ "A15", "mt7623",
+ MTK_EINT_FUNCTION(0, 135),
+ MTK_FUNCTION(0, "GPIO250"),
+ MTK_FUNCTION(1, "TEST_MD7"),
+ MTK_FUNCTION(6, "PCIE0_CLKREQ_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(251, "GPIO251"),
+ "B15", "mt7623",
+ MTK_EINT_FUNCTION(0, 136),
+ MTK_FUNCTION(0, "GPIO251"),
+ MTK_FUNCTION(1, "TEST_MD6"),
+ MTK_FUNCTION(6, "PCIE0_WAKE_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(252, "GPIO252"),
+ "C16", "mt7623",
+ MTK_EINT_FUNCTION(0, 137),
+ MTK_FUNCTION(0, "GPIO252"),
+ MTK_FUNCTION(1, "TEST_MD5"),
+ MTK_FUNCTION(6, "PCIE1_CLKREQ_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(253, "GPIO253"),
+ "D17", "mt7623",
+ MTK_EINT_FUNCTION(0, 138),
+ MTK_FUNCTION(0, "GPIO253"),
+ MTK_FUNCTION(1, "TEST_MD4"),
+ MTK_FUNCTION(6, "PCIE1_WAKE_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(254, "GPIO254"),
+ "D16", "mt7623",
+ MTK_EINT_FUNCTION(0, 139),
+ MTK_FUNCTION(0, "GPIO254"),
+ MTK_FUNCTION(1, "TEST_MD3"),
+ MTK_FUNCTION(6, "PCIE2_CLKREQ_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(255, "GPIO255"),
+ "C17", "mt7623",
+ MTK_EINT_FUNCTION(0, 140),
+ MTK_FUNCTION(0, "GPIO255"),
+ MTK_FUNCTION(1, "TEST_MD2"),
+ MTK_FUNCTION(6, "PCIE2_WAKE_N")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(256, "GPIO256"),
+ "B17", "mt7623",
+ MTK_EINT_FUNCTION(0, 141),
+ MTK_FUNCTION(0, "GPIO256"),
+ MTK_FUNCTION(1, "TEST_MD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(257, "GPIO257"),
+ "C15", "mt7623",
+ MTK_EINT_FUNCTION(0, 142),
+ MTK_FUNCTION(0, "GPIO257"),
+ MTK_FUNCTION(1, "TEST_MD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(258, "GPIO258"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO258")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(259, "GPIO259"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO259")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(260, "GPIO260"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO260")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(261, "MSDC1_INS"),
+ "AD1", "mt7623",
+ MTK_EINT_FUNCTION(0, 146),
+ MTK_FUNCTION(0, "GPIO261"),
+ MTK_FUNCTION(1, "MSDC1_INS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(262, "G2_TXEN"),
+ "A23", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO262"),
+ MTK_FUNCTION(1, "G2_TXEN")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(263, "G2_TXD3"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO263"),
+ MTK_FUNCTION(1, "G2_TXD3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(264, "G2_TXD2"),
+ "C24", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO264"),
+ MTK_FUNCTION(1, "G2_TXD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(265, "G2_TXD1"),
+ "B25", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO265"),
+ MTK_FUNCTION(1, "G2_TXD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(266, "G2_TXD0"),
+ "A24", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO266"),
+ MTK_FUNCTION(1, "G2_TXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(267, "G2_TXCLK"),
+ "C23", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO267"),
+ MTK_FUNCTION(1, "G2_TXC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(268, "G2_RXCLK"),
+ "B23", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO268"),
+ MTK_FUNCTION(1, "G2_RXC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(269, "G2_RXD0"),
+ "D21", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO269"),
+ MTK_FUNCTION(1, "G2_RXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(270, "G2_RXD1"),
+ "B22", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO270"),
+ MTK_FUNCTION(1, "G2_RXD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(271, "G2_RXD2"),
+ "A22", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO271"),
+ MTK_FUNCTION(1, "G2_RXD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(272, "G2_RXD3"),
+ "C22", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO272"),
+ MTK_FUNCTION(1, "G2_RXD3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(273, "GPIO273"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO273")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(274, "G2_RXDV"),
+ "C21", "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO274"),
+ MTK_FUNCTION(1, "G2_RXDV")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(275, "G2_MDC"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO275"),
+ MTK_FUNCTION(1, "MDC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(276, "G2_MDIO"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO276"),
+ MTK_FUNCTION(1, "MDIO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(277, "GPIO277"),
+ NULL, "mt7623",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO277")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(278, "JTAG_RESET"),
+ "H20", "mt7623",
+ MTK_EINT_FUNCTION(0, 147),
+ MTK_FUNCTION(0, "GPIO278"),
+ MTK_FUNCTION(1, "JTAG_RESET")
+ ),
+};
+
+#endif /* __PINCTRL_MTK_MT7623_H */
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 50cab27c64d4..0bdb8fd3afd1 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -49,7 +49,6 @@
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pinctrl/pinconf-generic.h>
@@ -104,15 +103,13 @@ static int meson_get_domain_and_bank(struct meson_pinctrl *pc, unsigned int pin,
struct meson_bank **bank)
{
struct meson_domain *d;
- int i;
- for (i = 0; i < pc->data->num_domains; i++) {
- d = &pc->domains[i];
- if (pin >= d->data->pin_base &&
- pin < d->data->pin_base + d->data->num_pins) {
- *domain = d;
- return meson_get_bank(d, pin, bank);
- }
+ d = pc->domain;
+
+ if (pin >= d->data->pin_base &&
+ pin < d->data->pin_base + d->data->num_pins) {
+ *domain = d;
+ return meson_get_bank(d, pin, bank);
}
return -EINVAL;
@@ -204,7 +201,7 @@ static void meson_pmx_disable_other_groups(struct meson_pinctrl *pc,
for (j = 0; j < group->num_pins; j++) {
if (group->pins[j] == pin) {
/* We have found a group using the pin */
- domain = &pc->domains[group->domain];
+ domain = pc->domain;
regmap_update_bits(domain->reg_mux,
group->reg * 4,
BIT(group->bit), 0);
@@ -219,7 +216,7 @@ static int meson_pmx_set_mux(struct pinctrl_dev *pcdev, unsigned func_num,
struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
struct meson_pmx_func *func = &pc->data->funcs[func_num];
struct meson_pmx_group *group = &pc->data->groups[group_num];
- struct meson_domain *domain = &pc->domains[group->domain];
+ struct meson_domain *domain = pc->domain;
int i, ret = 0;
dev_dbg(pc->dev, "enable function %s, group %s\n", func->name,
@@ -537,76 +534,67 @@ static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
static const struct of_device_id meson_pinctrl_dt_match[] = {
{
- .compatible = "amlogic,meson8-pinctrl",
- .data = &meson8_pinctrl_data,
+ .compatible = "amlogic,meson8-cbus-pinctrl",
+ .data = &meson8_cbus_pinctrl_data,
+ },
+ {
+ .compatible = "amlogic,meson8b-cbus-pinctrl",
+ .data = &meson8b_cbus_pinctrl_data,
+ },
+ {
+ .compatible = "amlogic,meson8-aobus-pinctrl",
+ .data = &meson8_aobus_pinctrl_data,
},
{
- .compatible = "amlogic,meson8b-pinctrl",
- .data = &meson8b_pinctrl_data,
+ .compatible = "amlogic,meson8b-aobus-pinctrl",
+ .data = &meson8b_aobus_pinctrl_data,
},
{ },
};
-MODULE_DEVICE_TABLE(of, meson_pinctrl_dt_match);
static int meson_gpiolib_register(struct meson_pinctrl *pc)
{
struct meson_domain *domain;
- int i, ret;
+ int ret;
- for (i = 0; i < pc->data->num_domains; i++) {
- domain = &pc->domains[i];
-
- domain->chip.label = domain->data->name;
- domain->chip.parent = pc->dev;
- domain->chip.request = meson_gpio_request;
- domain->chip.free = meson_gpio_free;
- domain->chip.direction_input = meson_gpio_direction_input;
- domain->chip.direction_output = meson_gpio_direction_output;
- domain->chip.get = meson_gpio_get;
- domain->chip.set = meson_gpio_set;
- domain->chip.base = domain->data->pin_base;
- domain->chip.ngpio = domain->data->num_pins;
- domain->chip.can_sleep = false;
- domain->chip.of_node = domain->of_node;
- domain->chip.of_gpio_n_cells = 2;
-
- ret = gpiochip_add_data(&domain->chip, domain);
- if (ret) {
- dev_err(pc->dev, "can't add gpio chip %s\n",
- domain->data->name);
- goto fail;
- }
+ domain = pc->domain;
+
+ domain->chip.label = domain->data->name;
+ domain->chip.parent = pc->dev;
+ domain->chip.request = meson_gpio_request;
+ domain->chip.free = meson_gpio_free;
+ domain->chip.direction_input = meson_gpio_direction_input;
+ domain->chip.direction_output = meson_gpio_direction_output;
+ domain->chip.get = meson_gpio_get;
+ domain->chip.set = meson_gpio_set;
+ domain->chip.base = domain->data->pin_base;
+ domain->chip.ngpio = domain->data->num_pins;
+ domain->chip.can_sleep = false;
+ domain->chip.of_node = domain->of_node;
+ domain->chip.of_gpio_n_cells = 2;
+
+ ret = gpiochip_add_data(&domain->chip, domain);
+ if (ret) {
+ dev_err(pc->dev, "can't add gpio chip %s\n",
+ domain->data->name);
+ goto fail;
+ }
- ret = gpiochip_add_pin_range(&domain->chip, dev_name(pc->dev),
- 0, domain->data->pin_base,
- domain->chip.ngpio);
- if (ret) {
- dev_err(pc->dev, "can't add pin range\n");
- goto fail;
- }
+ ret = gpiochip_add_pin_range(&domain->chip, dev_name(pc->dev),
+ 0, domain->data->pin_base,
+ domain->chip.ngpio);
+ if (ret) {
+ dev_err(pc->dev, "can't add pin range\n");
+ goto fail;
}
return 0;
fail:
- for (i--; i >= 0; i--)
- gpiochip_remove(&pc->domains[i].chip);
+ gpiochip_remove(&pc->domain->chip);
return ret;
}
-static struct meson_domain_data *meson_get_domain_data(struct meson_pinctrl *pc,
- struct device_node *np)
-{
- int i;
-
- for (i = 0; i < pc->data->num_domains; i++) {
- if (!strcmp(np->name, pc->data->domain_data[i].name))
- return &pc->data->domain_data[i];
- }
-
- return NULL;
-}
-
static struct regmap_config meson_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
@@ -643,7 +631,7 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
{
struct device_node *np;
struct meson_domain *domain;
- int i = 0, num_domains = 0;
+ int num_domains = 0;
for_each_child_of_node(node, np) {
if (!of_find_property(np, "gpio-controller", NULL))
@@ -651,29 +639,22 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
num_domains++;
}
- if (num_domains != pc->data->num_domains) {
+ if (num_domains != 1) {
dev_err(pc->dev, "wrong number of subnodes\n");
return -EINVAL;
}
- pc->domains = devm_kzalloc(pc->dev, num_domains *
- sizeof(struct meson_domain), GFP_KERNEL);
- if (!pc->domains)
+ pc->domain = devm_kzalloc(pc->dev, sizeof(struct meson_domain), GFP_KERNEL);
+ if (!pc->domain)
return -ENOMEM;
+ domain = pc->domain;
+ domain->data = pc->data->domain_data;
+
for_each_child_of_node(node, np) {
if (!of_find_property(np, "gpio-controller", NULL))
continue;
- domain = &pc->domains[i];
-
- domain->data = meson_get_domain_data(pc, np);
- if (!domain->data) {
- dev_err(pc->dev, "domain data not found for node %s\n",
- np->name);
- return -ENODEV;
- }
-
domain->of_node = np;
domain->reg_mux = meson_map_resource(pc, np, "mux");
@@ -699,7 +680,7 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
return PTR_ERR(domain->reg_gpio);
}
- i++;
+ break;
}
return 0;
@@ -718,7 +699,7 @@ static int meson_pinctrl_probe(struct platform_device *pdev)
pc->dev = dev;
match = of_match_node(meson_pinctrl_dt_match, pdev->dev.of_node);
- pc->data = (struct meson_pinctrl_data *)match->data;
+ pc->data = (struct meson_pinctrl_data *) match->data;
ret = meson_pinctrl_parse_dt(pc, pdev->dev.of_node);
if (ret)
@@ -754,8 +735,4 @@ static struct platform_driver meson_pinctrl_driver = {
.of_match_table = meson_pinctrl_dt_match,
},
};
-module_platform_driver(meson_pinctrl_driver);
-
-MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
-MODULE_DESCRIPTION("Amlogic Meson pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(meson_pinctrl_driver);
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 0fe7d53849ce..9c93e0d494a3 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -34,7 +34,6 @@ struct meson_pmx_group {
bool is_gpio;
unsigned int reg;
unsigned int bit;
- unsigned int domain;
};
/**
@@ -144,7 +143,6 @@ struct meson_pinctrl_data {
unsigned int num_pins;
unsigned int num_groups;
unsigned int num_funcs;
- unsigned int num_domains;
};
struct meson_pinctrl {
@@ -152,7 +150,7 @@ struct meson_pinctrl {
struct pinctrl_dev *pcdev;
struct pinctrl_desc desc;
struct meson_pinctrl_data *data;
- struct meson_domain *domains;
+ struct meson_domain *domain;
};
#define PIN(x, b) (b + x)
@@ -164,7 +162,6 @@ struct meson_pinctrl {
.num_pins = ARRAY_SIZE(grp ## _pins), \
.reg = r, \
.bit = b, \
- .domain = 0, \
}
#define GPIO_GROUP(gpio, b) \
@@ -175,16 +172,6 @@ struct meson_pinctrl {
.is_gpio = true, \
}
-#define GROUP_AO(grp, r, b) \
- { \
- .name = #grp, \
- .pins = grp ## _pins, \
- .num_pins = ARRAY_SIZE(grp ## _pins), \
- .reg = r, \
- .bit = b, \
- .domain = 1, \
- }
-
#define FUNCTION(fn) \
{ \
.name = #fn, \
@@ -208,5 +195,7 @@ struct meson_pinctrl {
#define MESON_PIN(x, b) PINCTRL_PIN(PIN(x, b), #x)
-extern struct meson_pinctrl_data meson8_pinctrl_data;
-extern struct meson_pinctrl_data meson8b_pinctrl_data;
+extern struct meson_pinctrl_data meson8_cbus_pinctrl_data;
+extern struct meson_pinctrl_data meson8_aobus_pinctrl_data;
+extern struct meson_pinctrl_data meson8b_cbus_pinctrl_data;
+extern struct meson_pinctrl_data meson8b_aobus_pinctrl_data;
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
index 7b1cc91733ef..32de191e0807 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -16,7 +16,7 @@
#define AO_OFF 120
-static const struct pinctrl_pin_desc meson8_pins[] = {
+static const struct pinctrl_pin_desc meson8_cbus_pins[] = {
MESON_PIN(GPIOX_0, 0),
MESON_PIN(GPIOX_1, 0),
MESON_PIN(GPIOX_2, 0),
@@ -137,6 +137,9 @@ static const struct pinctrl_pin_desc meson8_pins[] = {
MESON_PIN(BOOT_16, 0),
MESON_PIN(BOOT_17, 0),
MESON_PIN(BOOT_18, 0),
+};
+
+static const struct pinctrl_pin_desc meson8_aobus_pins[] = {
MESON_PIN(GPIOAO_0, AO_OFF),
MESON_PIN(GPIOAO_1, AO_OFF),
MESON_PIN(GPIOAO_2, AO_OFF),
@@ -379,7 +382,7 @@ static const unsigned int uart_rx_ao_b1_pins[] = { PIN(GPIOAO_5, AO_OFF) };
static const unsigned int i2c_mst_sck_ao_pins[] = { PIN(GPIOAO_4, AO_OFF) };
static const unsigned int i2c_mst_sda_ao_pins[] = { PIN(GPIOAO_5, AO_OFF) };
-static struct meson_pmx_group meson8_groups[] = {
+static struct meson_pmx_group meson8_cbus_groups[] = {
GPIO_GROUP(GPIOX_0, 0),
GPIO_GROUP(GPIOX_1, 0),
GPIO_GROUP(GPIOX_2, 0),
@@ -474,22 +477,6 @@ static struct meson_pmx_group meson8_groups[] = {
GPIO_GROUP(GPIOZ_12, 0),
GPIO_GROUP(GPIOZ_13, 0),
GPIO_GROUP(GPIOZ_14, 0),
- GPIO_GROUP(GPIOAO_0, AO_OFF),
- GPIO_GROUP(GPIOAO_1, AO_OFF),
- GPIO_GROUP(GPIOAO_2, AO_OFF),
- GPIO_GROUP(GPIOAO_3, AO_OFF),
- GPIO_GROUP(GPIOAO_4, AO_OFF),
- GPIO_GROUP(GPIOAO_5, AO_OFF),
- GPIO_GROUP(GPIOAO_6, AO_OFF),
- GPIO_GROUP(GPIOAO_7, AO_OFF),
- GPIO_GROUP(GPIOAO_8, AO_OFF),
- GPIO_GROUP(GPIOAO_9, AO_OFF),
- GPIO_GROUP(GPIOAO_10, AO_OFF),
- GPIO_GROUP(GPIOAO_11, AO_OFF),
- GPIO_GROUP(GPIOAO_12, AO_OFF),
- GPIO_GROUP(GPIOAO_13, AO_OFF),
- GPIO_GROUP(GPIO_BSD_EN, AO_OFF),
- GPIO_GROUP(GPIO_TEST_N, AO_OFF),
/* bank X */
GROUP(sd_d0_a, 8, 5),
@@ -675,26 +662,45 @@ static struct meson_pmx_group meson8_groups[] = {
GROUP(sdxc_d0_b, 2, 7),
GROUP(sdxc_clk_b, 2, 5),
GROUP(sdxc_cmd_b, 2, 4),
+};
+
+static struct meson_pmx_group meson8_aobus_groups[] = {
+ GPIO_GROUP(GPIOAO_0, AO_OFF),
+ GPIO_GROUP(GPIOAO_1, AO_OFF),
+ GPIO_GROUP(GPIOAO_2, AO_OFF),
+ GPIO_GROUP(GPIOAO_3, AO_OFF),
+ GPIO_GROUP(GPIOAO_4, AO_OFF),
+ GPIO_GROUP(GPIOAO_5, AO_OFF),
+ GPIO_GROUP(GPIOAO_6, AO_OFF),
+ GPIO_GROUP(GPIOAO_7, AO_OFF),
+ GPIO_GROUP(GPIOAO_8, AO_OFF),
+ GPIO_GROUP(GPIOAO_9, AO_OFF),
+ GPIO_GROUP(GPIOAO_10, AO_OFF),
+ GPIO_GROUP(GPIOAO_11, AO_OFF),
+ GPIO_GROUP(GPIOAO_12, AO_OFF),
+ GPIO_GROUP(GPIOAO_13, AO_OFF),
+ GPIO_GROUP(GPIO_BSD_EN, AO_OFF),
+ GPIO_GROUP(GPIO_TEST_N, AO_OFF),
/* bank AO */
- GROUP_AO(uart_tx_ao_a, 0, 12),
- GROUP_AO(uart_rx_ao_a, 0, 11),
- GROUP_AO(uart_cts_ao_a, 0, 10),
- GROUP_AO(uart_rts_ao_a, 0, 9),
+ GROUP(uart_tx_ao_a, 0, 12),
+ GROUP(uart_rx_ao_a, 0, 11),
+ GROUP(uart_cts_ao_a, 0, 10),
+ GROUP(uart_rts_ao_a, 0, 9),
- GROUP_AO(remote_input, 0, 0),
+ GROUP(remote_input, 0, 0),
- GROUP_AO(i2c_slave_sck_ao, 0, 2),
- GROUP_AO(i2c_slave_sda_ao, 0, 1),
+ GROUP(i2c_slave_sck_ao, 0, 2),
+ GROUP(i2c_slave_sda_ao, 0, 1),
- GROUP_AO(uart_tx_ao_b0, 0, 26),
- GROUP_AO(uart_rx_ao_b0, 0, 25),
+ GROUP(uart_tx_ao_b0, 0, 26),
+ GROUP(uart_rx_ao_b0, 0, 25),
- GROUP_AO(uart_tx_ao_b1, 0, 24),
- GROUP_AO(uart_rx_ao_b1, 0, 23),
+ GROUP(uart_tx_ao_b1, 0, 24),
+ GROUP(uart_rx_ao_b1, 0, 23),
- GROUP_AO(i2c_mst_sck_ao, 0, 6),
- GROUP_AO(i2c_mst_sda_ao, 0, 5),
+ GROUP(i2c_mst_sck_ao, 0, 6),
+ GROUP(i2c_mst_sda_ao, 0, 5),
};
static const char * const gpio_groups[] = {
@@ -872,7 +878,7 @@ static const char * const i2c_mst_ao_groups[] = {
"i2c_mst_sck_ao", "i2c_mst_sda_ao"
};
-static struct meson_pmx_func meson8_functions[] = {
+static struct meson_pmx_func meson8_cbus_functions[] = {
FUNCTION(gpio),
FUNCTION(sd_a),
FUNCTION(sdxc_a),
@@ -899,6 +905,9 @@ static struct meson_pmx_func meson8_functions[] = {
FUNCTION(nor),
FUNCTION(sd_b),
FUNCTION(sdxc_b),
+};
+
+static struct meson_pmx_func meson8_aobus_functions[] = {
FUNCTION(uart_ao),
FUNCTION(remote),
FUNCTION(i2c_slave_ao),
@@ -906,7 +915,7 @@ static struct meson_pmx_func meson8_functions[] = {
FUNCTION(i2c_mst_ao),
};
-static struct meson_bank meson8_banks[] = {
+static struct meson_bank meson8_cbus_banks[] = {
/* name first last pullen pull dir out in */
BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_16, 0), 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
@@ -917,35 +926,43 @@ static struct meson_bank meson8_banks[] = {
BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
};
-static struct meson_bank meson8_ao_banks[] = {
+static struct meson_bank meson8_aobus_banks[] = {
/* name first last pullen pull dir out in */
BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
-static struct meson_domain_data meson8_domain_data[] = {
- {
- .name = "banks",
- .banks = meson8_banks,
- .num_banks = ARRAY_SIZE(meson8_banks),
- .pin_base = 0,
- .num_pins = 120,
- },
- {
- .name = "ao-bank",
- .banks = meson8_ao_banks,
- .num_banks = ARRAY_SIZE(meson8_ao_banks),
- .pin_base = 120,
- .num_pins = 16,
- },
-};
-
-struct meson_pinctrl_data meson8_pinctrl_data = {
- .pins = meson8_pins,
- .groups = meson8_groups,
- .funcs = meson8_functions,
- .domain_data = meson8_domain_data,
- .num_pins = ARRAY_SIZE(meson8_pins),
- .num_groups = ARRAY_SIZE(meson8_groups),
- .num_funcs = ARRAY_SIZE(meson8_functions),
- .num_domains = ARRAY_SIZE(meson8_domain_data),
+static struct meson_domain_data meson8_cbus_domain_data = {
+ .name = "cbus-banks",
+ .banks = meson8_cbus_banks,
+ .num_banks = ARRAY_SIZE(meson8_cbus_banks),
+ .pin_base = 0,
+ .num_pins = 120,
+};
+
+static struct meson_domain_data meson8_aobus_domain_data = {
+ .name = "ao-bank",
+ .banks = meson8_aobus_banks,
+ .num_banks = ARRAY_SIZE(meson8_aobus_banks),
+ .pin_base = 120,
+ .num_pins = 16,
+};
+
+struct meson_pinctrl_data meson8_cbus_pinctrl_data = {
+ .pins = meson8_cbus_pins,
+ .groups = meson8_cbus_groups,
+ .funcs = meson8_cbus_functions,
+ .domain_data = &meson8_cbus_domain_data,
+ .num_pins = ARRAY_SIZE(meson8_cbus_pins),
+ .num_groups = ARRAY_SIZE(meson8_cbus_groups),
+ .num_funcs = ARRAY_SIZE(meson8_cbus_functions),
+};
+
+struct meson_pinctrl_data meson8_aobus_pinctrl_data = {
+ .pins = meson8_aobus_pins,
+ .groups = meson8_aobus_groups,
+ .funcs = meson8_aobus_functions,
+ .domain_data = &meson8_aobus_domain_data,
+ .num_pins = ARRAY_SIZE(meson8_aobus_pins),
+ .num_groups = ARRAY_SIZE(meson8_aobus_groups),
+ .num_funcs = ARRAY_SIZE(meson8_aobus_functions),
};
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index 9677807db364..a100bcf4b17f 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -17,7 +17,7 @@
#define AO_OFF 130
-static const struct pinctrl_pin_desc meson8b_pins[] = {
+static const struct pinctrl_pin_desc meson8b_cbus_pins[] = {
MESON_PIN(GPIOX_0, 0),
MESON_PIN(GPIOX_1, 0),
MESON_PIN(GPIOX_2, 0),
@@ -107,7 +107,9 @@ static const struct pinctrl_pin_desc meson8b_pins[] = {
MESON_PIN(DIF_3_N, 0),
MESON_PIN(DIF_4_P, 0),
MESON_PIN(DIF_4_N, 0),
+};
+static const struct pinctrl_pin_desc meson8b_aobus_pins[] = {
MESON_PIN(GPIOAO_0, AO_OFF),
MESON_PIN(GPIOAO_1, AO_OFF),
MESON_PIN(GPIOAO_2, AO_OFF),
@@ -346,7 +348,7 @@ static const unsigned int eth_ref_clk_pins[] = { PIN(DIF_3_N, 0) };
static const unsigned int eth_mdc_pins[] = { PIN(DIF_4_P, 0) };
static const unsigned int eth_mdio_en_pins[] = { PIN(DIF_4_N, 0) };
-static struct meson_pmx_group meson8b_groups[] = {
+static struct meson_pmx_group meson8b_cbus_groups[] = {
GPIO_GROUP(GPIOX_0, 0),
GPIO_GROUP(GPIOX_1, 0),
GPIO_GROUP(GPIOX_2, 0),
@@ -409,23 +411,6 @@ static struct meson_pmx_group meson8b_groups[] = {
GPIO_GROUP(DIF_4_P, 0),
GPIO_GROUP(DIF_4_N, 0),
- GPIO_GROUP(GPIOAO_0, AO_OFF),
- GPIO_GROUP(GPIOAO_1, AO_OFF),
- GPIO_GROUP(GPIOAO_2, AO_OFF),
- GPIO_GROUP(GPIOAO_3, AO_OFF),
- GPIO_GROUP(GPIOAO_4, AO_OFF),
- GPIO_GROUP(GPIOAO_5, AO_OFF),
- GPIO_GROUP(GPIOAO_6, AO_OFF),
- GPIO_GROUP(GPIOAO_7, AO_OFF),
- GPIO_GROUP(GPIOAO_8, AO_OFF),
- GPIO_GROUP(GPIOAO_9, AO_OFF),
- GPIO_GROUP(GPIOAO_10, AO_OFF),
- GPIO_GROUP(GPIOAO_11, AO_OFF),
- GPIO_GROUP(GPIOAO_12, AO_OFF),
- GPIO_GROUP(GPIOAO_13, AO_OFF),
- GPIO_GROUP(GPIO_BSD_EN, AO_OFF),
- GPIO_GROUP(GPIO_TEST_N, AO_OFF),
-
/* bank X */
GROUP(sd_d0_a, 8, 5),
GROUP(sd_d1_a, 8, 4),
@@ -572,6 +557,37 @@ static struct meson_pmx_group meson8b_groups[] = {
GROUP(sdxc_clk_b, 2, 5),
GROUP(sdxc_cmd_b, 2, 4),
+ /* bank DIF */
+ GROUP(eth_rxd1, 6, 0),
+ GROUP(eth_rxd0, 6, 1),
+ GROUP(eth_rx_dv, 6, 2),
+ GROUP(eth_rx_clk, 6, 3),
+ GROUP(eth_txd0_1, 6, 4),
+ GROUP(eth_txd1_1, 6, 5),
+ GROUP(eth_tx_en, 6, 0),
+ GROUP(eth_ref_clk, 6, 8),
+ GROUP(eth_mdc, 6, 9),
+ GROUP(eth_mdio_en, 6, 10),
+};
+
+static struct meson_pmx_group meson8b_aobus_groups[] = {
+ GPIO_GROUP(GPIOAO_0, AO_OFF),
+ GPIO_GROUP(GPIOAO_1, AO_OFF),
+ GPIO_GROUP(GPIOAO_2, AO_OFF),
+ GPIO_GROUP(GPIOAO_3, AO_OFF),
+ GPIO_GROUP(GPIOAO_4, AO_OFF),
+ GPIO_GROUP(GPIOAO_5, AO_OFF),
+ GPIO_GROUP(GPIOAO_6, AO_OFF),
+ GPIO_GROUP(GPIOAO_7, AO_OFF),
+ GPIO_GROUP(GPIOAO_8, AO_OFF),
+ GPIO_GROUP(GPIOAO_9, AO_OFF),
+ GPIO_GROUP(GPIOAO_10, AO_OFF),
+ GPIO_GROUP(GPIOAO_11, AO_OFF),
+ GPIO_GROUP(GPIOAO_12, AO_OFF),
+ GPIO_GROUP(GPIOAO_13, AO_OFF),
+ GPIO_GROUP(GPIO_BSD_EN, AO_OFF),
+ GPIO_GROUP(GPIO_TEST_N, AO_OFF),
+
/* bank AO */
GROUP(uart_tx_ao_a, 0, 12),
GROUP(uart_rx_ao_a, 0, 11),
@@ -601,18 +617,6 @@ static struct meson_pmx_group meson8b_groups[] = {
GROUP(i2s_in_ch01, 0, 13),
GROUP(i2s_ao_clk_in, 0, 15),
GROUP(i2s_lr_clk_in, 0, 14),
-
- /* bank DIF */
- GROUP(eth_rxd1, 6, 0),
- GROUP(eth_rxd0, 6, 1),
- GROUP(eth_rx_dv, 6, 2),
- GROUP(eth_rx_clk, 6, 3),
- GROUP(eth_txd0_1, 6, 4),
- GROUP(eth_txd1_1, 6, 5),
- GROUP(eth_tx_en, 6, 0),
- GROUP(eth_ref_clk, 6, 8),
- GROUP(eth_mdc, 6, 9),
- GROUP(eth_mdio_en, 6, 10),
};
static const char * const gpio_groups[] = {
@@ -694,7 +698,10 @@ static const char * const i2c_c_groups[] = {
};
static const char * const hdmi_groups[] = {
- "hdmi_hpd", "hdmi_sda", "hdmi_scl", "hdmi_cec_0",
+ "hdmi_hpd", "hdmi_sda", "hdmi_scl", "hdmi_cec_0"
+};
+
+static const char * const hdmi_cec_groups[] = {
"hdmi_cec_1"
};
@@ -770,12 +777,20 @@ static const char * const i2c_mst_ao_groups[] = {
"i2c_mst_sck_ao", "i2c_mst_sda_ao"
};
-static const char * const clk_groups[] = {
- "clk_24m_out", "clk_32k_in_out"
+static const char * const clk_24m_groups[] = {
+ "clk_24m_out"
};
-static const char * const spdif_groups[] = {
- "spdif_out_1", "spdif_out_0"
+static const char * const clk_32k_groups[] = {
+ "clk_32k_in_out"
+};
+
+static const char * const spdif_0_groups[] = {
+ "spdif_out_0"
+};
+
+static const char * const spdif_1_groups[] = {
+ "spdif_out_1"
};
static const char * const i2s_groups[] = {
@@ -789,7 +804,11 @@ static const char * const pwm_b_groups[] = {
};
static const char * const pwm_c_groups[] = {
- "pwm_c0", "pwm_c1", "pwm_c2"
+ "pwm_c0", "pwm_c1"
+};
+
+static const char * const pwm_c_ao_groups[] = {
+ "pwm_c2"
};
static const char * const pwm_d_groups[] = {
@@ -814,7 +833,7 @@ static const char * const tsin_b_groups[] = {
"tsin_d0_b", "tsin_clk_b", "tsin_sop_b", "tsin_d_valid_b"
};
-static struct meson_pmx_func meson8b_functions[] = {
+static struct meson_pmx_func meson8b_cbus_functions[] = {
FUNCTION(gpio),
FUNCTION(sd_a),
FUNCTION(sdxc_a),
@@ -837,14 +856,7 @@ static struct meson_pmx_func meson8b_functions[] = {
FUNCTION(nor),
FUNCTION(sd_b),
FUNCTION(sdxc_b),
- FUNCTION(uart_ao),
- FUNCTION(remote),
- FUNCTION(i2c_slave_ao),
- FUNCTION(uart_ao_b),
- FUNCTION(i2c_mst_ao),
- FUNCTION(clk),
- FUNCTION(spdif),
- FUNCTION(i2s),
+ FUNCTION(spdif_0),
FUNCTION(pwm_b),
FUNCTION(pwm_c),
FUNCTION(pwm_d),
@@ -852,9 +864,23 @@ static struct meson_pmx_func meson8b_functions[] = {
FUNCTION(pwm_vs),
FUNCTION(tsin_a),
FUNCTION(tsin_b),
+ FUNCTION(clk_24m),
+};
+
+static struct meson_pmx_func meson8b_aobus_functions[] = {
+ FUNCTION(uart_ao),
+ FUNCTION(uart_ao_b),
+ FUNCTION(i2c_slave_ao),
+ FUNCTION(i2c_mst_ao),
+ FUNCTION(i2s),
+ FUNCTION(remote),
+ FUNCTION(clk_32k),
+ FUNCTION(pwm_c_ao),
+ FUNCTION(spdif_1),
+ FUNCTION(hdmi_cec),
};
-static struct meson_bank meson8b_banks[] = {
+static struct meson_bank meson8b_cbus_banks[] = {
/* name first last pullen pull dir out in */
BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_14, 0), 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
@@ -865,35 +891,43 @@ static struct meson_bank meson8b_banks[] = {
BANK("DIF", PIN(DIF_0_P, 0), PIN(DIF_4_N, 0), 5, 8, 5, 8, 12, 12, 13, 12, 14, 12),
};
-static struct meson_bank meson8b_ao_banks[] = {
+static struct meson_bank meson8b_aobus_banks[] = {
/* name first last pullen pull dir out in */
BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
-static struct meson_domain_data meson8b_domain_data[] = {
- {
- .name = "banks",
- .banks = meson8b_banks,
- .num_banks = ARRAY_SIZE(meson8b_banks),
- .pin_base = 0,
- .num_pins = 130,
- },
- {
- .name = "ao-bank",
- .banks = meson8b_ao_banks,
- .num_banks = ARRAY_SIZE(meson8b_ao_banks),
- .pin_base = 130,
- .num_pins = 16,
- },
-};
-
-struct meson_pinctrl_data meson8b_pinctrl_data = {
- .pins = meson8b_pins,
- .groups = meson8b_groups,
- .funcs = meson8b_functions,
- .domain_data = meson8b_domain_data,
- .num_pins = ARRAY_SIZE(meson8b_pins),
- .num_groups = ARRAY_SIZE(meson8b_groups),
- .num_funcs = ARRAY_SIZE(meson8b_functions),
- .num_domains = ARRAY_SIZE(meson8b_domain_data),
+static struct meson_domain_data meson8b_cbus_domain_data = {
+ .name = "cbus-banks",
+ .banks = meson8b_cbus_banks,
+ .num_banks = ARRAY_SIZE(meson8b_cbus_banks),
+ .pin_base = 0,
+ .num_pins = 130,
+};
+
+static struct meson_domain_data meson8b_aobus_domain_data = {
+ .name = "aobus-banks",
+ .banks = meson8b_aobus_banks,
+ .num_banks = ARRAY_SIZE(meson8b_aobus_banks),
+ .pin_base = 130,
+ .num_pins = 16,
+};
+
+struct meson_pinctrl_data meson8b_cbus_pinctrl_data = {
+ .pins = meson8b_cbus_pins,
+ .groups = meson8b_cbus_groups,
+ .funcs = meson8b_cbus_functions,
+ .domain_data = &meson8b_cbus_domain_data,
+ .num_pins = ARRAY_SIZE(meson8b_cbus_pins),
+ .num_groups = ARRAY_SIZE(meson8b_cbus_groups),
+ .num_funcs = ARRAY_SIZE(meson8b_cbus_functions),
+};
+
+struct meson_pinctrl_data meson8b_aobus_pinctrl_data = {
+ .pins = meson8b_aobus_pins,
+ .groups = meson8b_aobus_groups,
+ .funcs = meson8b_aobus_functions,
+ .domain_data = &meson8b_aobus_domain_data,
+ .num_pins = ARRAY_SIZE(meson8b_aobus_pins),
+ .num_groups = ARRAY_SIZE(meson8b_aobus_groups),
+ .num_funcs = ARRAY_SIZE(meson8b_aobus_functions),
};
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index e4d473811bb3..3ef798fac81b 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -666,16 +666,19 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
struct mvebu_mpp_ctrl_setting *set = &mode->settings[0];
struct mvebu_pinctrl_group *grp;
unsigned num_settings;
+ unsigned supp_settings;
- for (num_settings = 0; ; set++) {
+ for (num_settings = 0, supp_settings = 0; ; set++) {
if (!set->name)
break;
+ num_settings++;
+
/* skip unsupported settings for this variant */
if (pctl->variant && !(pctl->variant & set->variant))
continue;
- num_settings++;
+ supp_settings++;
/* find gpio/gpo/gpi settings */
if (strcmp(set->name, "gpio") == 0)
@@ -688,7 +691,7 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
}
/* skip modes with no settings for this variant */
- if (!num_settings)
+ if (!supp_settings)
continue;
grp = mvebu_pinctrl_find_group_by_pid(pctl, mode->pid);
diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c
index 085e60106ec2..1f7469c9857d 100644
--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c
@@ -191,6 +191,7 @@ static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
dev_err(pct->dev, "%s write failed (%d)\n", __func__, ret);
}
+#ifdef CONFIG_DEBUG_FS
static int abx500_get_pull_updown(struct abx500_pinctrl *pct, int offset,
enum abx500_gpio_pull_updown *pull_updown)
{
@@ -226,6 +227,7 @@ out:
return ret;
}
+#endif
static int abx500_set_pull_updown(struct abx500_pinctrl *pct,
int offset, enum abx500_gpio_pull_updown val)
@@ -468,6 +470,7 @@ out:
return ret;
}
+#ifdef CONFIG_DEBUG_FS
static int abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
unsigned gpio)
{
@@ -553,8 +556,6 @@ out:
return ret;
}
-#ifdef CONFIG_DEBUG_FS
-
#include <linux/seq_file.h>
static void abx500_gpio_dbg_show_one(struct seq_file *s,
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
index 587b222f12f3..e852048c4c04 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
@@ -287,6 +287,10 @@ static const unsigned i2c0_a_1_pins[] = { STN8815_PIN_D3, STN8815_PIN_D2 };
/* Altfunction B */
static const unsigned u1_b_1_pins[] = { STN8815_PIN_B16, STN8815_PIN_A16 };
static const unsigned i2cusb_b_1_pins[] = { STN8815_PIN_C21, STN8815_PIN_C20 };
+static const unsigned clcd_16_23_b_1_pins[] = { STN8815_PIN_AB6,
+ STN8815_PIN_AA6, STN8815_PIN_Y6, STN8815_PIN_Y5, STN8815_PIN_AA5,
+ STN8815_PIN_AB5, STN8815_PIN_AB4, STN8815_PIN_Y4 };
+
#define STN8815_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \
.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
@@ -302,6 +306,7 @@ static const struct nmk_pingroup nmk_stn8815_groups[] = {
STN8815_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A),
STN8815_PIN_GROUP(u1_b_1, NMK_GPIO_ALT_B),
STN8815_PIN_GROUP(i2cusb_b_1, NMK_GPIO_ALT_B),
+ STN8815_PIN_GROUP(clcd_16_23_b_1, NMK_GPIO_ALT_B),
};
/* We use this macro to define the groups applicable to a function */
@@ -314,6 +319,7 @@ STN8815_FUNC_GROUPS(u1, "u1_a_1", "u1_b_1");
STN8815_FUNC_GROUPS(i2c1, "i2c1_a_1");
STN8815_FUNC_GROUPS(i2c0, "i2c0_a_1");
STN8815_FUNC_GROUPS(i2cusb, "i2cusb_b_1");
+STN8815_FUNC_GROUPS(clcd, "clcd_16_23_b_1");
#define FUNCTION(fname) \
{ \
@@ -329,6 +335,7 @@ static const struct nmk_function nmk_stn8815_functions[] = {
FUNCTION(i2c1),
FUNCTION(i2c0),
FUNCTION(i2cusb),
+ FUNCTION(clcd),
};
static const struct nmk_pinctrl_soc_data nmk_stn8815_soc = {
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 657449431301..5c025f5b5048 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -753,8 +753,8 @@ static int amd_gpio_probe(struct platform_device *pdev)
gpio_dev->base = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
- if (IS_ERR(gpio_dev->base))
- return PTR_ERR(gpio_dev->base);
+ if (!gpio_dev->base)
+ return -ENOMEM;
irq_base = platform_get_irq(pdev, 0);
if (irq_base < 0) {
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index ee69db6ae1c7..4429312e848d 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -824,7 +824,7 @@ static struct pinctrl_desc atmel_pinctrl_desc = {
.pmxops = &atmel_pmxops,
};
-static int atmel_pctrl_suspend(struct device *dev)
+static int __maybe_unused atmel_pctrl_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev);
@@ -844,7 +844,7 @@ static int atmel_pctrl_suspend(struct device *dev)
return 0;
}
-static int atmel_pctrl_resume(struct device *dev)
+static int __maybe_unused atmel_pctrl_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev);
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index cf7788df0f95..741b39eaeb8b 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -127,7 +127,7 @@ struct u300_gpio_confdata {
}
/* Initial configuration */
-static const struct __initconst u300_gpio_confdata
+static const struct u300_gpio_confdata __initconst
bs335_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
/* Port 0, pins 0-7 */
{
diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c
index f0bebbe0682b..b1767f7e45d1 100644
--- a/drivers/pinctrl/pinctrl-lpc18xx.c
+++ b/drivers/pinctrl/pinctrl-lpc18xx.c
@@ -49,6 +49,18 @@
#define LPC18XX_SCU_FUNC_PER_PIN 8
+/* LPC18XX SCU pin interrupt select registers */
+#define LPC18XX_SCU_PINTSEL0 0xe00
+#define LPC18XX_SCU_PINTSEL1 0xe04
+#define LPC18XX_SCU_PINTSEL_VAL_MASK 0xff
+#define LPC18XX_SCU_PINTSEL_PORT_SHIFT 5
+#define LPC18XX_SCU_IRQ_PER_PINTSEL 4
+#define LPC18XX_GPIO_PINS_PER_PORT 32
+#define LPC18XX_GPIO_PIN_INT_MAX 8
+
+#define LPC18XX_SCU_PINTSEL_VAL(val, n) \
+ ((val) << (((n) % LPC18XX_SCU_IRQ_PER_PINTSEL) * 8))
+
/* LPC18xx pin types */
enum {
TYPE_ND, /* Normal-drive */
@@ -618,6 +630,25 @@ static const struct pinctrl_pin_desc lpc18xx_pins[] = {
LPC18XX_PIN(i2c0_sda, PIN_I2C0_SDA),
};
+/**
+ * enum lpc18xx_pin_config_param - possible pin configuration parameters
+ * @PIN_CONFIG_GPIO_PIN_INT: route gpio to the gpio pin interrupt
+ * controller.
+ */
+enum lpc18xx_pin_config_param {
+ PIN_CONFIG_GPIO_PIN_INT = PIN_CONFIG_END + 1,
+};
+
+static const struct pinconf_generic_params lpc18xx_params[] = {
+ {"nxp,gpio-pin-interrupt", PIN_CONFIG_GPIO_PIN_INT, 0},
+};
+
+#ifdef CONFIG_DEBUG_FS
+static const struct pin_config_item lpc18xx_conf_items[ARRAY_SIZE(lpc18xx_params)] = {
+ PCONFDUMP(PIN_CONFIG_GPIO_PIN_INT, "gpio pin int", NULL, true),
+};
+#endif
+
static int lpc18xx_pconf_get_usb1(enum pin_config_param param, int *arg, u32 reg)
{
switch (param) {
@@ -693,7 +724,71 @@ static int lpc18xx_pconf_get_i2c0(enum pin_config_param param, int *arg, u32 reg
return 0;
}
-static int lpc18xx_pconf_get_pin(enum pin_config_param param, int *arg, u32 reg,
+static int lpc18xx_pin_to_gpio(struct pinctrl_dev *pctldev, unsigned pin)
+{
+ struct pinctrl_gpio_range *range;
+
+ range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin);
+ if (!range)
+ return -EINVAL;
+
+ return pin - range->pin_base + range->base;
+}
+
+static int lpc18xx_get_pintsel(void __iomem *addr, u32 val, int *arg)
+{
+ u32 reg_val;
+ int i;
+
+ reg_val = readl(addr);
+ for (i = 0; i < LPC18XX_SCU_IRQ_PER_PINTSEL; i++) {
+ if ((reg_val & LPC18XX_SCU_PINTSEL_VAL_MASK) == val)
+ return 0;
+
+ reg_val >>= BITS_PER_BYTE;
+ *arg += 1;
+ }
+
+ return -EINVAL;
+}
+
+static u32 lpc18xx_gpio_to_pintsel_val(int gpio)
+{
+ unsigned int gpio_port, gpio_pin;
+
+ gpio_port = gpio / LPC18XX_GPIO_PINS_PER_PORT;
+ gpio_pin = gpio % LPC18XX_GPIO_PINS_PER_PORT;
+
+ return gpio_pin | (gpio_port << LPC18XX_SCU_PINTSEL_PORT_SHIFT);
+}
+
+static int lpc18xx_pconf_get_gpio_pin_int(struct pinctrl_dev *pctldev,
+ int *arg, unsigned pin)
+{
+ struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
+ int gpio, ret;
+ u32 val;
+
+ gpio = lpc18xx_pin_to_gpio(pctldev, pin);
+ if (gpio < 0)
+ return -ENOTSUPP;
+
+ val = lpc18xx_gpio_to_pintsel_val(gpio);
+
+ /*
+ * Check if this pin has been enabled as a interrupt in any of the two
+ * PINTSEL registers. *arg indicates which interrupt number (0-7).
+ */
+ *arg = 0;
+ ret = lpc18xx_get_pintsel(scu->base + LPC18XX_SCU_PINTSEL0, val, arg);
+ if (ret == 0)
+ return ret;
+
+ return lpc18xx_get_pintsel(scu->base + LPC18XX_SCU_PINTSEL1, val, arg);
+}
+
+static int lpc18xx_pconf_get_pin(struct pinctrl_dev *pctldev, unsigned param,
+ int *arg, u32 reg, unsigned pin,
struct lpc18xx_pin_caps *pin_cap)
{
switch (param) {
@@ -755,6 +850,9 @@ static int lpc18xx_pconf_get_pin(enum pin_config_param param, int *arg, u32 reg,
}
break;
+ case PIN_CONFIG_GPIO_PIN_INT:
+ return lpc18xx_pconf_get_gpio_pin_int(pctldev, arg, pin);
+
default:
return -ENOTSUPP;
}
@@ -794,7 +892,7 @@ static int lpc18xx_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
else if (pin_cap->type == TYPE_USB1)
ret = lpc18xx_pconf_get_usb1(param, &arg, reg);
else
- ret = lpc18xx_pconf_get_pin(param, &arg, reg, pin_cap);
+ ret = lpc18xx_pconf_get_pin(pctldev, param, &arg, reg, pin, pin_cap);
if (ret < 0)
return ret;
@@ -883,9 +981,34 @@ static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev,
return 0;
}
-static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev,
- enum pin_config_param param,
- u16 param_val, u32 *reg,
+static int lpc18xx_pconf_set_gpio_pin_int(struct pinctrl_dev *pctldev,
+ u16 param_val, unsigned pin)
+{
+ struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
+ u32 val, reg_val, reg_offset = LPC18XX_SCU_PINTSEL0;
+ int gpio;
+
+ if (param_val >= LPC18XX_GPIO_PIN_INT_MAX)
+ return -EINVAL;
+
+ gpio = lpc18xx_pin_to_gpio(pctldev, pin);
+ if (gpio < 0)
+ return -ENOTSUPP;
+
+ val = lpc18xx_gpio_to_pintsel_val(gpio);
+
+ reg_offset += (param_val / LPC18XX_SCU_IRQ_PER_PINTSEL) * sizeof(u32);
+
+ reg_val = readl(scu->base + reg_offset);
+ reg_val &= ~LPC18XX_SCU_PINTSEL_VAL(LPC18XX_SCU_PINTSEL_VAL_MASK, param_val);
+ reg_val |= LPC18XX_SCU_PINTSEL_VAL(val, param_val);
+ writel(reg_val, scu->base + reg_offset);
+
+ return 0;
+}
+
+static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev, unsigned param,
+ u16 param_val, u32 *reg, unsigned pin,
struct lpc18xx_pin_caps *pin_cap)
{
switch (param) {
@@ -948,6 +1071,9 @@ static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev,
*reg |= param_val << LPC18XX_SCU_PIN_EHD_POS;
break;
+ case PIN_CONFIG_GPIO_PIN_INT:
+ return lpc18xx_pconf_set_gpio_pin_int(pctldev, param_val, pin);
+
default:
dev_err(pctldev->dev, "Property not supported\n");
return -ENOTSUPP;
@@ -982,7 +1108,7 @@ static int lpc18xx_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
else if (pin_cap->type == TYPE_USB1)
ret = lpc18xx_pconf_set_usb1(pctldev, param, param_val, &reg);
else
- ret = lpc18xx_pconf_set_pin(pctldev, param, param_val, &reg, pin_cap);
+ ret = lpc18xx_pconf_set_pin(pctldev, param, param_val, &reg, pin, pin_cap);
if (ret)
return ret;
@@ -1136,6 +1262,11 @@ static struct pinctrl_desc lpc18xx_scu_desc = {
.pctlops = &lpc18xx_pctl_ops,
.pmxops = &lpc18xx_pmx_ops,
.confops = &lpc18xx_pconf_ops,
+ .num_custom_params = ARRAY_SIZE(lpc18xx_params),
+ .custom_params = lpc18xx_params,
+#ifdef CONFIG_DEBUG_FS
+ .custom_conf_items = lpc18xx_conf_items,
+#endif
.owner = THIS_MODULE,
};
@@ -1170,9 +1301,8 @@ static int lpc18xx_create_group_func_map(struct device *dev,
u16 pins[ARRAY_SIZE(lpc18xx_pins)];
int func, ngroups, i;
- for (func = 0; func < FUNC_MAX; ngroups = 0, func++) {
-
- for (i = 0; i < ARRAY_SIZE(lpc18xx_pins); i++) {
+ for (func = 0; func < FUNC_MAX; func++) {
+ for (ngroups = 0, i = 0; i < ARRAY_SIZE(lpc18xx_pins); i++) {
if (lpc18xx_valid_pin_function(i, func))
pins[ngroups++] = i;
}
diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c
new file mode 100644
index 000000000000..0b07d4bdab95
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-pic32.c
@@ -0,0 +1,2312 @@
+/*
+ * PIC32 pinctrl driver
+ *
+ * Joshua Henderson, <joshua.henderson@microchip.com>
+ * Copyright (C) 2015 Microchip Technology Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm/mach-pic32/pic32.h>
+
+#include "pinctrl-utils.h"
+#include "pinctrl-pic32.h"
+
+#define PINS_PER_BANK 16
+
+#define PIC32_CNCON_EDGE 11
+#define PIC32_CNCON_ON 15
+
+#define PIN_CONFIG_MICROCHIP_DIGITAL (PIN_CONFIG_END + 1)
+#define PIN_CONFIG_MICROCHIP_ANALOG (PIN_CONFIG_END + 2)
+
+static const struct pinconf_generic_params pic32_mpp_bindings[] = {
+ {"microchip,digital", PIN_CONFIG_MICROCHIP_DIGITAL, 0},
+ {"microchip,analog", PIN_CONFIG_MICROCHIP_ANALOG, 0},
+};
+
+#define GPIO_BANK_START(bank) ((bank) * PINS_PER_BANK)
+
+struct pic32_function {
+ const char *name;
+ const char * const *groups;
+ unsigned int ngroups;
+};
+
+struct pic32_pin_group {
+ const char *name;
+ unsigned int pin;
+ struct pic32_desc_function *functions;
+};
+
+struct pic32_desc_function {
+ const char *name;
+ u32 muxreg;
+ u32 muxval;
+};
+
+struct pic32_gpio_bank {
+ void __iomem *reg_base;
+ struct gpio_chip gpio_chip;
+ struct irq_chip irq_chip;
+ struct clk *clk;
+};
+
+struct pic32_pinctrl {
+ void __iomem *reg_base;
+ struct device *dev;
+ struct pinctrl_dev *pctldev;
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+ const struct pic32_function *functions;
+ unsigned int nfunctions;
+ const struct pic32_pin_group *groups;
+ unsigned int ngroups;
+ struct pic32_gpio_bank *gpio_banks;
+ unsigned int nbanks;
+ struct clk *clk;
+};
+
+static const struct pinctrl_pin_desc pic32_pins[] = {
+ PINCTRL_PIN(0, "A0"),
+ PINCTRL_PIN(1, "A1"),
+ PINCTRL_PIN(2, "A2"),
+ PINCTRL_PIN(3, "A3"),
+ PINCTRL_PIN(4, "A4"),
+ PINCTRL_PIN(5, "A5"),
+ PINCTRL_PIN(6, "A6"),
+ PINCTRL_PIN(7, "A7"),
+ PINCTRL_PIN(8, "A8"),
+ PINCTRL_PIN(9, "A9"),
+ PINCTRL_PIN(10, "A10"),
+ PINCTRL_PIN(11, "A11"),
+ PINCTRL_PIN(12, "A12"),
+ PINCTRL_PIN(13, "A13"),
+ PINCTRL_PIN(14, "A14"),
+ PINCTRL_PIN(15, "A15"),
+ PINCTRL_PIN(16, "B0"),
+ PINCTRL_PIN(17, "B1"),
+ PINCTRL_PIN(18, "B2"),
+ PINCTRL_PIN(19, "B3"),
+ PINCTRL_PIN(20, "B4"),
+ PINCTRL_PIN(21, "B5"),
+ PINCTRL_PIN(22, "B6"),
+ PINCTRL_PIN(23, "B7"),
+ PINCTRL_PIN(24, "B8"),
+ PINCTRL_PIN(25, "B9"),
+ PINCTRL_PIN(26, "B10"),
+ PINCTRL_PIN(27, "B11"),
+ PINCTRL_PIN(28, "B12"),
+ PINCTRL_PIN(29, "B13"),
+ PINCTRL_PIN(30, "B14"),
+ PINCTRL_PIN(31, "B15"),
+ PINCTRL_PIN(33, "C1"),
+ PINCTRL_PIN(34, "C2"),
+ PINCTRL_PIN(35, "C3"),
+ PINCTRL_PIN(36, "C4"),
+ PINCTRL_PIN(44, "C12"),
+ PINCTRL_PIN(45, "C13"),
+ PINCTRL_PIN(46, "C14"),
+ PINCTRL_PIN(47, "C15"),
+ PINCTRL_PIN(48, "D0"),
+ PINCTRL_PIN(49, "D1"),
+ PINCTRL_PIN(50, "D2"),
+ PINCTRL_PIN(51, "D3"),
+ PINCTRL_PIN(52, "D4"),
+ PINCTRL_PIN(53, "D5"),
+ PINCTRL_PIN(54, "D6"),
+ PINCTRL_PIN(55, "D7"),
+ PINCTRL_PIN(57, "D9"),
+ PINCTRL_PIN(58, "D10"),
+ PINCTRL_PIN(59, "D11"),
+ PINCTRL_PIN(60, "D12"),
+ PINCTRL_PIN(61, "D13"),
+ PINCTRL_PIN(62, "D14"),
+ PINCTRL_PIN(63, "D15"),
+ PINCTRL_PIN(64, "E0"),
+ PINCTRL_PIN(65, "E1"),
+ PINCTRL_PIN(66, "E2"),
+ PINCTRL_PIN(67, "E3"),
+ PINCTRL_PIN(68, "E4"),
+ PINCTRL_PIN(69, "E5"),
+ PINCTRL_PIN(70, "E6"),
+ PINCTRL_PIN(71, "E7"),
+ PINCTRL_PIN(72, "E8"),
+ PINCTRL_PIN(73, "E9"),
+ PINCTRL_PIN(80, "F0"),
+ PINCTRL_PIN(81, "F1"),
+ PINCTRL_PIN(82, "F2"),
+ PINCTRL_PIN(83, "F3"),
+ PINCTRL_PIN(84, "F4"),
+ PINCTRL_PIN(85, "F5"),
+ PINCTRL_PIN(88, "F8"),
+ PINCTRL_PIN(92, "F12"),
+ PINCTRL_PIN(93, "F13"),
+ PINCTRL_PIN(96, "G0"),
+ PINCTRL_PIN(97, "G1"),
+ PINCTRL_PIN(102, "G6"),
+ PINCTRL_PIN(103, "G7"),
+ PINCTRL_PIN(104, "G8"),
+ PINCTRL_PIN(105, "G9"),
+ PINCTRL_PIN(108, "G12"),
+ PINCTRL_PIN(109, "G13"),
+ PINCTRL_PIN(110, "G14"),
+ PINCTRL_PIN(111, "G15"),
+ PINCTRL_PIN(112, "H0"),
+ PINCTRL_PIN(113, "H1"),
+ PINCTRL_PIN(114, "H2"),
+ PINCTRL_PIN(115, "H3"),
+ PINCTRL_PIN(116, "H4"),
+ PINCTRL_PIN(117, "H5"),
+ PINCTRL_PIN(118, "H6"),
+ PINCTRL_PIN(119, "H7"),
+ PINCTRL_PIN(120, "H8"),
+ PINCTRL_PIN(121, "H9"),
+ PINCTRL_PIN(122, "H10"),
+ PINCTRL_PIN(123, "H11"),
+ PINCTRL_PIN(124, "H12"),
+ PINCTRL_PIN(125, "H13"),
+ PINCTRL_PIN(126, "H14"),
+ PINCTRL_PIN(127, "H15"),
+ PINCTRL_PIN(128, "J0"),
+ PINCTRL_PIN(129, "J1"),
+ PINCTRL_PIN(130, "J2"),
+ PINCTRL_PIN(131, "J3"),
+ PINCTRL_PIN(132, "J4"),
+ PINCTRL_PIN(133, "J5"),
+ PINCTRL_PIN(134, "J6"),
+ PINCTRL_PIN(135, "J7"),
+ PINCTRL_PIN(136, "J8"),
+ PINCTRL_PIN(137, "J9"),
+ PINCTRL_PIN(138, "J10"),
+ PINCTRL_PIN(139, "J11"),
+ PINCTRL_PIN(140, "J12"),
+ PINCTRL_PIN(141, "J13"),
+ PINCTRL_PIN(142, "J14"),
+ PINCTRL_PIN(143, "J15"),
+ PINCTRL_PIN(144, "K0"),
+ PINCTRL_PIN(145, "K1"),
+ PINCTRL_PIN(146, "K2"),
+ PINCTRL_PIN(147, "K3"),
+ PINCTRL_PIN(148, "K4"),
+ PINCTRL_PIN(149, "K5"),
+ PINCTRL_PIN(150, "K6"),
+ PINCTRL_PIN(151, "K7"),
+};
+
+static const char * const pic32_input0_group[] = {
+ "D2", "G8", "F4", "F1", "B9", "B10", "C14", "B5",
+ "C1", "D14", "G1", "A14", "D6",
+};
+
+static const char * const pic32_input1_group[] = {
+ "D3", "G7", "F5", "D11", "F0", "B1", "E5", "C13",
+ "B3", "C4", "G0", "A15", "D7",
+};
+
+static const char * const pic32_input2_group[] = {
+ "D9", "G6", "B8", "B15", "D4", "B0", "E3", "B7",
+ "F12", "D12", "F8", "C3", "E9",
+};
+
+static const char * const pic32_input3_group[] = {
+ "G9", "B14", "D0", "B6", "D5", "B2", "F3", "F13",
+ "F2", "C2", "E8",
+};
+
+static const char * const pic32_output0_group[] = {
+ "D2", "G8", "F4", "D10", "F1", "B9", "B10", "C14",
+ "B5", "C1", "D14", "G1", "A14", "D6",
+};
+
+static const char * const pic32_output0_1_group[] = {
+ "D2", "G8", "F4", "D10", "F1", "B9", "B10", "C14",
+ "B5", "C1", "D14", "G1", "A14", "D6",
+ "D3", "G7", "F5", "D11", "F0", "B1", "E5", "C13",
+ "B3", "C4", "D15", "G0", "A15", "D7",
+};
+
+static const char *const pic32_output1_group[] = {
+ "D3", "G7", "F5", "D11", "F0", "B1", "E5", "C13",
+ "B3", "C4", "D15", "G0", "A15", "D7",
+};
+
+static const char *const pic32_output1_3_group[] = {
+ "D3", "G7", "F5", "D11", "F0", "B1", "E5", "C13",
+ "B3", "C4", "D15", "G0", "A15", "D7",
+ "G9", "B14", "D0", "B6", "D5", "B2", "F3", "F13",
+ "C2", "E8", "F2",
+};
+
+static const char * const pic32_output2_group[] = {
+ "D9", "G6", "B8", "B15", "D4", "B0", "E3", "B7",
+ "F12", "D12", "F8", "C3", "E9",
+};
+
+static const char * const pic32_output2_3_group[] = {
+ "D9", "G6", "B8", "B15", "D4", "B0", "E3", "B7",
+ "F12", "D12", "F8", "C3", "E9",
+ "G9", "B14", "D0", "B6", "D5", "B2", "F3", "F13",
+ "C2", "E8", "F2",
+};
+
+static const char * const pic32_output3_group[] = {
+ "G9", "B14", "D0", "B6", "D5", "B2", "F3", "F13",
+ "C2", "E8", "F2",
+};
+
+#define FUNCTION(_name, _gr) \
+ { \
+ .name = #_name, \
+ .groups = pic32_##_gr##_group, \
+ .ngroups = ARRAY_SIZE(pic32_##_gr##_group), \
+ }
+
+static const struct pic32_function pic32_functions[] = {
+ FUNCTION(INT3, input0),
+ FUNCTION(T2CK, input0),
+ FUNCTION(T6CK, input0),
+ FUNCTION(IC3, input0),
+ FUNCTION(IC7, input0),
+ FUNCTION(U1RX, input0),
+ FUNCTION(U2CTS, input0),
+ FUNCTION(U5RX, input0),
+ FUNCTION(U6CTS, input0),
+ FUNCTION(SDI1, input0),
+ FUNCTION(SDI3, input0),
+ FUNCTION(SDI5, input0),
+ FUNCTION(SS6IN, input0),
+ FUNCTION(REFCLKI1, input0),
+ FUNCTION(INT4, input1),
+ FUNCTION(T5CK, input1),
+ FUNCTION(T7CK, input1),
+ FUNCTION(IC4, input1),
+ FUNCTION(IC8, input1),
+ FUNCTION(U3RX, input1),
+ FUNCTION(U4CTS, input1),
+ FUNCTION(SDI2, input1),
+ FUNCTION(SDI4, input1),
+ FUNCTION(C1RX, input1),
+ FUNCTION(REFCLKI4, input1),
+ FUNCTION(INT2, input2),
+ FUNCTION(T3CK, input2),
+ FUNCTION(T8CK, input2),
+ FUNCTION(IC2, input2),
+ FUNCTION(IC5, input2),
+ FUNCTION(IC9, input2),
+ FUNCTION(U1CTS, input2),
+ FUNCTION(U2RX, input2),
+ FUNCTION(U5CTS, input2),
+ FUNCTION(SS1IN, input2),
+ FUNCTION(SS3IN, input2),
+ FUNCTION(SS4IN, input2),
+ FUNCTION(SS5IN, input2),
+ FUNCTION(C2RX, input2),
+ FUNCTION(INT1, input3),
+ FUNCTION(T4CK, input3),
+ FUNCTION(T9CK, input3),
+ FUNCTION(IC1, input3),
+ FUNCTION(IC6, input3),
+ FUNCTION(U3CTS, input3),
+ FUNCTION(U4RX, input3),
+ FUNCTION(U6RX, input3),
+ FUNCTION(SS2IN, input3),
+ FUNCTION(SDI6, input3),
+ FUNCTION(OCFA, input3),
+ FUNCTION(REFCLKI3, input3),
+ FUNCTION(U3TX, output0),
+ FUNCTION(U4RTS, output0),
+ FUNCTION(SDO1, output0_1),
+ FUNCTION(SDO2, output0_1),
+ FUNCTION(SDO3, output0_1),
+ FUNCTION(SDO5, output0_1),
+ FUNCTION(SS6OUT, output0),
+ FUNCTION(OC3, output0),
+ FUNCTION(OC6, output0),
+ FUNCTION(REFCLKO4, output0),
+ FUNCTION(C2OUT, output0),
+ FUNCTION(C1TX, output0),
+ FUNCTION(U1TX, output1),
+ FUNCTION(U2RTS, output1),
+ FUNCTION(U5TX, output1),
+ FUNCTION(U6RTS, output1),
+ FUNCTION(SDO4, output1_3),
+ FUNCTION(OC4, output1),
+ FUNCTION(OC7, output1),
+ FUNCTION(REFCLKO1, output1),
+ FUNCTION(U3RTS, output2),
+ FUNCTION(U4TX, output2),
+ FUNCTION(U6TX, output2_3),
+ FUNCTION(SS1OUT, output2),
+ FUNCTION(SS3OUT, output2),
+ FUNCTION(SS4OUT, output2),
+ FUNCTION(SS5OUT, output2),
+ FUNCTION(SDO6, output2_3),
+ FUNCTION(OC5, output2),
+ FUNCTION(OC8, output2),
+ FUNCTION(C1OUT, output2),
+ FUNCTION(REFCLKO3, output2),
+ FUNCTION(U1RTS, output3),
+ FUNCTION(U2TX, output3),
+ FUNCTION(U5RTS, output3),
+ FUNCTION(SS2OUT, output3),
+ FUNCTION(OC2, output3),
+ FUNCTION(OC1, output3),
+ FUNCTION(OC9, output3),
+ FUNCTION(C2TX, output3),
+};
+
+#define PIC32_PINCTRL_GROUP(_pin, _name, ...) \
+ { \
+ .name = #_name, \
+ .pin = _pin, \
+ .functions = (struct pic32_desc_function[]){ \
+ __VA_ARGS__, { } }, \
+ }
+
+#define PIC32_PINCTRL_FUNCTION(_name, _muxreg, _muxval) \
+ { \
+ .name = #_name, \
+ .muxreg = _muxreg, \
+ .muxval = _muxval, \
+ }
+
+static const struct pic32_pin_group pic32_groups[] = {
+ PIC32_PINCTRL_GROUP(14, A14,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 13),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 13),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 13),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 13),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 13),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 13),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 13),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 13),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 13),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 13),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 13),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 13),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 13),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 13),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPA14R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPA14R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPA14R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPA14R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPA14R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPA14R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPA14R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPA14R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPA14R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPA14R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPA14R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPA14R, 15)),
+ PIC32_PINCTRL_GROUP(15, A15,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 13),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 13),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 13),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 13),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 13),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 13),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 13),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 13),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 13),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 13),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 13),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPA15R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPA15R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPA15R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPA15R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPA15R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPA15R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPA15R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPA15R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPA15R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPA15R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPA15R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPA15R, 15)),
+ PIC32_PINCTRL_GROUP(16, B0,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 5),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 5),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 5),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 5),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 5),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 5),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 5),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 5),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 5),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 5),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 5),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 5),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 5),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 5),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPB0R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPB0R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPB0R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPB0R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPB0R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPB0R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPB0R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPB0R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPB0R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPB0R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPB0R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPB0R, 15)),
+ PIC32_PINCTRL_GROUP(17, B1,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 5),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 5),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 5),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 5),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 5),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 5),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 5),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 5),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 5),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 5),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 5),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPB1R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPB1R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPB1R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPB1R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPB1R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPB1R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPB1R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPB1R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPB1R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPB1R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPB1R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPB1R, 15)),
+ PIC32_PINCTRL_GROUP(18, B2,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 7),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 7),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 7),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 7),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 7),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 7),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 7),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 7),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 7),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 7),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 7),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 7),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPB2R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPB2R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPB2R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPB2R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPB2R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPB2R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPB2R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPB2R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPB2R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPB2R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPB2R, 15)),
+ PIC32_PINCTRL_GROUP(19, B3,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 8),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 8),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 8),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 8),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 8),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 8),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 8),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 8),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 8),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 8),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 8),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPB3R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPB3R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPB3R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPB3R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPB3R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPB3R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPB3R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPB3R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPB3R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPB3R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPB3R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPB3R, 15)),
+ PIC32_PINCTRL_GROUP(21, B5,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 8),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 8),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 8),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 8),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 8),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 8),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 8),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 8),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 8),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 8),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 8),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 8),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 8),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 8),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPB5R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPB5R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPB5R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPB5R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPB5R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPB5R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPB5R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPB5R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPB5R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPB5R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPB5R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPB5R, 15)),
+ PIC32_PINCTRL_GROUP(22, B6,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 4),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 4),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 4),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 4),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 4),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 4),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 4),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 4),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 4),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 4),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 4),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 4),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPB6R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPB6R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPB6R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPB6R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPB6R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPB6R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPB6R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPB6R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPB6R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPB6R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPB6R, 15)),
+ PIC32_PINCTRL_GROUP(23, B7,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 7),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 7),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 7),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 7),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 7),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 7),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 7),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 7),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 7),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 7),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 7),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 7),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 7),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 7),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPB7R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPB7R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPB7R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPB7R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPB7R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPB7R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPB7R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPB7R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPB7R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPB7R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPB7R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPB7R, 15)),
+ PIC32_PINCTRL_GROUP(24, B8,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 2),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 2),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 2),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 2),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 2),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 2),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 2),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 2),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 2),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 2),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 2),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 2),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 2),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 2),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPB8R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPB8R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPB8R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPB8R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPB8R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPB8R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPB8R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPB8R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPB8R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPB8R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPB8R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPB8R, 15)),
+ PIC32_PINCTRL_GROUP(25, B9,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 5),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 5),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 5),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 5),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 5),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 5),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 5),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 5),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 5),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 5),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 5),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 5),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 5),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 5),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPB9R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPB9R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPB9R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPB9R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPB9R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPB9R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPB9R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPB9R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPB9R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPB9R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPB9R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPB9R, 15)),
+ PIC32_PINCTRL_GROUP(26, B10,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 6),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 6),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 6),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 6),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 6),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 6),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 6),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 6),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 6),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 6),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 6),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 6),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 6),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 6),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPB10R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPB10R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPB10R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPB10R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPB10R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPB10R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPB10R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPB10R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPB10R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPB10R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPB10R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPB10R, 15)),
+ PIC32_PINCTRL_GROUP(30, B14,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 2),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 2),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 2),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 2),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 2),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 2),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 2),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 2),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 2),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 2),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 2),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 2),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPB14R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPB14R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPB14R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPB14R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPB14R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPB14R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPB14R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPB14R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPB14R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPB14R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPB14R, 15)),
+ PIC32_PINCTRL_GROUP(31, B15,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 3),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 3),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 3),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 3),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 3),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 3),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 3),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 3),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 3),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 3),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 3),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 3),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 3),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 3),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPB15R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPB15R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPB15R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPB15R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPB15R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPB15R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPB15R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPB15R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPB15R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPB15R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPB15R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPB15R, 15)),
+ PIC32_PINCTRL_GROUP(33, C1,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 10),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 10),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 10),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 10),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 10),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 10),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 10),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 10),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 10),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 10),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 10),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 10),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 10),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 10),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPC1R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPC1R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPC1R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPC1R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPC1R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPC1R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPC1R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPC1R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPC1R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPC1R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPC1R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPC1R, 15)),
+ PIC32_PINCTRL_GROUP(34, C2,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 12),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 12),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 12),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 12),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 12),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 12),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 12),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 12),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 12),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 12),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 12),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPC2R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPC2R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPC2R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPC2R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPC2R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPC2R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPC2R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPC2R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPC2R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPC2R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPC2R, 15)),
+ PIC32_PINCTRL_GROUP(35, C3,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 12),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 12),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 12),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 12),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 12),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 12),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 12),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 12),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 12),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 12),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 12),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 12),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 12),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 12),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPC3R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPC3R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPC3R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPC3R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPC3R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPC3R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPC3R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPC3R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPC3R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPC3R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPC3R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPC3R, 15)),
+ PIC32_PINCTRL_GROUP(36, C4,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 10),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 10),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 10),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 10),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 10),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 10),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 10),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 10),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 10),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 10),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 10),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPC4R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPC4R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPC4R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPC4R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPC4R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPC4R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPC4R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPC4R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPC4R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPC4R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPC4R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPC4R, 15)),
+ PIC32_PINCTRL_GROUP(45, C13,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 7),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 7),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 7),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 7),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 7),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 7),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 7),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 7),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 7),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 7),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 7),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPC13R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPC13R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPC13R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPC13R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPC13R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPC13R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPC13R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPC13R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPC13R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPC13R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPC13R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPC13R, 15)),
+ PIC32_PINCTRL_GROUP(46, C14,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 7),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 7),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 7),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 7),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 7),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 7),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 7),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 7),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 7),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 7),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 7),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 7),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 7),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 7),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPC14R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPC14R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPC14R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPC14R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPC14R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPC14R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPC14R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPC14R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPC14R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPC14R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPC14R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPC14R, 15)),
+ PIC32_PINCTRL_GROUP(48, D0,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 3),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 3),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 3),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 3),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 3),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 3),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 3),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 3),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 3),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 3),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 3),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 3),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPD0R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPD0R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPD0R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPD0R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPD0R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPD0R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPD0R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPD0R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPD0R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPD0R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPD0R, 15)),
+ PIC32_PINCTRL_GROUP(50, D2,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 0),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 0),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 0),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 0),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 0),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 0),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 0),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 0),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 0),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 0),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 0),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 0),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 0),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 0),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPD2R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPD2R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPD2R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPD2R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPD2R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPD2R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPD2R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPD2R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPD2R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPD2R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPD2R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPD2R, 15)),
+ PIC32_PINCTRL_GROUP(51, D3,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 0),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 0),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 0),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 0),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 0),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 0),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 0),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 0),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 0),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 0),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 0),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPD3R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPD3R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPD3R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPD3R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPD3R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPD3R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPD3R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPD3R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPD3R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPD3R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPD3R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPD3R, 15)),
+ PIC32_PINCTRL_GROUP(52, D4,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 4),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 4),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 4),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 4),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 4),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 4),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 4),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 4),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 4),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 4),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 4),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 4),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 4),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 4),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPD4R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPD4R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPD4R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPD4R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPD4R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPD4R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPD4R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPD4R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPD4R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPD4R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPD4R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPD4R, 15)),
+ PIC32_PINCTRL_GROUP(53, D5,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 6),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 6),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 6),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 6),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 6),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 6),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 6),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 6),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 6),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 6),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 6),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 6),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPD5R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPD5R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPD5R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPD5R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPD5R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPD5R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPD5R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPD5R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPD5R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPD5R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPD5R, 15)),
+ PIC32_PINCTRL_GROUP(54, D6,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 14),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 14),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 14),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 14),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 14),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 14),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 14),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 14),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 14),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 14),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 14),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 14),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 14),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPD6R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPD6R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPD6R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPD6R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPD6R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPD6R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPD6R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPD6R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPD6R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPD6R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPD6R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPD6R, 15)),
+ PIC32_PINCTRL_GROUP(55, D7,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 14),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 14),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 14),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 14),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 14),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 14),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 14),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 14),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 14),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 14),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPD7R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPD7R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPD7R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPD7R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPD7R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPD7R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPD7R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPD7R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPD7R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPD7R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPD7R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPD7R, 15)),
+ PIC32_PINCTRL_GROUP(57, D9,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 0),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 0),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 0),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 0),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 0),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 0),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 0),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 0),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 0),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 0),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 0),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 0),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 0),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 0),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPD9R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPD9R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPD9R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPD9R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPD9R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPD9R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPD9R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPD9R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPD9R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPD9R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPD9R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPD9R, 15)),
+ PIC32_PINCTRL_GROUP(58, D10,
+ PIC32_PINCTRL_FUNCTION(U3TX, RPD10R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPD10R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPD10R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPD10R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPD10R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPD10R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPD10R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPD10R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPD10R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPD10R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPD10R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPD10R, 15)),
+ PIC32_PINCTRL_GROUP(59, D11,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 3),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 3),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 3),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 3),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 3),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 3),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 3),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 3),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 3),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 3),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 3),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPD11R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPD11R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPD11R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPD11R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPD11R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPD11R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPD11R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPD11R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPD11R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPD11R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPD11R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPD11R, 15)),
+ PIC32_PINCTRL_GROUP(60, D12,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 10),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 10),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 10),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 10),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 10),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 10),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 10),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 10),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 10),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 10),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 10),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 10),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 10),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 10),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPD12R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPD12R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPD12R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPD12R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPD12R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPD12R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPD12R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPD12R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPD12R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPD12R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPD12R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPD12R, 15)),
+ PIC32_PINCTRL_GROUP(62, D14,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 11),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 11),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 11),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 11),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 11),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 11),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 11),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 11),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 11),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 11),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 11),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 11),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 11),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 11),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPD14R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPD14R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPD14R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPD14R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPD14R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPD14R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPD14R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPD14R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPD14R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPD14R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPD14R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPD14R, 15)),
+ PIC32_PINCTRL_GROUP(63, D15,
+ PIC32_PINCTRL_FUNCTION(U1TX, RPD15R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPD15R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPD15R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPD15R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPD15R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPD15R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPD15R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPD15R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPD15R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPD15R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPD15R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPD15R, 15)),
+ PIC32_PINCTRL_GROUP(67, E3,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 6),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 6),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 6),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 6),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 6),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 6),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 6),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 6),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 6),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 6),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 6),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 6),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 6),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 6),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPE3R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPE3R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPE3R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPE3R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPE3R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPE3R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPE3R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPE3R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPE3R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPE3R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPE3R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPE3R, 15)),
+ PIC32_PINCTRL_GROUP(69, E5,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 6),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 6),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 6),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 6),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 6),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 6),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 6),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 6),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 6),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 6),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 6),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPE5R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPE5R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPE5R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPE5R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPE5R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPE5R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPE5R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPE5R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPE5R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPE5R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPE5R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPE5R, 15)),
+ PIC32_PINCTRL_GROUP(72, E8,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 13),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 13),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 13),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 13),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 13),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 13),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 13),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 13),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 13),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 13),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 13),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 13),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPE8R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPE8R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPE8R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPE8R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPE8R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPE8R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPE8R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPE8R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPE8R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPE8R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPE8R, 15)),
+ PIC32_PINCTRL_GROUP(73, E9,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 13),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 13),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 13),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 13),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 13),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 13),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 13),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 13),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 13),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 13),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 13),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 13),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 13),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 13),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPE9R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPE9R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPE9R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPE9R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPE9R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPE9R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPE9R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPE9R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPE9R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPE9R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPE9R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPE9R, 15)),
+ PIC32_PINCTRL_GROUP(80, F0,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 4),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 4),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 4),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 4),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 4),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 4),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 4),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 4),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 4),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 4),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 4),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPF0R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPF0R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPF0R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPF0R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPF0R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPF0R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPF0R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPF0R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPF0R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPF0R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPF0R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPF0R, 15)),
+ PIC32_PINCTRL_GROUP(81, F1,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 4),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 4),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 4),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 4),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 4),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 4),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 4),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 4),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 4),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 4),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 4),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 4),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 4),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 4),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPF1R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPF1R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPF1R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPF1R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPF1R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPF1R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPF1R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPF1R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPF1R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPF1R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPF1R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPF1R, 15)),
+ PIC32_PINCTRL_GROUP(82, F2,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 11),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 11),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 11),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 11),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 11),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 11),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 11),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 11),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 11),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 11),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 11),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 11),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPF2R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPF2R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPF2R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPF2R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPF2R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPF2R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPF2R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPF2R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPF2R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPF2R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPF2R, 15)),
+ PIC32_PINCTRL_GROUP(83, F3,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 8),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 8),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 8),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 8),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 8),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 8),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 8),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 8),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 8),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 8),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 8),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 8),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPF3R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPF3R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPF3R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPF3R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPF3R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPF3R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPF3R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPF3R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPF3R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPF3R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPF3R, 15)),
+ PIC32_PINCTRL_GROUP(84, F4,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 2),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 2),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 2),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 2),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 2),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 2),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 2),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 2),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 2),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 2),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 2),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 2),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 2),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 2),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPF4R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPF4R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPF4R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPF4R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPF4R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPF4R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPF4R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPF4R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPF4R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPF4R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPF4R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPF4R, 15)),
+ PIC32_PINCTRL_GROUP(85, F5,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 2),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 2),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 2),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 2),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 2),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 2),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 2),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 2),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 2),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 2),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 2),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPF5R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPF5R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPF5R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPF5R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPF5R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPF5R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPF5R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPF5R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPF5R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPF5R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPF5R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPF5R, 15)),
+ PIC32_PINCTRL_GROUP(88, F8,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 11),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 11),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 11),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 11),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 11),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 11),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 11),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 11),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 11),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 11),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 11),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 11),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 11),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 11),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPF8R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPF8R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPF8R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPF8R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPF8R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPF8R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPF8R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPF8R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPF8R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPF8R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPF8R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPF8R, 15)),
+ PIC32_PINCTRL_GROUP(92, F12,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 9),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 9),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 9),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 9),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 9),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 9),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 9),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 9),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 9),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 9),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 9),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 9),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 9),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 9),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPF12R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPF12R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPF12R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPF12R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPF12R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPF12R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPF12R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPF12R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPF12R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPF12R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPF12R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPF12R, 15)),
+ PIC32_PINCTRL_GROUP(93, F13,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 9),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 9),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 9),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 9),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 9),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 9),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 9),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 9),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 9),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 9),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 9),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 9),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPF13R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPF13R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPF13R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPF13R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPF13R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPF13R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPF13R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPF13R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPF13R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPF13R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPF13R, 15)),
+ PIC32_PINCTRL_GROUP(96, G0,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 12),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 12),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 12),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 12),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 12),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 12),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 12),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 12),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 12),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 12),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPG0R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPG0R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPG0R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPG0R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPG0R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPG0R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPG0R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPG0R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPG0R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPG0R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPG0R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPG0R, 15)),
+ PIC32_PINCTRL_GROUP(97, G1,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 12),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 12),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 12),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 12),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 12),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 12),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 12),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 12),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 12),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 12),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 12),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 12),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 12),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPG1R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPG1R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPG1R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPG1R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPG1R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPG1R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPG1R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPG1R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPG1R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPG1R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPG1R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPG1R, 15)),
+ PIC32_PINCTRL_GROUP(102, G6,
+ PIC32_PINCTRL_FUNCTION(INT2, INT2R, 1),
+ PIC32_PINCTRL_FUNCTION(T3CK, T3CKR, 1),
+ PIC32_PINCTRL_FUNCTION(T8CK, T8CKR, 1),
+ PIC32_PINCTRL_FUNCTION(IC2, IC2R, 1),
+ PIC32_PINCTRL_FUNCTION(IC5, IC5R, 1),
+ PIC32_PINCTRL_FUNCTION(IC9, IC9R, 1),
+ PIC32_PINCTRL_FUNCTION(U1CTS, U1CTSR, 1),
+ PIC32_PINCTRL_FUNCTION(U2RX, U2RXR, 1),
+ PIC32_PINCTRL_FUNCTION(U5CTS, U5CTSR, 1),
+ PIC32_PINCTRL_FUNCTION(SS1IN, SS1INR, 1),
+ PIC32_PINCTRL_FUNCTION(SS3IN, SS3INR, 1),
+ PIC32_PINCTRL_FUNCTION(SS4IN, SS4INR, 1),
+ PIC32_PINCTRL_FUNCTION(SS5IN, SS5INR, 1),
+ PIC32_PINCTRL_FUNCTION(C2RX, C2RXR, 1),
+ PIC32_PINCTRL_FUNCTION(U3RTS, RPG6R, 1),
+ PIC32_PINCTRL_FUNCTION(U4TX, RPG6R, 2),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPG6R, 4),
+ PIC32_PINCTRL_FUNCTION(SS1OUT, RPG6R, 5),
+ PIC32_PINCTRL_FUNCTION(SS3OUT, RPG6R, 7),
+ PIC32_PINCTRL_FUNCTION(SS4OUT, RPG6R, 8),
+ PIC32_PINCTRL_FUNCTION(SS5OUT, RPG6R, 9),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPG6R, 10),
+ PIC32_PINCTRL_FUNCTION(OC5, RPG6R, 11),
+ PIC32_PINCTRL_FUNCTION(OC8, RPG6R, 12),
+ PIC32_PINCTRL_FUNCTION(C1OUT, RPG6R, 14),
+ PIC32_PINCTRL_FUNCTION(REFCLKO3, RPG6R, 15)),
+ PIC32_PINCTRL_GROUP(103, G7,
+ PIC32_PINCTRL_FUNCTION(INT4, INT4R, 1),
+ PIC32_PINCTRL_FUNCTION(T5CK, T5CKR, 1),
+ PIC32_PINCTRL_FUNCTION(T7CK, T7CKR, 1),
+ PIC32_PINCTRL_FUNCTION(IC4, IC4R, 1),
+ PIC32_PINCTRL_FUNCTION(IC8, IC8R, 1),
+ PIC32_PINCTRL_FUNCTION(U3RX, U3RXR, 1),
+ PIC32_PINCTRL_FUNCTION(U4CTS, U4CTSR, 1),
+ PIC32_PINCTRL_FUNCTION(SDI2, SDI2R, 1),
+ PIC32_PINCTRL_FUNCTION(SDI4, SDI4R, 1),
+ PIC32_PINCTRL_FUNCTION(C1RX, C1RXR, 1),
+ PIC32_PINCTRL_FUNCTION(REFCLKI4, REFCLKI4R, 1),
+ PIC32_PINCTRL_FUNCTION(U1TX, RPG7R, 1),
+ PIC32_PINCTRL_FUNCTION(U2RTS, RPG7R, 2),
+ PIC32_PINCTRL_FUNCTION(U5TX, RPG7R, 3),
+ PIC32_PINCTRL_FUNCTION(U6RTS, RPG7R, 4),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPG7R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPG7R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPG7R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPG7R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPG7R, 9),
+ PIC32_PINCTRL_FUNCTION(OC4, RPG7R, 11),
+ PIC32_PINCTRL_FUNCTION(OC7, RPG7R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO1, RPG7R, 15)),
+ PIC32_PINCTRL_GROUP(104, G8,
+ PIC32_PINCTRL_FUNCTION(INT3, INT3R, 1),
+ PIC32_PINCTRL_FUNCTION(T2CK, T2CKR, 1),
+ PIC32_PINCTRL_FUNCTION(T6CK, T6CKR, 1),
+ PIC32_PINCTRL_FUNCTION(IC3, IC3R, 1),
+ PIC32_PINCTRL_FUNCTION(IC7, IC7R, 1),
+ PIC32_PINCTRL_FUNCTION(U1RX, U1RXR, 1),
+ PIC32_PINCTRL_FUNCTION(U2CTS, U2CTSR, 1),
+ PIC32_PINCTRL_FUNCTION(U5RX, U5RXR, 1),
+ PIC32_PINCTRL_FUNCTION(U6CTS, U6CTSR, 1),
+ PIC32_PINCTRL_FUNCTION(SDI1, SDI1R, 1),
+ PIC32_PINCTRL_FUNCTION(SDI3, SDI3R, 1),
+ PIC32_PINCTRL_FUNCTION(SDI5, SDI5R, 1),
+ PIC32_PINCTRL_FUNCTION(SS6IN, SS6INR, 1),
+ PIC32_PINCTRL_FUNCTION(REFCLKI1, REFCLKI1R, 1),
+ PIC32_PINCTRL_FUNCTION(U3TX, RPG8R, 1),
+ PIC32_PINCTRL_FUNCTION(U4RTS, RPG8R, 2),
+ PIC32_PINCTRL_FUNCTION(SDO1, RPG8R, 5),
+ PIC32_PINCTRL_FUNCTION(SDO2, RPG8R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO3, RPG8R, 7),
+ PIC32_PINCTRL_FUNCTION(SDO5, RPG8R, 9),
+ PIC32_PINCTRL_FUNCTION(SS6OUT, RPG8R, 10),
+ PIC32_PINCTRL_FUNCTION(OC3, RPG8R, 11),
+ PIC32_PINCTRL_FUNCTION(OC6, RPG8R, 12),
+ PIC32_PINCTRL_FUNCTION(REFCLKO4, RPG8R, 13),
+ PIC32_PINCTRL_FUNCTION(C2OUT, RPG8R, 14),
+ PIC32_PINCTRL_FUNCTION(C1TX, RPG8R, 15)),
+ PIC32_PINCTRL_GROUP(105, G9,
+ PIC32_PINCTRL_FUNCTION(INT1, INT1R, 1),
+ PIC32_PINCTRL_FUNCTION(T4CK, T4CKR, 1),
+ PIC32_PINCTRL_FUNCTION(T9CK, T9CKR, 1),
+ PIC32_PINCTRL_FUNCTION(IC1, IC1R, 1),
+ PIC32_PINCTRL_FUNCTION(IC6, IC6R, 1),
+ PIC32_PINCTRL_FUNCTION(U3CTS, U3CTSR, 1),
+ PIC32_PINCTRL_FUNCTION(U4RX, U4RXR, 1),
+ PIC32_PINCTRL_FUNCTION(U6RX, U6RXR, 1),
+ PIC32_PINCTRL_FUNCTION(SS2IN, SS2INR, 1),
+ PIC32_PINCTRL_FUNCTION(SDI6, SDI6R, 1),
+ PIC32_PINCTRL_FUNCTION(OCFA, OCFAR, 1),
+ PIC32_PINCTRL_FUNCTION(REFCLKI3, REFCLKI3R, 1),
+ PIC32_PINCTRL_FUNCTION(U1RTS, RPG9R, 1),
+ PIC32_PINCTRL_FUNCTION(U2TX, RPG9R, 2),
+ PIC32_PINCTRL_FUNCTION(U5RTS, RPG9R, 3),
+ PIC32_PINCTRL_FUNCTION(U6TX, RPG9R, 4),
+ PIC32_PINCTRL_FUNCTION(SS2OUT, RPG9R, 6),
+ PIC32_PINCTRL_FUNCTION(SDO4, RPG9R, 8),
+ PIC32_PINCTRL_FUNCTION(SDO6, RPG9R, 10),
+ PIC32_PINCTRL_FUNCTION(OC2, RPG9R, 11),
+ PIC32_PINCTRL_FUNCTION(OC1, RPG9R, 12),
+ PIC32_PINCTRL_FUNCTION(OC9, RPG9R, 13),
+ PIC32_PINCTRL_FUNCTION(C2TX, RPG9R, 15)),
+};
+
+static inline struct pic32_gpio_bank *irqd_to_bank(struct irq_data *d)
+{
+ return gpiochip_get_data(irq_data_get_irq_chip_data(d));
+}
+
+static inline struct pic32_gpio_bank *pctl_to_bank(struct pic32_pinctrl *pctl,
+ unsigned pin)
+{
+ return &pctl->gpio_banks[pin / PINS_PER_BANK];
+}
+
+static int pic32_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->ngroups;
+}
+
+static const char *pic32_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->groups[group].name;
+}
+
+static int pic32_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = &pctl->groups[group].pin;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const struct pinctrl_ops pic32_pinctrl_ops = {
+ .get_groups_count = pic32_pinctrl_get_groups_count,
+ .get_group_name = pic32_pinctrl_get_group_name,
+ .get_group_pins = pic32_pinctrl_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static int pic32_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->nfunctions;
+}
+
+static const char *
+pic32_pinmux_get_function_name(struct pinctrl_dev *pctldev, unsigned func)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->functions[func].name;
+}
+
+static int pic32_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned func,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pctl->functions[func].groups;
+ *num_groups = pctl->functions[func].ngroups;
+
+ return 0;
+}
+
+static int pic32_pinmux_enable(struct pinctrl_dev *pctldev,
+ unsigned func, unsigned group)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct pic32_pin_group *pg = &pctl->groups[group];
+ const struct pic32_function *pf = &pctl->functions[func];
+ const char *fname = pf->name;
+ struct pic32_desc_function *functions = pg->functions;
+
+ while (functions->name) {
+ if (!strcmp(functions->name, fname)) {
+ dev_dbg(pctl->dev,
+ "setting function %s reg 0x%x = %d\n",
+ fname, functions->muxreg, functions->muxval);
+
+ writel(functions->muxval, pctl->reg_base + functions->muxreg);
+
+ return 0;
+ }
+
+ functions++;
+ }
+
+ dev_err(pctl->dev, "cannot mux pin %u to function %u\n", group, func);
+
+ return -EINVAL;
+}
+
+static int pic32_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pic32_gpio_bank *bank = gpiochip_get_data(range->gc);
+ u32 mask = BIT(offset - bank->gpio_chip.base);
+
+ dev_dbg(pctl->dev, "requesting gpio %d in bank %d with mask 0x%x\n",
+ offset, bank->gpio_chip.base, mask);
+
+ writel(mask, bank->reg_base + PIC32_CLR(ANSEL_REG));
+
+ return 0;
+}
+
+static int pic32_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct pic32_gpio_bank *bank = gpiochip_get_data(chip);
+ u32 mask = BIT(offset);
+
+ writel(mask, bank->reg_base + PIC32_SET(TRIS_REG));
+
+ return 0;
+}
+
+static int pic32_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct pic32_gpio_bank *bank = gpiochip_get_data(chip);
+
+ return !!(readl(bank->reg_base + PORT_REG) & BIT(offset));
+}
+
+static void pic32_gpio_set(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct pic32_gpio_bank *bank = gpiochip_get_data(chip);
+ u32 mask = BIT(offset);
+
+ if (value)
+ writel(mask, bank->reg_base + PIC32_SET(PORT_REG));
+ else
+ writel(mask, bank->reg_base + PIC32_CLR(PORT_REG));
+}
+
+static int pic32_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct pic32_gpio_bank *bank = gpiochip_get_data(chip);
+ u32 mask = BIT(offset);
+
+ pic32_gpio_set(chip, offset, value);
+ writel(mask, bank->reg_base + PIC32_CLR(TRIS_REG));
+
+ return 0;
+}
+
+static int pic32_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset, bool input)
+{
+ struct gpio_chip *chip = range->gc;
+
+ if (input)
+ pic32_gpio_direction_input(chip, offset);
+ else
+ pic32_gpio_direction_output(chip, offset, 0);
+
+ return 0;
+}
+
+static const struct pinmux_ops pic32_pinmux_ops = {
+ .get_functions_count = pic32_pinmux_get_functions_count,
+ .get_function_name = pic32_pinmux_get_function_name,
+ .get_function_groups = pic32_pinmux_get_function_groups,
+ .set_mux = pic32_pinmux_enable,
+ .gpio_request_enable = pic32_gpio_request_enable,
+ .gpio_set_direction = pic32_gpio_set_direction,
+};
+
+static int pic32_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pic32_gpio_bank *bank = pctl_to_bank(pctl, pin);
+ unsigned param = pinconf_to_config_param(*config);
+ u32 mask = BIT(pin - bank->gpio_chip.base);
+ u32 arg;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ arg = !!(readl(bank->reg_base + CNPU_REG) & mask);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ arg = !!(readl(bank->reg_base + CNPD_REG) & mask);
+ break;
+ case PIN_CONFIG_MICROCHIP_DIGITAL:
+ arg = !(readl(bank->reg_base + ANSEL_REG) & mask);
+ break;
+ case PIN_CONFIG_MICROCHIP_ANALOG:
+ arg = !!(readl(bank->reg_base + ANSEL_REG) & mask);
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ arg = !!(readl(bank->reg_base + ODCU_REG) & mask);
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ arg = !!(readl(bank->reg_base + TRIS_REG) & mask);
+ break;
+ case PIN_CONFIG_OUTPUT:
+ arg = !(readl(bank->reg_base + TRIS_REG) & mask);
+ break;
+ default:
+ dev_err(pctl->dev, "Property %u not supported\n", param);
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+}
+
+static int pic32_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct pic32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pic32_gpio_bank *bank = pctl_to_bank(pctl, pin);
+ unsigned param;
+ u32 arg;
+ unsigned int i;
+ u32 offset = pin - bank->gpio_chip.base;
+ u32 mask = BIT(offset);
+
+ dev_dbg(pctl->dev, "setting pin %d bank %d mask 0x%x\n",
+ pin, bank->gpio_chip.base, mask);
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ dev_dbg(pctl->dev, " pullup\n");
+ writel(mask, bank->reg_base +PIC32_SET(CNPU_REG));
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ dev_dbg(pctl->dev, " pulldown\n");
+ writel(mask, bank->reg_base + PIC32_SET(CNPD_REG));
+ break;
+ case PIN_CONFIG_MICROCHIP_DIGITAL:
+ dev_dbg(pctl->dev, " digital\n");
+ writel(mask, bank->reg_base + PIC32_CLR(ANSEL_REG));
+ break;
+ case PIN_CONFIG_MICROCHIP_ANALOG:
+ dev_dbg(pctl->dev, " analog\n");
+ writel(mask, bank->reg_base + PIC32_SET(ANSEL_REG));
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ dev_dbg(pctl->dev, " opendrain\n");
+ writel(mask, bank->reg_base + PIC32_SET(ODCU_REG));
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ pic32_gpio_direction_input(&bank->gpio_chip, offset);
+ break;
+ case PIN_CONFIG_OUTPUT:
+ pic32_gpio_direction_output(&bank->gpio_chip,
+ offset, arg);
+ break;
+ default:
+ dev_err(pctl->dev, "Property %u not supported\n",
+ param);
+ return -ENOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops pic32_pinconf_ops = {
+ .pin_config_get = pic32_pinconf_get,
+ .pin_config_set = pic32_pinconf_set,
+ .is_generic = true,
+};
+
+static struct pinctrl_desc pic32_pinctrl_desc = {
+ .name = "pic32-pinctrl",
+ .pctlops = &pic32_pinctrl_ops,
+ .pmxops = &pic32_pinmux_ops,
+ .confops = &pic32_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static int pic32_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct pic32_gpio_bank *bank = gpiochip_get_data(chip);
+
+ return !!(readl(bank->reg_base + TRIS_REG) & BIT(offset));
+}
+
+static void pic32_gpio_irq_ack(struct irq_data *data)
+{
+ struct pic32_gpio_bank *bank = irqd_to_bank(data);
+
+ writel(0, bank->reg_base + CNF_REG);
+}
+
+static void pic32_gpio_irq_mask(struct irq_data *data)
+{
+ struct pic32_gpio_bank *bank = irqd_to_bank(data);
+
+ writel(BIT(PIC32_CNCON_ON), bank->reg_base + PIC32_CLR(CNCON_REG));
+}
+
+static void pic32_gpio_irq_unmask(struct irq_data *data)
+{
+ struct pic32_gpio_bank *bank = irqd_to_bank(data);
+
+ writel(BIT(PIC32_CNCON_ON), bank->reg_base + PIC32_SET(CNCON_REG));
+}
+
+static unsigned int pic32_gpio_irq_startup(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+
+ pic32_gpio_direction_input(chip, data->hwirq);
+ pic32_gpio_irq_unmask(data);
+
+ return 0;
+}
+
+static int pic32_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct pic32_gpio_bank *bank = irqd_to_bank(data);
+ u32 mask = BIT(data->hwirq);
+
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_RISING:
+ /* enable RISE */
+ writel(mask, bank->reg_base + PIC32_SET(CNEN_REG));
+ /* disable FALL */
+ writel(mask, bank->reg_base + PIC32_CLR(CNNE_REG));
+ /* enable EDGE */
+ writel(BIT(PIC32_CNCON_EDGE), bank->reg_base + PIC32_SET(CNCON_REG));
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ /* disable RISE */
+ writel(mask, bank->reg_base + PIC32_CLR(CNEN_REG));
+ /* enable FALL */
+ writel(mask, bank->reg_base + PIC32_SET(CNNE_REG));
+ /* enable EDGE */
+ writel(BIT(PIC32_CNCON_EDGE), bank->reg_base + PIC32_SET(CNCON_REG));
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ /* enable RISE */
+ writel(mask, bank->reg_base + PIC32_SET(CNEN_REG));
+ /* enable FALL */
+ writel(mask, bank->reg_base + PIC32_SET(CNNE_REG));
+ /* enable EDGE */
+ writel(BIT(PIC32_CNCON_EDGE), bank->reg_base + PIC32_SET(CNCON_REG));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ irq_set_handler_locked(data, handle_edge_irq);
+
+ return 0;
+}
+
+static u32 pic32_gpio_get_pending(struct gpio_chip *gc, unsigned long status)
+{
+ struct pic32_gpio_bank *bank = gpiochip_get_data(gc);
+ u32 pending = 0;
+ u32 cnen_rise, cnne_fall;
+ u32 pin;
+
+ cnen_rise = readl(bank->reg_base + CNEN_REG);
+ cnne_fall = readl(bank->reg_base + CNNE_REG);
+
+ for_each_set_bit(pin, &status, BITS_PER_LONG) {
+ u32 mask = BIT(pin);
+
+ if ((mask & cnen_rise) || (mask && cnne_fall))
+ pending |= mask;
+ }
+
+ return pending;
+}
+
+static void pic32_gpio_irq_handler(struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct pic32_gpio_bank *bank = gpiochip_get_data(gc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long pending;
+ unsigned int pin;
+ u32 stat;
+
+ chained_irq_enter(chip, desc);
+
+ stat = readl(bank->reg_base + CNF_REG);
+ pending = pic32_gpio_get_pending(gc, stat);
+
+ for_each_set_bit(pin, &pending, BITS_PER_LONG)
+ generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+
+ chained_irq_exit(chip, desc);
+}
+
+#define GPIO_BANK(_bank, _npins) \
+ { \
+ .gpio_chip = { \
+ .label = "GPIO" #_bank, \
+ .request = gpiochip_generic_request, \
+ .free = gpiochip_generic_free, \
+ .get_direction = pic32_gpio_get_direction, \
+ .direction_input = pic32_gpio_direction_input, \
+ .direction_output = pic32_gpio_direction_output, \
+ .get = pic32_gpio_get, \
+ .set = pic32_gpio_set, \
+ .ngpio = _npins, \
+ .base = GPIO_BANK_START(_bank), \
+ .owner = THIS_MODULE, \
+ .can_sleep = 0, \
+ }, \
+ .irq_chip = { \
+ .name = "GPIO" #_bank, \
+ .irq_startup = pic32_gpio_irq_startup, \
+ .irq_ack = pic32_gpio_irq_ack, \
+ .irq_mask = pic32_gpio_irq_mask, \
+ .irq_unmask = pic32_gpio_irq_unmask, \
+ .irq_set_type = pic32_gpio_irq_set_type, \
+ }, \
+ }
+
+static struct pic32_gpio_bank pic32_gpio_banks[] = {
+ GPIO_BANK(0, PINS_PER_BANK),
+ GPIO_BANK(1, PINS_PER_BANK),
+ GPIO_BANK(2, PINS_PER_BANK),
+ GPIO_BANK(3, PINS_PER_BANK),
+ GPIO_BANK(4, PINS_PER_BANK),
+ GPIO_BANK(5, PINS_PER_BANK),
+ GPIO_BANK(6, PINS_PER_BANK),
+ GPIO_BANK(7, PINS_PER_BANK),
+ GPIO_BANK(8, PINS_PER_BANK),
+ GPIO_BANK(9, PINS_PER_BANK),
+};
+
+static int pic32_pinctrl_probe(struct platform_device *pdev)
+{
+ struct pic32_pinctrl *pctl;
+ struct resource *res;
+ int ret;
+
+ pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+ if (!pctl)
+ return -ENOMEM;
+ pctl->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, pctl);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pctl->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pctl->reg_base))
+ return PTR_ERR(pctl->reg_base);
+
+ pctl->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pctl->clk)) {
+ ret = PTR_ERR(pctl->clk);
+ dev_err(&pdev->dev, "clk get failed\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(pctl->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk enable failed\n");
+ return ret;
+ }
+
+ pctl->pins = pic32_pins;
+ pctl->npins = ARRAY_SIZE(pic32_pins);
+ pctl->functions = pic32_functions;
+ pctl->nfunctions = ARRAY_SIZE(pic32_functions);
+ pctl->groups = pic32_groups;
+ pctl->ngroups = ARRAY_SIZE(pic32_groups);
+ pctl->gpio_banks = pic32_gpio_banks;
+ pctl->nbanks = ARRAY_SIZE(pic32_gpio_banks);
+
+ pic32_pinctrl_desc.pins = pctl->pins;
+ pic32_pinctrl_desc.npins = pctl->npins;
+ pic32_pinctrl_desc.custom_params = pic32_mpp_bindings;
+ pic32_pinctrl_desc.num_custom_params = ARRAY_SIZE(pic32_mpp_bindings);
+
+ pctl->pctldev = pinctrl_register(&pic32_pinctrl_desc, &pdev->dev, pctl);
+ if (IS_ERR(pctl->pctldev)) {
+ dev_err(&pdev->dev, "Failed to register pinctrl device\n");
+ return PTR_ERR(pctl->pctldev);
+ }
+
+ return 0;
+}
+
+static int pic32_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct pic32_gpio_bank *bank;
+ u32 id;
+ int irq, ret;
+ struct resource *res;
+
+ if (of_property_read_u32(np, "microchip,gpio-bank", &id)) {
+ dev_err(&pdev->dev, "microchip,gpio-bank property not found\n");
+ return -EINVAL;
+ }
+
+ if (id >= ARRAY_SIZE(pic32_gpio_banks)) {
+ dev_err(&pdev->dev, "invalid microchip,gpio-bank property\n");
+ return -EINVAL;
+ }
+
+ bank = &pic32_gpio_banks[id];
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ bank->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(bank->reg_base))
+ return PTR_ERR(bank->reg_base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "irq get failed\n");
+ return irq;
+ }
+
+ bank->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(bank->clk)) {
+ ret = PTR_ERR(bank->clk);
+ dev_err(&pdev->dev, "clk get failed\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(bank->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk enable failed\n");
+ return ret;
+ }
+
+ bank->gpio_chip.parent = &pdev->dev;
+ bank->gpio_chip.of_node = np;
+ ret = gpiochip_add_data(&bank->gpio_chip, bank);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to add GPIO chip %u: %d\n",
+ id, ret);
+ return ret;
+ }
+
+ ret = gpiochip_irqchip_add(&bank->gpio_chip, &bank->irq_chip,
+ 0, handle_level_irq, IRQ_TYPE_NONE);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to add IRQ chip %u: %d\n",
+ id, ret);
+ gpiochip_remove(&bank->gpio_chip);
+ return ret;
+ }
+
+ gpiochip_set_chained_irqchip(&bank->gpio_chip, &bank->irq_chip,
+ irq, pic32_gpio_irq_handler);
+
+ return 0;
+}
+
+static const struct of_device_id pic32_pinctrl_of_match[] = {
+ { .compatible = "microchip,pic32mzda-pinctrl", },
+ { },
+};
+
+static struct platform_driver pic32_pinctrl_driver = {
+ .driver = {
+ .name = "pic32-pinctrl",
+ .of_match_table = pic32_pinctrl_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = pic32_pinctrl_probe,
+};
+
+static const struct of_device_id pic32_gpio_of_match[] = {
+ { .compatible = "microchip,pic32mzda-gpio", },
+ { },
+};
+
+static struct platform_driver pic32_gpio_driver = {
+ .driver = {
+ .name = "pic32-gpio",
+ .of_match_table = pic32_gpio_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = pic32_gpio_probe,
+};
+
+static int __init pic32_gpio_register(void)
+{
+ return platform_driver_register(&pic32_gpio_driver);
+}
+arch_initcall(pic32_gpio_register);
+
+static int __init pic32_pinctrl_register(void)
+{
+ return platform_driver_register(&pic32_pinctrl_driver);
+}
+arch_initcall(pic32_pinctrl_register);
diff --git a/drivers/pinctrl/pinctrl-pic32.h b/drivers/pinctrl/pinctrl-pic32.h
new file mode 100644
index 000000000000..12826267dc96
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-pic32.h
@@ -0,0 +1,141 @@
+/*
+ * PIC32 pinctrl driver
+ *
+ * Joshua Henderson, <joshua.henderson@microchip.com>
+ * Copyright (C) 2015 Microchip Technology Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 PINCTRL_PINCTRL_PIC32_H
+#define PINCTRL_PINCTRL_PIC32_H
+
+/* PORT Registers */
+#define ANSEL_REG 0x00
+#define TRIS_REG 0x10
+#define PORT_REG 0x20
+#define LAT_REG 0x30
+#define ODCU_REG 0x40
+#define CNPU_REG 0x50
+#define CNPD_REG 0x60
+#define CNCON_REG 0x70
+#define CNEN_REG 0x80
+#define CNSTAT_REG 0x90
+#define CNNE_REG 0xA0
+#define CNF_REG 0xB0
+
+/* Input PPS Registers */
+#define INT1R 0x04
+#define INT2R 0x08
+#define INT3R 0x0C
+#define INT4R 0x10
+#define T2CKR 0x18
+#define T3CKR 0x1C
+#define T4CKR 0x20
+#define T5CKR 0x24
+#define T6CKR 0x28
+#define T7CKR 0x2C
+#define T8CKR 0x30
+#define T9CKR 0x34
+#define IC1R 0x38
+#define IC2R 0x3C
+#define IC3R 0x40
+#define IC4R 0x44
+#define IC5R 0x48
+#define IC6R 0x4C
+#define IC7R 0x50
+#define IC8R 0x54
+#define IC9R 0x58
+#define OCFAR 0x60
+#define U1RXR 0x68
+#define U1CTSR 0x6C
+#define U2RXR 0x70
+#define U2CTSR 0x74
+#define U3RXR 0x78
+#define U3CTSR 0x7C
+#define U4RXR 0x80
+#define U4CTSR 0x84
+#define U5RXR 0x88
+#define U5CTSR 0x8C
+#define U6RXR 0x90
+#define U6CTSR 0x94
+#define SDI1R 0x9C
+#define SS1INR 0xA0
+#define SDI2R 0xA8
+#define SS2INR 0xAC
+#define SDI3R 0xB4
+#define SS3INR 0xB8
+#define SDI4R 0xC0
+#define SS4INR 0xC4
+#define SDI5R 0xCC
+#define SS5INR 0xD0
+#define SDI6R 0xD8
+#define SS6INR 0xDC
+#define C1RXR 0xE0
+#define C2RXR 0xE4
+#define REFCLKI1R 0xE8
+#define REFCLKI3R 0xF0
+#define REFCLKI4R 0xF4
+
+/* Output PPS Registers */
+#define RPA14R 0x138
+#define RPA15R 0x13C
+#define RPB0R 0x140
+#define RPB1R 0x144
+#define RPB2R 0x148
+#define RPB3R 0x14C
+#define RPB5R 0x154
+#define RPB6R 0x158
+#define RPB7R 0x15C
+#define RPB8R 0x160
+#define RPB9R 0x164
+#define RPB10R 0x168
+#define RPB14R 0x178
+#define RPB15R 0x17C
+#define RPC1R 0x184
+#define RPC2R 0x188
+#define RPC3R 0x18C
+#define RPC4R 0x190
+#define RPC13R 0x1B4
+#define RPC14R 0x1B8
+#define RPD0R 0x1C0
+#define RPD1R 0x1C4
+#define RPD2R 0x1C8
+#define RPD3R 0x1CC
+#define RPD4R 0x1D0
+#define RPD5R 0x1D4
+#define RPD6R 0x1D8
+#define RPD7R 0x1DC
+#define RPD9R 0x1E4
+#define RPD10R 0x1E8
+#define RPD11R 0x1EC
+#define RPD12R 0x1F0
+#define RPD14R 0x1F8
+#define RPD15R 0x1FC
+#define RPE3R 0x20C
+#define RPE5R 0x214
+#define RPE8R 0x220
+#define RPE9R 0x224
+#define RPF0R 0x240
+#define RPF1R 0x244
+#define RPF2R 0x248
+#define RPF3R 0x24C
+#define RPF4R 0x250
+#define RPF5R 0x254
+#define RPF8R 0x260
+#define RPF12R 0x270
+#define RPF13R 0x274
+#define RPG0R 0x280
+#define RPG1R 0x284
+#define RPG6R 0x298
+#define RPG7R 0x29C
+#define RPG8R 0x2A0
+#define RPG9R 0x2A4
+
+#endif /* PINCTRL_PINCTRL_PIC32_H */
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 183545a068ad..bf032b9b4c57 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -64,6 +64,7 @@ enum rockchip_pinctrl_type {
RK3188,
RK3288,
RK3368,
+ RK3399,
};
/**
@@ -86,6 +87,31 @@ struct rockchip_iomux {
};
/**
+ * enum type index corresponding to rockchip_perpin_drv_list arrays index.
+ */
+enum rockchip_pin_drv_type {
+ DRV_TYPE_IO_DEFAULT = 0,
+ DRV_TYPE_IO_1V8_OR_3V0,
+ DRV_TYPE_IO_1V8_ONLY,
+ DRV_TYPE_IO_1V8_3V0_AUTO,
+ DRV_TYPE_IO_3V3_ONLY,
+ DRV_TYPE_MAX
+};
+
+/**
+ * @drv_type: drive strength variant using rockchip_perpin_drv_type
+ * @offset: if initialized to -1 it will be autocalculated, by specifying
+ * an initial offset value the relevant source offset can be reset
+ * to a new value for autocalculating the following drive strength
+ * registers. if used chips own cal_drv func instead to calculate
+ * registers offset, the variant could be ignored.
+ */
+struct rockchip_drv {
+ enum rockchip_pin_drv_type drv_type;
+ int offset;
+};
+
+/**
* @reg_base: register base of the gpio bank
* @reg_pull: optional separate register for additional pull settings
* @clk: clock of the gpio bank
@@ -96,6 +122,7 @@ struct rockchip_iomux {
* @name: name of the bank
* @bank_num: number of the bank, to account for holes
* @iomux: array describing the 4 iomux sources of the bank
+ * @drv: array describing the 4 drive strength sources of the bank
* @valid: are all necessary informations present
* @of_node: dt node of this bank
* @drvdata: common pinctrl basedata
@@ -115,6 +142,7 @@ struct rockchip_pin_bank {
char *name;
u8 bank_num;
struct rockchip_iomux iomux[4];
+ struct rockchip_drv drv[4];
bool valid;
struct device_node *of_node;
struct rockchip_pinctrl *drvdata;
@@ -151,6 +179,47 @@ struct rockchip_pin_bank {
}, \
}
+#define PIN_BANK_DRV_FLAGS(id, pins, label, type0, type1, type2, type3) \
+ { \
+ .bank_num = id, \
+ .nr_pins = pins, \
+ .name = label, \
+ .iomux = { \
+ { .offset = -1 }, \
+ { .offset = -1 }, \
+ { .offset = -1 }, \
+ { .offset = -1 }, \
+ }, \
+ .drv = { \
+ { .drv_type = type0, .offset = -1 }, \
+ { .drv_type = type1, .offset = -1 }, \
+ { .drv_type = type2, .offset = -1 }, \
+ { .drv_type = type3, .offset = -1 }, \
+ }, \
+ }
+
+#define PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(id, pins, label, iom0, iom1, \
+ iom2, iom3, drv0, drv1, drv2, \
+ drv3, offset0, offset1, \
+ offset2, offset3) \
+ { \
+ .bank_num = id, \
+ .nr_pins = pins, \
+ .name = label, \
+ .iomux = { \
+ { .type = iom0, .offset = -1 }, \
+ { .type = iom1, .offset = -1 }, \
+ { .type = iom2, .offset = -1 }, \
+ { .type = iom3, .offset = -1 }, \
+ }, \
+ .drv = { \
+ { .drv_type = drv0, .offset = offset0 }, \
+ { .drv_type = drv1, .offset = offset1 }, \
+ { .drv_type = drv2, .offset = offset2 }, \
+ { .drv_type = drv3, .offset = offset3 }, \
+ }, \
+ }
+
/**
*/
struct rockchip_pin_ctrl {
@@ -161,6 +230,9 @@ struct rockchip_pin_ctrl {
enum rockchip_pinctrl_type type;
int grf_mux_offset;
int pmu_mux_offset;
+ int grf_drv_offset;
+ int pmu_drv_offset;
+
void (*pull_calc_reg)(struct rockchip_pin_bank *bank,
int pin_num, struct regmap **regmap,
int *reg, u8 *bit);
@@ -705,7 +777,68 @@ static void rk3368_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
}
}
-static int rockchip_perpin_drv_list[] = { 2, 4, 8, 12 };
+#define RK3399_PULL_GRF_OFFSET 0xe040
+#define RK3399_PULL_PMU_OFFSET 0x40
+#define RK3399_DRV_3BITS_PER_PIN 3
+
+static void rk3399_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl *info = bank->drvdata;
+
+ /* The bank0:16 and bank1:32 pins are located in PMU */
+ if ((bank->bank_num == 0) || (bank->bank_num == 1)) {
+ *regmap = info->regmap_pmu;
+ *reg = RK3399_PULL_PMU_OFFSET;
+
+ *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
+
+ *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
+ *bit = pin_num % RK3188_PULL_PINS_PER_REG;
+ *bit *= RK3188_PULL_BITS_PER_PIN;
+ } else {
+ *regmap = info->regmap_base;
+ *reg = RK3399_PULL_GRF_OFFSET;
+
+ /* correct the offset, as we're starting with the 3rd bank */
+ *reg -= 0x20;
+ *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
+ *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
+
+ *bit = (pin_num % RK3188_PULL_PINS_PER_REG);
+ *bit *= RK3188_PULL_BITS_PER_PIN;
+ }
+}
+
+static void rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl *info = bank->drvdata;
+ int drv_num = (pin_num / 8);
+
+ /* The bank0:16 and bank1:32 pins are located in PMU */
+ if ((bank->bank_num == 0) || (bank->bank_num == 1))
+ *regmap = info->regmap_pmu;
+ else
+ *regmap = info->regmap_base;
+
+ *reg = bank->drv[drv_num].offset;
+ if ((bank->drv[drv_num].drv_type == DRV_TYPE_IO_1V8_3V0_AUTO) ||
+ (bank->drv[drv_num].drv_type == DRV_TYPE_IO_3V3_ONLY))
+ *bit = (pin_num % 8) * 3;
+ else
+ *bit = (pin_num % 8) * 2;
+}
+
+static int rockchip_perpin_drv_list[DRV_TYPE_MAX][8] = {
+ { 2, 4, 8, 12, -1, -1, -1, -1 },
+ { 3, 6, 9, 12, -1, -1, -1, -1 },
+ { 5, 10, 15, 20, -1, -1, -1, -1 },
+ { 4, 6, 8, 10, 12, 14, 16, 18 },
+ { 4, 7, 10, 13, 16, 19, 22, 26 }
+};
static int rockchip_get_drive_perpin(struct rockchip_pin_bank *bank,
int pin_num)
@@ -714,19 +847,74 @@ static int rockchip_get_drive_perpin(struct rockchip_pin_bank *bank,
struct rockchip_pin_ctrl *ctrl = info->ctrl;
struct regmap *regmap;
int reg, ret;
- u32 data;
+ u32 data, temp, rmask_bits;
u8 bit;
+ int drv_type = bank->drv[pin_num / 8].drv_type;
ctrl->drv_calc_reg(bank, pin_num, &regmap, &reg, &bit);
+ switch (drv_type) {
+ case DRV_TYPE_IO_1V8_3V0_AUTO:
+ case DRV_TYPE_IO_3V3_ONLY:
+ rmask_bits = RK3399_DRV_3BITS_PER_PIN;
+ switch (bit) {
+ case 0 ... 12:
+ /* regular case, nothing to do */
+ break;
+ case 15:
+ /*
+ * drive-strength offset is special, as it is
+ * spread over 2 registers
+ */
+ ret = regmap_read(regmap, reg, &data);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(regmap, reg + 0x4, &temp);
+ if (ret)
+ return ret;
+
+ /*
+ * the bit data[15] contains bit 0 of the value
+ * while temp[1:0] contains bits 2 and 1
+ */
+ data >>= 15;
+ temp &= 0x3;
+ temp <<= 1;
+ data |= temp;
+
+ return rockchip_perpin_drv_list[drv_type][data];
+ case 18 ... 21:
+ /* setting fully enclosed in the second register */
+ reg += 4;
+ bit -= 16;
+ break;
+ default:
+ dev_err(info->dev, "unsupported bit: %d for pinctrl drive type: %d\n",
+ bit, drv_type);
+ return -EINVAL;
+ }
+
+ break;
+ case DRV_TYPE_IO_DEFAULT:
+ case DRV_TYPE_IO_1V8_OR_3V0:
+ case DRV_TYPE_IO_1V8_ONLY:
+ rmask_bits = RK3288_DRV_BITS_PER_PIN;
+ break;
+ default:
+ dev_err(info->dev, "unsupported pinctrl drive type: %d\n",
+ drv_type);
+ return -EINVAL;
+ }
+
ret = regmap_read(regmap, reg, &data);
if (ret)
return ret;
data >>= bit;
- data &= (1 << RK3288_DRV_BITS_PER_PIN) - 1;
+ data &= (1 << rmask_bits) - 1;
- return rockchip_perpin_drv_list[data];
+ return rockchip_perpin_drv_list[drv_type][data];
}
static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
@@ -737,16 +925,23 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
struct regmap *regmap;
unsigned long flags;
int reg, ret, i;
- u32 data, rmask;
+ u32 data, rmask, rmask_bits, temp;
u8 bit;
+ int drv_type = bank->drv[pin_num / 8].drv_type;
+
+ dev_dbg(info->dev, "setting drive of GPIO%d-%d to %d\n",
+ bank->bank_num, pin_num, strength);
ctrl->drv_calc_reg(bank, pin_num, &regmap, &reg, &bit);
ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(rockchip_perpin_drv_list); i++) {
- if (rockchip_perpin_drv_list[i] == strength) {
+ for (i = 0; i < ARRAY_SIZE(rockchip_perpin_drv_list[drv_type]); i++) {
+ if (rockchip_perpin_drv_list[drv_type][i] == strength) {
ret = i;
break;
+ } else if (rockchip_perpin_drv_list[drv_type][i] < 0) {
+ ret = rockchip_perpin_drv_list[drv_type][i];
+ break;
}
}
@@ -758,8 +953,64 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
spin_lock_irqsave(&bank->slock, flags);
+ switch (drv_type) {
+ case DRV_TYPE_IO_1V8_3V0_AUTO:
+ case DRV_TYPE_IO_3V3_ONLY:
+ rmask_bits = RK3399_DRV_3BITS_PER_PIN;
+ switch (bit) {
+ case 0 ... 12:
+ /* regular case, nothing to do */
+ break;
+ case 15:
+ /*
+ * drive-strength offset is special, as it is spread
+ * over 2 registers, the bit data[15] contains bit 0
+ * of the value while temp[1:0] contains bits 2 and 1
+ */
+ data = (ret & 0x1) << 15;
+ temp = (ret >> 0x1) & 0x3;
+
+ rmask = BIT(15) | BIT(31);
+ data |= BIT(31);
+ ret = regmap_update_bits(regmap, reg, rmask, data);
+ if (ret) {
+ spin_unlock_irqrestore(&bank->slock, flags);
+ return ret;
+ }
+
+ rmask = 0x3 | (0x3 << 16);
+ temp |= (0x3 << 16);
+ reg += 0x4;
+ ret = regmap_update_bits(regmap, reg, rmask, temp);
+
+ spin_unlock_irqrestore(&bank->slock, flags);
+ return ret;
+ case 18 ... 21:
+ /* setting fully enclosed in the second register */
+ reg += 4;
+ bit -= 16;
+ break;
+ default:
+ spin_unlock_irqrestore(&bank->slock, flags);
+ dev_err(info->dev, "unsupported bit: %d for pinctrl drive type: %d\n",
+ bit, drv_type);
+ return -EINVAL;
+ }
+ break;
+ case DRV_TYPE_IO_DEFAULT:
+ case DRV_TYPE_IO_1V8_OR_3V0:
+ case DRV_TYPE_IO_1V8_ONLY:
+ rmask_bits = RK3288_DRV_BITS_PER_PIN;
+ break;
+ default:
+ spin_unlock_irqrestore(&bank->slock, flags);
+ dev_err(info->dev, "unsupported pinctrl drive type: %d\n",
+ drv_type);
+ return -EINVAL;
+ }
+
/* enable the write to the equivalent lower bits */
- data = ((1 << RK3288_DRV_BITS_PER_PIN) - 1) << (bit + 16);
+ data = ((1 << rmask_bits) - 1) << (bit + 16);
rmask = data | (data >> 16);
data |= (ret << bit);
@@ -796,6 +1047,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
case RK3188:
case RK3288:
case RK3368:
+ case RK3399:
data >>= bit;
data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1;
@@ -852,6 +1104,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
case RK3188:
case RK3288:
case RK3368:
+ case RK3399:
spin_lock_irqsave(&bank->slock, flags);
/* enable the write to the equivalent lower bits */
@@ -1032,6 +1285,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
case RK3188:
case RK3288:
case RK3368:
+ case RK3399:
return (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT);
}
@@ -1892,7 +2146,7 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
struct device_node *np;
struct rockchip_pin_ctrl *ctrl;
struct rockchip_pin_bank *bank;
- int grf_offs, pmu_offs, i, j;
+ int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j;
match = of_match_node(rockchip_pinctrl_dt_match, node);
ctrl = (struct rockchip_pin_ctrl *)match->data;
@@ -1916,6 +2170,8 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
grf_offs = ctrl->grf_mux_offset;
pmu_offs = ctrl->pmu_mux_offset;
+ drv_pmu_offs = ctrl->pmu_drv_offset;
+ drv_grf_offs = ctrl->grf_drv_offset;
bank = ctrl->pin_banks;
for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
int bank_pins = 0;
@@ -1925,27 +2181,39 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
bank->pin_base = ctrl->nr_pins;
ctrl->nr_pins += bank->nr_pins;
- /* calculate iomux offsets */
+ /* calculate iomux and drv offsets */
for (j = 0; j < 4; j++) {
struct rockchip_iomux *iom = &bank->iomux[j];
+ struct rockchip_drv *drv = &bank->drv[j];
int inc;
if (bank_pins >= bank->nr_pins)
break;
- /* preset offset value, set new start value */
+ /* preset iomux offset value, set new start value */
if (iom->offset >= 0) {
if (iom->type & IOMUX_SOURCE_PMU)
pmu_offs = iom->offset;
else
grf_offs = iom->offset;
- } else { /* set current offset */
+ } else { /* set current iomux offset */
iom->offset = (iom->type & IOMUX_SOURCE_PMU) ?
pmu_offs : grf_offs;
}
- dev_dbg(d->dev, "bank %d, iomux %d has offset 0x%x\n",
- i, j, iom->offset);
+ /* preset drv offset value, set new start value */
+ if (drv->offset >= 0) {
+ if (iom->type & IOMUX_SOURCE_PMU)
+ drv_pmu_offs = drv->offset;
+ else
+ drv_grf_offs = drv->offset;
+ } else { /* set current drv offset */
+ drv->offset = (iom->type & IOMUX_SOURCE_PMU) ?
+ drv_pmu_offs : drv_grf_offs;
+ }
+
+ dev_dbg(d->dev, "bank %d, iomux %d has iom_offset 0x%x drv_offset 0x%x\n",
+ i, j, iom->offset, drv->offset);
/*
* Increase offset according to iomux width.
@@ -1957,6 +2225,21 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
else
grf_offs += inc;
+ /*
+ * Increase offset according to drv width.
+ * 3bit drive-strenth'es are spread over two registers.
+ */
+ if ((drv->drv_type == DRV_TYPE_IO_1V8_3V0_AUTO) ||
+ (drv->drv_type == DRV_TYPE_IO_3V3_ONLY))
+ inc = 8;
+ else
+ inc = 4;
+
+ if (iom->type & IOMUX_SOURCE_PMU)
+ drv_pmu_offs += inc;
+ else
+ drv_grf_offs += inc;
+
bank_pins += 8;
}
}
@@ -2257,6 +2540,62 @@ static struct rockchip_pin_ctrl rk3368_pin_ctrl = {
.drv_calc_reg = rk3368_calc_drv_reg_and_bit,
};
+static struct rockchip_pin_bank rk3399_pin_banks[] = {
+ PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(0, 32, "gpio0", IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ DRV_TYPE_IO_1V8_ONLY,
+ DRV_TYPE_IO_1V8_ONLY,
+ DRV_TYPE_IO_DEFAULT,
+ DRV_TYPE_IO_DEFAULT,
+ 0x0,
+ 0x8,
+ -1,
+ -1
+ ),
+ PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(1, 32, "gpio1", IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ DRV_TYPE_IO_1V8_OR_3V0,
+ DRV_TYPE_IO_1V8_OR_3V0,
+ DRV_TYPE_IO_1V8_OR_3V0,
+ DRV_TYPE_IO_1V8_OR_3V0,
+ 0x20,
+ 0x28,
+ 0x30,
+ 0x38
+ ),
+ PIN_BANK_DRV_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
+ DRV_TYPE_IO_1V8_OR_3V0,
+ DRV_TYPE_IO_1V8_ONLY,
+ DRV_TYPE_IO_1V8_ONLY
+ ),
+ PIN_BANK_DRV_FLAGS(3, 32, "gpio3", DRV_TYPE_IO_3V3_ONLY,
+ DRV_TYPE_IO_3V3_ONLY,
+ DRV_TYPE_IO_3V3_ONLY,
+ DRV_TYPE_IO_1V8_OR_3V0
+ ),
+ PIN_BANK_DRV_FLAGS(4, 32, "gpio4", DRV_TYPE_IO_1V8_OR_3V0,
+ DRV_TYPE_IO_1V8_3V0_AUTO,
+ DRV_TYPE_IO_1V8_OR_3V0,
+ DRV_TYPE_IO_1V8_OR_3V0
+ ),
+};
+
+static struct rockchip_pin_ctrl rk3399_pin_ctrl = {
+ .pin_banks = rk3399_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3399_pin_banks),
+ .label = "RK3399-GPIO",
+ .type = RK3399,
+ .grf_mux_offset = 0xe000,
+ .pmu_mux_offset = 0x0,
+ .grf_drv_offset = 0xe100,
+ .pmu_drv_offset = 0x80,
+ .pull_calc_reg = rk3399_calc_pull_reg_and_bit,
+ .drv_calc_reg = rk3399_calc_drv_reg_and_bit,
+};
static const struct of_device_id rockchip_pinctrl_dt_match[] = {
{ .compatible = "rockchip,rk2928-pinctrl",
@@ -2275,6 +2614,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
.data = (void *)&rk3288_pin_ctrl },
{ .compatible = "rockchip,rk3368-pinctrl",
.data = (void *)&rk3368_pin_ctrl },
+ { .compatible = "rockchip,rk3399-pinctrl",
+ .data = (void *)&rk3399_pin_ctrl },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_pinctrl_dt_match);
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index d24e5f1d1525..fb126d56ad40 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -255,6 +255,13 @@ static enum pin_config_param pcs_bias[] = {
};
/*
+ * This lock class tells lockdep that irqchip core that this single
+ * pinctrl can be in a different category than its parents, so it won't
+ * report false recursion.
+ */
+static struct lock_class_key pcs_lock_class;
+
+/*
* REVISIT: Reads and writes could eventually use regmap or something
* generic. But at least on omaps, some mux registers are performance
* critical as they may need to be remuxed every time before and after
@@ -1713,6 +1720,7 @@ static int pcs_irqdomain_map(struct irq_domain *d, unsigned int irq,
irq_set_chip_data(irq, pcs_soc);
irq_set_chip_and_handler(irq, &pcs->chip,
handle_level_irq);
+ irq_set_lockdep_class(irq, &pcs_lock_class);
irq_set_noprobe(irq);
return 0;
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index fac844a85cb4..cab66c64149f 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -985,6 +985,7 @@ static struct pinmux_ops st_pmxops = {
.get_function_groups = st_pmx_get_groups,
.set_mux = st_pmx_set_mux,
.gpio_set_direction = st_pmx_set_gpio_direction,
+ .strict = true,
};
/* Pinconf */
diff --git a/drivers/pinctrl/pinctrl-zynq.c b/drivers/pinctrl/pinctrl-zynq.c
index d57b5eca7b98..76f1abd71e31 100644
--- a/drivers/pinctrl/pinctrl-zynq.c
+++ b/drivers/pinctrl/pinctrl-zynq.c
@@ -590,7 +590,7 @@ static const char * const usb1_groups[] = {"usb1_0_grp"};
static const char * const mdio0_groups[] = {"mdio0_0_grp"};
static const char * const mdio1_groups[] = {"mdio1_0_grp"};
static const char * const qspi0_groups[] = {"qspi0_0_grp"};
-static const char * const qspi1_groups[] = {"qspi0_1_grp"};
+static const char * const qspi1_groups[] = {"qspi1_0_grp"};
static const char * const qspi_fbclk_groups[] = {"qspi_fbclk_grp"};
static const char * const qspi_cs1_groups[] = {"qspi_cs1_grp"};
static const char * const spi0_groups[] = {"spi0_0_grp", "spi0_1_grp",
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
index d90e205cf809..f553313bc2ef 100644
--- a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
+++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
@@ -426,6 +426,7 @@ int pxa2xx_pinctrl_init(struct platform_device *pdev,
return 0;
}
+EXPORT_SYMBOL_GPL(pxa2xx_pinctrl_init);
int pxa2xx_pinctrl_exit(struct platform_device *pdev)
{
@@ -434,3 +435,4 @@ int pxa2xx_pinctrl_exit(struct platform_device *pdev)
pinctrl_unregister(pctl->pctl_dev);
return 0;
}
+EXPORT_SYMBOL_GPL(pxa2xx_pinctrl_exit);
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index eeac8cba8a21..67bc70dcda64 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -23,6 +23,14 @@ config PINCTRL_APQ8084
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block found in the Qualcomm APQ8084 platform.
+config PINCTRL_IPQ4019
+ tristate "Qualcomm IPQ4019 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm TLMM block found in the Qualcomm IPQ4019 platform.
+
config PINCTRL_IPQ8064
tristate "Qualcomm IPQ8064 pin controller driver"
depends on GPIOLIB && OF
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index dfb50a9fe04a..c964a2c4b90a 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_PINCTRL_MSM) += pinctrl-msm.o
obj-$(CONFIG_PINCTRL_APQ8064) += pinctrl-apq8064.o
obj-$(CONFIG_PINCTRL_APQ8084) += pinctrl-apq8084.o
+obj-$(CONFIG_PINCTRL_IPQ4019) += pinctrl-ipq4019.o
obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o
obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o
obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
new file mode 100644
index 000000000000..b5d81ced6ce6
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+static const struct pinctrl_pin_desc ipq4019_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+};
+
+#define DECLARE_QCA_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_QCA_GPIO_PINS(0);
+DECLARE_QCA_GPIO_PINS(1);
+DECLARE_QCA_GPIO_PINS(2);
+DECLARE_QCA_GPIO_PINS(3);
+DECLARE_QCA_GPIO_PINS(4);
+DECLARE_QCA_GPIO_PINS(5);
+DECLARE_QCA_GPIO_PINS(6);
+DECLARE_QCA_GPIO_PINS(7);
+DECLARE_QCA_GPIO_PINS(8);
+DECLARE_QCA_GPIO_PINS(9);
+DECLARE_QCA_GPIO_PINS(10);
+DECLARE_QCA_GPIO_PINS(11);
+DECLARE_QCA_GPIO_PINS(12);
+DECLARE_QCA_GPIO_PINS(13);
+DECLARE_QCA_GPIO_PINS(14);
+DECLARE_QCA_GPIO_PINS(15);
+DECLARE_QCA_GPIO_PINS(16);
+DECLARE_QCA_GPIO_PINS(17);
+DECLARE_QCA_GPIO_PINS(18);
+DECLARE_QCA_GPIO_PINS(19);
+DECLARE_QCA_GPIO_PINS(20);
+DECLARE_QCA_GPIO_PINS(21);
+DECLARE_QCA_GPIO_PINS(22);
+DECLARE_QCA_GPIO_PINS(23);
+DECLARE_QCA_GPIO_PINS(24);
+DECLARE_QCA_GPIO_PINS(25);
+DECLARE_QCA_GPIO_PINS(26);
+DECLARE_QCA_GPIO_PINS(27);
+DECLARE_QCA_GPIO_PINS(28);
+DECLARE_QCA_GPIO_PINS(29);
+DECLARE_QCA_GPIO_PINS(30);
+DECLARE_QCA_GPIO_PINS(31);
+DECLARE_QCA_GPIO_PINS(32);
+DECLARE_QCA_GPIO_PINS(33);
+DECLARE_QCA_GPIO_PINS(34);
+DECLARE_QCA_GPIO_PINS(35);
+DECLARE_QCA_GPIO_PINS(36);
+DECLARE_QCA_GPIO_PINS(37);
+DECLARE_QCA_GPIO_PINS(38);
+DECLARE_QCA_GPIO_PINS(39);
+DECLARE_QCA_GPIO_PINS(40);
+DECLARE_QCA_GPIO_PINS(41);
+DECLARE_QCA_GPIO_PINS(42);
+DECLARE_QCA_GPIO_PINS(43);
+DECLARE_QCA_GPIO_PINS(44);
+DECLARE_QCA_GPIO_PINS(45);
+DECLARE_QCA_GPIO_PINS(46);
+DECLARE_QCA_GPIO_PINS(47);
+DECLARE_QCA_GPIO_PINS(48);
+DECLARE_QCA_GPIO_PINS(49);
+DECLARE_QCA_GPIO_PINS(50);
+DECLARE_QCA_GPIO_PINS(51);
+DECLARE_QCA_GPIO_PINS(52);
+DECLARE_QCA_GPIO_PINS(53);
+DECLARE_QCA_GPIO_PINS(54);
+DECLARE_QCA_GPIO_PINS(55);
+DECLARE_QCA_GPIO_PINS(56);
+DECLARE_QCA_GPIO_PINS(57);
+DECLARE_QCA_GPIO_PINS(58);
+DECLARE_QCA_GPIO_PINS(59);
+DECLARE_QCA_GPIO_PINS(60);
+DECLARE_QCA_GPIO_PINS(61);
+DECLARE_QCA_GPIO_PINS(62);
+DECLARE_QCA_GPIO_PINS(63);
+DECLARE_QCA_GPIO_PINS(64);
+DECLARE_QCA_GPIO_PINS(65);
+DECLARE_QCA_GPIO_PINS(66);
+DECLARE_QCA_GPIO_PINS(67);
+DECLARE_QCA_GPIO_PINS(68);
+DECLARE_QCA_GPIO_PINS(69);
+DECLARE_QCA_GPIO_PINS(70);
+DECLARE_QCA_GPIO_PINS(71);
+DECLARE_QCA_GPIO_PINS(72);
+DECLARE_QCA_GPIO_PINS(73);
+DECLARE_QCA_GPIO_PINS(74);
+DECLARE_QCA_GPIO_PINS(75);
+DECLARE_QCA_GPIO_PINS(76);
+DECLARE_QCA_GPIO_PINS(77);
+DECLARE_QCA_GPIO_PINS(78);
+DECLARE_QCA_GPIO_PINS(79);
+DECLARE_QCA_GPIO_PINS(80);
+DECLARE_QCA_GPIO_PINS(81);
+DECLARE_QCA_GPIO_PINS(82);
+DECLARE_QCA_GPIO_PINS(83);
+DECLARE_QCA_GPIO_PINS(84);
+DECLARE_QCA_GPIO_PINS(85);
+DECLARE_QCA_GPIO_PINS(86);
+DECLARE_QCA_GPIO_PINS(87);
+DECLARE_QCA_GPIO_PINS(88);
+DECLARE_QCA_GPIO_PINS(89);
+DECLARE_QCA_GPIO_PINS(90);
+DECLARE_QCA_GPIO_PINS(91);
+DECLARE_QCA_GPIO_PINS(92);
+DECLARE_QCA_GPIO_PINS(93);
+DECLARE_QCA_GPIO_PINS(94);
+DECLARE_QCA_GPIO_PINS(95);
+DECLARE_QCA_GPIO_PINS(96);
+DECLARE_QCA_GPIO_PINS(97);
+DECLARE_QCA_GPIO_PINS(98);
+DECLARE_QCA_GPIO_PINS(99);
+
+#define FUNCTION(fname) \
+ [qca_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ qca_mux_NA, /* gpio mode */ \
+ qca_mux_##f1, \
+ qca_mux_##f2, \
+ qca_mux_##f3, \
+ qca_mux_##f4, \
+ qca_mux_##f5, \
+ qca_mux_##f6, \
+ qca_mux_##f7, \
+ qca_mux_##f8, \
+ qca_mux_##f9, \
+ qca_mux_##f10, \
+ qca_mux_##f11, \
+ qca_mux_##f12, \
+ qca_mux_##f13, \
+ qca_mux_##f14 \
+ }, \
+ .nfuncs = 15, \
+ .ctl_reg = 0x1000 + 0x10 * id, \
+ .io_reg = 0x1004 + 0x10 * id, \
+ .intr_cfg_reg = 0x1008 + 0x10 * id, \
+ .intr_status_reg = 0x100c + 0x10 * id, \
+ .intr_target_reg = 0x400 + 0x4 * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+
+enum ipq4019_functions {
+ qca_mux_gpio,
+ qca_mux_blsp_uart1,
+ qca_mux_blsp_i2c0,
+ qca_mux_blsp_i2c1,
+ qca_mux_blsp_uart0,
+ qca_mux_blsp_spi1,
+ qca_mux_blsp_spi0,
+ qca_mux_NA,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99",
+};
+
+static const char * const blsp_uart1_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const blsp_i2c0_groups[] = {
+ "gpio10", "gpio11", "gpio20", "gpio21", "gpio58", "gpio59",
+};
+static const char * const blsp_spi0_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15", "gpio45",
+ "gpio54", "gpio55", "gpio56", "gpio57",
+};
+static const char * const blsp_i2c1_groups[] = {
+ "gpio12", "gpio13", "gpio34", "gpio35",
+};
+static const char * const blsp_uart0_groups[] = {
+ "gpio16", "gpio17", "gpio60", "gpio61",
+};
+static const char * const blsp_spi1_groups[] = {
+ "gpio44", "gpio45", "gpio46", "gpio47",
+};
+
+static const struct msm_function ipq4019_functions[] = {
+ FUNCTION(gpio),
+ FUNCTION(blsp_uart1),
+ FUNCTION(blsp_i2c0),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(blsp_uart0),
+ FUNCTION(blsp_spi1),
+ FUNCTION(blsp_spi0),
+};
+
+static const struct msm_pingroup ipq4019_groups[] = {
+ PINGROUP(0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(5, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(6, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(7, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(8, blsp_uart1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(9, blsp_uart1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(10, blsp_uart1, NA, NA, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(11, blsp_uart1, NA, NA, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(12, blsp_spi0, blsp_i2c1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(13, blsp_spi0, blsp_i2c1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(14, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(15, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(16, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(17, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(18, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(19, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(20, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(21, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(22, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(23, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(24, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(25, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(26, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(27, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(28, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(29, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(30, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(31, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(32, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(33, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(34, blsp_i2c1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(35, blsp_i2c1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(36, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(37, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(38, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(39, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(40, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(41, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(42, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(43, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(44, NA, blsp_spi1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(45, NA, blsp_spi1, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(46, NA, blsp_spi1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(47, NA, blsp_spi1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(48, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(49, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(50, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(51, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(52, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(53, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(54, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(55, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(56, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(57, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(58, NA, NA, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(59, NA, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(60, NA, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(61, NA, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(63, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(65, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(66, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(67, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(68, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(69, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+};
+
+static const struct msm_pinctrl_soc_data ipq4019_pinctrl = {
+ .pins = ipq4019_pins,
+ .npins = ARRAY_SIZE(ipq4019_pins),
+ .functions = ipq4019_functions,
+ .nfunctions = ARRAY_SIZE(ipq4019_functions),
+ .groups = ipq4019_groups,
+ .ngroups = ARRAY_SIZE(ipq4019_groups),
+ .ngpios = 70,
+};
+
+static int ipq4019_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &ipq4019_pinctrl);
+}
+
+static const struct of_device_id ipq4019_pinctrl_of_match[] = {
+ { .compatible = "qcom,ipq4019-pinctrl", },
+ { },
+};
+
+static struct platform_driver ipq4019_pinctrl_driver = {
+ .driver = {
+ .name = "ipq4019-pinctrl",
+ .of_match_table = ipq4019_pinctrl_of_match,
+ },
+ .probe = ipq4019_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init ipq4019_pinctrl_init(void)
+{
+ return platform_driver_register(&ipq4019_pinctrl_driver);
+}
+arch_initcall(ipq4019_pinctrl_init);
+
+static void __exit ipq4019_pinctrl_exit(void)
+{
+ platform_driver_unregister(&ipq4019_pinctrl_driver);
+}
+module_exit(ipq4019_pinctrl_exit);
+
+MODULE_DESCRIPTION("Qualcomm ipq4019 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, ipq4019_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
index 2f18323571a6..2a3e5490a483 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -117,6 +117,7 @@
* @output_enabled: Set to true if MPP output logic is enabled.
* @input_enabled: Set to true if MPP input buffer logic is enabled.
* @paired: Pin operates in paired mode
+ * @has_pullup: Pin has support to configure pullup
* @num_sources: Number of power-sources supported by this MPP.
* @power_source: Current power-source used.
* @amux_input: Set the source for analog input.
@@ -134,6 +135,7 @@ struct pmic_mpp_pad {
bool output_enabled;
bool input_enabled;
bool paired;
+ bool has_pullup;
unsigned int num_sources;
unsigned int power_source;
unsigned int amux_input;
@@ -477,11 +479,14 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
if (ret < 0)
return ret;
- val = pad->pullup << PMIC_MPP_REG_PULL_SHIFT;
+ if (pad->has_pullup) {
+ val = pad->pullup << PMIC_MPP_REG_PULL_SHIFT;
- ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_PULL_CTL, val);
- if (ret < 0)
- return ret;
+ ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_PULL_CTL,
+ val);
+ if (ret < 0)
+ return ret;
+ }
val = pad->amux_input & PMIC_MPP_REG_AIN_ROUTE_MASK;
@@ -534,7 +539,8 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]);
seq_printf(s, " vin-%d", pad->power_source);
seq_printf(s, " %d", pad->aout_level);
- seq_printf(s, " %-8s", biases[pad->pullup]);
+ if (pad->has_pullup)
+ seq_printf(s, " %-8s", biases[pad->pullup]);
seq_printf(s, " %-4s", pad->out_value ? "high" : "low");
if (pad->dtest)
seq_printf(s, " dtest%d", pad->dtest);
@@ -748,12 +754,16 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state,
pad->power_source = val >> PMIC_MPP_REG_VIN_SHIFT;
pad->power_source &= PMIC_MPP_REG_VIN_MASK;
- val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_PULL_CTL);
- if (val < 0)
- return val;
+ if (subtype != PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT &&
+ subtype != PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK) {
+ val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_PULL_CTL);
+ if (val < 0)
+ return val;
- pad->pullup = val >> PMIC_MPP_REG_PULL_SHIFT;
- pad->pullup &= PMIC_MPP_REG_PULL_MASK;
+ pad->pullup = val >> PMIC_MPP_REG_PULL_SHIFT;
+ pad->pullup &= PMIC_MPP_REG_PULL_MASK;
+ pad->has_pullup = true;
+ }
val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AIN_CTL);
if (val < 0)
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index f67b1e958589..5cc97f85db02 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -514,25 +514,35 @@ static const struct pinconf_ops samsung_pinconf_ops = {
.pin_config_group_set = samsung_pinconf_group_set,
};
-/* gpiolib gpio_set callback function */
-static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+/*
+ * The samsung_gpio_set_vlaue() should be called with "bank->slock" held
+ * to avoid race condition.
+ */
+static void samsung_gpio_set_value(struct gpio_chip *gc,
+ unsigned offset, int value)
{
struct samsung_pin_bank *bank = gpiochip_get_data(gc);
const struct samsung_pin_bank_type *type = bank->type;
- unsigned long flags;
void __iomem *reg;
u32 data;
reg = bank->drvdata->virt_base + bank->pctl_offset;
- spin_lock_irqsave(&bank->slock, flags);
-
data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
data &= ~(1 << offset);
if (value)
data |= 1 << offset;
writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]);
+}
+
+/* gpiolib gpio_set callback function */
+static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct samsung_pin_bank *bank = gpiochip_get_data(gc);
+ unsigned long flags;
+ spin_lock_irqsave(&bank->slock, flags);
+ samsung_gpio_set_value(gc, offset, value);
spin_unlock_irqrestore(&bank->slock, flags);
}
@@ -553,6 +563,8 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
}
/*
+ * The samsung_gpio_set_direction() should be called with "bank->slock" held
+ * to avoid race condition.
* The calls to gpio_direction_output() and gpio_direction_input()
* leads to this function call.
*/
@@ -564,7 +576,6 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc,
struct samsung_pinctrl_drv_data *drvdata;
void __iomem *reg;
u32 data, mask, shift;
- unsigned long flags;
bank = gpiochip_get_data(gc);
type = bank->type;
@@ -581,31 +592,42 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc,
reg += 4;
}
- spin_lock_irqsave(&bank->slock, flags);
-
data = readl(reg);
data &= ~(mask << shift);
if (!input)
data |= FUNC_OUTPUT << shift;
writel(data, reg);
- spin_unlock_irqrestore(&bank->slock, flags);
-
return 0;
}
/* gpiolib gpio_direction_input callback function. */
static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
- return samsung_gpio_set_direction(gc, offset, true);
+ struct samsung_pin_bank *bank = gpiochip_get_data(gc);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&bank->slock, flags);
+ ret = samsung_gpio_set_direction(gc, offset, true);
+ spin_unlock_irqrestore(&bank->slock, flags);
+ return ret;
}
/* gpiolib gpio_direction_output callback function. */
static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- samsung_gpio_set(gc, offset, value);
- return samsung_gpio_set_direction(gc, offset, false);
+ struct samsung_pin_bank *bank = gpiochip_get_data(gc);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&bank->slock, flags);
+ samsung_gpio_set_value(gc, offset, value);
+ ret = samsung_gpio_set_direction(gc, offset, false);
+ spin_unlock_irqrestore(&bank->slock, flags);
+
+ return ret;
}
/*
diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig
index 35d6e95fa21f..415dd8023063 100644
--- a/drivers/pinctrl/sh-pfc/Kconfig
+++ b/drivers/pinctrl/sh-pfc/Kconfig
@@ -2,10 +2,9 @@
# Renesas SH and SH Mobile PINCTRL drivers
#
-if ARCH_SHMOBILE || SUPERH
+if ARCH_RENESAS || SUPERH
config PINCTRL_SH_PFC
- select GPIO_SH_PFC if ARCH_REQUIRE_GPIOLIB
select PINMUX
select PINCONF
select GENERIC_PINCONF
@@ -13,12 +12,12 @@ config PINCTRL_SH_PFC
help
This enables pin control drivers for SH and SH Mobile platforms
-config GPIO_SH_PFC
- bool "SuperH PFC GPIO support"
- depends on PINCTRL_SH_PFC && GPIOLIB
+config PINCTRL_SH_PFC_GPIO
+ select GPIOLIB
+ select PINCTRL_SH_PFC
+ bool
help
- This enables support for GPIOs within the SoC's pin function
- controller.
+ This enables pin control and GPIO drivers for SH/SH Mobile platforms
config PINCTRL_PFC_EMEV2
def_bool y
@@ -28,12 +27,12 @@ config PINCTRL_PFC_EMEV2
config PINCTRL_PFC_R8A73A4
def_bool y
depends on ARCH_R8A73A4
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_R8A7740
def_bool y
depends on ARCH_R8A7740
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_R8A7778
def_bool y
@@ -73,79 +72,66 @@ config PINCTRL_PFC_R8A7795
config PINCTRL_PFC_SH7203
def_bool y
depends on CPU_SUBTYPE_SH7203
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH7264
def_bool y
depends on CPU_SUBTYPE_SH7264
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH7269
def_bool y
depends on CPU_SUBTYPE_SH7269
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH73A0
def_bool y
depends on ARCH_SH73A0
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
select REGULATOR
config PINCTRL_PFC_SH7720
def_bool y
depends on CPU_SUBTYPE_SH7720
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH7722
def_bool y
depends on CPU_SUBTYPE_SH7722
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH7723
def_bool y
depends on CPU_SUBTYPE_SH7723
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH7724
def_bool y
depends on CPU_SUBTYPE_SH7724
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH7734
def_bool y
depends on CPU_SUBTYPE_SH7734
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH7757
def_bool y
depends on CPU_SUBTYPE_SH7757
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH7785
def_bool y
depends on CPU_SUBTYPE_SH7785
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SH7786
def_bool y
depends on CPU_SUBTYPE_SH7786
- depends on GPIOLIB
- select PINCTRL_SH_PFC
+ select PINCTRL_SH_PFC_GPIO
config PINCTRL_PFC_SHX3
def_bool y
depends on CPU_SUBTYPE_SHX3
- depends on GPIOLIB
- select PINCTRL_SH_PFC
-
+ select PINCTRL_SH_PFC_GPIO
endif
diff --git a/drivers/pinctrl/sh-pfc/Makefile b/drivers/pinctrl/sh-pfc/Makefile
index 173305fa3811..8a2c8710fc93 100644
--- a/drivers/pinctrl/sh-pfc/Makefile
+++ b/drivers/pinctrl/sh-pfc/Makefile
@@ -1,8 +1,5 @@
-sh-pfc-objs = core.o pinctrl.o
-ifeq ($(CONFIG_GPIO_SH_PFC),y)
-sh-pfc-objs += gpio.o
-endif
-obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc.o
+obj-$(CONFIG_PINCTRL_SH_PFC) += core.o pinctrl.o
+obj-$(CONFIG_PINCTRL_SH_PFC_GPIO) += gpio.o
obj-$(CONFIG_PINCTRL_PFC_EMEV2) += pfc-emev2.o
obj-$(CONFIG_PINCTRL_PFC_R8A73A4) += pfc-r8a73a4.o
obj-$(CONFIG_PINCTRL_PFC_R8A7740) += pfc-r8a7740.o
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index 181ea98a63b7..dc3609f0c60b 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -1,5 +1,7 @@
/*
- * SuperH Pin Function Controller support.
+ * Pin Control and GPIO driver for SuperH Pin Function Controller.
+ *
+ * Authors: Magnus Damm, Paul Mundt, Laurent Pinchart
*
* Copyright (C) 2008 Magnus Damm
* Copyright (C) 2009 - 2012 Paul Mundt
@@ -17,7 +19,7 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/machine.h>
@@ -503,7 +505,6 @@ static const struct of_device_id sh_pfc_of_table[] = {
#endif
{ },
};
-MODULE_DEVICE_TABLE(of, sh_pfc_of_table);
#endif
static int sh_pfc_probe(struct platform_device *pdev)
@@ -518,7 +519,7 @@ static int sh_pfc_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
if (np)
- info = of_match_device(sh_pfc_of_table, &pdev->dev)->data;
+ info = of_device_get_match_data(&pdev->dev);
else
#endif
info = platid ? (const void *)platid->driver_data : NULL;
@@ -558,7 +559,7 @@ static int sh_pfc_probe(struct platform_device *pdev)
if (unlikely(ret != 0))
return ret;
-#ifdef CONFIG_GPIO_SH_PFC
+#ifdef CONFIG_PINCTRL_SH_PFC_GPIO
/*
* Then the GPIO chip
*/
@@ -584,7 +585,7 @@ static int sh_pfc_remove(struct platform_device *pdev)
{
struct sh_pfc *pfc = platform_get_drvdata(pdev);
-#ifdef CONFIG_GPIO_SH_PFC
+#ifdef CONFIG_PINCTRL_SH_PFC_GPIO
sh_pfc_unregister_gpiochip(pfc);
#endif
sh_pfc_unregister_pinctrl(pfc);
@@ -632,7 +633,6 @@ static const struct platform_device_id sh_pfc_id_table[] = {
{ "sh-pfc", 0 },
{ },
};
-MODULE_DEVICE_TABLE(platform, sh_pfc_id_table);
static struct platform_driver sh_pfc_driver = {
.probe = sh_pfc_probe,
@@ -649,13 +649,3 @@ static int __init sh_pfc_init(void)
return platform_driver_register(&sh_pfc_driver);
}
postcore_initcall(sh_pfc_init);
-
-static void __exit sh_pfc_exit(void)
-{
- platform_driver_unregister(&sh_pfc_driver);
-}
-module_exit(sh_pfc_exit);
-
-MODULE_AUTHOR("Magnus Damm, Paul Mundt, Laurent Pinchart");
-MODULE_DESCRIPTION("Pin Control and GPIO driver for SuperH pin function controller");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
index ad09a670c2ff..411d0887ba19 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
@@ -561,82 +561,82 @@ static const u16 pinmux_data[] = {
PINMUX_SINGLE(AVS2),
/* IPSR0 */
- PINMUX_IPSR_DATA(IP0_1_0, PRESETOUT),
- PINMUX_IPSR_DATA(IP0_1_0, PWM1),
+ PINMUX_IPSR_GPSR(IP0_1_0, PRESETOUT),
+ PINMUX_IPSR_GPSR(IP0_1_0, PWM1),
- PINMUX_IPSR_DATA(IP0_4_2, AUDATA0),
- PINMUX_IPSR_DATA(IP0_4_2, ARM_TRACEDATA_0),
+ PINMUX_IPSR_GPSR(IP0_4_2, AUDATA0),
+ PINMUX_IPSR_GPSR(IP0_4_2, ARM_TRACEDATA_0),
PINMUX_IPSR_MSEL(IP0_4_2, GPSCLK_C, SEL_GPS_C),
- PINMUX_IPSR_DATA(IP0_4_2, USB_OVC0),
- PINMUX_IPSR_DATA(IP0_4_2, TX2_E),
+ PINMUX_IPSR_GPSR(IP0_4_2, USB_OVC0),
+ PINMUX_IPSR_GPSR(IP0_4_2, TX2_E),
PINMUX_IPSR_MSEL(IP0_4_2, SDA2_B, SEL_I2C2_B),
- PINMUX_IPSR_DATA(IP0_7_5, AUDATA1),
- PINMUX_IPSR_DATA(IP0_7_5, ARM_TRACEDATA_1),
+ PINMUX_IPSR_GPSR(IP0_7_5, AUDATA1),
+ PINMUX_IPSR_GPSR(IP0_7_5, ARM_TRACEDATA_1),
PINMUX_IPSR_MSEL(IP0_7_5, GPSIN_C, SEL_GPS_C),
- PINMUX_IPSR_DATA(IP0_7_5, USB_OVC1),
+ PINMUX_IPSR_GPSR(IP0_7_5, USB_OVC1),
PINMUX_IPSR_MSEL(IP0_7_5, RX2_E, SEL_SCIF2_E),
PINMUX_IPSR_MSEL(IP0_7_5, SCL2_B, SEL_I2C2_B),
PINMUX_IPSR_MSEL(IP0_11_8, SD1_DAT2_A, SEL_SD1_A),
- PINMUX_IPSR_DATA(IP0_11_8, MMC_D2),
- PINMUX_IPSR_DATA(IP0_11_8, BS),
- PINMUX_IPSR_DATA(IP0_11_8, ATADIR0_A),
- PINMUX_IPSR_DATA(IP0_11_8, SDSELF_A),
- PINMUX_IPSR_DATA(IP0_11_8, PWM4_B),
+ PINMUX_IPSR_GPSR(IP0_11_8, MMC_D2),
+ PINMUX_IPSR_GPSR(IP0_11_8, BS),
+ PINMUX_IPSR_GPSR(IP0_11_8, ATADIR0_A),
+ PINMUX_IPSR_GPSR(IP0_11_8, SDSELF_A),
+ PINMUX_IPSR_GPSR(IP0_11_8, PWM4_B),
PINMUX_IPSR_MSEL(IP0_14_12, SD1_DAT3_A, SEL_SD1_A),
- PINMUX_IPSR_DATA(IP0_14_12, MMC_D3),
- PINMUX_IPSR_DATA(IP0_14_12, A0),
- PINMUX_IPSR_DATA(IP0_14_12, ATAG0_A),
+ PINMUX_IPSR_GPSR(IP0_14_12, MMC_D3),
+ PINMUX_IPSR_GPSR(IP0_14_12, A0),
+ PINMUX_IPSR_GPSR(IP0_14_12, ATAG0_A),
PINMUX_IPSR_MSEL(IP0_14_12, REMOCON_B, SEL_REMOCON_B),
- PINMUX_IPSR_DATA(IP0_15, A4),
- PINMUX_IPSR_DATA(IP0_16, A5),
- PINMUX_IPSR_DATA(IP0_17, A6),
- PINMUX_IPSR_DATA(IP0_18, A7),
- PINMUX_IPSR_DATA(IP0_19, A8),
- PINMUX_IPSR_DATA(IP0_20, A9),
- PINMUX_IPSR_DATA(IP0_21, A10),
- PINMUX_IPSR_DATA(IP0_22, A11),
- PINMUX_IPSR_DATA(IP0_23, A12),
- PINMUX_IPSR_DATA(IP0_24, A13),
- PINMUX_IPSR_DATA(IP0_25, A14),
- PINMUX_IPSR_DATA(IP0_26, A15),
- PINMUX_IPSR_DATA(IP0_27, A16),
- PINMUX_IPSR_DATA(IP0_28, A17),
- PINMUX_IPSR_DATA(IP0_29, A18),
- PINMUX_IPSR_DATA(IP0_30, A19),
+ PINMUX_IPSR_GPSR(IP0_15, A4),
+ PINMUX_IPSR_GPSR(IP0_16, A5),
+ PINMUX_IPSR_GPSR(IP0_17, A6),
+ PINMUX_IPSR_GPSR(IP0_18, A7),
+ PINMUX_IPSR_GPSR(IP0_19, A8),
+ PINMUX_IPSR_GPSR(IP0_20, A9),
+ PINMUX_IPSR_GPSR(IP0_21, A10),
+ PINMUX_IPSR_GPSR(IP0_22, A11),
+ PINMUX_IPSR_GPSR(IP0_23, A12),
+ PINMUX_IPSR_GPSR(IP0_24, A13),
+ PINMUX_IPSR_GPSR(IP0_25, A14),
+ PINMUX_IPSR_GPSR(IP0_26, A15),
+ PINMUX_IPSR_GPSR(IP0_27, A16),
+ PINMUX_IPSR_GPSR(IP0_28, A17),
+ PINMUX_IPSR_GPSR(IP0_29, A18),
+ PINMUX_IPSR_GPSR(IP0_30, A19),
/* IPSR1 */
- PINMUX_IPSR_DATA(IP1_0, A20),
+ PINMUX_IPSR_GPSR(IP1_0, A20),
PINMUX_IPSR_MSEL(IP1_0, HSPI_CS1_B, SEL_HSPI1_B),
- PINMUX_IPSR_DATA(IP1_1, A21),
+ PINMUX_IPSR_GPSR(IP1_1, A21),
PINMUX_IPSR_MSEL(IP1_1, HSPI_CLK1_B, SEL_HSPI1_B),
- PINMUX_IPSR_DATA(IP1_4_2, A22),
+ PINMUX_IPSR_GPSR(IP1_4_2, A22),
PINMUX_IPSR_MSEL(IP1_4_2, HRTS0_B, SEL_HSCIF0_B),
PINMUX_IPSR_MSEL(IP1_4_2, RX2_B, SEL_SCIF2_B),
PINMUX_IPSR_MSEL(IP1_4_2, DREQ2_A, SEL_DREQ2_A),
- PINMUX_IPSR_DATA(IP1_7_5, A23),
- PINMUX_IPSR_DATA(IP1_7_5, HTX0_B),
- PINMUX_IPSR_DATA(IP1_7_5, TX2_B),
- PINMUX_IPSR_DATA(IP1_7_5, DACK2_A),
+ PINMUX_IPSR_GPSR(IP1_7_5, A23),
+ PINMUX_IPSR_GPSR(IP1_7_5, HTX0_B),
+ PINMUX_IPSR_GPSR(IP1_7_5, TX2_B),
+ PINMUX_IPSR_GPSR(IP1_7_5, DACK2_A),
PINMUX_IPSR_MSEL(IP1_7_5, TS_SDEN0_A, SEL_TSIF0_A),
PINMUX_IPSR_MSEL(IP1_10_8, SD1_CD_A, SEL_SD1_A),
- PINMUX_IPSR_DATA(IP1_10_8, MMC_D6),
- PINMUX_IPSR_DATA(IP1_10_8, A24),
+ PINMUX_IPSR_GPSR(IP1_10_8, MMC_D6),
+ PINMUX_IPSR_GPSR(IP1_10_8, A24),
PINMUX_IPSR_MSEL(IP1_10_8, DREQ1_A, SEL_DREQ1_A),
PINMUX_IPSR_MSEL(IP1_10_8, HRX0_B, SEL_HSCIF0_B),
PINMUX_IPSR_MSEL(IP1_10_8, TS_SPSYNC0_A, SEL_TSIF0_A),
PINMUX_IPSR_MSEL(IP1_14_11, SD1_WP_A, SEL_SD1_A),
- PINMUX_IPSR_DATA(IP1_14_11, MMC_D7),
- PINMUX_IPSR_DATA(IP1_14_11, A25),
- PINMUX_IPSR_DATA(IP1_14_11, DACK1_A),
+ PINMUX_IPSR_GPSR(IP1_14_11, MMC_D7),
+ PINMUX_IPSR_GPSR(IP1_14_11, A25),
+ PINMUX_IPSR_GPSR(IP1_14_11, DACK1_A),
PINMUX_IPSR_MSEL(IP1_14_11, HCTS0_B, SEL_HSCIF0_B),
PINMUX_IPSR_MSEL(IP1_14_11, RX3_C, SEL_SCIF3_C),
PINMUX_IPSR_MSEL(IP1_14_11, TS_SDAT0_A, SEL_TSIF0_A),
@@ -654,54 +654,54 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_NOGM(IP1_20_18, SDA2_A, SEL_I2C2_A),
PINMUX_IPSR_NOGM(IP1_20_18, SCK2_B, SEL_SCIF2_B),
- PINMUX_IPSR_DATA(IP1_23_21, MMC_D5),
- PINMUX_IPSR_DATA(IP1_23_21, ATADIR0_B),
- PINMUX_IPSR_DATA(IP1_23_21, RD_WR),
+ PINMUX_IPSR_GPSR(IP1_23_21, MMC_D5),
+ PINMUX_IPSR_GPSR(IP1_23_21, ATADIR0_B),
+ PINMUX_IPSR_GPSR(IP1_23_21, RD_WR),
- PINMUX_IPSR_DATA(IP1_24, WE1),
- PINMUX_IPSR_DATA(IP1_24, ATAWR0_B),
+ PINMUX_IPSR_GPSR(IP1_24, WE1),
+ PINMUX_IPSR_GPSR(IP1_24, ATAWR0_B),
PINMUX_IPSR_MSEL(IP1_27_25, SSI_WS1_B, SEL_SSI1_B),
- PINMUX_IPSR_DATA(IP1_27_25, EX_CS0),
+ PINMUX_IPSR_GPSR(IP1_27_25, EX_CS0),
PINMUX_IPSR_MSEL(IP1_27_25, SCL2_A, SEL_I2C2_A),
- PINMUX_IPSR_DATA(IP1_27_25, TX3_C),
+ PINMUX_IPSR_GPSR(IP1_27_25, TX3_C),
PINMUX_IPSR_MSEL(IP1_27_25, TS_SCK0_A, SEL_TSIF0_A),
- PINMUX_IPSR_DATA(IP1_29_28, EX_CS1),
- PINMUX_IPSR_DATA(IP1_29_28, MMC_D4),
+ PINMUX_IPSR_GPSR(IP1_29_28, EX_CS1),
+ PINMUX_IPSR_GPSR(IP1_29_28, MMC_D4),
/* IPSR2 */
- PINMUX_IPSR_DATA(IP2_2_0, SD1_CLK_A),
- PINMUX_IPSR_DATA(IP2_2_0, MMC_CLK),
- PINMUX_IPSR_DATA(IP2_2_0, ATACS00),
- PINMUX_IPSR_DATA(IP2_2_0, EX_CS2),
+ PINMUX_IPSR_GPSR(IP2_2_0, SD1_CLK_A),
+ PINMUX_IPSR_GPSR(IP2_2_0, MMC_CLK),
+ PINMUX_IPSR_GPSR(IP2_2_0, ATACS00),
+ PINMUX_IPSR_GPSR(IP2_2_0, EX_CS2),
PINMUX_IPSR_MSEL(IP2_5_3, SD1_CMD_A, SEL_SD1_A),
- PINMUX_IPSR_DATA(IP2_5_3, MMC_CMD),
- PINMUX_IPSR_DATA(IP2_5_3, ATACS10),
- PINMUX_IPSR_DATA(IP2_5_3, EX_CS3),
+ PINMUX_IPSR_GPSR(IP2_5_3, MMC_CMD),
+ PINMUX_IPSR_GPSR(IP2_5_3, ATACS10),
+ PINMUX_IPSR_GPSR(IP2_5_3, EX_CS3),
PINMUX_IPSR_MSEL(IP2_8_6, SD1_DAT0_A, SEL_SD1_A),
- PINMUX_IPSR_DATA(IP2_8_6, MMC_D0),
- PINMUX_IPSR_DATA(IP2_8_6, ATARD0),
- PINMUX_IPSR_DATA(IP2_8_6, EX_CS4),
+ PINMUX_IPSR_GPSR(IP2_8_6, MMC_D0),
+ PINMUX_IPSR_GPSR(IP2_8_6, ATARD0),
+ PINMUX_IPSR_GPSR(IP2_8_6, EX_CS4),
PINMUX_IPSR_MSEL(IP2_8_6, EX_WAIT1_A, SEL_WAIT1_A),
PINMUX_IPSR_MSEL(IP2_11_9, SD1_DAT1_A, SEL_SD1_A),
- PINMUX_IPSR_DATA(IP2_11_9, MMC_D1),
- PINMUX_IPSR_DATA(IP2_11_9, ATAWR0_A),
- PINMUX_IPSR_DATA(IP2_11_9, EX_CS5),
+ PINMUX_IPSR_GPSR(IP2_11_9, MMC_D1),
+ PINMUX_IPSR_GPSR(IP2_11_9, ATAWR0_A),
+ PINMUX_IPSR_GPSR(IP2_11_9, EX_CS5),
PINMUX_IPSR_MSEL(IP2_11_9, EX_WAIT2_A, SEL_WAIT2_A),
PINMUX_IPSR_MSEL(IP2_13_12, DREQ0_A, SEL_DREQ0_A),
PINMUX_IPSR_MSEL(IP2_13_12, RX3_A, SEL_SCIF3_A),
- PINMUX_IPSR_DATA(IP2_16_14, DACK0),
- PINMUX_IPSR_DATA(IP2_16_14, TX3_A),
- PINMUX_IPSR_DATA(IP2_16_14, DRACK0),
+ PINMUX_IPSR_GPSR(IP2_16_14, DACK0),
+ PINMUX_IPSR_GPSR(IP2_16_14, TX3_A),
+ PINMUX_IPSR_GPSR(IP2_16_14, DRACK0),
- PINMUX_IPSR_DATA(IP2_17, EX_WAIT0),
- PINMUX_IPSR_DATA(IP2_17, PWM0_C),
+ PINMUX_IPSR_GPSR(IP2_17, EX_WAIT0),
+ PINMUX_IPSR_GPSR(IP2_17, PWM0_C),
PINMUX_IPSR_NOGP(IP2_18, D0),
PINMUX_IPSR_NOGP(IP2_19, D1),
@@ -716,33 +716,33 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_NOGP(IP2_28, D10),
PINMUX_IPSR_NOGP(IP2_29, D11),
- PINMUX_IPSR_DATA(IP2_30, RD_WR_B),
- PINMUX_IPSR_DATA(IP2_30, IRQ0),
+ PINMUX_IPSR_GPSR(IP2_30, RD_WR_B),
+ PINMUX_IPSR_GPSR(IP2_30, IRQ0),
- PINMUX_IPSR_DATA(IP2_31, MLB_CLK),
+ PINMUX_IPSR_GPSR(IP2_31, MLB_CLK),
PINMUX_IPSR_MSEL(IP2_31, IRQ1_A, SEL_IRQ1_A),
/* IPSR3 */
- PINMUX_IPSR_DATA(IP3_1_0, MLB_SIG),
+ PINMUX_IPSR_GPSR(IP3_1_0, MLB_SIG),
PINMUX_IPSR_MSEL(IP3_1_0, RX5_B, SEL_SCIF5_B),
PINMUX_IPSR_MSEL(IP3_1_0, SDA3_A, SEL_I2C3_A),
PINMUX_IPSR_MSEL(IP3_1_0, IRQ2_A, SEL_IRQ2_A),
- PINMUX_IPSR_DATA(IP3_4_2, MLB_DAT),
- PINMUX_IPSR_DATA(IP3_4_2, TX5_B),
+ PINMUX_IPSR_GPSR(IP3_4_2, MLB_DAT),
+ PINMUX_IPSR_GPSR(IP3_4_2, TX5_B),
PINMUX_IPSR_MSEL(IP3_4_2, SCL3_A, SEL_I2C3_A),
PINMUX_IPSR_MSEL(IP3_4_2, IRQ3_A, SEL_IRQ3_A),
- PINMUX_IPSR_DATA(IP3_4_2, SDSELF_B),
+ PINMUX_IPSR_GPSR(IP3_4_2, SDSELF_B),
PINMUX_IPSR_MSEL(IP3_7_5, SD1_CMD_B, SEL_SD1_B),
- PINMUX_IPSR_DATA(IP3_7_5, SCIF_CLK),
- PINMUX_IPSR_DATA(IP3_7_5, AUDIO_CLKOUT_B),
+ PINMUX_IPSR_GPSR(IP3_7_5, SCIF_CLK),
+ PINMUX_IPSR_GPSR(IP3_7_5, AUDIO_CLKOUT_B),
PINMUX_IPSR_MSEL(IP3_7_5, CAN_CLK_B, SEL_CANCLK_B),
PINMUX_IPSR_MSEL(IP3_7_5, SDA3_B, SEL_I2C3_B),
- PINMUX_IPSR_DATA(IP3_9_8, SD1_CLK_B),
- PINMUX_IPSR_DATA(IP3_9_8, HTX0_A),
- PINMUX_IPSR_DATA(IP3_9_8, TX0_A),
+ PINMUX_IPSR_GPSR(IP3_9_8, SD1_CLK_B),
+ PINMUX_IPSR_GPSR(IP3_9_8, HTX0_A),
+ PINMUX_IPSR_GPSR(IP3_9_8, TX0_A),
PINMUX_IPSR_MSEL(IP3_12_10, SD1_DAT0_B, SEL_SD1_B),
PINMUX_IPSR_MSEL(IP3_12_10, HRX0_A, SEL_HSCIF0_A),
@@ -750,513 +750,513 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP3_15_13, SD1_DAT1_B, SEL_SD1_B),
PINMUX_IPSR_MSEL(IP3_15_13, HSCK0, SEL_HSCIF0_A),
- PINMUX_IPSR_DATA(IP3_15_13, SCK0),
+ PINMUX_IPSR_GPSR(IP3_15_13, SCK0),
PINMUX_IPSR_MSEL(IP3_15_13, SCL3_B, SEL_I2C3_B),
PINMUX_IPSR_MSEL(IP3_18_16, SD1_DAT2_B, SEL_SD1_B),
PINMUX_IPSR_MSEL(IP3_18_16, HCTS0_A, SEL_HSCIF0_A),
- PINMUX_IPSR_DATA(IP3_18_16, CTS0),
+ PINMUX_IPSR_GPSR(IP3_18_16, CTS0),
PINMUX_IPSR_MSEL(IP3_20_19, SD1_DAT3_B, SEL_SD1_B),
PINMUX_IPSR_MSEL(IP3_20_19, HRTS0_A, SEL_HSCIF0_A),
- PINMUX_IPSR_DATA(IP3_20_19, RTS0),
+ PINMUX_IPSR_GPSR(IP3_20_19, RTS0),
- PINMUX_IPSR_DATA(IP3_23_21, SSI_SCK4),
- PINMUX_IPSR_DATA(IP3_23_21, DU0_DR0),
- PINMUX_IPSR_DATA(IP3_23_21, LCDOUT0),
- PINMUX_IPSR_DATA(IP3_23_21, AUDATA2),
- PINMUX_IPSR_DATA(IP3_23_21, ARM_TRACEDATA_2),
+ PINMUX_IPSR_GPSR(IP3_23_21, SSI_SCK4),
+ PINMUX_IPSR_GPSR(IP3_23_21, DU0_DR0),
+ PINMUX_IPSR_GPSR(IP3_23_21, LCDOUT0),
+ PINMUX_IPSR_GPSR(IP3_23_21, AUDATA2),
+ PINMUX_IPSR_GPSR(IP3_23_21, ARM_TRACEDATA_2),
PINMUX_IPSR_MSEL(IP3_23_21, SDA3_C, SEL_I2C3_C),
- PINMUX_IPSR_DATA(IP3_23_21, ADICHS1),
+ PINMUX_IPSR_GPSR(IP3_23_21, ADICHS1),
PINMUX_IPSR_MSEL(IP3_23_21, TS_SDEN0_B, SEL_TSIF0_B),
- PINMUX_IPSR_DATA(IP3_26_24, SSI_WS4),
- PINMUX_IPSR_DATA(IP3_26_24, DU0_DR1),
- PINMUX_IPSR_DATA(IP3_26_24, LCDOUT1),
- PINMUX_IPSR_DATA(IP3_26_24, AUDATA3),
- PINMUX_IPSR_DATA(IP3_26_24, ARM_TRACEDATA_3),
+ PINMUX_IPSR_GPSR(IP3_26_24, SSI_WS4),
+ PINMUX_IPSR_GPSR(IP3_26_24, DU0_DR1),
+ PINMUX_IPSR_GPSR(IP3_26_24, LCDOUT1),
+ PINMUX_IPSR_GPSR(IP3_26_24, AUDATA3),
+ PINMUX_IPSR_GPSR(IP3_26_24, ARM_TRACEDATA_3),
PINMUX_IPSR_MSEL(IP3_26_24, SCL3_C, SEL_I2C3_C),
- PINMUX_IPSR_DATA(IP3_26_24, ADICHS2),
+ PINMUX_IPSR_GPSR(IP3_26_24, ADICHS2),
PINMUX_IPSR_MSEL(IP3_26_24, TS_SPSYNC0_B, SEL_TSIF0_B),
- PINMUX_IPSR_DATA(IP3_27, DU0_DR2),
- PINMUX_IPSR_DATA(IP3_27, LCDOUT2),
+ PINMUX_IPSR_GPSR(IP3_27, DU0_DR2),
+ PINMUX_IPSR_GPSR(IP3_27, LCDOUT2),
- PINMUX_IPSR_DATA(IP3_28, DU0_DR3),
- PINMUX_IPSR_DATA(IP3_28, LCDOUT3),
+ PINMUX_IPSR_GPSR(IP3_28, DU0_DR3),
+ PINMUX_IPSR_GPSR(IP3_28, LCDOUT3),
- PINMUX_IPSR_DATA(IP3_29, DU0_DR4),
- PINMUX_IPSR_DATA(IP3_29, LCDOUT4),
+ PINMUX_IPSR_GPSR(IP3_29, DU0_DR4),
+ PINMUX_IPSR_GPSR(IP3_29, LCDOUT4),
- PINMUX_IPSR_DATA(IP3_30, DU0_DR5),
- PINMUX_IPSR_DATA(IP3_30, LCDOUT5),
+ PINMUX_IPSR_GPSR(IP3_30, DU0_DR5),
+ PINMUX_IPSR_GPSR(IP3_30, LCDOUT5),
- PINMUX_IPSR_DATA(IP3_31, DU0_DR6),
- PINMUX_IPSR_DATA(IP3_31, LCDOUT6),
+ PINMUX_IPSR_GPSR(IP3_31, DU0_DR6),
+ PINMUX_IPSR_GPSR(IP3_31, LCDOUT6),
/* IPSR4 */
- PINMUX_IPSR_DATA(IP4_0, DU0_DR7),
- PINMUX_IPSR_DATA(IP4_0, LCDOUT7),
-
- PINMUX_IPSR_DATA(IP4_3_1, DU0_DG0),
- PINMUX_IPSR_DATA(IP4_3_1, LCDOUT8),
- PINMUX_IPSR_DATA(IP4_3_1, AUDATA4),
- PINMUX_IPSR_DATA(IP4_3_1, ARM_TRACEDATA_4),
- PINMUX_IPSR_DATA(IP4_3_1, TX1_D),
- PINMUX_IPSR_DATA(IP4_3_1, CAN0_TX_A),
- PINMUX_IPSR_DATA(IP4_3_1, ADICHS0),
-
- PINMUX_IPSR_DATA(IP4_6_4, DU0_DG1),
- PINMUX_IPSR_DATA(IP4_6_4, LCDOUT9),
- PINMUX_IPSR_DATA(IP4_6_4, AUDATA5),
- PINMUX_IPSR_DATA(IP4_6_4, ARM_TRACEDATA_5),
+ PINMUX_IPSR_GPSR(IP4_0, DU0_DR7),
+ PINMUX_IPSR_GPSR(IP4_0, LCDOUT7),
+
+ PINMUX_IPSR_GPSR(IP4_3_1, DU0_DG0),
+ PINMUX_IPSR_GPSR(IP4_3_1, LCDOUT8),
+ PINMUX_IPSR_GPSR(IP4_3_1, AUDATA4),
+ PINMUX_IPSR_GPSR(IP4_3_1, ARM_TRACEDATA_4),
+ PINMUX_IPSR_GPSR(IP4_3_1, TX1_D),
+ PINMUX_IPSR_GPSR(IP4_3_1, CAN0_TX_A),
+ PINMUX_IPSR_GPSR(IP4_3_1, ADICHS0),
+
+ PINMUX_IPSR_GPSR(IP4_6_4, DU0_DG1),
+ PINMUX_IPSR_GPSR(IP4_6_4, LCDOUT9),
+ PINMUX_IPSR_GPSR(IP4_6_4, AUDATA5),
+ PINMUX_IPSR_GPSR(IP4_6_4, ARM_TRACEDATA_5),
PINMUX_IPSR_MSEL(IP4_6_4, RX1_D, SEL_SCIF1_D),
PINMUX_IPSR_MSEL(IP4_6_4, CAN0_RX_A, SEL_CAN0_A),
- PINMUX_IPSR_DATA(IP4_6_4, ADIDATA),
+ PINMUX_IPSR_GPSR(IP4_6_4, ADIDATA),
- PINMUX_IPSR_DATA(IP4_7, DU0_DG2),
- PINMUX_IPSR_DATA(IP4_7, LCDOUT10),
+ PINMUX_IPSR_GPSR(IP4_7, DU0_DG2),
+ PINMUX_IPSR_GPSR(IP4_7, LCDOUT10),
- PINMUX_IPSR_DATA(IP4_8, DU0_DG3),
- PINMUX_IPSR_DATA(IP4_8, LCDOUT11),
+ PINMUX_IPSR_GPSR(IP4_8, DU0_DG3),
+ PINMUX_IPSR_GPSR(IP4_8, LCDOUT11),
- PINMUX_IPSR_DATA(IP4_10_9, DU0_DG4),
- PINMUX_IPSR_DATA(IP4_10_9, LCDOUT12),
+ PINMUX_IPSR_GPSR(IP4_10_9, DU0_DG4),
+ PINMUX_IPSR_GPSR(IP4_10_9, LCDOUT12),
PINMUX_IPSR_MSEL(IP4_10_9, RX0_B, SEL_SCIF0_B),
- PINMUX_IPSR_DATA(IP4_12_11, DU0_DG5),
- PINMUX_IPSR_DATA(IP4_12_11, LCDOUT13),
- PINMUX_IPSR_DATA(IP4_12_11, TX0_B),
+ PINMUX_IPSR_GPSR(IP4_12_11, DU0_DG5),
+ PINMUX_IPSR_GPSR(IP4_12_11, LCDOUT13),
+ PINMUX_IPSR_GPSR(IP4_12_11, TX0_B),
- PINMUX_IPSR_DATA(IP4_14_13, DU0_DG6),
- PINMUX_IPSR_DATA(IP4_14_13, LCDOUT14),
+ PINMUX_IPSR_GPSR(IP4_14_13, DU0_DG6),
+ PINMUX_IPSR_GPSR(IP4_14_13, LCDOUT14),
PINMUX_IPSR_MSEL(IP4_14_13, RX4_A, SEL_SCIF4_A),
- PINMUX_IPSR_DATA(IP4_16_15, DU0_DG7),
- PINMUX_IPSR_DATA(IP4_16_15, LCDOUT15),
- PINMUX_IPSR_DATA(IP4_16_15, TX4_A),
+ PINMUX_IPSR_GPSR(IP4_16_15, DU0_DG7),
+ PINMUX_IPSR_GPSR(IP4_16_15, LCDOUT15),
+ PINMUX_IPSR_GPSR(IP4_16_15, TX4_A),
PINMUX_IPSR_MSEL(IP4_20_17, SSI_SCK2_B, SEL_SSI2_B),
PINMUX_DATA(VI0_R0_B_MARK, FN_IP4_20_17, FN_VI0_R0_B, FN_SEL_VI0_B), /* see sel_vi0 */
PINMUX_DATA(VI0_R0_D_MARK, FN_IP4_20_17, FN_VI0_R0_B, FN_SEL_VI0_D), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP4_20_17, DU0_DB0),
- PINMUX_IPSR_DATA(IP4_20_17, LCDOUT16),
- PINMUX_IPSR_DATA(IP4_20_17, AUDATA6),
- PINMUX_IPSR_DATA(IP4_20_17, ARM_TRACEDATA_6),
+ PINMUX_IPSR_GPSR(IP4_20_17, DU0_DB0),
+ PINMUX_IPSR_GPSR(IP4_20_17, LCDOUT16),
+ PINMUX_IPSR_GPSR(IP4_20_17, AUDATA6),
+ PINMUX_IPSR_GPSR(IP4_20_17, ARM_TRACEDATA_6),
PINMUX_IPSR_MSEL(IP4_20_17, GPSCLK_A, SEL_GPS_A),
- PINMUX_IPSR_DATA(IP4_20_17, PWM0_A),
- PINMUX_IPSR_DATA(IP4_20_17, ADICLK),
+ PINMUX_IPSR_GPSR(IP4_20_17, PWM0_A),
+ PINMUX_IPSR_GPSR(IP4_20_17, ADICLK),
PINMUX_IPSR_MSEL(IP4_20_17, TS_SDAT0_B, SEL_TSIF0_B),
- PINMUX_IPSR_DATA(IP4_24_21, AUDIO_CLKC),
+ PINMUX_IPSR_GPSR(IP4_24_21, AUDIO_CLKC),
PINMUX_DATA(VI0_R1_B_MARK, FN_IP4_24_21, FN_VI0_R1_B, FN_SEL_VI0_B), /* see sel_vi0 */
PINMUX_DATA(VI0_R1_D_MARK, FN_IP4_24_21, FN_VI0_R1_B, FN_SEL_VI0_D), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP4_24_21, DU0_DB1),
- PINMUX_IPSR_DATA(IP4_24_21, LCDOUT17),
- PINMUX_IPSR_DATA(IP4_24_21, AUDATA7),
- PINMUX_IPSR_DATA(IP4_24_21, ARM_TRACEDATA_7),
+ PINMUX_IPSR_GPSR(IP4_24_21, DU0_DB1),
+ PINMUX_IPSR_GPSR(IP4_24_21, LCDOUT17),
+ PINMUX_IPSR_GPSR(IP4_24_21, AUDATA7),
+ PINMUX_IPSR_GPSR(IP4_24_21, ARM_TRACEDATA_7),
PINMUX_IPSR_MSEL(IP4_24_21, GPSIN_A, SEL_GPS_A),
- PINMUX_IPSR_DATA(IP4_24_21, ADICS_SAMP),
+ PINMUX_IPSR_GPSR(IP4_24_21, ADICS_SAMP),
PINMUX_IPSR_MSEL(IP4_24_21, TS_SCK0_B, SEL_TSIF0_B),
PINMUX_DATA(VI0_R2_B_MARK, FN_IP4_26_25, FN_VI0_R2_B, FN_SEL_VI0_B), /* see sel_vi0 */
PINMUX_DATA(VI0_R2_D_MARK, FN_IP4_26_25, FN_VI0_R2_B, FN_SEL_VI0_D), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP4_26_25, DU0_DB2),
- PINMUX_IPSR_DATA(IP4_26_25, LCDOUT18),
+ PINMUX_IPSR_GPSR(IP4_26_25, DU0_DB2),
+ PINMUX_IPSR_GPSR(IP4_26_25, LCDOUT18),
PINMUX_IPSR_MSEL(IP4_28_27, VI0_R3_B, SEL_VI0_B),
- PINMUX_IPSR_DATA(IP4_28_27, DU0_DB3),
- PINMUX_IPSR_DATA(IP4_28_27, LCDOUT19),
+ PINMUX_IPSR_GPSR(IP4_28_27, DU0_DB3),
+ PINMUX_IPSR_GPSR(IP4_28_27, LCDOUT19),
PINMUX_DATA(VI0_R4_B_MARK, FN_IP4_30_29, FN_VI0_R4_B, FN_SEL_VI0_B), /* see sel_vi0 */
PINMUX_DATA(VI0_R4_D_MARK, FN_IP4_30_29, FN_VI0_R4_B, FN_SEL_VI0_D), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP4_30_29, DU0_DB4),
- PINMUX_IPSR_DATA(IP4_30_29, LCDOUT20),
+ PINMUX_IPSR_GPSR(IP4_30_29, DU0_DB4),
+ PINMUX_IPSR_GPSR(IP4_30_29, LCDOUT20),
/* IPSR5 */
PINMUX_DATA(VI0_R5_B_MARK, FN_IP5_1_0, FN_VI0_R5_B, FN_SEL_VI0_B), /* see sel_vi0 */
PINMUX_DATA(VI0_R5_D_MARK, FN_IP5_1_0, FN_VI0_R5_B, FN_SEL_VI0_D), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP5_1_0, DU0_DB5),
- PINMUX_IPSR_DATA(IP5_1_0, LCDOUT21),
+ PINMUX_IPSR_GPSR(IP5_1_0, DU0_DB5),
+ PINMUX_IPSR_GPSR(IP5_1_0, LCDOUT21),
PINMUX_IPSR_MSEL(IP5_3_2, VI1_DATA10_B, SEL_VI1_B),
- PINMUX_IPSR_DATA(IP5_3_2, DU0_DB6),
- PINMUX_IPSR_DATA(IP5_3_2, LCDOUT22),
+ PINMUX_IPSR_GPSR(IP5_3_2, DU0_DB6),
+ PINMUX_IPSR_GPSR(IP5_3_2, LCDOUT22),
PINMUX_IPSR_MSEL(IP5_5_4, VI1_DATA11_B, SEL_VI1_B),
- PINMUX_IPSR_DATA(IP5_5_4, DU0_DB7),
- PINMUX_IPSR_DATA(IP5_5_4, LCDOUT23),
+ PINMUX_IPSR_GPSR(IP5_5_4, DU0_DB7),
+ PINMUX_IPSR_GPSR(IP5_5_4, LCDOUT23),
- PINMUX_IPSR_DATA(IP5_6, DU0_DOTCLKIN),
- PINMUX_IPSR_DATA(IP5_6, QSTVA_QVS),
+ PINMUX_IPSR_GPSR(IP5_6, DU0_DOTCLKIN),
+ PINMUX_IPSR_GPSR(IP5_6, QSTVA_QVS),
- PINMUX_IPSR_DATA(IP5_7, DU0_DOTCLKO_UT0),
- PINMUX_IPSR_DATA(IP5_7, QCLK),
+ PINMUX_IPSR_GPSR(IP5_7, DU0_DOTCLKO_UT0),
+ PINMUX_IPSR_GPSR(IP5_7, QCLK),
- PINMUX_IPSR_DATA(IP5_9_8, DU0_DOTCLKO_UT1),
- PINMUX_IPSR_DATA(IP5_9_8, QSTVB_QVE),
- PINMUX_IPSR_DATA(IP5_9_8, AUDIO_CLKOUT_A),
+ PINMUX_IPSR_GPSR(IP5_9_8, DU0_DOTCLKO_UT1),
+ PINMUX_IPSR_GPSR(IP5_9_8, QSTVB_QVE),
+ PINMUX_IPSR_GPSR(IP5_9_8, AUDIO_CLKOUT_A),
PINMUX_IPSR_MSEL(IP5_9_8, REMOCON_C, SEL_REMOCON_C),
PINMUX_IPSR_MSEL(IP5_11_10, SSI_WS2_B, SEL_SSI2_B),
- PINMUX_IPSR_DATA(IP5_11_10, DU0_EXHSYNC_DU0_HSYNC),
- PINMUX_IPSR_DATA(IP5_11_10, QSTH_QHS),
+ PINMUX_IPSR_GPSR(IP5_11_10, DU0_EXHSYNC_DU0_HSYNC),
+ PINMUX_IPSR_GPSR(IP5_11_10, QSTH_QHS),
- PINMUX_IPSR_DATA(IP5_12, DU0_EXVSYNC_DU0_VSYNC),
- PINMUX_IPSR_DATA(IP5_12, QSTB_QHE),
+ PINMUX_IPSR_GPSR(IP5_12, DU0_EXVSYNC_DU0_VSYNC),
+ PINMUX_IPSR_GPSR(IP5_12, QSTB_QHE),
- PINMUX_IPSR_DATA(IP5_14_13, DU0_EXODDF_DU0_ODDF_DISP_CDE),
- PINMUX_IPSR_DATA(IP5_14_13, QCPV_QDE),
+ PINMUX_IPSR_GPSR(IP5_14_13, DU0_EXODDF_DU0_ODDF_DISP_CDE),
+ PINMUX_IPSR_GPSR(IP5_14_13, QCPV_QDE),
PINMUX_IPSR_MSEL(IP5_14_13, FMCLK_D, SEL_FM_D),
PINMUX_IPSR_MSEL(IP5_17_15, SSI_SCK1_A, SEL_SSI1_A),
- PINMUX_IPSR_DATA(IP5_17_15, DU0_DISP),
- PINMUX_IPSR_DATA(IP5_17_15, QPOLA),
- PINMUX_IPSR_DATA(IP5_17_15, AUDCK),
- PINMUX_IPSR_DATA(IP5_17_15, ARM_TRACECLK),
- PINMUX_IPSR_DATA(IP5_17_15, BPFCLK_D),
+ PINMUX_IPSR_GPSR(IP5_17_15, DU0_DISP),
+ PINMUX_IPSR_GPSR(IP5_17_15, QPOLA),
+ PINMUX_IPSR_GPSR(IP5_17_15, AUDCK),
+ PINMUX_IPSR_GPSR(IP5_17_15, ARM_TRACECLK),
+ PINMUX_IPSR_GPSR(IP5_17_15, BPFCLK_D),
PINMUX_IPSR_MSEL(IP5_20_18, SSI_WS1_A, SEL_SSI1_A),
- PINMUX_IPSR_DATA(IP5_20_18, DU0_CDE),
- PINMUX_IPSR_DATA(IP5_20_18, QPOLB),
- PINMUX_IPSR_DATA(IP5_20_18, AUDSYNC),
- PINMUX_IPSR_DATA(IP5_20_18, ARM_TRACECTL),
+ PINMUX_IPSR_GPSR(IP5_20_18, DU0_CDE),
+ PINMUX_IPSR_GPSR(IP5_20_18, QPOLB),
+ PINMUX_IPSR_GPSR(IP5_20_18, AUDSYNC),
+ PINMUX_IPSR_GPSR(IP5_20_18, ARM_TRACECTL),
PINMUX_IPSR_MSEL(IP5_20_18, FMIN_D, SEL_FM_D),
PINMUX_IPSR_MSEL(IP5_22_21, SD1_CD_B, SEL_SD1_B),
- PINMUX_IPSR_DATA(IP5_22_21, SSI_SCK78),
+ PINMUX_IPSR_GPSR(IP5_22_21, SSI_SCK78),
PINMUX_IPSR_MSEL(IP5_22_21, HSPI_RX0_B, SEL_HSPI0_B),
- PINMUX_IPSR_DATA(IP5_22_21, TX1_B),
+ PINMUX_IPSR_GPSR(IP5_22_21, TX1_B),
PINMUX_IPSR_MSEL(IP5_25_23, SD1_WP_B, SEL_SD1_B),
- PINMUX_IPSR_DATA(IP5_25_23, SSI_WS78),
+ PINMUX_IPSR_GPSR(IP5_25_23, SSI_WS78),
PINMUX_IPSR_MSEL(IP5_25_23, HSPI_CLK0_B, SEL_HSPI0_B),
PINMUX_IPSR_MSEL(IP5_25_23, RX1_B, SEL_SCIF1_B),
PINMUX_IPSR_MSEL(IP5_25_23, CAN_CLK_D, SEL_CANCLK_D),
- PINMUX_IPSR_DATA(IP5_28_26, SSI_SDATA8),
+ PINMUX_IPSR_GPSR(IP5_28_26, SSI_SDATA8),
PINMUX_IPSR_MSEL(IP5_28_26, SSI_SCK2_A, SEL_SSI2_A),
PINMUX_IPSR_MSEL(IP5_28_26, HSPI_CS0_B, SEL_HSPI0_B),
- PINMUX_IPSR_DATA(IP5_28_26, TX2_A),
- PINMUX_IPSR_DATA(IP5_28_26, CAN0_TX_B),
+ PINMUX_IPSR_GPSR(IP5_28_26, TX2_A),
+ PINMUX_IPSR_GPSR(IP5_28_26, CAN0_TX_B),
- PINMUX_IPSR_DATA(IP5_30_29, SSI_SDATA7),
- PINMUX_IPSR_DATA(IP5_30_29, HSPI_TX0_B),
+ PINMUX_IPSR_GPSR(IP5_30_29, SSI_SDATA7),
+ PINMUX_IPSR_GPSR(IP5_30_29, HSPI_TX0_B),
PINMUX_IPSR_MSEL(IP5_30_29, RX2_A, SEL_SCIF2_A),
PINMUX_IPSR_MSEL(IP5_30_29, CAN0_RX_B, SEL_CAN0_B),
/* IPSR6 */
- PINMUX_IPSR_DATA(IP6_1_0, SSI_SCK6),
+ PINMUX_IPSR_GPSR(IP6_1_0, SSI_SCK6),
PINMUX_IPSR_MSEL(IP6_1_0, HSPI_RX2_A, SEL_HSPI2_A),
PINMUX_IPSR_MSEL(IP6_1_0, FMCLK_B, SEL_FM_B),
- PINMUX_IPSR_DATA(IP6_1_0, CAN1_TX_B),
+ PINMUX_IPSR_GPSR(IP6_1_0, CAN1_TX_B),
- PINMUX_IPSR_DATA(IP6_4_2, SSI_WS6),
+ PINMUX_IPSR_GPSR(IP6_4_2, SSI_WS6),
PINMUX_IPSR_MSEL(IP6_4_2, HSPI_CLK2_A, SEL_HSPI2_A),
- PINMUX_IPSR_DATA(IP6_4_2, BPFCLK_B),
+ PINMUX_IPSR_GPSR(IP6_4_2, BPFCLK_B),
PINMUX_IPSR_MSEL(IP6_4_2, CAN1_RX_B, SEL_CAN1_B),
- PINMUX_IPSR_DATA(IP6_6_5, SSI_SDATA6),
- PINMUX_IPSR_DATA(IP6_6_5, HSPI_TX2_A),
+ PINMUX_IPSR_GPSR(IP6_6_5, SSI_SDATA6),
+ PINMUX_IPSR_GPSR(IP6_6_5, HSPI_TX2_A),
PINMUX_IPSR_MSEL(IP6_6_5, FMIN_B, SEL_FM_B),
- PINMUX_IPSR_DATA(IP6_7, SSI_SCK5),
+ PINMUX_IPSR_GPSR(IP6_7, SSI_SCK5),
PINMUX_IPSR_MSEL(IP6_7, RX4_C, SEL_SCIF4_C),
- PINMUX_IPSR_DATA(IP6_8, SSI_WS5),
- PINMUX_IPSR_DATA(IP6_8, TX4_C),
+ PINMUX_IPSR_GPSR(IP6_8, SSI_WS5),
+ PINMUX_IPSR_GPSR(IP6_8, TX4_C),
- PINMUX_IPSR_DATA(IP6_9, SSI_SDATA5),
+ PINMUX_IPSR_GPSR(IP6_9, SSI_SDATA5),
PINMUX_IPSR_MSEL(IP6_9, RX0_D, SEL_SCIF0_D),
- PINMUX_IPSR_DATA(IP6_10, SSI_WS34),
- PINMUX_IPSR_DATA(IP6_10, ARM_TRACEDATA_8),
+ PINMUX_IPSR_GPSR(IP6_10, SSI_WS34),
+ PINMUX_IPSR_GPSR(IP6_10, ARM_TRACEDATA_8),
- PINMUX_IPSR_DATA(IP6_12_11, SSI_SDATA4),
+ PINMUX_IPSR_GPSR(IP6_12_11, SSI_SDATA4),
PINMUX_IPSR_MSEL(IP6_12_11, SSI_WS2_A, SEL_SSI2_A),
- PINMUX_IPSR_DATA(IP6_12_11, ARM_TRACEDATA_9),
+ PINMUX_IPSR_GPSR(IP6_12_11, ARM_TRACEDATA_9),
- PINMUX_IPSR_DATA(IP6_13, SSI_SDATA3),
- PINMUX_IPSR_DATA(IP6_13, ARM_TRACEDATA_10),
+ PINMUX_IPSR_GPSR(IP6_13, SSI_SDATA3),
+ PINMUX_IPSR_GPSR(IP6_13, ARM_TRACEDATA_10),
- PINMUX_IPSR_DATA(IP6_15_14, SSI_SCK012),
- PINMUX_IPSR_DATA(IP6_15_14, ARM_TRACEDATA_11),
- PINMUX_IPSR_DATA(IP6_15_14, TX0_D),
+ PINMUX_IPSR_GPSR(IP6_15_14, SSI_SCK012),
+ PINMUX_IPSR_GPSR(IP6_15_14, ARM_TRACEDATA_11),
+ PINMUX_IPSR_GPSR(IP6_15_14, TX0_D),
- PINMUX_IPSR_DATA(IP6_16, SSI_WS012),
- PINMUX_IPSR_DATA(IP6_16, ARM_TRACEDATA_12),
+ PINMUX_IPSR_GPSR(IP6_16, SSI_WS012),
+ PINMUX_IPSR_GPSR(IP6_16, ARM_TRACEDATA_12),
- PINMUX_IPSR_DATA(IP6_18_17, SSI_SDATA2),
+ PINMUX_IPSR_GPSR(IP6_18_17, SSI_SDATA2),
PINMUX_IPSR_MSEL(IP6_18_17, HSPI_CS2_A, SEL_HSPI2_A),
- PINMUX_IPSR_DATA(IP6_18_17, ARM_TRACEDATA_13),
+ PINMUX_IPSR_GPSR(IP6_18_17, ARM_TRACEDATA_13),
PINMUX_IPSR_MSEL(IP6_18_17, SDA1_A, SEL_I2C1_A),
- PINMUX_IPSR_DATA(IP6_20_19, SSI_SDATA1),
- PINMUX_IPSR_DATA(IP6_20_19, ARM_TRACEDATA_14),
+ PINMUX_IPSR_GPSR(IP6_20_19, SSI_SDATA1),
+ PINMUX_IPSR_GPSR(IP6_20_19, ARM_TRACEDATA_14),
PINMUX_IPSR_MSEL(IP6_20_19, SCL1_A, SEL_I2C1_A),
PINMUX_IPSR_MSEL(IP6_20_19, SCK2_A, SEL_SCIF2_A),
- PINMUX_IPSR_DATA(IP6_21, SSI_SDATA0),
- PINMUX_IPSR_DATA(IP6_21, ARM_TRACEDATA_15),
+ PINMUX_IPSR_GPSR(IP6_21, SSI_SDATA0),
+ PINMUX_IPSR_GPSR(IP6_21, ARM_TRACEDATA_15),
- PINMUX_IPSR_DATA(IP6_23_22, SD0_CLK),
- PINMUX_IPSR_DATA(IP6_23_22, SUB_TDO),
+ PINMUX_IPSR_GPSR(IP6_23_22, SD0_CLK),
+ PINMUX_IPSR_GPSR(IP6_23_22, SUB_TDO),
- PINMUX_IPSR_DATA(IP6_25_24, SD0_CMD),
- PINMUX_IPSR_DATA(IP6_25_24, SUB_TRST),
+ PINMUX_IPSR_GPSR(IP6_25_24, SD0_CMD),
+ PINMUX_IPSR_GPSR(IP6_25_24, SUB_TRST),
- PINMUX_IPSR_DATA(IP6_27_26, SD0_DAT0),
- PINMUX_IPSR_DATA(IP6_27_26, SUB_TMS),
+ PINMUX_IPSR_GPSR(IP6_27_26, SD0_DAT0),
+ PINMUX_IPSR_GPSR(IP6_27_26, SUB_TMS),
- PINMUX_IPSR_DATA(IP6_29_28, SD0_DAT1),
- PINMUX_IPSR_DATA(IP6_29_28, SUB_TCK),
+ PINMUX_IPSR_GPSR(IP6_29_28, SD0_DAT1),
+ PINMUX_IPSR_GPSR(IP6_29_28, SUB_TCK),
- PINMUX_IPSR_DATA(IP6_31_30, SD0_DAT2),
- PINMUX_IPSR_DATA(IP6_31_30, SUB_TDI),
+ PINMUX_IPSR_GPSR(IP6_31_30, SD0_DAT2),
+ PINMUX_IPSR_GPSR(IP6_31_30, SUB_TDI),
/* IPSR7 */
- PINMUX_IPSR_DATA(IP7_1_0, SD0_DAT3),
+ PINMUX_IPSR_GPSR(IP7_1_0, SD0_DAT3),
PINMUX_IPSR_MSEL(IP7_1_0, IRQ1_B, SEL_IRQ1_B),
- PINMUX_IPSR_DATA(IP7_3_2, SD0_CD),
- PINMUX_IPSR_DATA(IP7_3_2, TX5_A),
+ PINMUX_IPSR_GPSR(IP7_3_2, SD0_CD),
+ PINMUX_IPSR_GPSR(IP7_3_2, TX5_A),
- PINMUX_IPSR_DATA(IP7_5_4, SD0_WP),
+ PINMUX_IPSR_GPSR(IP7_5_4, SD0_WP),
PINMUX_IPSR_MSEL(IP7_5_4, RX5_A, SEL_SCIF5_A),
- PINMUX_IPSR_DATA(IP7_8_6, VI1_CLKENB),
+ PINMUX_IPSR_GPSR(IP7_8_6, VI1_CLKENB),
PINMUX_IPSR_MSEL(IP7_8_6, HSPI_CLK0_A, SEL_HSPI0_A),
- PINMUX_IPSR_DATA(IP7_8_6, HTX1_A),
+ PINMUX_IPSR_GPSR(IP7_8_6, HTX1_A),
PINMUX_IPSR_MSEL(IP7_8_6, RTS1_C, SEL_SCIF1_C),
- PINMUX_IPSR_DATA(IP7_11_9, VI1_FIELD),
+ PINMUX_IPSR_GPSR(IP7_11_9, VI1_FIELD),
PINMUX_IPSR_MSEL(IP7_11_9, HSPI_CS0_A, SEL_HSPI0_A),
PINMUX_IPSR_MSEL(IP7_11_9, HRX1_A, SEL_HSCIF1_A),
PINMUX_IPSR_MSEL(IP7_11_9, SCK1_C, SEL_SCIF1_C),
- PINMUX_IPSR_DATA(IP7_14_12, VI1_HSYNC),
+ PINMUX_IPSR_GPSR(IP7_14_12, VI1_HSYNC),
PINMUX_IPSR_MSEL(IP7_14_12, HSPI_RX0_A, SEL_HSPI0_A),
PINMUX_IPSR_MSEL(IP7_14_12, HRTS1_A, SEL_HSCIF1_A),
PINMUX_IPSR_MSEL(IP7_14_12, FMCLK_A, SEL_FM_A),
PINMUX_IPSR_MSEL(IP7_14_12, RX1_C, SEL_SCIF1_C),
- PINMUX_IPSR_DATA(IP7_17_15, VI1_VSYNC),
- PINMUX_IPSR_DATA(IP7_17_15, HSPI_TX0),
+ PINMUX_IPSR_GPSR(IP7_17_15, VI1_VSYNC),
+ PINMUX_IPSR_GPSR(IP7_17_15, HSPI_TX0),
PINMUX_IPSR_MSEL(IP7_17_15, HCTS1_A, SEL_HSCIF1_A),
- PINMUX_IPSR_DATA(IP7_17_15, BPFCLK_A),
- PINMUX_IPSR_DATA(IP7_17_15, TX1_C),
+ PINMUX_IPSR_GPSR(IP7_17_15, BPFCLK_A),
+ PINMUX_IPSR_GPSR(IP7_17_15, TX1_C),
- PINMUX_IPSR_DATA(IP7_20_18, TCLK0),
+ PINMUX_IPSR_GPSR(IP7_20_18, TCLK0),
PINMUX_IPSR_MSEL(IP7_20_18, HSCK1_A, SEL_HSCIF1_A),
PINMUX_IPSR_MSEL(IP7_20_18, FMIN_A, SEL_FM_A),
PINMUX_IPSR_MSEL(IP7_20_18, IRQ2_C, SEL_IRQ2_C),
PINMUX_IPSR_MSEL(IP7_20_18, CTS1_C, SEL_SCIF1_C),
- PINMUX_IPSR_DATA(IP7_20_18, SPEEDIN),
+ PINMUX_IPSR_GPSR(IP7_20_18, SPEEDIN),
- PINMUX_IPSR_DATA(IP7_21, VI0_CLK),
+ PINMUX_IPSR_GPSR(IP7_21, VI0_CLK),
PINMUX_IPSR_MSEL(IP7_21, CAN_CLK_A, SEL_CANCLK_A),
- PINMUX_IPSR_DATA(IP7_24_22, VI0_CLKENB),
+ PINMUX_IPSR_GPSR(IP7_24_22, VI0_CLKENB),
PINMUX_IPSR_MSEL(IP7_24_22, SD2_DAT2_B, SEL_SD2_B),
- PINMUX_IPSR_DATA(IP7_24_22, VI1_DATA0),
- PINMUX_IPSR_DATA(IP7_24_22, DU1_DG6),
+ PINMUX_IPSR_GPSR(IP7_24_22, VI1_DATA0),
+ PINMUX_IPSR_GPSR(IP7_24_22, DU1_DG6),
PINMUX_IPSR_MSEL(IP7_24_22, HSPI_RX1_A, SEL_HSPI1_A),
PINMUX_IPSR_MSEL(IP7_24_22, RX4_B, SEL_SCIF4_B),
- PINMUX_IPSR_DATA(IP7_28_25, VI0_FIELD),
+ PINMUX_IPSR_GPSR(IP7_28_25, VI0_FIELD),
PINMUX_IPSR_MSEL(IP7_28_25, SD2_DAT3_B, SEL_SD2_B),
PINMUX_DATA(VI0_R3_C_MARK, FN_IP7_28_25, FN_VI0_R3_C, FN_SEL_VI0_C), /* see sel_vi0 */
PINMUX_DATA(VI0_R3_D_MARK, FN_IP7_28_25, FN_VI0_R3_C, FN_SEL_VI0_D), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP7_28_25, VI1_DATA1),
- PINMUX_IPSR_DATA(IP7_28_25, DU1_DG7),
+ PINMUX_IPSR_GPSR(IP7_28_25, VI1_DATA1),
+ PINMUX_IPSR_GPSR(IP7_28_25, DU1_DG7),
PINMUX_IPSR_MSEL(IP7_28_25, HSPI_CLK1_A, SEL_HSPI1_A),
- PINMUX_IPSR_DATA(IP7_28_25, TX4_B),
+ PINMUX_IPSR_GPSR(IP7_28_25, TX4_B),
- PINMUX_IPSR_DATA(IP7_31_29, VI0_HSYNC),
+ PINMUX_IPSR_GPSR(IP7_31_29, VI0_HSYNC),
PINMUX_IPSR_MSEL(IP7_31_29, SD2_CD_B, SEL_SD2_B),
- PINMUX_IPSR_DATA(IP7_31_29, VI1_DATA2),
- PINMUX_IPSR_DATA(IP7_31_29, DU1_DR2),
+ PINMUX_IPSR_GPSR(IP7_31_29, VI1_DATA2),
+ PINMUX_IPSR_GPSR(IP7_31_29, DU1_DR2),
PINMUX_IPSR_MSEL(IP7_31_29, HSPI_CS1_A, SEL_HSPI1_A),
PINMUX_IPSR_MSEL(IP7_31_29, RX3_B, SEL_SCIF3_B),
/* IPSR8 */
- PINMUX_IPSR_DATA(IP8_2_0, VI0_VSYNC),
+ PINMUX_IPSR_GPSR(IP8_2_0, VI0_VSYNC),
PINMUX_IPSR_MSEL(IP8_2_0, SD2_WP_B, SEL_SD2_B),
- PINMUX_IPSR_DATA(IP8_2_0, VI1_DATA3),
- PINMUX_IPSR_DATA(IP8_2_0, DU1_DR3),
- PINMUX_IPSR_DATA(IP8_2_0, HSPI_TX1_A),
- PINMUX_IPSR_DATA(IP8_2_0, TX3_B),
+ PINMUX_IPSR_GPSR(IP8_2_0, VI1_DATA3),
+ PINMUX_IPSR_GPSR(IP8_2_0, DU1_DR3),
+ PINMUX_IPSR_GPSR(IP8_2_0, HSPI_TX1_A),
+ PINMUX_IPSR_GPSR(IP8_2_0, TX3_B),
- PINMUX_IPSR_DATA(IP8_5_3, VI0_DATA0_VI0_B0),
- PINMUX_IPSR_DATA(IP8_5_3, DU1_DG2),
+ PINMUX_IPSR_GPSR(IP8_5_3, VI0_DATA0_VI0_B0),
+ PINMUX_IPSR_GPSR(IP8_5_3, DU1_DG2),
PINMUX_IPSR_MSEL(IP8_5_3, IRQ2_B, SEL_IRQ2_B),
PINMUX_IPSR_MSEL(IP8_5_3, RX3_D, SEL_SCIF3_D),
- PINMUX_IPSR_DATA(IP8_8_6, VI0_DATA1_VI0_B1),
- PINMUX_IPSR_DATA(IP8_8_6, DU1_DG3),
+ PINMUX_IPSR_GPSR(IP8_8_6, VI0_DATA1_VI0_B1),
+ PINMUX_IPSR_GPSR(IP8_8_6, DU1_DG3),
PINMUX_IPSR_MSEL(IP8_8_6, IRQ3_B, SEL_IRQ3_B),
- PINMUX_IPSR_DATA(IP8_8_6, TX3_D),
+ PINMUX_IPSR_GPSR(IP8_8_6, TX3_D),
- PINMUX_IPSR_DATA(IP8_10_9, VI0_DATA2_VI0_B2),
- PINMUX_IPSR_DATA(IP8_10_9, DU1_DG4),
+ PINMUX_IPSR_GPSR(IP8_10_9, VI0_DATA2_VI0_B2),
+ PINMUX_IPSR_GPSR(IP8_10_9, DU1_DG4),
PINMUX_IPSR_MSEL(IP8_10_9, RX0_C, SEL_SCIF0_C),
- PINMUX_IPSR_DATA(IP8_13_11, VI0_DATA3_VI0_B3),
- PINMUX_IPSR_DATA(IP8_13_11, DU1_DG5),
- PINMUX_IPSR_DATA(IP8_13_11, TX1_A),
- PINMUX_IPSR_DATA(IP8_13_11, TX0_C),
+ PINMUX_IPSR_GPSR(IP8_13_11, VI0_DATA3_VI0_B3),
+ PINMUX_IPSR_GPSR(IP8_13_11, DU1_DG5),
+ PINMUX_IPSR_GPSR(IP8_13_11, TX1_A),
+ PINMUX_IPSR_GPSR(IP8_13_11, TX0_C),
- PINMUX_IPSR_DATA(IP8_15_14, VI0_DATA4_VI0_B4),
- PINMUX_IPSR_DATA(IP8_15_14, DU1_DB2),
+ PINMUX_IPSR_GPSR(IP8_15_14, VI0_DATA4_VI0_B4),
+ PINMUX_IPSR_GPSR(IP8_15_14, DU1_DB2),
PINMUX_IPSR_MSEL(IP8_15_14, RX1_A, SEL_SCIF1_A),
- PINMUX_IPSR_DATA(IP8_18_16, VI0_DATA5_VI0_B5),
- PINMUX_IPSR_DATA(IP8_18_16, DU1_DB3),
+ PINMUX_IPSR_GPSR(IP8_18_16, VI0_DATA5_VI0_B5),
+ PINMUX_IPSR_GPSR(IP8_18_16, DU1_DB3),
PINMUX_IPSR_MSEL(IP8_18_16, SCK1_A, SEL_SCIF1_A),
- PINMUX_IPSR_DATA(IP8_18_16, PWM4),
+ PINMUX_IPSR_GPSR(IP8_18_16, PWM4),
PINMUX_IPSR_MSEL(IP8_18_16, HSCK1_B, SEL_HSCIF1_B),
- PINMUX_IPSR_DATA(IP8_21_19, VI0_DATA6_VI0_G0),
- PINMUX_IPSR_DATA(IP8_21_19, DU1_DB4),
+ PINMUX_IPSR_GPSR(IP8_21_19, VI0_DATA6_VI0_G0),
+ PINMUX_IPSR_GPSR(IP8_21_19, DU1_DB4),
PINMUX_IPSR_MSEL(IP8_21_19, CTS1_A, SEL_SCIF1_A),
- PINMUX_IPSR_DATA(IP8_21_19, PWM5),
+ PINMUX_IPSR_GPSR(IP8_21_19, PWM5),
- PINMUX_IPSR_DATA(IP8_23_22, VI0_DATA7_VI0_G1),
- PINMUX_IPSR_DATA(IP8_23_22, DU1_DB5),
+ PINMUX_IPSR_GPSR(IP8_23_22, VI0_DATA7_VI0_G1),
+ PINMUX_IPSR_GPSR(IP8_23_22, DU1_DB5),
PINMUX_IPSR_MSEL(IP8_23_22, RTS1_A, SEL_SCIF1_A),
- PINMUX_IPSR_DATA(IP8_26_24, VI0_G2),
- PINMUX_IPSR_DATA(IP8_26_24, SD2_CLK_B),
- PINMUX_IPSR_DATA(IP8_26_24, VI1_DATA4),
- PINMUX_IPSR_DATA(IP8_26_24, DU1_DR4),
- PINMUX_IPSR_DATA(IP8_26_24, HTX1_B),
+ PINMUX_IPSR_GPSR(IP8_26_24, VI0_G2),
+ PINMUX_IPSR_GPSR(IP8_26_24, SD2_CLK_B),
+ PINMUX_IPSR_GPSR(IP8_26_24, VI1_DATA4),
+ PINMUX_IPSR_GPSR(IP8_26_24, DU1_DR4),
+ PINMUX_IPSR_GPSR(IP8_26_24, HTX1_B),
- PINMUX_IPSR_DATA(IP8_29_27, VI0_G3),
+ PINMUX_IPSR_GPSR(IP8_29_27, VI0_G3),
PINMUX_IPSR_MSEL(IP8_29_27, SD2_CMD_B, SEL_SD2_B),
- PINMUX_IPSR_DATA(IP8_29_27, VI1_DATA5),
- PINMUX_IPSR_DATA(IP8_29_27, DU1_DR5),
+ PINMUX_IPSR_GPSR(IP8_29_27, VI1_DATA5),
+ PINMUX_IPSR_GPSR(IP8_29_27, DU1_DR5),
PINMUX_IPSR_MSEL(IP8_29_27, HRX1_B, SEL_HSCIF1_B),
/* IPSR9 */
- PINMUX_IPSR_DATA(IP9_2_0, VI0_G4),
+ PINMUX_IPSR_GPSR(IP9_2_0, VI0_G4),
PINMUX_IPSR_MSEL(IP9_2_0, SD2_DAT0_B, SEL_SD2_B),
- PINMUX_IPSR_DATA(IP9_2_0, VI1_DATA6),
- PINMUX_IPSR_DATA(IP9_2_0, DU1_DR6),
+ PINMUX_IPSR_GPSR(IP9_2_0, VI1_DATA6),
+ PINMUX_IPSR_GPSR(IP9_2_0, DU1_DR6),
PINMUX_IPSR_MSEL(IP9_2_0, HRTS1_B, SEL_HSCIF1_B),
- PINMUX_IPSR_DATA(IP9_5_3, VI0_G5),
+ PINMUX_IPSR_GPSR(IP9_5_3, VI0_G5),
PINMUX_IPSR_MSEL(IP9_5_3, SD2_DAT1_B, SEL_SD2_B),
- PINMUX_IPSR_DATA(IP9_5_3, VI1_DATA7),
- PINMUX_IPSR_DATA(IP9_5_3, DU1_DR7),
+ PINMUX_IPSR_GPSR(IP9_5_3, VI1_DATA7),
+ PINMUX_IPSR_GPSR(IP9_5_3, DU1_DR7),
PINMUX_IPSR_MSEL(IP9_5_3, HCTS1_B, SEL_HSCIF1_B),
PINMUX_DATA(VI0_R0_A_MARK, FN_IP9_8_6, FN_VI0_R0_A, FN_SEL_VI0_A), /* see sel_vi0 */
PINMUX_DATA(VI0_R0_C_MARK, FN_IP9_8_6, FN_VI0_R0_A, FN_SEL_VI0_C), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP9_8_6, VI1_CLK),
- PINMUX_IPSR_DATA(IP9_8_6, ETH_REF_CLK),
- PINMUX_IPSR_DATA(IP9_8_6, DU1_DOTCLKIN),
+ PINMUX_IPSR_GPSR(IP9_8_6, VI1_CLK),
+ PINMUX_IPSR_GPSR(IP9_8_6, ETH_REF_CLK),
+ PINMUX_IPSR_GPSR(IP9_8_6, DU1_DOTCLKIN),
PINMUX_DATA(VI0_R1_A_MARK, FN_IP9_11_9, FN_VI0_R1_A, FN_SEL_VI0_A), /* see sel_vi0 */
PINMUX_DATA(VI0_R1_C_MARK, FN_IP9_11_9, FN_VI0_R1_A, FN_SEL_VI0_C), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP9_11_9, VI1_DATA8),
- PINMUX_IPSR_DATA(IP9_11_9, DU1_DB6),
- PINMUX_IPSR_DATA(IP9_11_9, ETH_TXD0),
- PINMUX_IPSR_DATA(IP9_11_9, PWM2),
- PINMUX_IPSR_DATA(IP9_11_9, TCLK1),
+ PINMUX_IPSR_GPSR(IP9_11_9, VI1_DATA8),
+ PINMUX_IPSR_GPSR(IP9_11_9, DU1_DB6),
+ PINMUX_IPSR_GPSR(IP9_11_9, ETH_TXD0),
+ PINMUX_IPSR_GPSR(IP9_11_9, PWM2),
+ PINMUX_IPSR_GPSR(IP9_11_9, TCLK1),
PINMUX_DATA(VI0_R2_A_MARK, FN_IP9_14_12, FN_VI0_R2_A, FN_SEL_VI0_A), /* see sel_vi0 */
PINMUX_DATA(VI0_R2_C_MARK, FN_IP9_14_12, FN_VI0_R2_A, FN_SEL_VI0_C), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP9_14_12, VI1_DATA9),
- PINMUX_IPSR_DATA(IP9_14_12, DU1_DB7),
- PINMUX_IPSR_DATA(IP9_14_12, ETH_TXD1),
- PINMUX_IPSR_DATA(IP9_14_12, PWM3),
+ PINMUX_IPSR_GPSR(IP9_14_12, VI1_DATA9),
+ PINMUX_IPSR_GPSR(IP9_14_12, DU1_DB7),
+ PINMUX_IPSR_GPSR(IP9_14_12, ETH_TXD1),
+ PINMUX_IPSR_GPSR(IP9_14_12, PWM3),
PINMUX_IPSR_MSEL(IP9_17_15, VI0_R3_A, SEL_VI0_A),
- PINMUX_IPSR_DATA(IP9_17_15, ETH_CRS_DV),
- PINMUX_IPSR_DATA(IP9_17_15, IECLK),
+ PINMUX_IPSR_GPSR(IP9_17_15, ETH_CRS_DV),
+ PINMUX_IPSR_GPSR(IP9_17_15, IECLK),
PINMUX_IPSR_MSEL(IP9_17_15, SCK2_C, SEL_SCIF2_C),
PINMUX_DATA(VI0_R4_A_MARK, FN_IP9_20_18, FN_VI0_R4_A, FN_SEL_VI0_A), /* see sel_vi0 */
PINMUX_DATA(VI0_R3_C_MARK, FN_IP9_20_18, FN_VI0_R4_A, FN_SEL_VI0_C), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP9_20_18, ETH_TX_EN),
- PINMUX_IPSR_DATA(IP9_20_18, IETX),
- PINMUX_IPSR_DATA(IP9_20_18, TX2_C),
+ PINMUX_IPSR_GPSR(IP9_20_18, ETH_TX_EN),
+ PINMUX_IPSR_GPSR(IP9_20_18, IETX),
+ PINMUX_IPSR_GPSR(IP9_20_18, TX2_C),
PINMUX_DATA(VI0_R5_A_MARK, FN_IP9_23_21, FN_VI0_R5_A, FN_SEL_VI0_A), /* see sel_vi0 */
PINMUX_DATA(VI0_R5_C_MARK, FN_IP9_23_21, FN_VI0_R5_A, FN_SEL_VI0_C), /* see sel_vi0 */
- PINMUX_IPSR_DATA(IP9_23_21, ETH_RX_ER),
+ PINMUX_IPSR_GPSR(IP9_23_21, ETH_RX_ER),
PINMUX_IPSR_MSEL(IP9_23_21, FMCLK_C, SEL_FM_C),
- PINMUX_IPSR_DATA(IP9_23_21, IERX),
+ PINMUX_IPSR_GPSR(IP9_23_21, IERX),
PINMUX_IPSR_MSEL(IP9_23_21, RX2_C, SEL_SCIF2_C),
PINMUX_IPSR_MSEL(IP9_26_24, VI1_DATA10_A, SEL_VI1_A),
- PINMUX_IPSR_DATA(IP9_26_24, DU1_DOTCLKOUT),
- PINMUX_IPSR_DATA(IP9_26_24, ETH_RXD0),
- PINMUX_IPSR_DATA(IP9_26_24, BPFCLK_C),
- PINMUX_IPSR_DATA(IP9_26_24, TX2_D),
+ PINMUX_IPSR_GPSR(IP9_26_24, DU1_DOTCLKOUT),
+ PINMUX_IPSR_GPSR(IP9_26_24, ETH_RXD0),
+ PINMUX_IPSR_GPSR(IP9_26_24, BPFCLK_C),
+ PINMUX_IPSR_GPSR(IP9_26_24, TX2_D),
PINMUX_IPSR_MSEL(IP9_26_24, SDA2_C, SEL_I2C2_C),
PINMUX_IPSR_MSEL(IP9_29_27, VI1_DATA11_A, SEL_VI1_A),
- PINMUX_IPSR_DATA(IP9_29_27, DU1_EXHSYNC_DU1_HSYNC),
- PINMUX_IPSR_DATA(IP9_29_27, ETH_RXD1),
+ PINMUX_IPSR_GPSR(IP9_29_27, DU1_EXHSYNC_DU1_HSYNC),
+ PINMUX_IPSR_GPSR(IP9_29_27, ETH_RXD1),
PINMUX_IPSR_MSEL(IP9_29_27, FMIN_C, SEL_FM_C),
PINMUX_IPSR_MSEL(IP9_29_27, RX2_D, SEL_SCIF2_D),
PINMUX_IPSR_MSEL(IP9_29_27, SCL2_C, SEL_I2C2_C),
/* IPSR10 */
- PINMUX_IPSR_DATA(IP10_2_0, SD2_CLK_A),
- PINMUX_IPSR_DATA(IP10_2_0, DU1_EXVSYNC_DU1_VSYNC),
- PINMUX_IPSR_DATA(IP10_2_0, ATARD1),
- PINMUX_IPSR_DATA(IP10_2_0, ETH_MDC),
+ PINMUX_IPSR_GPSR(IP10_2_0, SD2_CLK_A),
+ PINMUX_IPSR_GPSR(IP10_2_0, DU1_EXVSYNC_DU1_VSYNC),
+ PINMUX_IPSR_GPSR(IP10_2_0, ATARD1),
+ PINMUX_IPSR_GPSR(IP10_2_0, ETH_MDC),
PINMUX_IPSR_MSEL(IP10_2_0, SDA1_B, SEL_I2C1_B),
PINMUX_IPSR_MSEL(IP10_5_3, SD2_CMD_A, SEL_SD2_A),
- PINMUX_IPSR_DATA(IP10_5_3, DU1_EXODDF_DU1_ODDF_DISP_CDE),
- PINMUX_IPSR_DATA(IP10_5_3, ATAWR1),
- PINMUX_IPSR_DATA(IP10_5_3, ETH_MDIO),
+ PINMUX_IPSR_GPSR(IP10_5_3, DU1_EXODDF_DU1_ODDF_DISP_CDE),
+ PINMUX_IPSR_GPSR(IP10_5_3, ATAWR1),
+ PINMUX_IPSR_GPSR(IP10_5_3, ETH_MDIO),
PINMUX_IPSR_MSEL(IP10_5_3, SCL1_B, SEL_I2C1_B),
PINMUX_IPSR_MSEL(IP10_8_6, SD2_DAT0_A, SEL_SD2_A),
- PINMUX_IPSR_DATA(IP10_8_6, DU1_DISP),
- PINMUX_IPSR_DATA(IP10_8_6, ATACS01),
+ PINMUX_IPSR_GPSR(IP10_8_6, DU1_DISP),
+ PINMUX_IPSR_GPSR(IP10_8_6, ATACS01),
PINMUX_IPSR_MSEL(IP10_8_6, DREQ1_B, SEL_DREQ1_B),
- PINMUX_IPSR_DATA(IP10_8_6, ETH_LINK),
+ PINMUX_IPSR_GPSR(IP10_8_6, ETH_LINK),
PINMUX_IPSR_MSEL(IP10_8_6, CAN1_RX_A, SEL_CAN1_A),
PINMUX_IPSR_MSEL(IP10_12_9, SD2_DAT1_A, SEL_SD2_A),
- PINMUX_IPSR_DATA(IP10_12_9, DU1_CDE),
- PINMUX_IPSR_DATA(IP10_12_9, ATACS11),
- PINMUX_IPSR_DATA(IP10_12_9, DACK1_B),
- PINMUX_IPSR_DATA(IP10_12_9, ETH_MAGIC),
- PINMUX_IPSR_DATA(IP10_12_9, CAN1_TX_A),
- PINMUX_IPSR_DATA(IP10_12_9, PWM6),
+ PINMUX_IPSR_GPSR(IP10_12_9, DU1_CDE),
+ PINMUX_IPSR_GPSR(IP10_12_9, ATACS11),
+ PINMUX_IPSR_GPSR(IP10_12_9, DACK1_B),
+ PINMUX_IPSR_GPSR(IP10_12_9, ETH_MAGIC),
+ PINMUX_IPSR_GPSR(IP10_12_9, CAN1_TX_A),
+ PINMUX_IPSR_GPSR(IP10_12_9, PWM6),
PINMUX_IPSR_MSEL(IP10_15_13, SD2_DAT2_A, SEL_SD2_A),
- PINMUX_IPSR_DATA(IP10_15_13, VI1_DATA12),
+ PINMUX_IPSR_GPSR(IP10_15_13, VI1_DATA12),
PINMUX_IPSR_MSEL(IP10_15_13, DREQ2_B, SEL_DREQ2_B),
- PINMUX_IPSR_DATA(IP10_15_13, ATADIR1),
+ PINMUX_IPSR_GPSR(IP10_15_13, ATADIR1),
PINMUX_IPSR_MSEL(IP10_15_13, HSPI_CLK2_B, SEL_HSPI2_B),
PINMUX_IPSR_MSEL(IP10_15_13, GPSCLK_B, SEL_GPS_B),
PINMUX_IPSR_MSEL(IP10_18_16, SD2_DAT3_A, SEL_SD2_A),
- PINMUX_IPSR_DATA(IP10_18_16, VI1_DATA13),
- PINMUX_IPSR_DATA(IP10_18_16, DACK2_B),
- PINMUX_IPSR_DATA(IP10_18_16, ATAG1),
+ PINMUX_IPSR_GPSR(IP10_18_16, VI1_DATA13),
+ PINMUX_IPSR_GPSR(IP10_18_16, DACK2_B),
+ PINMUX_IPSR_GPSR(IP10_18_16, ATAG1),
PINMUX_IPSR_MSEL(IP10_18_16, HSPI_CS2_B, SEL_HSPI2_B),
PINMUX_IPSR_MSEL(IP10_18_16, GPSIN_B, SEL_GPS_B),
PINMUX_IPSR_MSEL(IP10_21_19, SD2_CD_A, SEL_SD2_A),
- PINMUX_IPSR_DATA(IP10_21_19, VI1_DATA14),
+ PINMUX_IPSR_GPSR(IP10_21_19, VI1_DATA14),
PINMUX_IPSR_MSEL(IP10_21_19, EX_WAIT1_B, SEL_WAIT1_B),
PINMUX_IPSR_MSEL(IP10_21_19, DREQ0_B, SEL_DREQ0_B),
PINMUX_IPSR_MSEL(IP10_21_19, HSPI_RX2_B, SEL_HSPI2_B),
PINMUX_IPSR_MSEL(IP10_21_19, REMOCON_A, SEL_REMOCON_A),
PINMUX_IPSR_MSEL(IP10_24_22, SD2_WP_A, SEL_SD2_A),
- PINMUX_IPSR_DATA(IP10_24_22, VI1_DATA15),
+ PINMUX_IPSR_GPSR(IP10_24_22, VI1_DATA15),
PINMUX_IPSR_MSEL(IP10_24_22, EX_WAIT2_B, SEL_WAIT2_B),
- PINMUX_IPSR_DATA(IP10_24_22, DACK0_B),
- PINMUX_IPSR_DATA(IP10_24_22, HSPI_TX2_B),
+ PINMUX_IPSR_GPSR(IP10_24_22, DACK0_B),
+ PINMUX_IPSR_GPSR(IP10_24_22, HSPI_TX2_B),
PINMUX_IPSR_MSEL(IP10_24_22, CAN_CLK_C, SEL_CANCLK_C),
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
index bd17eccb6a89..5bef934f823d 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
@@ -611,577 +611,577 @@ static const u16 pinmux_data[] = {
PINMUX_SINGLE(USB_PENC0),
PINMUX_SINGLE(USB_PENC1),
- PINMUX_IPSR_DATA(IP0_2_0, USB_PENC2),
+ PINMUX_IPSR_GPSR(IP0_2_0, USB_PENC2),
PINMUX_IPSR_MSEL(IP0_2_0, SCK0, SEL_SCIF0_0),
- PINMUX_IPSR_DATA(IP0_2_0, PWM1),
+ PINMUX_IPSR_GPSR(IP0_2_0, PWM1),
PINMUX_IPSR_MSEL(IP0_2_0, PWMFSW0, SEL_PWMFSW_0),
PINMUX_IPSR_MSEL(IP0_2_0, SCIF_CLK, SEL_SCIF_0),
PINMUX_IPSR_MSEL(IP0_2_0, TCLK0_C, SEL_TMU0_2),
- PINMUX_IPSR_DATA(IP0_5_3, BS),
- PINMUX_IPSR_DATA(IP0_5_3, SD1_DAT2),
- PINMUX_IPSR_DATA(IP0_5_3, MMC0_D2),
- PINMUX_IPSR_DATA(IP0_5_3, FD2),
- PINMUX_IPSR_DATA(IP0_5_3, ATADIR0),
- PINMUX_IPSR_DATA(IP0_5_3, SDSELF),
+ PINMUX_IPSR_GPSR(IP0_5_3, BS),
+ PINMUX_IPSR_GPSR(IP0_5_3, SD1_DAT2),
+ PINMUX_IPSR_GPSR(IP0_5_3, MMC0_D2),
+ PINMUX_IPSR_GPSR(IP0_5_3, FD2),
+ PINMUX_IPSR_GPSR(IP0_5_3, ATADIR0),
+ PINMUX_IPSR_GPSR(IP0_5_3, SDSELF),
PINMUX_IPSR_MSEL(IP0_5_3, HCTS1, SEL_HSCIF1_0),
- PINMUX_IPSR_DATA(IP0_5_3, TX4_C),
- PINMUX_IPSR_DATA(IP0_7_6, A0),
- PINMUX_IPSR_DATA(IP0_7_6, SD1_DAT3),
- PINMUX_IPSR_DATA(IP0_7_6, MMC0_D3),
- PINMUX_IPSR_DATA(IP0_7_6, FD3),
- PINMUX_IPSR_DATA(IP0_9_8, A20),
- PINMUX_IPSR_DATA(IP0_9_8, TX5_D),
- PINMUX_IPSR_DATA(IP0_9_8, HSPI_TX2_B),
- PINMUX_IPSR_DATA(IP0_11_10, A21),
+ PINMUX_IPSR_GPSR(IP0_5_3, TX4_C),
+ PINMUX_IPSR_GPSR(IP0_7_6, A0),
+ PINMUX_IPSR_GPSR(IP0_7_6, SD1_DAT3),
+ PINMUX_IPSR_GPSR(IP0_7_6, MMC0_D3),
+ PINMUX_IPSR_GPSR(IP0_7_6, FD3),
+ PINMUX_IPSR_GPSR(IP0_9_8, A20),
+ PINMUX_IPSR_GPSR(IP0_9_8, TX5_D),
+ PINMUX_IPSR_GPSR(IP0_9_8, HSPI_TX2_B),
+ PINMUX_IPSR_GPSR(IP0_11_10, A21),
PINMUX_IPSR_MSEL(IP0_11_10, SCK5_D, SEL_SCIF5_3),
PINMUX_IPSR_MSEL(IP0_11_10, HSPI_CLK2_B, SEL_HSPI2_1),
- PINMUX_IPSR_DATA(IP0_13_12, A22),
+ PINMUX_IPSR_GPSR(IP0_13_12, A22),
PINMUX_IPSR_MSEL(IP0_13_12, RX5_D, SEL_SCIF5_3),
PINMUX_IPSR_MSEL(IP0_13_12, HSPI_RX2_B, SEL_HSPI2_1),
- PINMUX_IPSR_DATA(IP0_13_12, VI1_R0),
- PINMUX_IPSR_DATA(IP0_15_14, A23),
- PINMUX_IPSR_DATA(IP0_15_14, FCLE),
+ PINMUX_IPSR_GPSR(IP0_13_12, VI1_R0),
+ PINMUX_IPSR_GPSR(IP0_15_14, A23),
+ PINMUX_IPSR_GPSR(IP0_15_14, FCLE),
PINMUX_IPSR_MSEL(IP0_15_14, HSPI_CLK2, SEL_HSPI2_0),
- PINMUX_IPSR_DATA(IP0_15_14, VI1_R1),
- PINMUX_IPSR_DATA(IP0_18_16, A24),
- PINMUX_IPSR_DATA(IP0_18_16, SD1_CD),
- PINMUX_IPSR_DATA(IP0_18_16, MMC0_D4),
- PINMUX_IPSR_DATA(IP0_18_16, FD4),
+ PINMUX_IPSR_GPSR(IP0_15_14, VI1_R1),
+ PINMUX_IPSR_GPSR(IP0_18_16, A24),
+ PINMUX_IPSR_GPSR(IP0_18_16, SD1_CD),
+ PINMUX_IPSR_GPSR(IP0_18_16, MMC0_D4),
+ PINMUX_IPSR_GPSR(IP0_18_16, FD4),
PINMUX_IPSR_MSEL(IP0_18_16, HSPI_CS2, SEL_HSPI2_0),
- PINMUX_IPSR_DATA(IP0_18_16, VI1_R2),
+ PINMUX_IPSR_GPSR(IP0_18_16, VI1_R2),
PINMUX_IPSR_MSEL(IP0_18_16, SSI_WS78_B, SEL_SSI7_1),
- PINMUX_IPSR_DATA(IP0_22_19, A25),
- PINMUX_IPSR_DATA(IP0_22_19, SD1_WP),
- PINMUX_IPSR_DATA(IP0_22_19, MMC0_D5),
- PINMUX_IPSR_DATA(IP0_22_19, FD5),
+ PINMUX_IPSR_GPSR(IP0_22_19, A25),
+ PINMUX_IPSR_GPSR(IP0_22_19, SD1_WP),
+ PINMUX_IPSR_GPSR(IP0_22_19, MMC0_D5),
+ PINMUX_IPSR_GPSR(IP0_22_19, FD5),
PINMUX_IPSR_MSEL(IP0_22_19, HSPI_RX2, SEL_HSPI2_0),
- PINMUX_IPSR_DATA(IP0_22_19, VI1_R3),
- PINMUX_IPSR_DATA(IP0_22_19, TX5_B),
+ PINMUX_IPSR_GPSR(IP0_22_19, VI1_R3),
+ PINMUX_IPSR_GPSR(IP0_22_19, TX5_B),
PINMUX_IPSR_MSEL(IP0_22_19, SSI_SDATA7_B, SEL_SSI7_1),
PINMUX_IPSR_MSEL(IP0_22_19, CTS0_B, SEL_SCIF0_1),
- PINMUX_IPSR_DATA(IP0_24_23, CLKOUT),
- PINMUX_IPSR_DATA(IP0_24_23, TX3C_IRDA_TX_C),
- PINMUX_IPSR_DATA(IP0_24_23, PWM0_B),
- PINMUX_IPSR_DATA(IP0_25, CS0),
+ PINMUX_IPSR_GPSR(IP0_24_23, CLKOUT),
+ PINMUX_IPSR_GPSR(IP0_24_23, TX3C_IRDA_TX_C),
+ PINMUX_IPSR_GPSR(IP0_24_23, PWM0_B),
+ PINMUX_IPSR_GPSR(IP0_25, CS0),
PINMUX_IPSR_MSEL(IP0_25, HSPI_CS2_B, SEL_HSPI2_1),
- PINMUX_IPSR_DATA(IP0_27_26, CS1_A26),
- PINMUX_IPSR_DATA(IP0_27_26, HSPI_TX2),
- PINMUX_IPSR_DATA(IP0_27_26, SDSELF_B),
- PINMUX_IPSR_DATA(IP0_30_28, RD_WR),
- PINMUX_IPSR_DATA(IP0_30_28, FWE),
- PINMUX_IPSR_DATA(IP0_30_28, ATAG0),
- PINMUX_IPSR_DATA(IP0_30_28, VI1_R7),
+ PINMUX_IPSR_GPSR(IP0_27_26, CS1_A26),
+ PINMUX_IPSR_GPSR(IP0_27_26, HSPI_TX2),
+ PINMUX_IPSR_GPSR(IP0_27_26, SDSELF_B),
+ PINMUX_IPSR_GPSR(IP0_30_28, RD_WR),
+ PINMUX_IPSR_GPSR(IP0_30_28, FWE),
+ PINMUX_IPSR_GPSR(IP0_30_28, ATAG0),
+ PINMUX_IPSR_GPSR(IP0_30_28, VI1_R7),
PINMUX_IPSR_MSEL(IP0_30_28, HRTS1, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP0_30_28, RX4_C, SEL_SCIF4_2),
- PINMUX_IPSR_DATA(IP1_1_0, EX_CS0),
+ PINMUX_IPSR_GPSR(IP1_1_0, EX_CS0),
PINMUX_IPSR_MSEL(IP1_1_0, RX3_C_IRDA_RX_C, SEL_SCIF3_2),
- PINMUX_IPSR_DATA(IP1_1_0, MMC0_D6),
- PINMUX_IPSR_DATA(IP1_1_0, FD6),
- PINMUX_IPSR_DATA(IP1_3_2, EX_CS1),
- PINMUX_IPSR_DATA(IP1_3_2, MMC0_D7),
- PINMUX_IPSR_DATA(IP1_3_2, FD7),
- PINMUX_IPSR_DATA(IP1_6_4, EX_CS2),
- PINMUX_IPSR_DATA(IP1_6_4, SD1_CLK),
- PINMUX_IPSR_DATA(IP1_6_4, MMC0_CLK),
- PINMUX_IPSR_DATA(IP1_6_4, FALE),
- PINMUX_IPSR_DATA(IP1_6_4, ATACS00),
- PINMUX_IPSR_DATA(IP1_10_7, EX_CS3),
- PINMUX_IPSR_DATA(IP1_10_7, SD1_CMD),
- PINMUX_IPSR_DATA(IP1_10_7, MMC0_CMD),
- PINMUX_IPSR_DATA(IP1_10_7, FRE),
- PINMUX_IPSR_DATA(IP1_10_7, ATACS10),
- PINMUX_IPSR_DATA(IP1_10_7, VI1_R4),
+ PINMUX_IPSR_GPSR(IP1_1_0, MMC0_D6),
+ PINMUX_IPSR_GPSR(IP1_1_0, FD6),
+ PINMUX_IPSR_GPSR(IP1_3_2, EX_CS1),
+ PINMUX_IPSR_GPSR(IP1_3_2, MMC0_D7),
+ PINMUX_IPSR_GPSR(IP1_3_2, FD7),
+ PINMUX_IPSR_GPSR(IP1_6_4, EX_CS2),
+ PINMUX_IPSR_GPSR(IP1_6_4, SD1_CLK),
+ PINMUX_IPSR_GPSR(IP1_6_4, MMC0_CLK),
+ PINMUX_IPSR_GPSR(IP1_6_4, FALE),
+ PINMUX_IPSR_GPSR(IP1_6_4, ATACS00),
+ PINMUX_IPSR_GPSR(IP1_10_7, EX_CS3),
+ PINMUX_IPSR_GPSR(IP1_10_7, SD1_CMD),
+ PINMUX_IPSR_GPSR(IP1_10_7, MMC0_CMD),
+ PINMUX_IPSR_GPSR(IP1_10_7, FRE),
+ PINMUX_IPSR_GPSR(IP1_10_7, ATACS10),
+ PINMUX_IPSR_GPSR(IP1_10_7, VI1_R4),
PINMUX_IPSR_MSEL(IP1_10_7, RX5_B, SEL_SCIF5_1),
PINMUX_IPSR_MSEL(IP1_10_7, HSCK1, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP1_10_7, SSI_SDATA8_B, SEL_SSI8_1),
PINMUX_IPSR_MSEL(IP1_10_7, RTS0_B_TANS_B, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP1_10_7, SSI_SDATA9, SEL_SSI9_0),
- PINMUX_IPSR_DATA(IP1_14_11, EX_CS4),
- PINMUX_IPSR_DATA(IP1_14_11, SD1_DAT0),
- PINMUX_IPSR_DATA(IP1_14_11, MMC0_D0),
- PINMUX_IPSR_DATA(IP1_14_11, FD0),
- PINMUX_IPSR_DATA(IP1_14_11, ATARD0),
- PINMUX_IPSR_DATA(IP1_14_11, VI1_R5),
+ PINMUX_IPSR_GPSR(IP1_14_11, EX_CS4),
+ PINMUX_IPSR_GPSR(IP1_14_11, SD1_DAT0),
+ PINMUX_IPSR_GPSR(IP1_14_11, MMC0_D0),
+ PINMUX_IPSR_GPSR(IP1_14_11, FD0),
+ PINMUX_IPSR_GPSR(IP1_14_11, ATARD0),
+ PINMUX_IPSR_GPSR(IP1_14_11, VI1_R5),
PINMUX_IPSR_MSEL(IP1_14_11, SCK5_B, SEL_SCIF5_1),
- PINMUX_IPSR_DATA(IP1_14_11, HTX1),
- PINMUX_IPSR_DATA(IP1_14_11, TX2_E),
- PINMUX_IPSR_DATA(IP1_14_11, TX0_B),
+ PINMUX_IPSR_GPSR(IP1_14_11, HTX1),
+ PINMUX_IPSR_GPSR(IP1_14_11, TX2_E),
+ PINMUX_IPSR_GPSR(IP1_14_11, TX0_B),
PINMUX_IPSR_MSEL(IP1_14_11, SSI_SCK9, SEL_SSI9_0),
- PINMUX_IPSR_DATA(IP1_18_15, EX_CS5),
- PINMUX_IPSR_DATA(IP1_18_15, SD1_DAT1),
- PINMUX_IPSR_DATA(IP1_18_15, MMC0_D1),
- PINMUX_IPSR_DATA(IP1_18_15, FD1),
- PINMUX_IPSR_DATA(IP1_18_15, ATAWR0),
- PINMUX_IPSR_DATA(IP1_18_15, VI1_R6),
+ PINMUX_IPSR_GPSR(IP1_18_15, EX_CS5),
+ PINMUX_IPSR_GPSR(IP1_18_15, SD1_DAT1),
+ PINMUX_IPSR_GPSR(IP1_18_15, MMC0_D1),
+ PINMUX_IPSR_GPSR(IP1_18_15, FD1),
+ PINMUX_IPSR_GPSR(IP1_18_15, ATAWR0),
+ PINMUX_IPSR_GPSR(IP1_18_15, VI1_R6),
PINMUX_IPSR_MSEL(IP1_18_15, HRX1, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP1_18_15, RX2_E, SEL_SCIF2_4),
PINMUX_IPSR_MSEL(IP1_18_15, RX0_B, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP1_18_15, SSI_WS9, SEL_SSI9_0),
- PINMUX_IPSR_DATA(IP1_20_19, MLB_CLK),
- PINMUX_IPSR_DATA(IP1_20_19, PWM2),
+ PINMUX_IPSR_GPSR(IP1_20_19, MLB_CLK),
+ PINMUX_IPSR_GPSR(IP1_20_19, PWM2),
PINMUX_IPSR_MSEL(IP1_20_19, SCK4, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP1_22_21, MLB_SIG),
- PINMUX_IPSR_DATA(IP1_22_21, PWM3),
- PINMUX_IPSR_DATA(IP1_22_21, TX4),
- PINMUX_IPSR_DATA(IP1_24_23, MLB_DAT),
- PINMUX_IPSR_DATA(IP1_24_23, PWM4),
+ PINMUX_IPSR_GPSR(IP1_22_21, MLB_SIG),
+ PINMUX_IPSR_GPSR(IP1_22_21, PWM3),
+ PINMUX_IPSR_GPSR(IP1_22_21, TX4),
+ PINMUX_IPSR_GPSR(IP1_24_23, MLB_DAT),
+ PINMUX_IPSR_GPSR(IP1_24_23, PWM4),
PINMUX_IPSR_MSEL(IP1_24_23, RX4, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP1_28_25, HTX0),
- PINMUX_IPSR_DATA(IP1_28_25, TX1),
- PINMUX_IPSR_DATA(IP1_28_25, SDATA),
+ PINMUX_IPSR_GPSR(IP1_28_25, HTX0),
+ PINMUX_IPSR_GPSR(IP1_28_25, TX1),
+ PINMUX_IPSR_GPSR(IP1_28_25, SDATA),
PINMUX_IPSR_MSEL(IP1_28_25, CTS0_C, SEL_SCIF0_2),
- PINMUX_IPSR_DATA(IP1_28_25, SUB_TCK),
- PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE2),
- PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE10),
- PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE18),
- PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE26),
- PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE34),
+ PINMUX_IPSR_GPSR(IP1_28_25, SUB_TCK),
+ PINMUX_IPSR_GPSR(IP1_28_25, CC5_STATE2),
+ PINMUX_IPSR_GPSR(IP1_28_25, CC5_STATE10),
+ PINMUX_IPSR_GPSR(IP1_28_25, CC5_STATE18),
+ PINMUX_IPSR_GPSR(IP1_28_25, CC5_STATE26),
+ PINMUX_IPSR_GPSR(IP1_28_25, CC5_STATE34),
PINMUX_IPSR_MSEL(IP2_3_0, HRX0, SEL_HSCIF0_0),
PINMUX_IPSR_MSEL(IP2_3_0, RX1, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP2_3_0, SCKZ),
+ PINMUX_IPSR_GPSR(IP2_3_0, SCKZ),
PINMUX_IPSR_MSEL(IP2_3_0, RTS0_C_TANS_C, SEL_SCIF0_2),
- PINMUX_IPSR_DATA(IP2_3_0, SUB_TDI),
- PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE3),
- PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE11),
- PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE19),
- PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE27),
- PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE35),
+ PINMUX_IPSR_GPSR(IP2_3_0, SUB_TDI),
+ PINMUX_IPSR_GPSR(IP2_3_0, CC5_STATE3),
+ PINMUX_IPSR_GPSR(IP2_3_0, CC5_STATE11),
+ PINMUX_IPSR_GPSR(IP2_3_0, CC5_STATE19),
+ PINMUX_IPSR_GPSR(IP2_3_0, CC5_STATE27),
+ PINMUX_IPSR_GPSR(IP2_3_0, CC5_STATE35),
PINMUX_IPSR_MSEL(IP2_7_4, HSCK0, SEL_HSCIF0_0),
PINMUX_IPSR_MSEL(IP2_7_4, SCK1, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP2_7_4, MTS),
- PINMUX_IPSR_DATA(IP2_7_4, PWM5),
+ PINMUX_IPSR_GPSR(IP2_7_4, MTS),
+ PINMUX_IPSR_GPSR(IP2_7_4, PWM5),
PINMUX_IPSR_MSEL(IP2_7_4, SCK0_C, SEL_SCIF0_2),
PINMUX_IPSR_MSEL(IP2_7_4, SSI_SDATA9_B, SEL_SSI9_1),
- PINMUX_IPSR_DATA(IP2_7_4, SUB_TDO),
- PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE0),
- PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE8),
- PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE16),
- PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE24),
- PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE32),
+ PINMUX_IPSR_GPSR(IP2_7_4, SUB_TDO),
+ PINMUX_IPSR_GPSR(IP2_7_4, CC5_STATE0),
+ PINMUX_IPSR_GPSR(IP2_7_4, CC5_STATE8),
+ PINMUX_IPSR_GPSR(IP2_7_4, CC5_STATE16),
+ PINMUX_IPSR_GPSR(IP2_7_4, CC5_STATE24),
+ PINMUX_IPSR_GPSR(IP2_7_4, CC5_STATE32),
PINMUX_IPSR_MSEL(IP2_11_8, HCTS0, SEL_HSCIF0_0),
PINMUX_IPSR_MSEL(IP2_11_8, CTS1, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP2_11_8, STM),
- PINMUX_IPSR_DATA(IP2_11_8, PWM0_D),
+ PINMUX_IPSR_GPSR(IP2_11_8, STM),
+ PINMUX_IPSR_GPSR(IP2_11_8, PWM0_D),
PINMUX_IPSR_MSEL(IP2_11_8, RX0_C, SEL_SCIF0_2),
PINMUX_IPSR_MSEL(IP2_11_8, SCIF_CLK_C, SEL_SCIF_2),
- PINMUX_IPSR_DATA(IP2_11_8, SUB_TRST),
+ PINMUX_IPSR_GPSR(IP2_11_8, SUB_TRST),
PINMUX_IPSR_MSEL(IP2_11_8, TCLK1_B, SEL_TMU1_1),
- PINMUX_IPSR_DATA(IP2_11_8, CC5_OSCOUT),
+ PINMUX_IPSR_GPSR(IP2_11_8, CC5_OSCOUT),
PINMUX_IPSR_MSEL(IP2_15_12, HRTS0, SEL_HSCIF0_0),
PINMUX_IPSR_MSEL(IP2_15_12, RTS1_TANS, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP2_15_12, MDATA),
- PINMUX_IPSR_DATA(IP2_15_12, TX0_C),
- PINMUX_IPSR_DATA(IP2_15_12, SUB_TMS),
- PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE1),
- PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE9),
- PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE17),
- PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE25),
- PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE33),
- PINMUX_IPSR_DATA(IP2_18_16, DU0_DR0),
- PINMUX_IPSR_DATA(IP2_18_16, LCDOUT0),
+ PINMUX_IPSR_GPSR(IP2_15_12, MDATA),
+ PINMUX_IPSR_GPSR(IP2_15_12, TX0_C),
+ PINMUX_IPSR_GPSR(IP2_15_12, SUB_TMS),
+ PINMUX_IPSR_GPSR(IP2_15_12, CC5_STATE1),
+ PINMUX_IPSR_GPSR(IP2_15_12, CC5_STATE9),
+ PINMUX_IPSR_GPSR(IP2_15_12, CC5_STATE17),
+ PINMUX_IPSR_GPSR(IP2_15_12, CC5_STATE25),
+ PINMUX_IPSR_GPSR(IP2_15_12, CC5_STATE33),
+ PINMUX_IPSR_GPSR(IP2_18_16, DU0_DR0),
+ PINMUX_IPSR_GPSR(IP2_18_16, LCDOUT0),
PINMUX_IPSR_MSEL(IP2_18_16, DREQ0, SEL_EXBUS0_0),
PINMUX_IPSR_MSEL(IP2_18_16, GPS_CLK_B, SEL_GPS_1),
- PINMUX_IPSR_DATA(IP2_18_16, AUDATA0),
- PINMUX_IPSR_DATA(IP2_18_16, TX5_C),
- PINMUX_IPSR_DATA(IP2_21_19, DU0_DR1),
- PINMUX_IPSR_DATA(IP2_21_19, LCDOUT1),
- PINMUX_IPSR_DATA(IP2_21_19, DACK0),
- PINMUX_IPSR_DATA(IP2_21_19, DRACK0),
+ PINMUX_IPSR_GPSR(IP2_18_16, AUDATA0),
+ PINMUX_IPSR_GPSR(IP2_18_16, TX5_C),
+ PINMUX_IPSR_GPSR(IP2_21_19, DU0_DR1),
+ PINMUX_IPSR_GPSR(IP2_21_19, LCDOUT1),
+ PINMUX_IPSR_GPSR(IP2_21_19, DACK0),
+ PINMUX_IPSR_GPSR(IP2_21_19, DRACK0),
PINMUX_IPSR_MSEL(IP2_21_19, GPS_SIGN_B, SEL_GPS_1),
- PINMUX_IPSR_DATA(IP2_21_19, AUDATA1),
+ PINMUX_IPSR_GPSR(IP2_21_19, AUDATA1),
PINMUX_IPSR_MSEL(IP2_21_19, RX5_C, SEL_SCIF5_2),
- PINMUX_IPSR_DATA(IP2_22, DU0_DR2),
- PINMUX_IPSR_DATA(IP2_22, LCDOUT2),
- PINMUX_IPSR_DATA(IP2_23, DU0_DR3),
- PINMUX_IPSR_DATA(IP2_23, LCDOUT3),
- PINMUX_IPSR_DATA(IP2_24, DU0_DR4),
- PINMUX_IPSR_DATA(IP2_24, LCDOUT4),
- PINMUX_IPSR_DATA(IP2_25, DU0_DR5),
- PINMUX_IPSR_DATA(IP2_25, LCDOUT5),
- PINMUX_IPSR_DATA(IP2_26, DU0_DR6),
- PINMUX_IPSR_DATA(IP2_26, LCDOUT6),
- PINMUX_IPSR_DATA(IP2_27, DU0_DR7),
- PINMUX_IPSR_DATA(IP2_27, LCDOUT7),
- PINMUX_IPSR_DATA(IP2_30_28, DU0_DG0),
- PINMUX_IPSR_DATA(IP2_30_28, LCDOUT8),
+ PINMUX_IPSR_GPSR(IP2_22, DU0_DR2),
+ PINMUX_IPSR_GPSR(IP2_22, LCDOUT2),
+ PINMUX_IPSR_GPSR(IP2_23, DU0_DR3),
+ PINMUX_IPSR_GPSR(IP2_23, LCDOUT3),
+ PINMUX_IPSR_GPSR(IP2_24, DU0_DR4),
+ PINMUX_IPSR_GPSR(IP2_24, LCDOUT4),
+ PINMUX_IPSR_GPSR(IP2_25, DU0_DR5),
+ PINMUX_IPSR_GPSR(IP2_25, LCDOUT5),
+ PINMUX_IPSR_GPSR(IP2_26, DU0_DR6),
+ PINMUX_IPSR_GPSR(IP2_26, LCDOUT6),
+ PINMUX_IPSR_GPSR(IP2_27, DU0_DR7),
+ PINMUX_IPSR_GPSR(IP2_27, LCDOUT7),
+ PINMUX_IPSR_GPSR(IP2_30_28, DU0_DG0),
+ PINMUX_IPSR_GPSR(IP2_30_28, LCDOUT8),
PINMUX_IPSR_MSEL(IP2_30_28, DREQ1, SEL_EXBUS1_0),
PINMUX_IPSR_MSEL(IP2_30_28, SCL2, SEL_I2C2_0),
- PINMUX_IPSR_DATA(IP2_30_28, AUDATA2),
+ PINMUX_IPSR_GPSR(IP2_30_28, AUDATA2),
- PINMUX_IPSR_DATA(IP3_2_0, DU0_DG1),
- PINMUX_IPSR_DATA(IP3_2_0, LCDOUT9),
- PINMUX_IPSR_DATA(IP3_2_0, DACK1),
+ PINMUX_IPSR_GPSR(IP3_2_0, DU0_DG1),
+ PINMUX_IPSR_GPSR(IP3_2_0, LCDOUT9),
+ PINMUX_IPSR_GPSR(IP3_2_0, DACK1),
PINMUX_IPSR_MSEL(IP3_2_0, SDA2, SEL_I2C2_0),
- PINMUX_IPSR_DATA(IP3_2_0, AUDATA3),
- PINMUX_IPSR_DATA(IP3_3, DU0_DG2),
- PINMUX_IPSR_DATA(IP3_3, LCDOUT10),
- PINMUX_IPSR_DATA(IP3_4, DU0_DG3),
- PINMUX_IPSR_DATA(IP3_4, LCDOUT11),
- PINMUX_IPSR_DATA(IP3_5, DU0_DG4),
- PINMUX_IPSR_DATA(IP3_5, LCDOUT12),
- PINMUX_IPSR_DATA(IP3_6, DU0_DG5),
- PINMUX_IPSR_DATA(IP3_6, LCDOUT13),
- PINMUX_IPSR_DATA(IP3_7, DU0_DG6),
- PINMUX_IPSR_DATA(IP3_7, LCDOUT14),
- PINMUX_IPSR_DATA(IP3_8, DU0_DG7),
- PINMUX_IPSR_DATA(IP3_8, LCDOUT15),
- PINMUX_IPSR_DATA(IP3_11_9, DU0_DB0),
- PINMUX_IPSR_DATA(IP3_11_9, LCDOUT16),
- PINMUX_IPSR_DATA(IP3_11_9, EX_WAIT1),
+ PINMUX_IPSR_GPSR(IP3_2_0, AUDATA3),
+ PINMUX_IPSR_GPSR(IP3_3, DU0_DG2),
+ PINMUX_IPSR_GPSR(IP3_3, LCDOUT10),
+ PINMUX_IPSR_GPSR(IP3_4, DU0_DG3),
+ PINMUX_IPSR_GPSR(IP3_4, LCDOUT11),
+ PINMUX_IPSR_GPSR(IP3_5, DU0_DG4),
+ PINMUX_IPSR_GPSR(IP3_5, LCDOUT12),
+ PINMUX_IPSR_GPSR(IP3_6, DU0_DG5),
+ PINMUX_IPSR_GPSR(IP3_6, LCDOUT13),
+ PINMUX_IPSR_GPSR(IP3_7, DU0_DG6),
+ PINMUX_IPSR_GPSR(IP3_7, LCDOUT14),
+ PINMUX_IPSR_GPSR(IP3_8, DU0_DG7),
+ PINMUX_IPSR_GPSR(IP3_8, LCDOUT15),
+ PINMUX_IPSR_GPSR(IP3_11_9, DU0_DB0),
+ PINMUX_IPSR_GPSR(IP3_11_9, LCDOUT16),
+ PINMUX_IPSR_GPSR(IP3_11_9, EX_WAIT1),
PINMUX_IPSR_MSEL(IP3_11_9, SCL1, SEL_I2C1_0),
PINMUX_IPSR_MSEL(IP3_11_9, TCLK1, SEL_TMU1_0),
- PINMUX_IPSR_DATA(IP3_11_9, AUDATA4),
- PINMUX_IPSR_DATA(IP3_14_12, DU0_DB1),
- PINMUX_IPSR_DATA(IP3_14_12, LCDOUT17),
- PINMUX_IPSR_DATA(IP3_14_12, EX_WAIT2),
+ PINMUX_IPSR_GPSR(IP3_11_9, AUDATA4),
+ PINMUX_IPSR_GPSR(IP3_14_12, DU0_DB1),
+ PINMUX_IPSR_GPSR(IP3_14_12, LCDOUT17),
+ PINMUX_IPSR_GPSR(IP3_14_12, EX_WAIT2),
PINMUX_IPSR_MSEL(IP3_14_12, SDA1, SEL_I2C1_0),
PINMUX_IPSR_MSEL(IP3_14_12, GPS_MAG_B, SEL_GPS_1),
- PINMUX_IPSR_DATA(IP3_14_12, AUDATA5),
+ PINMUX_IPSR_GPSR(IP3_14_12, AUDATA5),
PINMUX_IPSR_MSEL(IP3_14_12, SCK5_C, SEL_SCIF5_2),
- PINMUX_IPSR_DATA(IP3_15, DU0_DB2),
- PINMUX_IPSR_DATA(IP3_15, LCDOUT18),
- PINMUX_IPSR_DATA(IP3_16, DU0_DB3),
- PINMUX_IPSR_DATA(IP3_16, LCDOUT19),
- PINMUX_IPSR_DATA(IP3_17, DU0_DB4),
- PINMUX_IPSR_DATA(IP3_17, LCDOUT20),
- PINMUX_IPSR_DATA(IP3_18, DU0_DB5),
- PINMUX_IPSR_DATA(IP3_18, LCDOUT21),
- PINMUX_IPSR_DATA(IP3_19, DU0_DB6),
- PINMUX_IPSR_DATA(IP3_19, LCDOUT22),
- PINMUX_IPSR_DATA(IP3_20, DU0_DB7),
- PINMUX_IPSR_DATA(IP3_20, LCDOUT23),
- PINMUX_IPSR_DATA(IP3_22_21, DU0_DOTCLKIN),
- PINMUX_IPSR_DATA(IP3_22_21, QSTVA_QVS),
- PINMUX_IPSR_DATA(IP3_22_21, TX3_D_IRDA_TX_D),
+ PINMUX_IPSR_GPSR(IP3_15, DU0_DB2),
+ PINMUX_IPSR_GPSR(IP3_15, LCDOUT18),
+ PINMUX_IPSR_GPSR(IP3_16, DU0_DB3),
+ PINMUX_IPSR_GPSR(IP3_16, LCDOUT19),
+ PINMUX_IPSR_GPSR(IP3_17, DU0_DB4),
+ PINMUX_IPSR_GPSR(IP3_17, LCDOUT20),
+ PINMUX_IPSR_GPSR(IP3_18, DU0_DB5),
+ PINMUX_IPSR_GPSR(IP3_18, LCDOUT21),
+ PINMUX_IPSR_GPSR(IP3_19, DU0_DB6),
+ PINMUX_IPSR_GPSR(IP3_19, LCDOUT22),
+ PINMUX_IPSR_GPSR(IP3_20, DU0_DB7),
+ PINMUX_IPSR_GPSR(IP3_20, LCDOUT23),
+ PINMUX_IPSR_GPSR(IP3_22_21, DU0_DOTCLKIN),
+ PINMUX_IPSR_GPSR(IP3_22_21, QSTVA_QVS),
+ PINMUX_IPSR_GPSR(IP3_22_21, TX3_D_IRDA_TX_D),
PINMUX_IPSR_MSEL(IP3_22_21, SCL3_B, SEL_I2C3_1),
- PINMUX_IPSR_DATA(IP3_23, DU0_DOTCLKOUT0),
- PINMUX_IPSR_DATA(IP3_23, QCLK),
- PINMUX_IPSR_DATA(IP3_26_24, DU0_DOTCLKOUT1),
- PINMUX_IPSR_DATA(IP3_26_24, QSTVB_QVE),
+ PINMUX_IPSR_GPSR(IP3_23, DU0_DOTCLKOUT0),
+ PINMUX_IPSR_GPSR(IP3_23, QCLK),
+ PINMUX_IPSR_GPSR(IP3_26_24, DU0_DOTCLKOUT1),
+ PINMUX_IPSR_GPSR(IP3_26_24, QSTVB_QVE),
PINMUX_IPSR_MSEL(IP3_26_24, RX3_D_IRDA_RX_D, SEL_SCIF3_3),
PINMUX_IPSR_MSEL(IP3_26_24, SDA3_B, SEL_I2C3_1),
PINMUX_IPSR_MSEL(IP3_26_24, SDA2_C, SEL_I2C2_2),
- PINMUX_IPSR_DATA(IP3_26_24, DACK0_B),
- PINMUX_IPSR_DATA(IP3_26_24, DRACK0_B),
- PINMUX_IPSR_DATA(IP3_27, DU0_EXHSYNC_DU0_HSYNC),
- PINMUX_IPSR_DATA(IP3_27, QSTH_QHS),
- PINMUX_IPSR_DATA(IP3_28, DU0_EXVSYNC_DU0_VSYNC),
- PINMUX_IPSR_DATA(IP3_28, QSTB_QHE),
- PINMUX_IPSR_DATA(IP3_31_29, DU0_EXODDF_DU0_ODDF_DISP_CDE),
- PINMUX_IPSR_DATA(IP3_31_29, QCPV_QDE),
- PINMUX_IPSR_DATA(IP3_31_29, CAN1_TX),
- PINMUX_IPSR_DATA(IP3_31_29, TX2_C),
+ PINMUX_IPSR_GPSR(IP3_26_24, DACK0_B),
+ PINMUX_IPSR_GPSR(IP3_26_24, DRACK0_B),
+ PINMUX_IPSR_GPSR(IP3_27, DU0_EXHSYNC_DU0_HSYNC),
+ PINMUX_IPSR_GPSR(IP3_27, QSTH_QHS),
+ PINMUX_IPSR_GPSR(IP3_28, DU0_EXVSYNC_DU0_VSYNC),
+ PINMUX_IPSR_GPSR(IP3_28, QSTB_QHE),
+ PINMUX_IPSR_GPSR(IP3_31_29, DU0_EXODDF_DU0_ODDF_DISP_CDE),
+ PINMUX_IPSR_GPSR(IP3_31_29, QCPV_QDE),
+ PINMUX_IPSR_GPSR(IP3_31_29, CAN1_TX),
+ PINMUX_IPSR_GPSR(IP3_31_29, TX2_C),
PINMUX_IPSR_MSEL(IP3_31_29, SCL2_C, SEL_I2C2_2),
- PINMUX_IPSR_DATA(IP3_31_29, REMOCON),
+ PINMUX_IPSR_GPSR(IP3_31_29, REMOCON),
- PINMUX_IPSR_DATA(IP4_1_0, DU0_DISP),
- PINMUX_IPSR_DATA(IP4_1_0, QPOLA),
+ PINMUX_IPSR_GPSR(IP4_1_0, DU0_DISP),
+ PINMUX_IPSR_GPSR(IP4_1_0, QPOLA),
PINMUX_IPSR_MSEL(IP4_1_0, CAN_CLK_C, SEL_CANCLK_2),
PINMUX_IPSR_MSEL(IP4_1_0, SCK2_C, SEL_SCIF2_2),
- PINMUX_IPSR_DATA(IP4_4_2, DU0_CDE),
- PINMUX_IPSR_DATA(IP4_4_2, QPOLB),
- PINMUX_IPSR_DATA(IP4_4_2, CAN1_RX),
+ PINMUX_IPSR_GPSR(IP4_4_2, DU0_CDE),
+ PINMUX_IPSR_GPSR(IP4_4_2, QPOLB),
+ PINMUX_IPSR_GPSR(IP4_4_2, CAN1_RX),
PINMUX_IPSR_MSEL(IP4_4_2, RX2_C, SEL_SCIF2_2),
PINMUX_IPSR_MSEL(IP4_4_2, DREQ0_B, SEL_EXBUS0_1),
PINMUX_IPSR_MSEL(IP4_4_2, SSI_SCK78_B, SEL_SSI7_1),
PINMUX_IPSR_MSEL(IP4_4_2, SCK0_B, SEL_SCIF0_1),
- PINMUX_IPSR_DATA(IP4_7_5, DU1_DR0),
- PINMUX_IPSR_DATA(IP4_7_5, VI2_DATA0_VI2_B0),
- PINMUX_IPSR_DATA(IP4_7_5, PWM6),
- PINMUX_IPSR_DATA(IP4_7_5, SD3_CLK),
- PINMUX_IPSR_DATA(IP4_7_5, TX3_E_IRDA_TX_E),
- PINMUX_IPSR_DATA(IP4_7_5, AUDCK),
+ PINMUX_IPSR_GPSR(IP4_7_5, DU1_DR0),
+ PINMUX_IPSR_GPSR(IP4_7_5, VI2_DATA0_VI2_B0),
+ PINMUX_IPSR_GPSR(IP4_7_5, PWM6),
+ PINMUX_IPSR_GPSR(IP4_7_5, SD3_CLK),
+ PINMUX_IPSR_GPSR(IP4_7_5, TX3_E_IRDA_TX_E),
+ PINMUX_IPSR_GPSR(IP4_7_5, AUDCK),
PINMUX_IPSR_MSEL(IP4_7_5, PWMFSW0_B, SEL_PWMFSW_1),
- PINMUX_IPSR_DATA(IP4_10_8, DU1_DR1),
- PINMUX_IPSR_DATA(IP4_10_8, VI2_DATA1_VI2_B1),
- PINMUX_IPSR_DATA(IP4_10_8, PWM0),
- PINMUX_IPSR_DATA(IP4_10_8, SD3_CMD),
+ PINMUX_IPSR_GPSR(IP4_10_8, DU1_DR1),
+ PINMUX_IPSR_GPSR(IP4_10_8, VI2_DATA1_VI2_B1),
+ PINMUX_IPSR_GPSR(IP4_10_8, PWM0),
+ PINMUX_IPSR_GPSR(IP4_10_8, SD3_CMD),
PINMUX_IPSR_MSEL(IP4_10_8, RX3_E_IRDA_RX_E, SEL_SCIF3_4),
- PINMUX_IPSR_DATA(IP4_10_8, AUDSYNC),
+ PINMUX_IPSR_GPSR(IP4_10_8, AUDSYNC),
PINMUX_IPSR_MSEL(IP4_10_8, CTS0_D, SEL_SCIF0_3),
- PINMUX_IPSR_DATA(IP4_11, DU1_DR2),
- PINMUX_IPSR_DATA(IP4_11, VI2_G0),
- PINMUX_IPSR_DATA(IP4_12, DU1_DR3),
- PINMUX_IPSR_DATA(IP4_12, VI2_G1),
- PINMUX_IPSR_DATA(IP4_13, DU1_DR4),
- PINMUX_IPSR_DATA(IP4_13, VI2_G2),
- PINMUX_IPSR_DATA(IP4_14, DU1_DR5),
- PINMUX_IPSR_DATA(IP4_14, VI2_G3),
- PINMUX_IPSR_DATA(IP4_15, DU1_DR6),
- PINMUX_IPSR_DATA(IP4_15, VI2_G4),
- PINMUX_IPSR_DATA(IP4_16, DU1_DR7),
- PINMUX_IPSR_DATA(IP4_16, VI2_G5),
- PINMUX_IPSR_DATA(IP4_19_17, DU1_DG0),
- PINMUX_IPSR_DATA(IP4_19_17, VI2_DATA2_VI2_B2),
+ PINMUX_IPSR_GPSR(IP4_11, DU1_DR2),
+ PINMUX_IPSR_GPSR(IP4_11, VI2_G0),
+ PINMUX_IPSR_GPSR(IP4_12, DU1_DR3),
+ PINMUX_IPSR_GPSR(IP4_12, VI2_G1),
+ PINMUX_IPSR_GPSR(IP4_13, DU1_DR4),
+ PINMUX_IPSR_GPSR(IP4_13, VI2_G2),
+ PINMUX_IPSR_GPSR(IP4_14, DU1_DR5),
+ PINMUX_IPSR_GPSR(IP4_14, VI2_G3),
+ PINMUX_IPSR_GPSR(IP4_15, DU1_DR6),
+ PINMUX_IPSR_GPSR(IP4_15, VI2_G4),
+ PINMUX_IPSR_GPSR(IP4_16, DU1_DR7),
+ PINMUX_IPSR_GPSR(IP4_16, VI2_G5),
+ PINMUX_IPSR_GPSR(IP4_19_17, DU1_DG0),
+ PINMUX_IPSR_GPSR(IP4_19_17, VI2_DATA2_VI2_B2),
PINMUX_IPSR_MSEL(IP4_19_17, SCL1_B, SEL_I2C1_1),
- PINMUX_IPSR_DATA(IP4_19_17, SD3_DAT2),
+ PINMUX_IPSR_GPSR(IP4_19_17, SD3_DAT2),
PINMUX_IPSR_MSEL(IP4_19_17, SCK3_E, SEL_SCIF3_4),
- PINMUX_IPSR_DATA(IP4_19_17, AUDATA6),
- PINMUX_IPSR_DATA(IP4_19_17, TX0_D),
- PINMUX_IPSR_DATA(IP4_22_20, DU1_DG1),
- PINMUX_IPSR_DATA(IP4_22_20, VI2_DATA3_VI2_B3),
+ PINMUX_IPSR_GPSR(IP4_19_17, AUDATA6),
+ PINMUX_IPSR_GPSR(IP4_19_17, TX0_D),
+ PINMUX_IPSR_GPSR(IP4_22_20, DU1_DG1),
+ PINMUX_IPSR_GPSR(IP4_22_20, VI2_DATA3_VI2_B3),
PINMUX_IPSR_MSEL(IP4_22_20, SDA1_B, SEL_I2C1_1),
- PINMUX_IPSR_DATA(IP4_22_20, SD3_DAT3),
+ PINMUX_IPSR_GPSR(IP4_22_20, SD3_DAT3),
PINMUX_IPSR_MSEL(IP4_22_20, SCK5, SEL_SCIF5_0),
- PINMUX_IPSR_DATA(IP4_22_20, AUDATA7),
+ PINMUX_IPSR_GPSR(IP4_22_20, AUDATA7),
PINMUX_IPSR_MSEL(IP4_22_20, RX0_D, SEL_SCIF0_3),
- PINMUX_IPSR_DATA(IP4_23, DU1_DG2),
- PINMUX_IPSR_DATA(IP4_23, VI2_G6),
- PINMUX_IPSR_DATA(IP4_24, DU1_DG3),
- PINMUX_IPSR_DATA(IP4_24, VI2_G7),
- PINMUX_IPSR_DATA(IP4_25, DU1_DG4),
- PINMUX_IPSR_DATA(IP4_25, VI2_R0),
- PINMUX_IPSR_DATA(IP4_26, DU1_DG5),
- PINMUX_IPSR_DATA(IP4_26, VI2_R1),
- PINMUX_IPSR_DATA(IP4_27, DU1_DG6),
- PINMUX_IPSR_DATA(IP4_27, VI2_R2),
- PINMUX_IPSR_DATA(IP4_28, DU1_DG7),
- PINMUX_IPSR_DATA(IP4_28, VI2_R3),
- PINMUX_IPSR_DATA(IP4_31_29, DU1_DB0),
- PINMUX_IPSR_DATA(IP4_31_29, VI2_DATA4_VI2_B4),
+ PINMUX_IPSR_GPSR(IP4_23, DU1_DG2),
+ PINMUX_IPSR_GPSR(IP4_23, VI2_G6),
+ PINMUX_IPSR_GPSR(IP4_24, DU1_DG3),
+ PINMUX_IPSR_GPSR(IP4_24, VI2_G7),
+ PINMUX_IPSR_GPSR(IP4_25, DU1_DG4),
+ PINMUX_IPSR_GPSR(IP4_25, VI2_R0),
+ PINMUX_IPSR_GPSR(IP4_26, DU1_DG5),
+ PINMUX_IPSR_GPSR(IP4_26, VI2_R1),
+ PINMUX_IPSR_GPSR(IP4_27, DU1_DG6),
+ PINMUX_IPSR_GPSR(IP4_27, VI2_R2),
+ PINMUX_IPSR_GPSR(IP4_28, DU1_DG7),
+ PINMUX_IPSR_GPSR(IP4_28, VI2_R3),
+ PINMUX_IPSR_GPSR(IP4_31_29, DU1_DB0),
+ PINMUX_IPSR_GPSR(IP4_31_29, VI2_DATA4_VI2_B4),
PINMUX_IPSR_MSEL(IP4_31_29, SCL2_B, SEL_I2C2_1),
- PINMUX_IPSR_DATA(IP4_31_29, SD3_DAT0),
- PINMUX_IPSR_DATA(IP4_31_29, TX5),
+ PINMUX_IPSR_GPSR(IP4_31_29, SD3_DAT0),
+ PINMUX_IPSR_GPSR(IP4_31_29, TX5),
PINMUX_IPSR_MSEL(IP4_31_29, SCK0_D, SEL_SCIF0_3),
- PINMUX_IPSR_DATA(IP5_2_0, DU1_DB1),
- PINMUX_IPSR_DATA(IP5_2_0, VI2_DATA5_VI2_B5),
+ PINMUX_IPSR_GPSR(IP5_2_0, DU1_DB1),
+ PINMUX_IPSR_GPSR(IP5_2_0, VI2_DATA5_VI2_B5),
PINMUX_IPSR_MSEL(IP5_2_0, SDA2_B, SEL_I2C2_1),
- PINMUX_IPSR_DATA(IP5_2_0, SD3_DAT1),
+ PINMUX_IPSR_GPSR(IP5_2_0, SD3_DAT1),
PINMUX_IPSR_MSEL(IP5_2_0, RX5, SEL_SCIF5_0),
PINMUX_IPSR_MSEL(IP5_2_0, RTS0_D_TANS_D, SEL_SCIF0_3),
- PINMUX_IPSR_DATA(IP5_3, DU1_DB2),
- PINMUX_IPSR_DATA(IP5_3, VI2_R4),
- PINMUX_IPSR_DATA(IP5_4, DU1_DB3),
- PINMUX_IPSR_DATA(IP5_4, VI2_R5),
- PINMUX_IPSR_DATA(IP5_5, DU1_DB4),
- PINMUX_IPSR_DATA(IP5_5, VI2_R6),
- PINMUX_IPSR_DATA(IP5_6, DU1_DB5),
- PINMUX_IPSR_DATA(IP5_6, VI2_R7),
- PINMUX_IPSR_DATA(IP5_7, DU1_DB6),
+ PINMUX_IPSR_GPSR(IP5_3, DU1_DB2),
+ PINMUX_IPSR_GPSR(IP5_3, VI2_R4),
+ PINMUX_IPSR_GPSR(IP5_4, DU1_DB3),
+ PINMUX_IPSR_GPSR(IP5_4, VI2_R5),
+ PINMUX_IPSR_GPSR(IP5_5, DU1_DB4),
+ PINMUX_IPSR_GPSR(IP5_5, VI2_R6),
+ PINMUX_IPSR_GPSR(IP5_6, DU1_DB5),
+ PINMUX_IPSR_GPSR(IP5_6, VI2_R7),
+ PINMUX_IPSR_GPSR(IP5_7, DU1_DB6),
PINMUX_IPSR_MSEL(IP5_7, SCL2_D, SEL_I2C2_3),
- PINMUX_IPSR_DATA(IP5_8, DU1_DB7),
+ PINMUX_IPSR_GPSR(IP5_8, DU1_DB7),
PINMUX_IPSR_MSEL(IP5_8, SDA2_D, SEL_I2C2_3),
- PINMUX_IPSR_DATA(IP5_10_9, DU1_DOTCLKIN),
- PINMUX_IPSR_DATA(IP5_10_9, VI2_CLKENB),
+ PINMUX_IPSR_GPSR(IP5_10_9, DU1_DOTCLKIN),
+ PINMUX_IPSR_GPSR(IP5_10_9, VI2_CLKENB),
PINMUX_IPSR_MSEL(IP5_10_9, HSPI_CS1, SEL_HSPI1_0),
PINMUX_IPSR_MSEL(IP5_10_9, SCL1_D, SEL_I2C1_3),
- PINMUX_IPSR_DATA(IP5_12_11, DU1_DOTCLKOUT),
- PINMUX_IPSR_DATA(IP5_12_11, VI2_FIELD),
+ PINMUX_IPSR_GPSR(IP5_12_11, DU1_DOTCLKOUT),
+ PINMUX_IPSR_GPSR(IP5_12_11, VI2_FIELD),
PINMUX_IPSR_MSEL(IP5_12_11, SDA1_D, SEL_I2C1_3),
- PINMUX_IPSR_DATA(IP5_14_13, DU1_EXHSYNC_DU1_HSYNC),
- PINMUX_IPSR_DATA(IP5_14_13, VI2_HSYNC),
- PINMUX_IPSR_DATA(IP5_14_13, VI3_HSYNC),
- PINMUX_IPSR_DATA(IP5_16_15, DU1_EXVSYNC_DU1_VSYNC),
- PINMUX_IPSR_DATA(IP5_16_15, VI2_VSYNC),
- PINMUX_IPSR_DATA(IP5_16_15, VI3_VSYNC),
- PINMUX_IPSR_DATA(IP5_20_17, DU1_EXODDF_DU1_ODDF_DISP_CDE),
- PINMUX_IPSR_DATA(IP5_20_17, VI2_CLK),
- PINMUX_IPSR_DATA(IP5_20_17, TX3_B_IRDA_TX_B),
- PINMUX_IPSR_DATA(IP5_20_17, SD3_CD),
- PINMUX_IPSR_DATA(IP5_20_17, HSPI_TX1),
- PINMUX_IPSR_DATA(IP5_20_17, VI1_CLKENB),
- PINMUX_IPSR_DATA(IP5_20_17, VI3_CLKENB),
- PINMUX_IPSR_DATA(IP5_20_17, AUDIO_CLKC),
- PINMUX_IPSR_DATA(IP5_20_17, TX2_D),
- PINMUX_IPSR_DATA(IP5_20_17, SPEEDIN),
+ PINMUX_IPSR_GPSR(IP5_14_13, DU1_EXHSYNC_DU1_HSYNC),
+ PINMUX_IPSR_GPSR(IP5_14_13, VI2_HSYNC),
+ PINMUX_IPSR_GPSR(IP5_14_13, VI3_HSYNC),
+ PINMUX_IPSR_GPSR(IP5_16_15, DU1_EXVSYNC_DU1_VSYNC),
+ PINMUX_IPSR_GPSR(IP5_16_15, VI2_VSYNC),
+ PINMUX_IPSR_GPSR(IP5_16_15, VI3_VSYNC),
+ PINMUX_IPSR_GPSR(IP5_20_17, DU1_EXODDF_DU1_ODDF_DISP_CDE),
+ PINMUX_IPSR_GPSR(IP5_20_17, VI2_CLK),
+ PINMUX_IPSR_GPSR(IP5_20_17, TX3_B_IRDA_TX_B),
+ PINMUX_IPSR_GPSR(IP5_20_17, SD3_CD),
+ PINMUX_IPSR_GPSR(IP5_20_17, HSPI_TX1),
+ PINMUX_IPSR_GPSR(IP5_20_17, VI1_CLKENB),
+ PINMUX_IPSR_GPSR(IP5_20_17, VI3_CLKENB),
+ PINMUX_IPSR_GPSR(IP5_20_17, AUDIO_CLKC),
+ PINMUX_IPSR_GPSR(IP5_20_17, TX2_D),
+ PINMUX_IPSR_GPSR(IP5_20_17, SPEEDIN),
PINMUX_IPSR_MSEL(IP5_20_17, GPS_SIGN_D, SEL_GPS_3),
- PINMUX_IPSR_DATA(IP5_23_21, DU1_DISP),
- PINMUX_IPSR_DATA(IP5_23_21, VI2_DATA6_VI2_B6),
+ PINMUX_IPSR_GPSR(IP5_23_21, DU1_DISP),
+ PINMUX_IPSR_GPSR(IP5_23_21, VI2_DATA6_VI2_B6),
PINMUX_IPSR_MSEL(IP5_23_21, TCLK0, SEL_TMU0_0),
- PINMUX_IPSR_DATA(IP5_23_21, QSTVA_B_QVS_B),
+ PINMUX_IPSR_GPSR(IP5_23_21, QSTVA_B_QVS_B),
PINMUX_IPSR_MSEL(IP5_23_21, HSPI_CLK1, SEL_HSPI1_0),
PINMUX_IPSR_MSEL(IP5_23_21, SCK2_D, SEL_SCIF2_3),
- PINMUX_IPSR_DATA(IP5_23_21, AUDIO_CLKOUT_B),
+ PINMUX_IPSR_GPSR(IP5_23_21, AUDIO_CLKOUT_B),
PINMUX_IPSR_MSEL(IP5_23_21, GPS_MAG_D, SEL_GPS_3),
- PINMUX_IPSR_DATA(IP5_27_24, DU1_CDE),
- PINMUX_IPSR_DATA(IP5_27_24, VI2_DATA7_VI2_B7),
+ PINMUX_IPSR_GPSR(IP5_27_24, DU1_CDE),
+ PINMUX_IPSR_GPSR(IP5_27_24, VI2_DATA7_VI2_B7),
PINMUX_IPSR_MSEL(IP5_27_24, RX3_B_IRDA_RX_B, SEL_SCIF3_1),
- PINMUX_IPSR_DATA(IP5_27_24, SD3_WP),
+ PINMUX_IPSR_GPSR(IP5_27_24, SD3_WP),
PINMUX_IPSR_MSEL(IP5_27_24, HSPI_RX1, SEL_HSPI1_0),
- PINMUX_IPSR_DATA(IP5_27_24, VI1_FIELD),
- PINMUX_IPSR_DATA(IP5_27_24, VI3_FIELD),
- PINMUX_IPSR_DATA(IP5_27_24, AUDIO_CLKOUT),
+ PINMUX_IPSR_GPSR(IP5_27_24, VI1_FIELD),
+ PINMUX_IPSR_GPSR(IP5_27_24, VI3_FIELD),
+ PINMUX_IPSR_GPSR(IP5_27_24, AUDIO_CLKOUT),
PINMUX_IPSR_MSEL(IP5_27_24, RX2_D, SEL_SCIF2_3),
PINMUX_IPSR_MSEL(IP5_27_24, GPS_CLK_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP5_27_24, GPS_CLK_D, SEL_GPS_3),
- PINMUX_IPSR_DATA(IP5_28, AUDIO_CLKA),
- PINMUX_IPSR_DATA(IP5_28, CAN_TXCLK),
- PINMUX_IPSR_DATA(IP5_30_29, AUDIO_CLKB),
- PINMUX_IPSR_DATA(IP5_30_29, USB_OVC2),
- PINMUX_IPSR_DATA(IP5_30_29, CAN_DEBUGOUT0),
- PINMUX_IPSR_DATA(IP5_30_29, MOUT0),
-
- PINMUX_IPSR_DATA(IP6_1_0, SSI_SCK0129),
- PINMUX_IPSR_DATA(IP6_1_0, CAN_DEBUGOUT1),
- PINMUX_IPSR_DATA(IP6_1_0, MOUT1),
- PINMUX_IPSR_DATA(IP6_3_2, SSI_WS0129),
- PINMUX_IPSR_DATA(IP6_3_2, CAN_DEBUGOUT2),
- PINMUX_IPSR_DATA(IP6_3_2, MOUT2),
- PINMUX_IPSR_DATA(IP6_5_4, SSI_SDATA0),
- PINMUX_IPSR_DATA(IP6_5_4, CAN_DEBUGOUT3),
- PINMUX_IPSR_DATA(IP6_5_4, MOUT5),
- PINMUX_IPSR_DATA(IP6_7_6, SSI_SDATA1),
- PINMUX_IPSR_DATA(IP6_7_6, CAN_DEBUGOUT4),
- PINMUX_IPSR_DATA(IP6_7_6, MOUT6),
- PINMUX_IPSR_DATA(IP6_8, SSI_SDATA2),
- PINMUX_IPSR_DATA(IP6_8, CAN_DEBUGOUT5),
- PINMUX_IPSR_DATA(IP6_11_9, SSI_SCK34),
- PINMUX_IPSR_DATA(IP6_11_9, CAN_DEBUGOUT6),
- PINMUX_IPSR_DATA(IP6_11_9, CAN0_TX_B),
+ PINMUX_IPSR_GPSR(IP5_28, AUDIO_CLKA),
+ PINMUX_IPSR_GPSR(IP5_28, CAN_TXCLK),
+ PINMUX_IPSR_GPSR(IP5_30_29, AUDIO_CLKB),
+ PINMUX_IPSR_GPSR(IP5_30_29, USB_OVC2),
+ PINMUX_IPSR_GPSR(IP5_30_29, CAN_DEBUGOUT0),
+ PINMUX_IPSR_GPSR(IP5_30_29, MOUT0),
+
+ PINMUX_IPSR_GPSR(IP6_1_0, SSI_SCK0129),
+ PINMUX_IPSR_GPSR(IP6_1_0, CAN_DEBUGOUT1),
+ PINMUX_IPSR_GPSR(IP6_1_0, MOUT1),
+ PINMUX_IPSR_GPSR(IP6_3_2, SSI_WS0129),
+ PINMUX_IPSR_GPSR(IP6_3_2, CAN_DEBUGOUT2),
+ PINMUX_IPSR_GPSR(IP6_3_2, MOUT2),
+ PINMUX_IPSR_GPSR(IP6_5_4, SSI_SDATA0),
+ PINMUX_IPSR_GPSR(IP6_5_4, CAN_DEBUGOUT3),
+ PINMUX_IPSR_GPSR(IP6_5_4, MOUT5),
+ PINMUX_IPSR_GPSR(IP6_7_6, SSI_SDATA1),
+ PINMUX_IPSR_GPSR(IP6_7_6, CAN_DEBUGOUT4),
+ PINMUX_IPSR_GPSR(IP6_7_6, MOUT6),
+ PINMUX_IPSR_GPSR(IP6_8, SSI_SDATA2),
+ PINMUX_IPSR_GPSR(IP6_8, CAN_DEBUGOUT5),
+ PINMUX_IPSR_GPSR(IP6_11_9, SSI_SCK34),
+ PINMUX_IPSR_GPSR(IP6_11_9, CAN_DEBUGOUT6),
+ PINMUX_IPSR_GPSR(IP6_11_9, CAN0_TX_B),
PINMUX_IPSR_MSEL(IP6_11_9, IERX, SEL_IE_0),
PINMUX_IPSR_MSEL(IP6_11_9, SSI_SCK9_C, SEL_SSI9_2),
- PINMUX_IPSR_DATA(IP6_14_12, SSI_WS34),
- PINMUX_IPSR_DATA(IP6_14_12, CAN_DEBUGOUT7),
+ PINMUX_IPSR_GPSR(IP6_14_12, SSI_WS34),
+ PINMUX_IPSR_GPSR(IP6_14_12, CAN_DEBUGOUT7),
PINMUX_IPSR_MSEL(IP6_14_12, CAN0_RX_B, SEL_CAN0_1),
- PINMUX_IPSR_DATA(IP6_14_12, IETX),
+ PINMUX_IPSR_GPSR(IP6_14_12, IETX),
PINMUX_IPSR_MSEL(IP6_14_12, SSI_WS9_C, SEL_SSI9_2),
- PINMUX_IPSR_DATA(IP6_17_15, SSI_SDATA3),
- PINMUX_IPSR_DATA(IP6_17_15, PWM0_C),
- PINMUX_IPSR_DATA(IP6_17_15, CAN_DEBUGOUT8),
+ PINMUX_IPSR_GPSR(IP6_17_15, SSI_SDATA3),
+ PINMUX_IPSR_GPSR(IP6_17_15, PWM0_C),
+ PINMUX_IPSR_GPSR(IP6_17_15, CAN_DEBUGOUT8),
PINMUX_IPSR_MSEL(IP6_17_15, CAN_CLK_B, SEL_CANCLK_1),
PINMUX_IPSR_MSEL(IP6_17_15, IECLK, SEL_IE_0),
PINMUX_IPSR_MSEL(IP6_17_15, SCIF_CLK_B, SEL_SCIF_1),
PINMUX_IPSR_MSEL(IP6_17_15, TCLK0_B, SEL_TMU0_1),
- PINMUX_IPSR_DATA(IP6_19_18, SSI_SDATA4),
- PINMUX_IPSR_DATA(IP6_19_18, CAN_DEBUGOUT9),
+ PINMUX_IPSR_GPSR(IP6_19_18, SSI_SDATA4),
+ PINMUX_IPSR_GPSR(IP6_19_18, CAN_DEBUGOUT9),
PINMUX_IPSR_MSEL(IP6_19_18, SSI_SDATA9_C, SEL_SSI9_2),
- PINMUX_IPSR_DATA(IP6_22_20, SSI_SCK5),
- PINMUX_IPSR_DATA(IP6_22_20, ADICLK),
- PINMUX_IPSR_DATA(IP6_22_20, CAN_DEBUGOUT10),
+ PINMUX_IPSR_GPSR(IP6_22_20, SSI_SCK5),
+ PINMUX_IPSR_GPSR(IP6_22_20, ADICLK),
+ PINMUX_IPSR_GPSR(IP6_22_20, CAN_DEBUGOUT10),
PINMUX_IPSR_MSEL(IP6_22_20, SCK3, SEL_SCIF3_0),
PINMUX_IPSR_MSEL(IP6_22_20, TCLK0_D, SEL_TMU0_3),
- PINMUX_IPSR_DATA(IP6_24_23, SSI_WS5),
+ PINMUX_IPSR_GPSR(IP6_24_23, SSI_WS5),
PINMUX_IPSR_MSEL(IP6_24_23, ADICS_SAMP, SEL_ADI_0),
- PINMUX_IPSR_DATA(IP6_24_23, CAN_DEBUGOUT11),
- PINMUX_IPSR_DATA(IP6_24_23, TX3_IRDA_TX),
- PINMUX_IPSR_DATA(IP6_26_25, SSI_SDATA5),
+ PINMUX_IPSR_GPSR(IP6_24_23, CAN_DEBUGOUT11),
+ PINMUX_IPSR_GPSR(IP6_24_23, TX3_IRDA_TX),
+ PINMUX_IPSR_GPSR(IP6_26_25, SSI_SDATA5),
PINMUX_IPSR_MSEL(IP6_26_25, ADIDATA, SEL_ADI_0),
- PINMUX_IPSR_DATA(IP6_26_25, CAN_DEBUGOUT12),
+ PINMUX_IPSR_GPSR(IP6_26_25, CAN_DEBUGOUT12),
PINMUX_IPSR_MSEL(IP6_26_25, RX3_IRDA_RX, SEL_SCIF3_0),
- PINMUX_IPSR_DATA(IP6_30_29, SSI_SCK6),
- PINMUX_IPSR_DATA(IP6_30_29, ADICHS0),
- PINMUX_IPSR_DATA(IP6_30_29, CAN0_TX),
+ PINMUX_IPSR_GPSR(IP6_30_29, SSI_SCK6),
+ PINMUX_IPSR_GPSR(IP6_30_29, ADICHS0),
+ PINMUX_IPSR_GPSR(IP6_30_29, CAN0_TX),
PINMUX_IPSR_MSEL(IP6_30_29, IERX_B, SEL_IE_1),
- PINMUX_IPSR_DATA(IP7_1_0, SSI_WS6),
- PINMUX_IPSR_DATA(IP7_1_0, ADICHS1),
+ PINMUX_IPSR_GPSR(IP7_1_0, SSI_WS6),
+ PINMUX_IPSR_GPSR(IP7_1_0, ADICHS1),
PINMUX_IPSR_MSEL(IP7_1_0, CAN0_RX, SEL_CAN0_0),
- PINMUX_IPSR_DATA(IP7_1_0, IETX_B),
- PINMUX_IPSR_DATA(IP7_3_2, SSI_SDATA6),
- PINMUX_IPSR_DATA(IP7_3_2, ADICHS2),
+ PINMUX_IPSR_GPSR(IP7_1_0, IETX_B),
+ PINMUX_IPSR_GPSR(IP7_3_2, SSI_SDATA6),
+ PINMUX_IPSR_GPSR(IP7_3_2, ADICHS2),
PINMUX_IPSR_MSEL(IP7_3_2, CAN_CLK, SEL_CANCLK_0),
PINMUX_IPSR_MSEL(IP7_3_2, IECLK_B, SEL_IE_1),
PINMUX_IPSR_MSEL(IP7_6_4, SSI_SCK78, SEL_SSI7_0),
- PINMUX_IPSR_DATA(IP7_6_4, CAN_DEBUGOUT13),
+ PINMUX_IPSR_GPSR(IP7_6_4, CAN_DEBUGOUT13),
PINMUX_IPSR_MSEL(IP7_6_4, IRQ0_B, SEL_INT0_1),
PINMUX_IPSR_MSEL(IP7_6_4, SSI_SCK9_B, SEL_SSI9_1),
PINMUX_IPSR_MSEL(IP7_6_4, HSPI_CLK1_C, SEL_HSPI1_2),
PINMUX_IPSR_MSEL(IP7_9_7, SSI_WS78, SEL_SSI7_0),
- PINMUX_IPSR_DATA(IP7_9_7, CAN_DEBUGOUT14),
+ PINMUX_IPSR_GPSR(IP7_9_7, CAN_DEBUGOUT14),
PINMUX_IPSR_MSEL(IP7_9_7, IRQ1_B, SEL_INT1_1),
PINMUX_IPSR_MSEL(IP7_9_7, SSI_WS9_B, SEL_SSI9_1),
PINMUX_IPSR_MSEL(IP7_9_7, HSPI_CS1_C, SEL_HSPI1_2),
PINMUX_IPSR_MSEL(IP7_12_10, SSI_SDATA7, SEL_SSI7_0),
- PINMUX_IPSR_DATA(IP7_12_10, CAN_DEBUGOUT15),
+ PINMUX_IPSR_GPSR(IP7_12_10, CAN_DEBUGOUT15),
PINMUX_IPSR_MSEL(IP7_12_10, IRQ2_B, SEL_INT2_1),
PINMUX_IPSR_MSEL(IP7_12_10, TCLK1_C, SEL_TMU1_2),
- PINMUX_IPSR_DATA(IP7_12_10, HSPI_TX1_C),
+ PINMUX_IPSR_GPSR(IP7_12_10, HSPI_TX1_C),
PINMUX_IPSR_MSEL(IP7_14_13, SSI_SDATA8, SEL_SSI8_0),
- PINMUX_IPSR_DATA(IP7_14_13, VSP),
+ PINMUX_IPSR_GPSR(IP7_14_13, VSP),
PINMUX_IPSR_MSEL(IP7_14_13, IRQ3_B, SEL_INT3_1),
PINMUX_IPSR_MSEL(IP7_14_13, HSPI_RX1_C, SEL_HSPI1_2),
- PINMUX_IPSR_DATA(IP7_16_15, SD0_CLK),
- PINMUX_IPSR_DATA(IP7_16_15, ATACS01),
+ PINMUX_IPSR_GPSR(IP7_16_15, SD0_CLK),
+ PINMUX_IPSR_GPSR(IP7_16_15, ATACS01),
PINMUX_IPSR_MSEL(IP7_16_15, SCK1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP7_18_17, SD0_CMD),
- PINMUX_IPSR_DATA(IP7_18_17, ATACS11),
- PINMUX_IPSR_DATA(IP7_18_17, TX1_B),
- PINMUX_IPSR_DATA(IP7_18_17, CC5_TDO),
- PINMUX_IPSR_DATA(IP7_20_19, SD0_DAT0),
- PINMUX_IPSR_DATA(IP7_20_19, ATADIR1),
+ PINMUX_IPSR_GPSR(IP7_18_17, SD0_CMD),
+ PINMUX_IPSR_GPSR(IP7_18_17, ATACS11),
+ PINMUX_IPSR_GPSR(IP7_18_17, TX1_B),
+ PINMUX_IPSR_GPSR(IP7_18_17, CC5_TDO),
+ PINMUX_IPSR_GPSR(IP7_20_19, SD0_DAT0),
+ PINMUX_IPSR_GPSR(IP7_20_19, ATADIR1),
PINMUX_IPSR_MSEL(IP7_20_19, RX1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP7_20_19, CC5_TRST),
- PINMUX_IPSR_DATA(IP7_22_21, SD0_DAT1),
- PINMUX_IPSR_DATA(IP7_22_21, ATAG1),
+ PINMUX_IPSR_GPSR(IP7_20_19, CC5_TRST),
+ PINMUX_IPSR_GPSR(IP7_22_21, SD0_DAT1),
+ PINMUX_IPSR_GPSR(IP7_22_21, ATAG1),
PINMUX_IPSR_MSEL(IP7_22_21, SCK2_B, SEL_SCIF2_1),
- PINMUX_IPSR_DATA(IP7_22_21, CC5_TMS),
- PINMUX_IPSR_DATA(IP7_24_23, SD0_DAT2),
- PINMUX_IPSR_DATA(IP7_24_23, ATARD1),
- PINMUX_IPSR_DATA(IP7_24_23, TX2_B),
- PINMUX_IPSR_DATA(IP7_24_23, CC5_TCK),
- PINMUX_IPSR_DATA(IP7_26_25, SD0_DAT3),
- PINMUX_IPSR_DATA(IP7_26_25, ATAWR1),
+ PINMUX_IPSR_GPSR(IP7_22_21, CC5_TMS),
+ PINMUX_IPSR_GPSR(IP7_24_23, SD0_DAT2),
+ PINMUX_IPSR_GPSR(IP7_24_23, ATARD1),
+ PINMUX_IPSR_GPSR(IP7_24_23, TX2_B),
+ PINMUX_IPSR_GPSR(IP7_24_23, CC5_TCK),
+ PINMUX_IPSR_GPSR(IP7_26_25, SD0_DAT3),
+ PINMUX_IPSR_GPSR(IP7_26_25, ATAWR1),
PINMUX_IPSR_MSEL(IP7_26_25, RX2_B, SEL_SCIF2_1),
- PINMUX_IPSR_DATA(IP7_26_25, CC5_TDI),
- PINMUX_IPSR_DATA(IP7_28_27, SD0_CD),
+ PINMUX_IPSR_GPSR(IP7_26_25, CC5_TDI),
+ PINMUX_IPSR_GPSR(IP7_28_27, SD0_CD),
PINMUX_IPSR_MSEL(IP7_28_27, DREQ2, SEL_EXBUS2_0),
PINMUX_IPSR_MSEL(IP7_28_27, RTS1_B_TANS_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP7_30_29, SD0_WP),
- PINMUX_IPSR_DATA(IP7_30_29, DACK2),
+ PINMUX_IPSR_GPSR(IP7_30_29, SD0_WP),
+ PINMUX_IPSR_GPSR(IP7_30_29, DACK2),
PINMUX_IPSR_MSEL(IP7_30_29, CTS1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP8_3_0, HSPI_CLK0),
+ PINMUX_IPSR_GPSR(IP8_3_0, HSPI_CLK0),
PINMUX_IPSR_MSEL(IP8_3_0, CTS0, SEL_SCIF0_0),
- PINMUX_IPSR_DATA(IP8_3_0, USB_OVC0),
- PINMUX_IPSR_DATA(IP8_3_0, AD_CLK),
- PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE4),
- PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE12),
- PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE20),
- PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE28),
- PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE36),
- PINMUX_IPSR_DATA(IP8_7_4, HSPI_CS0),
+ PINMUX_IPSR_GPSR(IP8_3_0, USB_OVC0),
+ PINMUX_IPSR_GPSR(IP8_3_0, AD_CLK),
+ PINMUX_IPSR_GPSR(IP8_3_0, CC5_STATE4),
+ PINMUX_IPSR_GPSR(IP8_3_0, CC5_STATE12),
+ PINMUX_IPSR_GPSR(IP8_3_0, CC5_STATE20),
+ PINMUX_IPSR_GPSR(IP8_3_0, CC5_STATE28),
+ PINMUX_IPSR_GPSR(IP8_3_0, CC5_STATE36),
+ PINMUX_IPSR_GPSR(IP8_7_4, HSPI_CS0),
PINMUX_IPSR_MSEL(IP8_7_4, RTS0_TANS, SEL_SCIF0_0),
- PINMUX_IPSR_DATA(IP8_7_4, USB_OVC1),
- PINMUX_IPSR_DATA(IP8_7_4, AD_DI),
- PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE5),
- PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE13),
- PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE21),
- PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE29),
- PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE37),
- PINMUX_IPSR_DATA(IP8_11_8, HSPI_TX0),
- PINMUX_IPSR_DATA(IP8_11_8, TX0),
- PINMUX_IPSR_DATA(IP8_11_8, CAN_DEBUG_HW_TRIGGER),
- PINMUX_IPSR_DATA(IP8_11_8, AD_DO),
- PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE6),
- PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE14),
- PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE22),
- PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE30),
- PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE38),
- PINMUX_IPSR_DATA(IP8_15_12, HSPI_RX0),
+ PINMUX_IPSR_GPSR(IP8_7_4, USB_OVC1),
+ PINMUX_IPSR_GPSR(IP8_7_4, AD_DI),
+ PINMUX_IPSR_GPSR(IP8_7_4, CC5_STATE5),
+ PINMUX_IPSR_GPSR(IP8_7_4, CC5_STATE13),
+ PINMUX_IPSR_GPSR(IP8_7_4, CC5_STATE21),
+ PINMUX_IPSR_GPSR(IP8_7_4, CC5_STATE29),
+ PINMUX_IPSR_GPSR(IP8_7_4, CC5_STATE37),
+ PINMUX_IPSR_GPSR(IP8_11_8, HSPI_TX0),
+ PINMUX_IPSR_GPSR(IP8_11_8, TX0),
+ PINMUX_IPSR_GPSR(IP8_11_8, CAN_DEBUG_HW_TRIGGER),
+ PINMUX_IPSR_GPSR(IP8_11_8, AD_DO),
+ PINMUX_IPSR_GPSR(IP8_11_8, CC5_STATE6),
+ PINMUX_IPSR_GPSR(IP8_11_8, CC5_STATE14),
+ PINMUX_IPSR_GPSR(IP8_11_8, CC5_STATE22),
+ PINMUX_IPSR_GPSR(IP8_11_8, CC5_STATE30),
+ PINMUX_IPSR_GPSR(IP8_11_8, CC5_STATE38),
+ PINMUX_IPSR_GPSR(IP8_15_12, HSPI_RX0),
PINMUX_IPSR_MSEL(IP8_15_12, RX0, SEL_SCIF0_0),
- PINMUX_IPSR_DATA(IP8_15_12, CAN_STEP0),
- PINMUX_IPSR_DATA(IP8_15_12, AD_NCS),
- PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE7),
- PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE15),
- PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE23),
- PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE31),
- PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE39),
- PINMUX_IPSR_DATA(IP8_17_16, FMCLK),
- PINMUX_IPSR_DATA(IP8_17_16, RDS_CLK),
- PINMUX_IPSR_DATA(IP8_17_16, PCMOE),
- PINMUX_IPSR_DATA(IP8_18, BPFCLK),
- PINMUX_IPSR_DATA(IP8_18, PCMWE),
- PINMUX_IPSR_DATA(IP8_19, FMIN),
- PINMUX_IPSR_DATA(IP8_19, RDS_DATA),
- PINMUX_IPSR_DATA(IP8_20, VI0_CLK),
- PINMUX_IPSR_DATA(IP8_20, MMC1_CLK),
- PINMUX_IPSR_DATA(IP8_22_21, VI0_CLKENB),
- PINMUX_IPSR_DATA(IP8_22_21, TX1_C),
- PINMUX_IPSR_DATA(IP8_22_21, HTX1_B),
- PINMUX_IPSR_DATA(IP8_22_21, MT1_SYNC),
- PINMUX_IPSR_DATA(IP8_24_23, VI0_FIELD),
+ PINMUX_IPSR_GPSR(IP8_15_12, CAN_STEP0),
+ PINMUX_IPSR_GPSR(IP8_15_12, AD_NCS),
+ PINMUX_IPSR_GPSR(IP8_15_12, CC5_STATE7),
+ PINMUX_IPSR_GPSR(IP8_15_12, CC5_STATE15),
+ PINMUX_IPSR_GPSR(IP8_15_12, CC5_STATE23),
+ PINMUX_IPSR_GPSR(IP8_15_12, CC5_STATE31),
+ PINMUX_IPSR_GPSR(IP8_15_12, CC5_STATE39),
+ PINMUX_IPSR_GPSR(IP8_17_16, FMCLK),
+ PINMUX_IPSR_GPSR(IP8_17_16, RDS_CLK),
+ PINMUX_IPSR_GPSR(IP8_17_16, PCMOE),
+ PINMUX_IPSR_GPSR(IP8_18, BPFCLK),
+ PINMUX_IPSR_GPSR(IP8_18, PCMWE),
+ PINMUX_IPSR_GPSR(IP8_19, FMIN),
+ PINMUX_IPSR_GPSR(IP8_19, RDS_DATA),
+ PINMUX_IPSR_GPSR(IP8_20, VI0_CLK),
+ PINMUX_IPSR_GPSR(IP8_20, MMC1_CLK),
+ PINMUX_IPSR_GPSR(IP8_22_21, VI0_CLKENB),
+ PINMUX_IPSR_GPSR(IP8_22_21, TX1_C),
+ PINMUX_IPSR_GPSR(IP8_22_21, HTX1_B),
+ PINMUX_IPSR_GPSR(IP8_22_21, MT1_SYNC),
+ PINMUX_IPSR_GPSR(IP8_24_23, VI0_FIELD),
PINMUX_IPSR_MSEL(IP8_24_23, RX1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP8_24_23, HRX1_B, SEL_HSCIF1_1),
- PINMUX_IPSR_DATA(IP8_27_25, VI0_HSYNC),
+ PINMUX_IPSR_GPSR(IP8_27_25, VI0_HSYNC),
PINMUX_IPSR_MSEL(IP8_27_25, VI0_DATA0_B_VI0_B0_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP8_27_25, CTS1_C, SEL_SCIF1_2),
- PINMUX_IPSR_DATA(IP8_27_25, TX4_D),
- PINMUX_IPSR_DATA(IP8_27_25, MMC1_CMD),
+ PINMUX_IPSR_GPSR(IP8_27_25, TX4_D),
+ PINMUX_IPSR_GPSR(IP8_27_25, MMC1_CMD),
PINMUX_IPSR_MSEL(IP8_27_25, HSCK1_B, SEL_HSCIF1_1),
- PINMUX_IPSR_DATA(IP8_30_28, VI0_VSYNC),
+ PINMUX_IPSR_GPSR(IP8_30_28, VI0_VSYNC),
PINMUX_IPSR_MSEL(IP8_30_28, VI0_DATA1_B_VI0_B1_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP8_30_28, RTS1_C_TANS_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP8_30_28, RX4_D, SEL_SCIF4_3),
@@ -1189,216 +1189,216 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP9_1_0, VI0_DATA0_VI0_B0, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP9_1_0, HRTS1_B, SEL_HSCIF1_1),
- PINMUX_IPSR_DATA(IP9_1_0, MT1_VCXO),
+ PINMUX_IPSR_GPSR(IP9_1_0, MT1_VCXO),
PINMUX_IPSR_MSEL(IP9_3_2, VI0_DATA1_VI0_B1, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP9_3_2, HCTS1_B, SEL_HSCIF1_1),
- PINMUX_IPSR_DATA(IP9_3_2, MT1_PWM),
- PINMUX_IPSR_DATA(IP9_4, VI0_DATA2_VI0_B2),
- PINMUX_IPSR_DATA(IP9_4, MMC1_D0),
- PINMUX_IPSR_DATA(IP9_5, VI0_DATA3_VI0_B3),
- PINMUX_IPSR_DATA(IP9_5, MMC1_D1),
- PINMUX_IPSR_DATA(IP9_6, VI0_DATA4_VI0_B4),
- PINMUX_IPSR_DATA(IP9_6, MMC1_D2),
- PINMUX_IPSR_DATA(IP9_7, VI0_DATA5_VI0_B5),
- PINMUX_IPSR_DATA(IP9_7, MMC1_D3),
- PINMUX_IPSR_DATA(IP9_9_8, VI0_DATA6_VI0_B6),
- PINMUX_IPSR_DATA(IP9_9_8, MMC1_D4),
- PINMUX_IPSR_DATA(IP9_9_8, ARM_TRACEDATA_0),
- PINMUX_IPSR_DATA(IP9_11_10, VI0_DATA7_VI0_B7),
- PINMUX_IPSR_DATA(IP9_11_10, MMC1_D5),
- PINMUX_IPSR_DATA(IP9_11_10, ARM_TRACEDATA_1),
- PINMUX_IPSR_DATA(IP9_13_12, VI0_G0),
+ PINMUX_IPSR_GPSR(IP9_3_2, MT1_PWM),
+ PINMUX_IPSR_GPSR(IP9_4, VI0_DATA2_VI0_B2),
+ PINMUX_IPSR_GPSR(IP9_4, MMC1_D0),
+ PINMUX_IPSR_GPSR(IP9_5, VI0_DATA3_VI0_B3),
+ PINMUX_IPSR_GPSR(IP9_5, MMC1_D1),
+ PINMUX_IPSR_GPSR(IP9_6, VI0_DATA4_VI0_B4),
+ PINMUX_IPSR_GPSR(IP9_6, MMC1_D2),
+ PINMUX_IPSR_GPSR(IP9_7, VI0_DATA5_VI0_B5),
+ PINMUX_IPSR_GPSR(IP9_7, MMC1_D3),
+ PINMUX_IPSR_GPSR(IP9_9_8, VI0_DATA6_VI0_B6),
+ PINMUX_IPSR_GPSR(IP9_9_8, MMC1_D4),
+ PINMUX_IPSR_GPSR(IP9_9_8, ARM_TRACEDATA_0),
+ PINMUX_IPSR_GPSR(IP9_11_10, VI0_DATA7_VI0_B7),
+ PINMUX_IPSR_GPSR(IP9_11_10, MMC1_D5),
+ PINMUX_IPSR_GPSR(IP9_11_10, ARM_TRACEDATA_1),
+ PINMUX_IPSR_GPSR(IP9_13_12, VI0_G0),
PINMUX_IPSR_MSEL(IP9_13_12, SSI_SCK78_C, SEL_SSI7_2),
PINMUX_IPSR_MSEL(IP9_13_12, IRQ0, SEL_INT0_0),
- PINMUX_IPSR_DATA(IP9_13_12, ARM_TRACEDATA_2),
- PINMUX_IPSR_DATA(IP9_15_14, VI0_G1),
+ PINMUX_IPSR_GPSR(IP9_13_12, ARM_TRACEDATA_2),
+ PINMUX_IPSR_GPSR(IP9_15_14, VI0_G1),
PINMUX_IPSR_MSEL(IP9_15_14, SSI_WS78_C, SEL_SSI7_2),
PINMUX_IPSR_MSEL(IP9_15_14, IRQ1, SEL_INT1_0),
- PINMUX_IPSR_DATA(IP9_15_14, ARM_TRACEDATA_3),
- PINMUX_IPSR_DATA(IP9_18_16, VI0_G2),
- PINMUX_IPSR_DATA(IP9_18_16, ETH_TXD1),
- PINMUX_IPSR_DATA(IP9_18_16, MMC1_D6),
- PINMUX_IPSR_DATA(IP9_18_16, ARM_TRACEDATA_4),
- PINMUX_IPSR_DATA(IP9_18_16, TS_SPSYNC0),
- PINMUX_IPSR_DATA(IP9_21_19, VI0_G3),
- PINMUX_IPSR_DATA(IP9_21_19, ETH_CRS_DV),
- PINMUX_IPSR_DATA(IP9_21_19, MMC1_D7),
- PINMUX_IPSR_DATA(IP9_21_19, ARM_TRACEDATA_5),
- PINMUX_IPSR_DATA(IP9_21_19, TS_SDAT0),
- PINMUX_IPSR_DATA(IP9_23_22, VI0_G4),
- PINMUX_IPSR_DATA(IP9_23_22, ETH_TX_EN),
+ PINMUX_IPSR_GPSR(IP9_15_14, ARM_TRACEDATA_3),
+ PINMUX_IPSR_GPSR(IP9_18_16, VI0_G2),
+ PINMUX_IPSR_GPSR(IP9_18_16, ETH_TXD1),
+ PINMUX_IPSR_GPSR(IP9_18_16, MMC1_D6),
+ PINMUX_IPSR_GPSR(IP9_18_16, ARM_TRACEDATA_4),
+ PINMUX_IPSR_GPSR(IP9_18_16, TS_SPSYNC0),
+ PINMUX_IPSR_GPSR(IP9_21_19, VI0_G3),
+ PINMUX_IPSR_GPSR(IP9_21_19, ETH_CRS_DV),
+ PINMUX_IPSR_GPSR(IP9_21_19, MMC1_D7),
+ PINMUX_IPSR_GPSR(IP9_21_19, ARM_TRACEDATA_5),
+ PINMUX_IPSR_GPSR(IP9_21_19, TS_SDAT0),
+ PINMUX_IPSR_GPSR(IP9_23_22, VI0_G4),
+ PINMUX_IPSR_GPSR(IP9_23_22, ETH_TX_EN),
PINMUX_IPSR_MSEL(IP9_23_22, SD2_DAT0_B, SEL_SD2_1),
- PINMUX_IPSR_DATA(IP9_23_22, ARM_TRACEDATA_6),
- PINMUX_IPSR_DATA(IP9_25_24, VI0_G5),
- PINMUX_IPSR_DATA(IP9_25_24, ETH_RX_ER),
+ PINMUX_IPSR_GPSR(IP9_23_22, ARM_TRACEDATA_6),
+ PINMUX_IPSR_GPSR(IP9_25_24, VI0_G5),
+ PINMUX_IPSR_GPSR(IP9_25_24, ETH_RX_ER),
PINMUX_IPSR_MSEL(IP9_25_24, SD2_DAT1_B, SEL_SD2_1),
- PINMUX_IPSR_DATA(IP9_25_24, ARM_TRACEDATA_7),
- PINMUX_IPSR_DATA(IP9_27_26, VI0_G6),
- PINMUX_IPSR_DATA(IP9_27_26, ETH_RXD0),
+ PINMUX_IPSR_GPSR(IP9_25_24, ARM_TRACEDATA_7),
+ PINMUX_IPSR_GPSR(IP9_27_26, VI0_G6),
+ PINMUX_IPSR_GPSR(IP9_27_26, ETH_RXD0),
PINMUX_IPSR_MSEL(IP9_27_26, SD2_DAT2_B, SEL_SD2_1),
- PINMUX_IPSR_DATA(IP9_27_26, ARM_TRACEDATA_8),
- PINMUX_IPSR_DATA(IP9_29_28, VI0_G7),
- PINMUX_IPSR_DATA(IP9_29_28, ETH_RXD1),
+ PINMUX_IPSR_GPSR(IP9_27_26, ARM_TRACEDATA_8),
+ PINMUX_IPSR_GPSR(IP9_29_28, VI0_G7),
+ PINMUX_IPSR_GPSR(IP9_29_28, ETH_RXD1),
PINMUX_IPSR_MSEL(IP9_29_28, SD2_DAT3_B, SEL_SD2_1),
- PINMUX_IPSR_DATA(IP9_29_28, ARM_TRACEDATA_9),
+ PINMUX_IPSR_GPSR(IP9_29_28, ARM_TRACEDATA_9),
- PINMUX_IPSR_DATA(IP10_2_0, VI0_R0),
+ PINMUX_IPSR_GPSR(IP10_2_0, VI0_R0),
PINMUX_IPSR_MSEL(IP10_2_0, SSI_SDATA7_C, SEL_SSI7_2),
PINMUX_IPSR_MSEL(IP10_2_0, SCK1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP10_2_0, DREQ1_B, SEL_EXBUS1_0),
- PINMUX_IPSR_DATA(IP10_2_0, ARM_TRACEDATA_10),
+ PINMUX_IPSR_GPSR(IP10_2_0, ARM_TRACEDATA_10),
PINMUX_IPSR_MSEL(IP10_2_0, DREQ0_C, SEL_EXBUS0_2),
- PINMUX_IPSR_DATA(IP10_5_3, VI0_R1),
+ PINMUX_IPSR_GPSR(IP10_5_3, VI0_R1),
PINMUX_IPSR_MSEL(IP10_5_3, SSI_SDATA8_C, SEL_SSI8_2),
- PINMUX_IPSR_DATA(IP10_5_3, DACK1_B),
- PINMUX_IPSR_DATA(IP10_5_3, ARM_TRACEDATA_11),
- PINMUX_IPSR_DATA(IP10_5_3, DACK0_C),
- PINMUX_IPSR_DATA(IP10_5_3, DRACK0_C),
- PINMUX_IPSR_DATA(IP10_8_6, VI0_R2),
- PINMUX_IPSR_DATA(IP10_8_6, ETH_LINK),
- PINMUX_IPSR_DATA(IP10_8_6, SD2_CLK_B),
+ PINMUX_IPSR_GPSR(IP10_5_3, DACK1_B),
+ PINMUX_IPSR_GPSR(IP10_5_3, ARM_TRACEDATA_11),
+ PINMUX_IPSR_GPSR(IP10_5_3, DACK0_C),
+ PINMUX_IPSR_GPSR(IP10_5_3, DRACK0_C),
+ PINMUX_IPSR_GPSR(IP10_8_6, VI0_R2),
+ PINMUX_IPSR_GPSR(IP10_8_6, ETH_LINK),
+ PINMUX_IPSR_GPSR(IP10_8_6, SD2_CLK_B),
PINMUX_IPSR_MSEL(IP10_8_6, IRQ2, SEL_INT2_0),
- PINMUX_IPSR_DATA(IP10_8_6, ARM_TRACEDATA_12),
- PINMUX_IPSR_DATA(IP10_11_9, VI0_R3),
- PINMUX_IPSR_DATA(IP10_11_9, ETH_MAGIC),
+ PINMUX_IPSR_GPSR(IP10_8_6, ARM_TRACEDATA_12),
+ PINMUX_IPSR_GPSR(IP10_11_9, VI0_R3),
+ PINMUX_IPSR_GPSR(IP10_11_9, ETH_MAGIC),
PINMUX_IPSR_MSEL(IP10_11_9, SD2_CMD_B, SEL_SD2_1),
PINMUX_IPSR_MSEL(IP10_11_9, IRQ3, SEL_INT3_0),
- PINMUX_IPSR_DATA(IP10_11_9, ARM_TRACEDATA_13),
- PINMUX_IPSR_DATA(IP10_14_12, VI0_R4),
- PINMUX_IPSR_DATA(IP10_14_12, ETH_REFCLK),
+ PINMUX_IPSR_GPSR(IP10_11_9, ARM_TRACEDATA_13),
+ PINMUX_IPSR_GPSR(IP10_14_12, VI0_R4),
+ PINMUX_IPSR_GPSR(IP10_14_12, ETH_REFCLK),
PINMUX_IPSR_MSEL(IP10_14_12, SD2_CD_B, SEL_SD2_1),
PINMUX_IPSR_MSEL(IP10_14_12, HSPI_CLK1_B, SEL_HSPI1_1),
- PINMUX_IPSR_DATA(IP10_14_12, ARM_TRACEDATA_14),
- PINMUX_IPSR_DATA(IP10_14_12, MT1_CLK),
- PINMUX_IPSR_DATA(IP10_14_12, TS_SCK0),
- PINMUX_IPSR_DATA(IP10_17_15, VI0_R5),
- PINMUX_IPSR_DATA(IP10_17_15, ETH_TXD0),
+ PINMUX_IPSR_GPSR(IP10_14_12, ARM_TRACEDATA_14),
+ PINMUX_IPSR_GPSR(IP10_14_12, MT1_CLK),
+ PINMUX_IPSR_GPSR(IP10_14_12, TS_SCK0),
+ PINMUX_IPSR_GPSR(IP10_17_15, VI0_R5),
+ PINMUX_IPSR_GPSR(IP10_17_15, ETH_TXD0),
PINMUX_IPSR_MSEL(IP10_17_15, SD2_WP_B, SEL_SD2_1),
PINMUX_IPSR_MSEL(IP10_17_15, HSPI_CS1_B, SEL_HSPI1_1),
- PINMUX_IPSR_DATA(IP10_17_15, ARM_TRACEDATA_15),
- PINMUX_IPSR_DATA(IP10_17_15, MT1_D),
- PINMUX_IPSR_DATA(IP10_17_15, TS_SDEN0),
- PINMUX_IPSR_DATA(IP10_20_18, VI0_R6),
- PINMUX_IPSR_DATA(IP10_20_18, ETH_MDC),
+ PINMUX_IPSR_GPSR(IP10_17_15, ARM_TRACEDATA_15),
+ PINMUX_IPSR_GPSR(IP10_17_15, MT1_D),
+ PINMUX_IPSR_GPSR(IP10_17_15, TS_SDEN0),
+ PINMUX_IPSR_GPSR(IP10_20_18, VI0_R6),
+ PINMUX_IPSR_GPSR(IP10_20_18, ETH_MDC),
PINMUX_IPSR_MSEL(IP10_20_18, DREQ2_C, SEL_EXBUS2_2),
- PINMUX_IPSR_DATA(IP10_20_18, HSPI_TX1_B),
- PINMUX_IPSR_DATA(IP10_20_18, TRACECLK),
- PINMUX_IPSR_DATA(IP10_20_18, MT1_BEN),
+ PINMUX_IPSR_GPSR(IP10_20_18, HSPI_TX1_B),
+ PINMUX_IPSR_GPSR(IP10_20_18, TRACECLK),
+ PINMUX_IPSR_GPSR(IP10_20_18, MT1_BEN),
PINMUX_IPSR_MSEL(IP10_20_18, PWMFSW0_D, SEL_PWMFSW_3),
- PINMUX_IPSR_DATA(IP10_23_21, VI0_R7),
- PINMUX_IPSR_DATA(IP10_23_21, ETH_MDIO),
- PINMUX_IPSR_DATA(IP10_23_21, DACK2_C),
+ PINMUX_IPSR_GPSR(IP10_23_21, VI0_R7),
+ PINMUX_IPSR_GPSR(IP10_23_21, ETH_MDIO),
+ PINMUX_IPSR_GPSR(IP10_23_21, DACK2_C),
PINMUX_IPSR_MSEL(IP10_23_21, HSPI_RX1_B, SEL_HSPI1_1),
PINMUX_IPSR_MSEL(IP10_23_21, SCIF_CLK_D, SEL_SCIF_3),
- PINMUX_IPSR_DATA(IP10_23_21, TRACECTL),
- PINMUX_IPSR_DATA(IP10_23_21, MT1_PEN),
- PINMUX_IPSR_DATA(IP10_25_24, VI1_CLK),
+ PINMUX_IPSR_GPSR(IP10_23_21, TRACECTL),
+ PINMUX_IPSR_GPSR(IP10_23_21, MT1_PEN),
+ PINMUX_IPSR_GPSR(IP10_25_24, VI1_CLK),
PINMUX_IPSR_MSEL(IP10_25_24, SIM_D, SEL_SIM_0),
PINMUX_IPSR_MSEL(IP10_25_24, SDA3, SEL_I2C3_0),
- PINMUX_IPSR_DATA(IP10_28_26, VI1_HSYNC),
- PINMUX_IPSR_DATA(IP10_28_26, VI3_CLK),
- PINMUX_IPSR_DATA(IP10_28_26, SSI_SCK4),
+ PINMUX_IPSR_GPSR(IP10_28_26, VI1_HSYNC),
+ PINMUX_IPSR_GPSR(IP10_28_26, VI3_CLK),
+ PINMUX_IPSR_GPSR(IP10_28_26, SSI_SCK4),
PINMUX_IPSR_MSEL(IP10_28_26, GPS_SIGN_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP10_28_26, PWMFSW0_E, SEL_PWMFSW_4),
- PINMUX_IPSR_DATA(IP10_31_29, VI1_VSYNC),
- PINMUX_IPSR_DATA(IP10_31_29, AUDIO_CLKOUT_C),
- PINMUX_IPSR_DATA(IP10_31_29, SSI_WS4),
- PINMUX_IPSR_DATA(IP10_31_29, SIM_CLK),
+ PINMUX_IPSR_GPSR(IP10_31_29, VI1_VSYNC),
+ PINMUX_IPSR_GPSR(IP10_31_29, AUDIO_CLKOUT_C),
+ PINMUX_IPSR_GPSR(IP10_31_29, SSI_WS4),
+ PINMUX_IPSR_GPSR(IP10_31_29, SIM_CLK),
PINMUX_IPSR_MSEL(IP10_31_29, GPS_MAG_C, SEL_GPS_2),
- PINMUX_IPSR_DATA(IP10_31_29, SPV_TRST),
+ PINMUX_IPSR_GPSR(IP10_31_29, SPV_TRST),
PINMUX_IPSR_MSEL(IP10_31_29, SCL3, SEL_I2C3_0),
- PINMUX_IPSR_DATA(IP11_2_0, VI1_DATA0_VI1_B0),
+ PINMUX_IPSR_GPSR(IP11_2_0, VI1_DATA0_VI1_B0),
PINMUX_IPSR_MSEL(IP11_2_0, SD2_DAT0, SEL_SD2_0),
- PINMUX_IPSR_DATA(IP11_2_0, SIM_RST),
- PINMUX_IPSR_DATA(IP11_2_0, SPV_TCK),
- PINMUX_IPSR_DATA(IP11_2_0, ADICLK_B),
- PINMUX_IPSR_DATA(IP11_5_3, VI1_DATA1_VI1_B1),
+ PINMUX_IPSR_GPSR(IP11_2_0, SIM_RST),
+ PINMUX_IPSR_GPSR(IP11_2_0, SPV_TCK),
+ PINMUX_IPSR_GPSR(IP11_2_0, ADICLK_B),
+ PINMUX_IPSR_GPSR(IP11_5_3, VI1_DATA1_VI1_B1),
PINMUX_IPSR_MSEL(IP11_5_3, SD2_DAT1, SEL_SD2_0),
- PINMUX_IPSR_DATA(IP11_5_3, MT0_CLK),
- PINMUX_IPSR_DATA(IP11_5_3, SPV_TMS),
+ PINMUX_IPSR_GPSR(IP11_5_3, MT0_CLK),
+ PINMUX_IPSR_GPSR(IP11_5_3, SPV_TMS),
PINMUX_IPSR_MSEL(IP11_5_3, ADICS_B_SAMP_B, SEL_ADI_1),
- PINMUX_IPSR_DATA(IP11_8_6, VI1_DATA2_VI1_B2),
+ PINMUX_IPSR_GPSR(IP11_8_6, VI1_DATA2_VI1_B2),
PINMUX_IPSR_MSEL(IP11_8_6, SD2_DAT2, SEL_SD2_0),
- PINMUX_IPSR_DATA(IP11_8_6, MT0_D),
- PINMUX_IPSR_DATA(IP11_8_6, SPVTDI),
+ PINMUX_IPSR_GPSR(IP11_8_6, MT0_D),
+ PINMUX_IPSR_GPSR(IP11_8_6, SPVTDI),
PINMUX_IPSR_MSEL(IP11_8_6, ADIDATA_B, SEL_ADI_1),
- PINMUX_IPSR_DATA(IP11_11_9, VI1_DATA3_VI1_B3),
+ PINMUX_IPSR_GPSR(IP11_11_9, VI1_DATA3_VI1_B3),
PINMUX_IPSR_MSEL(IP11_11_9, SD2_DAT3, SEL_SD2_0),
- PINMUX_IPSR_DATA(IP11_11_9, MT0_BEN),
- PINMUX_IPSR_DATA(IP11_11_9, SPV_TDO),
- PINMUX_IPSR_DATA(IP11_11_9, ADICHS0_B),
- PINMUX_IPSR_DATA(IP11_14_12, VI1_DATA4_VI1_B4),
- PINMUX_IPSR_DATA(IP11_14_12, SD2_CLK),
- PINMUX_IPSR_DATA(IP11_14_12, MT0_PEN),
- PINMUX_IPSR_DATA(IP11_14_12, SPA_TRST),
+ PINMUX_IPSR_GPSR(IP11_11_9, MT0_BEN),
+ PINMUX_IPSR_GPSR(IP11_11_9, SPV_TDO),
+ PINMUX_IPSR_GPSR(IP11_11_9, ADICHS0_B),
+ PINMUX_IPSR_GPSR(IP11_14_12, VI1_DATA4_VI1_B4),
+ PINMUX_IPSR_GPSR(IP11_14_12, SD2_CLK),
+ PINMUX_IPSR_GPSR(IP11_14_12, MT0_PEN),
+ PINMUX_IPSR_GPSR(IP11_14_12, SPA_TRST),
PINMUX_IPSR_MSEL(IP11_14_12, HSPI_CLK1_D, SEL_HSPI1_3),
- PINMUX_IPSR_DATA(IP11_14_12, ADICHS1_B),
- PINMUX_IPSR_DATA(IP11_17_15, VI1_DATA5_VI1_B5),
+ PINMUX_IPSR_GPSR(IP11_14_12, ADICHS1_B),
+ PINMUX_IPSR_GPSR(IP11_17_15, VI1_DATA5_VI1_B5),
PINMUX_IPSR_MSEL(IP11_17_15, SD2_CMD, SEL_SD2_0),
- PINMUX_IPSR_DATA(IP11_17_15, MT0_SYNC),
- PINMUX_IPSR_DATA(IP11_17_15, SPA_TCK),
+ PINMUX_IPSR_GPSR(IP11_17_15, MT0_SYNC),
+ PINMUX_IPSR_GPSR(IP11_17_15, SPA_TCK),
PINMUX_IPSR_MSEL(IP11_17_15, HSPI_CS1_D, SEL_HSPI1_3),
- PINMUX_IPSR_DATA(IP11_17_15, ADICHS2_B),
- PINMUX_IPSR_DATA(IP11_20_18, VI1_DATA6_VI1_B6),
+ PINMUX_IPSR_GPSR(IP11_17_15, ADICHS2_B),
+ PINMUX_IPSR_GPSR(IP11_20_18, VI1_DATA6_VI1_B6),
PINMUX_IPSR_MSEL(IP11_20_18, SD2_CD, SEL_SD2_0),
- PINMUX_IPSR_DATA(IP11_20_18, MT0_VCXO),
- PINMUX_IPSR_DATA(IP11_20_18, SPA_TMS),
- PINMUX_IPSR_DATA(IP11_20_18, HSPI_TX1_D),
- PINMUX_IPSR_DATA(IP11_23_21, VI1_DATA7_VI1_B7),
+ PINMUX_IPSR_GPSR(IP11_20_18, MT0_VCXO),
+ PINMUX_IPSR_GPSR(IP11_20_18, SPA_TMS),
+ PINMUX_IPSR_GPSR(IP11_20_18, HSPI_TX1_D),
+ PINMUX_IPSR_GPSR(IP11_23_21, VI1_DATA7_VI1_B7),
PINMUX_IPSR_MSEL(IP11_23_21, SD2_WP, SEL_SD2_0),
- PINMUX_IPSR_DATA(IP11_23_21, MT0_PWM),
- PINMUX_IPSR_DATA(IP11_23_21, SPA_TDI),
+ PINMUX_IPSR_GPSR(IP11_23_21, MT0_PWM),
+ PINMUX_IPSR_GPSR(IP11_23_21, SPA_TDI),
PINMUX_IPSR_MSEL(IP11_23_21, HSPI_RX1_D, SEL_HSPI1_3),
- PINMUX_IPSR_DATA(IP11_26_24, VI1_G0),
- PINMUX_IPSR_DATA(IP11_26_24, VI3_DATA0),
- PINMUX_IPSR_DATA(IP11_26_24, TS_SCK1),
+ PINMUX_IPSR_GPSR(IP11_26_24, VI1_G0),
+ PINMUX_IPSR_GPSR(IP11_26_24, VI3_DATA0),
+ PINMUX_IPSR_GPSR(IP11_26_24, TS_SCK1),
PINMUX_IPSR_MSEL(IP11_26_24, DREQ2_B, SEL_EXBUS2_1),
- PINMUX_IPSR_DATA(IP11_26_24, TX2),
- PINMUX_IPSR_DATA(IP11_26_24, SPA_TDO),
+ PINMUX_IPSR_GPSR(IP11_26_24, TX2),
+ PINMUX_IPSR_GPSR(IP11_26_24, SPA_TDO),
PINMUX_IPSR_MSEL(IP11_26_24, HCTS0_B, SEL_HSCIF0_1),
- PINMUX_IPSR_DATA(IP11_29_27, VI1_G1),
- PINMUX_IPSR_DATA(IP11_29_27, VI3_DATA1),
- PINMUX_IPSR_DATA(IP11_29_27, SSI_SCK1),
- PINMUX_IPSR_DATA(IP11_29_27, TS_SDEN1),
- PINMUX_IPSR_DATA(IP11_29_27, DACK2_B),
+ PINMUX_IPSR_GPSR(IP11_29_27, VI1_G1),
+ PINMUX_IPSR_GPSR(IP11_29_27, VI3_DATA1),
+ PINMUX_IPSR_GPSR(IP11_29_27, SSI_SCK1),
+ PINMUX_IPSR_GPSR(IP11_29_27, TS_SDEN1),
+ PINMUX_IPSR_GPSR(IP11_29_27, DACK2_B),
PINMUX_IPSR_MSEL(IP11_29_27, RX2, SEL_SCIF2_0),
PINMUX_IPSR_MSEL(IP11_29_27, HRTS0_B, SEL_HSCIF0_1),
- PINMUX_IPSR_DATA(IP12_2_0, VI1_G2),
- PINMUX_IPSR_DATA(IP12_2_0, VI3_DATA2),
- PINMUX_IPSR_DATA(IP12_2_0, SSI_WS1),
- PINMUX_IPSR_DATA(IP12_2_0, TS_SPSYNC1),
+ PINMUX_IPSR_GPSR(IP12_2_0, VI1_G2),
+ PINMUX_IPSR_GPSR(IP12_2_0, VI3_DATA2),
+ PINMUX_IPSR_GPSR(IP12_2_0, SSI_WS1),
+ PINMUX_IPSR_GPSR(IP12_2_0, TS_SPSYNC1),
PINMUX_IPSR_MSEL(IP12_2_0, SCK2, SEL_SCIF2_0),
PINMUX_IPSR_MSEL(IP12_2_0, HSCK0_B, SEL_HSCIF0_1),
- PINMUX_IPSR_DATA(IP12_5_3, VI1_G3),
- PINMUX_IPSR_DATA(IP12_5_3, VI3_DATA3),
- PINMUX_IPSR_DATA(IP12_5_3, SSI_SCK2),
- PINMUX_IPSR_DATA(IP12_5_3, TS_SDAT1),
+ PINMUX_IPSR_GPSR(IP12_5_3, VI1_G3),
+ PINMUX_IPSR_GPSR(IP12_5_3, VI3_DATA3),
+ PINMUX_IPSR_GPSR(IP12_5_3, SSI_SCK2),
+ PINMUX_IPSR_GPSR(IP12_5_3, TS_SDAT1),
PINMUX_IPSR_MSEL(IP12_5_3, SCL1_C, SEL_I2C1_2),
- PINMUX_IPSR_DATA(IP12_5_3, HTX0_B),
- PINMUX_IPSR_DATA(IP12_8_6, VI1_G4),
- PINMUX_IPSR_DATA(IP12_8_6, VI3_DATA4),
- PINMUX_IPSR_DATA(IP12_8_6, SSI_WS2),
+ PINMUX_IPSR_GPSR(IP12_5_3, HTX0_B),
+ PINMUX_IPSR_GPSR(IP12_8_6, VI1_G4),
+ PINMUX_IPSR_GPSR(IP12_8_6, VI3_DATA4),
+ PINMUX_IPSR_GPSR(IP12_8_6, SSI_WS2),
PINMUX_IPSR_MSEL(IP12_8_6, SDA1_C, SEL_I2C1_2),
- PINMUX_IPSR_DATA(IP12_8_6, SIM_RST_B),
+ PINMUX_IPSR_GPSR(IP12_8_6, SIM_RST_B),
PINMUX_IPSR_MSEL(IP12_8_6, HRX0_B, SEL_HSCIF0_1),
- PINMUX_IPSR_DATA(IP12_11_9, VI1_G5),
- PINMUX_IPSR_DATA(IP12_11_9, VI3_DATA5),
+ PINMUX_IPSR_GPSR(IP12_11_9, VI1_G5),
+ PINMUX_IPSR_GPSR(IP12_11_9, VI3_DATA5),
PINMUX_IPSR_MSEL(IP12_11_9, GPS_CLK, SEL_GPS_0),
- PINMUX_IPSR_DATA(IP12_11_9, FSE),
- PINMUX_IPSR_DATA(IP12_11_9, TX4_B),
+ PINMUX_IPSR_GPSR(IP12_11_9, FSE),
+ PINMUX_IPSR_GPSR(IP12_11_9, TX4_B),
PINMUX_IPSR_MSEL(IP12_11_9, SIM_D_B, SEL_SIM_1),
- PINMUX_IPSR_DATA(IP12_14_12, VI1_G6),
- PINMUX_IPSR_DATA(IP12_14_12, VI3_DATA6),
+ PINMUX_IPSR_GPSR(IP12_14_12, VI1_G6),
+ PINMUX_IPSR_GPSR(IP12_14_12, VI3_DATA6),
PINMUX_IPSR_MSEL(IP12_14_12, GPS_SIGN, SEL_GPS_0),
- PINMUX_IPSR_DATA(IP12_14_12, FRB),
+ PINMUX_IPSR_GPSR(IP12_14_12, FRB),
PINMUX_IPSR_MSEL(IP12_14_12, RX4_B, SEL_SCIF4_1),
- PINMUX_IPSR_DATA(IP12_14_12, SIM_CLK_B),
- PINMUX_IPSR_DATA(IP12_17_15, VI1_G7),
- PINMUX_IPSR_DATA(IP12_17_15, VI3_DATA7),
+ PINMUX_IPSR_GPSR(IP12_14_12, SIM_CLK_B),
+ PINMUX_IPSR_GPSR(IP12_17_15, VI1_G7),
+ PINMUX_IPSR_GPSR(IP12_17_15, VI3_DATA7),
PINMUX_IPSR_MSEL(IP12_17_15, GPS_MAG, SEL_GPS_0),
- PINMUX_IPSR_DATA(IP12_17_15, FCE),
+ PINMUX_IPSR_GPSR(IP12_17_15, FCE),
PINMUX_IPSR_MSEL(IP12_17_15, SCK4_B, SEL_SCIF4_1),
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index a8b629bc7a55..0f4d48f9400b 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -799,47 +799,47 @@ static const u16 pinmux_data[] = {
PINMUX_SINGLE(DU_DOTCLKIN0),
PINMUX_SINGLE(DU_DOTCLKIN2),
- PINMUX_IPSR_DATA(IP0_2_0, D0),
+ PINMUX_IPSR_GPSR(IP0_2_0, D0),
PINMUX_IPSR_MSEL(IP0_2_0, MSIOF3_SCK_B, SEL_SOF3_1),
PINMUX_IPSR_MSEL(IP0_2_0, VI3_DATA0, SEL_VI3_0),
PINMUX_IPSR_MSEL(IP0_2_0, VI0_G4, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP0_2_0, VI0_G4_B, SEL_VI0_1),
- PINMUX_IPSR_DATA(IP0_5_3, D1),
+ PINMUX_IPSR_GPSR(IP0_5_3, D1),
PINMUX_IPSR_MSEL(IP0_5_3, MSIOF3_SYNC_B, SEL_SOF3_1),
PINMUX_IPSR_MSEL(IP0_5_3, VI3_DATA1, SEL_VI3_0),
PINMUX_IPSR_MSEL(IP0_5_3, VI0_G5, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP0_5_3, VI0_G5_B, SEL_VI0_1),
- PINMUX_IPSR_DATA(IP0_8_6, D2),
+ PINMUX_IPSR_GPSR(IP0_8_6, D2),
PINMUX_IPSR_MSEL(IP0_8_6, MSIOF3_RXD_B, SEL_SOF3_1),
PINMUX_IPSR_MSEL(IP0_8_6, VI3_DATA2, SEL_VI3_0),
PINMUX_IPSR_MSEL(IP0_8_6, VI0_G6, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP0_8_6, VI0_G6_B, SEL_VI0_1),
- PINMUX_IPSR_DATA(IP0_11_9, D3),
+ PINMUX_IPSR_GPSR(IP0_11_9, D3),
PINMUX_IPSR_MSEL(IP0_11_9, MSIOF3_TXD_B, SEL_SOF3_1),
PINMUX_IPSR_MSEL(IP0_11_9, VI3_DATA3, SEL_VI3_0),
PINMUX_IPSR_MSEL(IP0_11_9, VI0_G7, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP0_11_9, VI0_G7_B, SEL_VI0_1),
- PINMUX_IPSR_DATA(IP0_15_12, D4),
+ PINMUX_IPSR_GPSR(IP0_15_12, D4),
PINMUX_IPSR_MSEL(IP0_15_12, SCIFB1_RXD_F, SEL_SCIFB1_5),
PINMUX_IPSR_MSEL(IP0_15_12, SCIFB0_RXD_C, SEL_SCIFB_2),
PINMUX_IPSR_MSEL(IP0_15_12, VI3_DATA4, SEL_VI3_0),
PINMUX_IPSR_MSEL(IP0_15_12, VI0_R0, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP0_15_12, VI0_R0_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP0_15_12, RX0_B, SEL_SCIF0_1),
- PINMUX_IPSR_DATA(IP0_19_16, D5),
+ PINMUX_IPSR_GPSR(IP0_19_16, D5),
PINMUX_IPSR_MSEL(IP0_19_16, SCIFB1_TXD_F, SEL_SCIFB1_5),
PINMUX_IPSR_MSEL(IP0_19_16, SCIFB0_TXD_C, SEL_SCIFB_2),
PINMUX_IPSR_MSEL(IP0_19_16, VI3_DATA5, SEL_VI3_0),
PINMUX_IPSR_MSEL(IP0_19_16, VI0_R1, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP0_19_16, VI0_R1_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP0_19_16, TX0_B, SEL_SCIF0_1),
- PINMUX_IPSR_DATA(IP0_22_20, D6),
+ PINMUX_IPSR_GPSR(IP0_22_20, D6),
PINMUX_IPSR_MSEL(IP0_22_20, IIC2_SCL_C, SEL_IIC2_2),
PINMUX_IPSR_MSEL(IP0_22_20, VI3_DATA6, SEL_VI3_0),
PINMUX_IPSR_MSEL(IP0_22_20, VI0_R2, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP0_22_20, VI0_R2_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP0_22_20, I2C2_SCL_C, SEL_I2C2_2),
- PINMUX_IPSR_DATA(IP0_26_23, D7),
+ PINMUX_IPSR_GPSR(IP0_26_23, D7),
PINMUX_IPSR_MSEL(IP0_26_23, AD_DI_B, SEL_ADI_1),
PINMUX_IPSR_MSEL(IP0_26_23, IIC2_SDA_C, SEL_IIC2_2),
PINMUX_IPSR_MSEL(IP0_26_23, VI3_DATA7, SEL_VI3_0),
@@ -847,81 +847,81 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP0_26_23, VI0_R3_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP0_26_23, I2C2_SDA_C, SEL_I2C2_2),
PINMUX_IPSR_MSEL(IP0_26_23, TCLK1, SEL_TMU1_0),
- PINMUX_IPSR_DATA(IP0_30_27, D8),
+ PINMUX_IPSR_GPSR(IP0_30_27, D8),
PINMUX_IPSR_MSEL(IP0_30_27, SCIFA1_SCK_C, SEL_SCIFA1_2),
- PINMUX_IPSR_DATA(IP0_30_27, AVB_TXD0),
+ PINMUX_IPSR_GPSR(IP0_30_27, AVB_TXD0),
PINMUX_IPSR_MSEL(IP0_30_27, VI0_G0, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP0_30_27, VI0_G0_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP0_30_27, VI2_DATA0_VI2_B0, SEL_VI2_0),
- PINMUX_IPSR_DATA(IP1_3_0, D9),
+ PINMUX_IPSR_GPSR(IP1_3_0, D9),
PINMUX_IPSR_MSEL(IP1_3_0, SCIFA1_RXD_C, SEL_SCIFA1_2),
- PINMUX_IPSR_DATA(IP1_3_0, AVB_TXD1),
+ PINMUX_IPSR_GPSR(IP1_3_0, AVB_TXD1),
PINMUX_IPSR_MSEL(IP1_3_0, VI0_G1, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP1_3_0, VI0_G1_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP1_3_0, VI2_DATA1_VI2_B1, SEL_VI2_0),
- PINMUX_IPSR_DATA(IP1_7_4, D10),
+ PINMUX_IPSR_GPSR(IP1_7_4, D10),
PINMUX_IPSR_MSEL(IP1_7_4, SCIFA1_TXD_C, SEL_SCIFA1_2),
- PINMUX_IPSR_DATA(IP1_7_4, AVB_TXD2),
+ PINMUX_IPSR_GPSR(IP1_7_4, AVB_TXD2),
PINMUX_IPSR_MSEL(IP1_7_4, VI0_G2, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP1_7_4, VI0_G2_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP1_7_4, VI2_DATA2_VI2_B2, SEL_VI2_0),
- PINMUX_IPSR_DATA(IP1_11_8, D11),
+ PINMUX_IPSR_GPSR(IP1_11_8, D11),
PINMUX_IPSR_MSEL(IP1_11_8, SCIFA1_CTS_N_C, SEL_SCIFA1_2),
- PINMUX_IPSR_DATA(IP1_11_8, AVB_TXD3),
+ PINMUX_IPSR_GPSR(IP1_11_8, AVB_TXD3),
PINMUX_IPSR_MSEL(IP1_11_8, VI0_G3, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP1_11_8, VI0_G3_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP1_11_8, VI2_DATA3_VI2_B3, SEL_VI2_0),
- PINMUX_IPSR_DATA(IP1_14_12, D12),
+ PINMUX_IPSR_GPSR(IP1_14_12, D12),
PINMUX_IPSR_MSEL(IP1_14_12, SCIFA1_RTS_N_C, SEL_SCIFA1_2),
- PINMUX_IPSR_DATA(IP1_14_12, AVB_TXD4),
+ PINMUX_IPSR_GPSR(IP1_14_12, AVB_TXD4),
PINMUX_IPSR_MSEL(IP1_14_12, VI0_HSYNC_N, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP1_14_12, VI0_HSYNC_N_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP1_14_12, VI2_DATA4_VI2_B4, SEL_VI2_0),
- PINMUX_IPSR_DATA(IP1_17_15, D13),
- PINMUX_IPSR_DATA(IP1_17_15, AVB_TXD5),
+ PINMUX_IPSR_GPSR(IP1_17_15, D13),
+ PINMUX_IPSR_GPSR(IP1_17_15, AVB_TXD5),
PINMUX_IPSR_MSEL(IP1_17_15, VI0_VSYNC_N, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP1_17_15, VI0_VSYNC_N_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP1_17_15, VI2_DATA5_VI2_B5, SEL_VI2_0),
- PINMUX_IPSR_DATA(IP1_21_18, D14),
+ PINMUX_IPSR_GPSR(IP1_21_18, D14),
PINMUX_IPSR_MSEL(IP1_21_18, SCIFB1_RXD_C, SEL_SCIFB1_2),
- PINMUX_IPSR_DATA(IP1_21_18, AVB_TXD6),
+ PINMUX_IPSR_GPSR(IP1_21_18, AVB_TXD6),
PINMUX_IPSR_MSEL(IP1_21_18, RX1_B, SEL_SCIF1_1),
PINMUX_IPSR_MSEL(IP1_21_18, VI0_CLKENB, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP1_21_18, VI0_CLKENB_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP1_21_18, VI2_DATA6_VI2_B6, SEL_VI2_0),
- PINMUX_IPSR_DATA(IP1_25_22, D15),
+ PINMUX_IPSR_GPSR(IP1_25_22, D15),
PINMUX_IPSR_MSEL(IP1_25_22, SCIFB1_TXD_C, SEL_SCIFB1_2),
- PINMUX_IPSR_DATA(IP1_25_22, AVB_TXD7),
+ PINMUX_IPSR_GPSR(IP1_25_22, AVB_TXD7),
PINMUX_IPSR_MSEL(IP1_25_22, TX1_B, SEL_SCIF1_1),
PINMUX_IPSR_MSEL(IP1_25_22, VI0_FIELD, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP1_25_22, VI0_FIELD_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP1_25_22, VI2_DATA7_VI2_B7, SEL_VI2_0),
- PINMUX_IPSR_DATA(IP1_27_26, A0),
- PINMUX_IPSR_DATA(IP1_27_26, PWM3),
- PINMUX_IPSR_DATA(IP1_29_28, A1),
- PINMUX_IPSR_DATA(IP1_29_28, PWM4),
+ PINMUX_IPSR_GPSR(IP1_27_26, A0),
+ PINMUX_IPSR_GPSR(IP1_27_26, PWM3),
+ PINMUX_IPSR_GPSR(IP1_29_28, A1),
+ PINMUX_IPSR_GPSR(IP1_29_28, PWM4),
- PINMUX_IPSR_DATA(IP2_2_0, A2),
- PINMUX_IPSR_DATA(IP2_2_0, PWM5),
+ PINMUX_IPSR_GPSR(IP2_2_0, A2),
+ PINMUX_IPSR_GPSR(IP2_2_0, PWM5),
PINMUX_IPSR_MSEL(IP2_2_0, MSIOF1_SS1_B, SEL_SOF1_1),
- PINMUX_IPSR_DATA(IP2_5_3, A3),
- PINMUX_IPSR_DATA(IP2_5_3, PWM6),
+ PINMUX_IPSR_GPSR(IP2_5_3, A3),
+ PINMUX_IPSR_GPSR(IP2_5_3, PWM6),
PINMUX_IPSR_MSEL(IP2_5_3, MSIOF1_SS2_B, SEL_SOF1_1),
- PINMUX_IPSR_DATA(IP2_8_6, A4),
+ PINMUX_IPSR_GPSR(IP2_8_6, A4),
PINMUX_IPSR_MSEL(IP2_8_6, MSIOF1_TXD_B, SEL_SOF1_1),
- PINMUX_IPSR_DATA(IP2_8_6, TPU0TO0),
- PINMUX_IPSR_DATA(IP2_11_9, A5),
+ PINMUX_IPSR_GPSR(IP2_8_6, TPU0TO0),
+ PINMUX_IPSR_GPSR(IP2_11_9, A5),
PINMUX_IPSR_MSEL(IP2_11_9, SCIFA1_TXD_B, SEL_SCIFA1_1),
- PINMUX_IPSR_DATA(IP2_11_9, TPU0TO1),
- PINMUX_IPSR_DATA(IP2_14_12, A6),
+ PINMUX_IPSR_GPSR(IP2_11_9, TPU0TO1),
+ PINMUX_IPSR_GPSR(IP2_14_12, A6),
PINMUX_IPSR_MSEL(IP2_14_12, SCIFA1_RTS_N_B, SEL_SCIFA1_1),
- PINMUX_IPSR_DATA(IP2_14_12, TPU0TO2),
- PINMUX_IPSR_DATA(IP2_17_15, A7),
+ PINMUX_IPSR_GPSR(IP2_14_12, TPU0TO2),
+ PINMUX_IPSR_GPSR(IP2_17_15, A7),
PINMUX_IPSR_MSEL(IP2_17_15, SCIFA1_SCK_B, SEL_SCIFA1_1),
- PINMUX_IPSR_DATA(IP2_17_15, AUDIO_CLKOUT_B),
- PINMUX_IPSR_DATA(IP2_17_15, TPU0TO3),
- PINMUX_IPSR_DATA(IP2_21_18, A8),
+ PINMUX_IPSR_GPSR(IP2_17_15, AUDIO_CLKOUT_B),
+ PINMUX_IPSR_GPSR(IP2_17_15, TPU0TO3),
+ PINMUX_IPSR_GPSR(IP2_21_18, A8),
PINMUX_IPSR_MSEL(IP2_21_18, SCIFA1_RXD_B, SEL_SCIFA1_1),
PINMUX_IPSR_MSEL(IP2_21_18, SSI_SCK5_B, SEL_SSI5_1),
PINMUX_IPSR_MSEL(IP2_21_18, VI0_R4, SEL_VI0_0),
@@ -929,7 +929,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP2_21_18, SCIFB2_RXD_C, SEL_SCIFB2_2),
PINMUX_IPSR_MSEL(IP2_21_18, RX2_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP2_21_18, VI2_DATA0_VI2_B0_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP2_25_22, A9),
+ PINMUX_IPSR_GPSR(IP2_25_22, A9),
PINMUX_IPSR_MSEL(IP2_25_22, SCIFA1_CTS_N_B, SEL_SCIFA1_1),
PINMUX_IPSR_MSEL(IP2_25_22, SSI_WS5_B, SEL_SSI5_1),
PINMUX_IPSR_MSEL(IP2_25_22, VI0_R5, SEL_VI0_0),
@@ -937,392 +937,392 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP2_25_22, SCIFB2_TXD_C, SEL_SCIFB2_2),
PINMUX_IPSR_MSEL(IP2_25_22, TX2_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP2_25_22, VI2_DATA1_VI2_B1_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP2_28_26, A10),
+ PINMUX_IPSR_GPSR(IP2_28_26, A10),
PINMUX_IPSR_MSEL(IP2_28_26, SSI_SDATA5_B, SEL_SSI5_1),
- PINMUX_IPSR_DATA(IP2_28_26, MSIOF2_SYNC),
+ PINMUX_IPSR_GPSR(IP2_28_26, MSIOF2_SYNC),
PINMUX_IPSR_MSEL(IP2_28_26, VI0_R6, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP2_28_26, VI0_R6_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP2_28_26, VI2_DATA2_VI2_B2_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP3_3_0, A11),
+ PINMUX_IPSR_GPSR(IP3_3_0, A11),
PINMUX_IPSR_MSEL(IP3_3_0, SCIFB2_CTS_N_B, SEL_SCIFB2_1),
- PINMUX_IPSR_DATA(IP3_3_0, MSIOF2_SCK),
+ PINMUX_IPSR_GPSR(IP3_3_0, MSIOF2_SCK),
PINMUX_IPSR_MSEL(IP3_3_0, VI1_R0, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP3_3_0, VI1_R0_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP3_3_0, VI2_G0),
+ PINMUX_IPSR_GPSR(IP3_3_0, VI2_G0),
PINMUX_IPSR_MSEL(IP3_3_0, VI2_DATA3_VI2_B3_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP3_7_4, A12),
+ PINMUX_IPSR_GPSR(IP3_7_4, A12),
PINMUX_IPSR_MSEL(IP3_7_4, SCIFB2_RXD_B, SEL_SCIFB2_1),
- PINMUX_IPSR_DATA(IP3_7_4, MSIOF2_TXD),
+ PINMUX_IPSR_GPSR(IP3_7_4, MSIOF2_TXD),
PINMUX_IPSR_MSEL(IP3_7_4, VI1_R1, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP3_7_4, VI1_R1_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP3_7_4, VI2_G1),
+ PINMUX_IPSR_GPSR(IP3_7_4, VI2_G1),
PINMUX_IPSR_MSEL(IP3_7_4, VI2_DATA4_VI2_B4_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP3_11_8, A13),
+ PINMUX_IPSR_GPSR(IP3_11_8, A13),
PINMUX_IPSR_MSEL(IP3_11_8, SCIFB2_RTS_N_B, SEL_SCIFB2_1),
- PINMUX_IPSR_DATA(IP3_11_8, EX_WAIT2),
- PINMUX_IPSR_DATA(IP3_11_8, MSIOF2_RXD),
+ PINMUX_IPSR_GPSR(IP3_11_8, EX_WAIT2),
+ PINMUX_IPSR_GPSR(IP3_11_8, MSIOF2_RXD),
PINMUX_IPSR_MSEL(IP3_11_8, VI1_R2, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP3_11_8, VI1_R2_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP3_11_8, VI2_G2),
+ PINMUX_IPSR_GPSR(IP3_11_8, VI2_G2),
PINMUX_IPSR_MSEL(IP3_11_8, VI2_DATA5_VI2_B5_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP3_14_12, A14),
+ PINMUX_IPSR_GPSR(IP3_14_12, A14),
PINMUX_IPSR_MSEL(IP3_14_12, SCIFB2_TXD_B, SEL_SCIFB2_1),
- PINMUX_IPSR_DATA(IP3_14_12, ATACS11_N),
- PINMUX_IPSR_DATA(IP3_14_12, MSIOF2_SS1),
- PINMUX_IPSR_DATA(IP3_17_15, A15),
+ PINMUX_IPSR_GPSR(IP3_14_12, ATACS11_N),
+ PINMUX_IPSR_GPSR(IP3_14_12, MSIOF2_SS1),
+ PINMUX_IPSR_GPSR(IP3_17_15, A15),
PINMUX_IPSR_MSEL(IP3_17_15, SCIFB2_SCK_B, SEL_SCIFB2_1),
- PINMUX_IPSR_DATA(IP3_17_15, ATARD1_N),
- PINMUX_IPSR_DATA(IP3_17_15, MSIOF2_SS2),
- PINMUX_IPSR_DATA(IP3_19_18, A16),
- PINMUX_IPSR_DATA(IP3_19_18, ATAWR1_N),
- PINMUX_IPSR_DATA(IP3_22_20, A17),
+ PINMUX_IPSR_GPSR(IP3_17_15, ATARD1_N),
+ PINMUX_IPSR_GPSR(IP3_17_15, MSIOF2_SS2),
+ PINMUX_IPSR_GPSR(IP3_19_18, A16),
+ PINMUX_IPSR_GPSR(IP3_19_18, ATAWR1_N),
+ PINMUX_IPSR_GPSR(IP3_22_20, A17),
PINMUX_IPSR_MSEL(IP3_22_20, AD_DO_B, SEL_ADI_1),
- PINMUX_IPSR_DATA(IP3_22_20, ATADIR1_N),
- PINMUX_IPSR_DATA(IP3_25_23, A18),
+ PINMUX_IPSR_GPSR(IP3_22_20, ATADIR1_N),
+ PINMUX_IPSR_GPSR(IP3_25_23, A18),
PINMUX_IPSR_MSEL(IP3_25_23, AD_CLK_B, SEL_ADI_1),
- PINMUX_IPSR_DATA(IP3_25_23, ATAG1_N),
- PINMUX_IPSR_DATA(IP3_28_26, A19),
+ PINMUX_IPSR_GPSR(IP3_25_23, ATAG1_N),
+ PINMUX_IPSR_GPSR(IP3_28_26, A19),
PINMUX_IPSR_MSEL(IP3_28_26, AD_NCS_N_B, SEL_ADI_1),
- PINMUX_IPSR_DATA(IP3_28_26, ATACS01_N),
+ PINMUX_IPSR_GPSR(IP3_28_26, ATACS01_N),
PINMUX_IPSR_MSEL(IP3_28_26, EX_WAIT0_B, SEL_LBS_1),
- PINMUX_IPSR_DATA(IP3_31_29, A20),
- PINMUX_IPSR_DATA(IP3_31_29, SPCLK),
+ PINMUX_IPSR_GPSR(IP3_31_29, A20),
+ PINMUX_IPSR_GPSR(IP3_31_29, SPCLK),
PINMUX_IPSR_MSEL(IP3_31_29, VI1_R3, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP3_31_29, VI1_R3_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP3_31_29, VI2_G4),
+ PINMUX_IPSR_GPSR(IP3_31_29, VI2_G4),
- PINMUX_IPSR_DATA(IP4_2_0, A21),
- PINMUX_IPSR_DATA(IP4_2_0, MOSI_IO0),
+ PINMUX_IPSR_GPSR(IP4_2_0, A21),
+ PINMUX_IPSR_GPSR(IP4_2_0, MOSI_IO0),
PINMUX_IPSR_MSEL(IP4_2_0, VI1_R4, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP4_2_0, VI1_R4_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP4_2_0, VI2_G5),
- PINMUX_IPSR_DATA(IP4_5_3, A22),
- PINMUX_IPSR_DATA(IP4_5_3, MISO_IO1),
+ PINMUX_IPSR_GPSR(IP4_2_0, VI2_G5),
+ PINMUX_IPSR_GPSR(IP4_5_3, A22),
+ PINMUX_IPSR_GPSR(IP4_5_3, MISO_IO1),
PINMUX_IPSR_MSEL(IP4_5_3, VI1_R5, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP4_5_3, VI1_R5_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP4_5_3, VI2_G6),
- PINMUX_IPSR_DATA(IP4_8_6, A23),
- PINMUX_IPSR_DATA(IP4_8_6, IO2),
+ PINMUX_IPSR_GPSR(IP4_5_3, VI2_G6),
+ PINMUX_IPSR_GPSR(IP4_8_6, A23),
+ PINMUX_IPSR_GPSR(IP4_8_6, IO2),
PINMUX_IPSR_MSEL(IP4_8_6, VI1_G7, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP4_8_6, VI1_G7_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP4_8_6, VI2_G7),
- PINMUX_IPSR_DATA(IP4_11_9, A24),
- PINMUX_IPSR_DATA(IP4_11_9, IO3),
+ PINMUX_IPSR_GPSR(IP4_8_6, VI2_G7),
+ PINMUX_IPSR_GPSR(IP4_11_9, A24),
+ PINMUX_IPSR_GPSR(IP4_11_9, IO3),
PINMUX_IPSR_MSEL(IP4_11_9, VI1_R7, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP4_11_9, VI1_R7_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP4_11_9, VI2_CLKENB, SEL_VI2_0),
PINMUX_IPSR_MSEL(IP4_11_9, VI2_CLKENB_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP4_14_12, A25),
- PINMUX_IPSR_DATA(IP4_14_12, SSL),
+ PINMUX_IPSR_GPSR(IP4_14_12, A25),
+ PINMUX_IPSR_GPSR(IP4_14_12, SSL),
PINMUX_IPSR_MSEL(IP4_14_12, VI1_G6, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP4_14_12, VI1_G6_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP4_14_12, VI2_FIELD, SEL_VI2_0),
PINMUX_IPSR_MSEL(IP4_14_12, VI2_FIELD_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP4_17_15, CS0_N),
+ PINMUX_IPSR_GPSR(IP4_17_15, CS0_N),
PINMUX_IPSR_MSEL(IP4_17_15, VI1_R6, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP4_17_15, VI1_R6_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP4_17_15, VI2_G3),
+ PINMUX_IPSR_GPSR(IP4_17_15, VI2_G3),
PINMUX_IPSR_MSEL(IP4_17_15, MSIOF0_SS2_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP4_20_18, CS1_N_A26),
- PINMUX_IPSR_DATA(IP4_20_18, SPEEDIN),
+ PINMUX_IPSR_GPSR(IP4_20_18, CS1_N_A26),
+ PINMUX_IPSR_GPSR(IP4_20_18, SPEEDIN),
PINMUX_IPSR_MSEL(IP4_20_18, VI0_R7, SEL_VI0_0),
PINMUX_IPSR_MSEL(IP4_20_18, VI0_R7_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP4_20_18, VI2_CLK, SEL_VI2_0),
PINMUX_IPSR_MSEL(IP4_20_18, VI2_CLK_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP4_23_21, EX_CS0_N),
+ PINMUX_IPSR_GPSR(IP4_23_21, EX_CS0_N),
PINMUX_IPSR_MSEL(IP4_23_21, HRX1_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP4_23_21, VI1_G5, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP4_23_21, VI1_G5_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP4_23_21, VI2_R0),
+ PINMUX_IPSR_GPSR(IP4_23_21, VI2_R0),
PINMUX_IPSR_MSEL(IP4_23_21, HTX0_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP4_23_21, MSIOF0_SS1_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP4_26_24, EX_CS1_N),
- PINMUX_IPSR_DATA(IP4_26_24, GPS_CLK),
+ PINMUX_IPSR_GPSR(IP4_26_24, EX_CS1_N),
+ PINMUX_IPSR_GPSR(IP4_26_24, GPS_CLK),
PINMUX_IPSR_MSEL(IP4_26_24, HCTS1_N_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP4_26_24, VI1_FIELD, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP4_26_24, VI1_FIELD_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP4_26_24, VI2_R1),
- PINMUX_IPSR_DATA(IP4_29_27, EX_CS2_N),
- PINMUX_IPSR_DATA(IP4_29_27, GPS_SIGN),
+ PINMUX_IPSR_GPSR(IP4_26_24, VI2_R1),
+ PINMUX_IPSR_GPSR(IP4_29_27, EX_CS2_N),
+ PINMUX_IPSR_GPSR(IP4_29_27, GPS_SIGN),
PINMUX_IPSR_MSEL(IP4_29_27, HRTS1_N_B, SEL_HSCIF1_1),
- PINMUX_IPSR_DATA(IP4_29_27, VI3_CLKENB),
+ PINMUX_IPSR_GPSR(IP4_29_27, VI3_CLKENB),
PINMUX_IPSR_MSEL(IP4_29_27, VI1_G0, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP4_29_27, VI1_G0_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP4_29_27, VI2_R2),
+ PINMUX_IPSR_GPSR(IP4_29_27, VI2_R2),
- PINMUX_IPSR_DATA(IP5_2_0, EX_CS3_N),
- PINMUX_IPSR_DATA(IP5_2_0, GPS_MAG),
- PINMUX_IPSR_DATA(IP5_2_0, VI3_FIELD),
+ PINMUX_IPSR_GPSR(IP5_2_0, EX_CS3_N),
+ PINMUX_IPSR_GPSR(IP5_2_0, GPS_MAG),
+ PINMUX_IPSR_GPSR(IP5_2_0, VI3_FIELD),
PINMUX_IPSR_MSEL(IP5_2_0, VI1_G1, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP5_2_0, VI1_G1_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP5_2_0, VI2_R3),
- PINMUX_IPSR_DATA(IP5_5_3, EX_CS4_N),
+ PINMUX_IPSR_GPSR(IP5_2_0, VI2_R3),
+ PINMUX_IPSR_GPSR(IP5_5_3, EX_CS4_N),
PINMUX_IPSR_MSEL(IP5_5_3, MSIOF1_SCK_B, SEL_SOF1_1),
- PINMUX_IPSR_DATA(IP5_5_3, VI3_HSYNC_N),
+ PINMUX_IPSR_GPSR(IP5_5_3, VI3_HSYNC_N),
PINMUX_IPSR_MSEL(IP5_5_3, VI2_HSYNC_N, SEL_VI2_0),
PINMUX_IPSR_MSEL(IP5_5_3, IIC1_SCL, SEL_IIC1_0),
PINMUX_IPSR_MSEL(IP5_5_3, VI2_HSYNC_N_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP5_5_3, INTC_EN0_N),
+ PINMUX_IPSR_GPSR(IP5_5_3, INTC_EN0_N),
PINMUX_IPSR_MSEL(IP5_5_3, I2C1_SCL, SEL_I2C1_0),
- PINMUX_IPSR_DATA(IP5_9_6, EX_CS5_N),
+ PINMUX_IPSR_GPSR(IP5_9_6, EX_CS5_N),
PINMUX_IPSR_MSEL(IP5_9_6, CAN0_RX, SEL_CAN0_0),
PINMUX_IPSR_MSEL(IP5_9_6, MSIOF1_RXD_B, SEL_SOF1_1),
- PINMUX_IPSR_DATA(IP5_9_6, VI3_VSYNC_N),
+ PINMUX_IPSR_GPSR(IP5_9_6, VI3_VSYNC_N),
PINMUX_IPSR_MSEL(IP5_9_6, VI1_G2, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP5_9_6, VI1_G2_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP5_9_6, VI2_R4),
+ PINMUX_IPSR_GPSR(IP5_9_6, VI2_R4),
PINMUX_IPSR_MSEL(IP5_9_6, IIC1_SDA, SEL_IIC1_0),
- PINMUX_IPSR_DATA(IP5_9_6, INTC_EN1_N),
+ PINMUX_IPSR_GPSR(IP5_9_6, INTC_EN1_N),
PINMUX_IPSR_MSEL(IP5_9_6, I2C1_SDA, SEL_I2C1_0),
- PINMUX_IPSR_DATA(IP5_12_10, BS_N),
+ PINMUX_IPSR_GPSR(IP5_12_10, BS_N),
PINMUX_IPSR_MSEL(IP5_12_10, IETX, SEL_IEB_0),
PINMUX_IPSR_MSEL(IP5_12_10, HTX1_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP5_12_10, CAN1_TX, SEL_CAN1_0),
- PINMUX_IPSR_DATA(IP5_12_10, DRACK0),
+ PINMUX_IPSR_GPSR(IP5_12_10, DRACK0),
PINMUX_IPSR_MSEL(IP5_12_10, IETX_C, SEL_IEB_2),
- PINMUX_IPSR_DATA(IP5_14_13, RD_N),
+ PINMUX_IPSR_GPSR(IP5_14_13, RD_N),
PINMUX_IPSR_MSEL(IP5_14_13, CAN0_TX, SEL_CAN0_0),
PINMUX_IPSR_MSEL(IP5_14_13, SCIFA0_SCK_B, SEL_SCFA_1),
- PINMUX_IPSR_DATA(IP5_17_15, RD_WR_N),
+ PINMUX_IPSR_GPSR(IP5_17_15, RD_WR_N),
PINMUX_IPSR_MSEL(IP5_17_15, VI1_G3, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP5_17_15, VI1_G3_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP5_17_15, VI2_R5),
+ PINMUX_IPSR_GPSR(IP5_17_15, VI2_R5),
PINMUX_IPSR_MSEL(IP5_17_15, SCIFA0_RXD_B, SEL_SCFA_1),
- PINMUX_IPSR_DATA(IP5_17_15, INTC_IRQ4_N),
- PINMUX_IPSR_DATA(IP5_20_18, WE0_N),
+ PINMUX_IPSR_GPSR(IP5_17_15, INTC_IRQ4_N),
+ PINMUX_IPSR_GPSR(IP5_20_18, WE0_N),
PINMUX_IPSR_MSEL(IP5_20_18, IECLK, SEL_IEB_0),
PINMUX_IPSR_MSEL(IP5_20_18, CAN_CLK, SEL_CANCLK_0),
PINMUX_IPSR_MSEL(IP5_20_18, VI2_VSYNC_N, SEL_VI2_0),
PINMUX_IPSR_MSEL(IP5_20_18, SCIFA0_TXD_B, SEL_SCFA_1),
PINMUX_IPSR_MSEL(IP5_20_18, VI2_VSYNC_N_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP5_23_21, WE1_N),
+ PINMUX_IPSR_GPSR(IP5_23_21, WE1_N),
PINMUX_IPSR_MSEL(IP5_23_21, IERX, SEL_IEB_0),
PINMUX_IPSR_MSEL(IP5_23_21, CAN1_RX, SEL_CAN1_0),
PINMUX_IPSR_MSEL(IP5_23_21, VI1_G4, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP5_23_21, VI1_G4_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP5_23_21, VI2_R6),
+ PINMUX_IPSR_GPSR(IP5_23_21, VI2_R6),
PINMUX_IPSR_MSEL(IP5_23_21, SCIFA0_CTS_N_B, SEL_SCFA_1),
PINMUX_IPSR_MSEL(IP5_23_21, IERX_C, SEL_IEB_2),
PINMUX_IPSR_MSEL(IP5_26_24, EX_WAIT0, SEL_LBS_0),
- PINMUX_IPSR_DATA(IP5_26_24, IRQ3),
- PINMUX_IPSR_DATA(IP5_26_24, INTC_IRQ3_N),
+ PINMUX_IPSR_GPSR(IP5_26_24, IRQ3),
+ PINMUX_IPSR_GPSR(IP5_26_24, INTC_IRQ3_N),
PINMUX_IPSR_MSEL(IP5_26_24, VI3_CLK, SEL_VI3_0),
PINMUX_IPSR_MSEL(IP5_26_24, SCIFA0_RTS_N_B, SEL_SCFA_1),
PINMUX_IPSR_MSEL(IP5_26_24, HRX0_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP5_26_24, MSIOF0_SCK_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP5_29_27, DREQ0_N),
+ PINMUX_IPSR_GPSR(IP5_29_27, DREQ0_N),
PINMUX_IPSR_MSEL(IP5_29_27, VI1_HSYNC_N, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP5_29_27, VI1_HSYNC_N_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP5_29_27, VI2_R7),
+ PINMUX_IPSR_GPSR(IP5_29_27, VI2_R7),
PINMUX_IPSR_MSEL(IP5_29_27, SSI_SCK78_C, SEL_SSI7_2),
PINMUX_IPSR_MSEL(IP5_29_27, SSI_WS78_B, SEL_SSI7_1),
- PINMUX_IPSR_DATA(IP6_2_0, DACK0),
- PINMUX_IPSR_DATA(IP6_2_0, IRQ0),
- PINMUX_IPSR_DATA(IP6_2_0, INTC_IRQ0_N),
+ PINMUX_IPSR_GPSR(IP6_2_0, DACK0),
+ PINMUX_IPSR_GPSR(IP6_2_0, IRQ0),
+ PINMUX_IPSR_GPSR(IP6_2_0, INTC_IRQ0_N),
PINMUX_IPSR_MSEL(IP6_2_0, SSI_SCK6_B, SEL_SSI6_1),
PINMUX_IPSR_MSEL(IP6_2_0, VI1_VSYNC_N, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP6_2_0, VI1_VSYNC_N_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP6_2_0, SSI_WS78_C, SEL_SSI7_2),
- PINMUX_IPSR_DATA(IP6_5_3, DREQ1_N),
+ PINMUX_IPSR_GPSR(IP6_5_3, DREQ1_N),
PINMUX_IPSR_MSEL(IP6_5_3, VI1_CLKENB, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP6_5_3, VI1_CLKENB_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP6_5_3, SSI_SDATA7_C, SEL_SSI7_2),
PINMUX_IPSR_MSEL(IP6_5_3, SSI_SCK78_B, SEL_SSI7_1),
- PINMUX_IPSR_DATA(IP6_8_6, DACK1),
- PINMUX_IPSR_DATA(IP6_8_6, IRQ1),
- PINMUX_IPSR_DATA(IP6_8_6, INTC_IRQ1_N),
+ PINMUX_IPSR_GPSR(IP6_8_6, DACK1),
+ PINMUX_IPSR_GPSR(IP6_8_6, IRQ1),
+ PINMUX_IPSR_GPSR(IP6_8_6, INTC_IRQ1_N),
PINMUX_IPSR_MSEL(IP6_8_6, SSI_WS6_B, SEL_SSI6_1),
PINMUX_IPSR_MSEL(IP6_8_6, SSI_SDATA8_C, SEL_SSI8_2),
- PINMUX_IPSR_DATA(IP6_10_9, DREQ2_N),
+ PINMUX_IPSR_GPSR(IP6_10_9, DREQ2_N),
PINMUX_IPSR_MSEL(IP6_10_9, HSCK1_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP6_10_9, HCTS0_N_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP6_10_9, MSIOF0_TXD_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP6_13_11, DACK2),
- PINMUX_IPSR_DATA(IP6_13_11, IRQ2),
- PINMUX_IPSR_DATA(IP6_13_11, INTC_IRQ2_N),
+ PINMUX_IPSR_GPSR(IP6_13_11, DACK2),
+ PINMUX_IPSR_GPSR(IP6_13_11, IRQ2),
+ PINMUX_IPSR_GPSR(IP6_13_11, INTC_IRQ2_N),
PINMUX_IPSR_MSEL(IP6_13_11, SSI_SDATA6_B, SEL_SSI6_1),
PINMUX_IPSR_MSEL(IP6_13_11, HRTS0_N_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP6_13_11, MSIOF0_RXD_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP6_16_14, ETH_CRS_DV),
+ PINMUX_IPSR_GPSR(IP6_16_14, ETH_CRS_DV),
PINMUX_IPSR_MSEL(IP6_16_14, STP_ISCLK_0_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP6_16_14, TS_SDEN0_D, SEL_TSIF0_3),
PINMUX_IPSR_MSEL(IP6_16_14, GLO_Q0_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP6_16_14, IIC2_SCL_E, SEL_IIC2_4),
PINMUX_IPSR_MSEL(IP6_16_14, I2C2_SCL_E, SEL_I2C2_4),
- PINMUX_IPSR_DATA(IP6_19_17, ETH_RX_ER),
+ PINMUX_IPSR_GPSR(IP6_19_17, ETH_RX_ER),
PINMUX_IPSR_MSEL(IP6_19_17, STP_ISD_0_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP6_19_17, TS_SPSYNC0_D, SEL_TSIF0_3),
PINMUX_IPSR_MSEL(IP6_19_17, GLO_Q1_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP6_19_17, IIC2_SDA_E, SEL_IIC2_4),
PINMUX_IPSR_MSEL(IP6_19_17, I2C2_SDA_E, SEL_I2C2_4),
- PINMUX_IPSR_DATA(IP6_22_20, ETH_RXD0),
+ PINMUX_IPSR_GPSR(IP6_22_20, ETH_RXD0),
PINMUX_IPSR_MSEL(IP6_22_20, STP_ISEN_0_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP6_22_20, TS_SDAT0_D, SEL_TSIF0_3),
PINMUX_IPSR_MSEL(IP6_22_20, GLO_I0_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP6_22_20, SCIFB1_SCK_G, SEL_SCIFB1_6),
PINMUX_IPSR_MSEL(IP6_22_20, SCK1_E, SEL_SCIF1_4),
- PINMUX_IPSR_DATA(IP6_25_23, ETH_RXD1),
+ PINMUX_IPSR_GPSR(IP6_25_23, ETH_RXD1),
PINMUX_IPSR_MSEL(IP6_25_23, HRX0_E, SEL_HSCIF0_4),
PINMUX_IPSR_MSEL(IP6_25_23, STP_ISSYNC_0_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP6_25_23, TS_SCK0_D, SEL_TSIF0_3),
PINMUX_IPSR_MSEL(IP6_25_23, GLO_I1_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP6_25_23, SCIFB1_RXD_G, SEL_SCIFB1_6),
PINMUX_IPSR_MSEL(IP6_25_23, RX1_E, SEL_SCIF1_4),
- PINMUX_IPSR_DATA(IP6_28_26, ETH_LINK),
+ PINMUX_IPSR_GPSR(IP6_28_26, ETH_LINK),
PINMUX_IPSR_MSEL(IP6_28_26, HTX0_E, SEL_HSCIF0_4),
PINMUX_IPSR_MSEL(IP6_28_26, STP_IVCXO27_0_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP6_28_26, SCIFB1_TXD_G, SEL_SCIFB1_6),
PINMUX_IPSR_MSEL(IP6_28_26, TX1_E, SEL_SCIF1_4),
- PINMUX_IPSR_DATA(IP6_31_29, ETH_REF_CLK),
+ PINMUX_IPSR_GPSR(IP6_31_29, ETH_REF_CLK),
PINMUX_IPSR_MSEL(IP6_31_29, HCTS0_N_E, SEL_HSCIF0_4),
PINMUX_IPSR_MSEL(IP6_31_29, STP_IVCXO27_1_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP6_31_29, HRX0_F, SEL_HSCIF0_5),
- PINMUX_IPSR_DATA(IP7_2_0, ETH_MDIO),
+ PINMUX_IPSR_GPSR(IP7_2_0, ETH_MDIO),
PINMUX_IPSR_MSEL(IP7_2_0, HRTS0_N_E, SEL_HSCIF0_4),
PINMUX_IPSR_MSEL(IP7_2_0, SIM0_D_C, SEL_SIM_2),
PINMUX_IPSR_MSEL(IP7_2_0, HCTS0_N_F, SEL_HSCIF0_5),
- PINMUX_IPSR_DATA(IP7_5_3, ETH_TXD1),
+ PINMUX_IPSR_GPSR(IP7_5_3, ETH_TXD1),
PINMUX_IPSR_MSEL(IP7_5_3, HTX0_F, SEL_HSCIF0_5),
PINMUX_IPSR_MSEL(IP7_5_3, BPFCLK_G, SEL_FM_6),
- PINMUX_IPSR_DATA(IP7_7_6, ETH_TX_EN),
+ PINMUX_IPSR_GPSR(IP7_7_6, ETH_TX_EN),
PINMUX_IPSR_MSEL(IP7_7_6, SIM0_CLK_C, SEL_SIM_2),
PINMUX_IPSR_MSEL(IP7_7_6, HRTS0_N_F, SEL_HSCIF0_5),
- PINMUX_IPSR_DATA(IP7_9_8, ETH_MAGIC),
+ PINMUX_IPSR_GPSR(IP7_9_8, ETH_MAGIC),
PINMUX_IPSR_MSEL(IP7_9_8, SIM0_RST_C, SEL_SIM_2),
- PINMUX_IPSR_DATA(IP7_12_10, ETH_TXD0),
+ PINMUX_IPSR_GPSR(IP7_12_10, ETH_TXD0),
PINMUX_IPSR_MSEL(IP7_12_10, STP_ISCLK_1_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP7_12_10, TS_SDEN1_C, SEL_TSIF1_2),
PINMUX_IPSR_MSEL(IP7_12_10, GLO_SCLK_C, SEL_GPS_2),
- PINMUX_IPSR_DATA(IP7_15_13, ETH_MDC),
+ PINMUX_IPSR_GPSR(IP7_15_13, ETH_MDC),
PINMUX_IPSR_MSEL(IP7_15_13, STP_ISD_1_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP7_15_13, TS_SPSYNC1_C, SEL_TSIF1_2),
PINMUX_IPSR_MSEL(IP7_15_13, GLO_SDATA_C, SEL_GPS_2),
- PINMUX_IPSR_DATA(IP7_18_16, PWM0),
+ PINMUX_IPSR_GPSR(IP7_18_16, PWM0),
PINMUX_IPSR_MSEL(IP7_18_16, SCIFA2_SCK_C, SEL_SCIFA2_2),
PINMUX_IPSR_MSEL(IP7_18_16, STP_ISEN_1_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP7_18_16, TS_SDAT1_C, SEL_TSIF1_2),
PINMUX_IPSR_MSEL(IP7_18_16, GLO_SS_C, SEL_GPS_2),
- PINMUX_IPSR_DATA(IP7_21_19, PWM1),
+ PINMUX_IPSR_GPSR(IP7_21_19, PWM1),
PINMUX_IPSR_MSEL(IP7_21_19, SCIFA2_TXD_C, SEL_SCIFA2_2),
PINMUX_IPSR_MSEL(IP7_21_19, STP_ISSYNC_1_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP7_21_19, TS_SCK1_C, SEL_TSIF1_2),
PINMUX_IPSR_MSEL(IP7_21_19, GLO_RFON_C, SEL_GPS_2),
- PINMUX_IPSR_DATA(IP7_21_19, PCMOE_N),
- PINMUX_IPSR_DATA(IP7_24_22, PWM2),
- PINMUX_IPSR_DATA(IP7_24_22, PWMFSW0),
+ PINMUX_IPSR_GPSR(IP7_21_19, PCMOE_N),
+ PINMUX_IPSR_GPSR(IP7_24_22, PWM2),
+ PINMUX_IPSR_GPSR(IP7_24_22, PWMFSW0),
PINMUX_IPSR_MSEL(IP7_24_22, SCIFA2_RXD_C, SEL_SCIFA2_2),
- PINMUX_IPSR_DATA(IP7_24_22, PCMWE_N),
+ PINMUX_IPSR_GPSR(IP7_24_22, PCMWE_N),
PINMUX_IPSR_MSEL(IP7_24_22, IECLK_C, SEL_IEB_2),
- PINMUX_IPSR_DATA(IP7_26_25, DU_DOTCLKIN1),
- PINMUX_IPSR_DATA(IP7_26_25, AUDIO_CLKC),
- PINMUX_IPSR_DATA(IP7_26_25, AUDIO_CLKOUT_C),
+ PINMUX_IPSR_GPSR(IP7_26_25, DU_DOTCLKIN1),
+ PINMUX_IPSR_GPSR(IP7_26_25, AUDIO_CLKC),
+ PINMUX_IPSR_GPSR(IP7_26_25, AUDIO_CLKOUT_C),
PINMUX_IPSR_MSEL(IP7_28_27, VI0_CLK, SEL_VI0_0),
- PINMUX_IPSR_DATA(IP7_28_27, ATACS00_N),
- PINMUX_IPSR_DATA(IP7_28_27, AVB_RXD1),
+ PINMUX_IPSR_GPSR(IP7_28_27, ATACS00_N),
+ PINMUX_IPSR_GPSR(IP7_28_27, AVB_RXD1),
PINMUX_IPSR_MSEL(IP7_30_29, VI0_DATA0_VI0_B0, SEL_VI0_0),
- PINMUX_IPSR_DATA(IP7_30_29, ATACS10_N),
- PINMUX_IPSR_DATA(IP7_30_29, AVB_RXD2),
+ PINMUX_IPSR_GPSR(IP7_30_29, ATACS10_N),
+ PINMUX_IPSR_GPSR(IP7_30_29, AVB_RXD2),
PINMUX_IPSR_MSEL(IP8_1_0, VI0_DATA1_VI0_B1, SEL_VI0_0),
- PINMUX_IPSR_DATA(IP8_1_0, ATARD0_N),
- PINMUX_IPSR_DATA(IP8_1_0, AVB_RXD3),
+ PINMUX_IPSR_GPSR(IP8_1_0, ATARD0_N),
+ PINMUX_IPSR_GPSR(IP8_1_0, AVB_RXD3),
PINMUX_IPSR_MSEL(IP8_3_2, VI0_DATA2_VI0_B2, SEL_VI0_0),
- PINMUX_IPSR_DATA(IP8_3_2, ATAWR0_N),
- PINMUX_IPSR_DATA(IP8_3_2, AVB_RXD4),
+ PINMUX_IPSR_GPSR(IP8_3_2, ATAWR0_N),
+ PINMUX_IPSR_GPSR(IP8_3_2, AVB_RXD4),
PINMUX_IPSR_MSEL(IP8_5_4, VI0_DATA3_VI0_B3, SEL_VI0_0),
- PINMUX_IPSR_DATA(IP8_5_4, ATADIR0_N),
- PINMUX_IPSR_DATA(IP8_5_4, AVB_RXD5),
+ PINMUX_IPSR_GPSR(IP8_5_4, ATADIR0_N),
+ PINMUX_IPSR_GPSR(IP8_5_4, AVB_RXD5),
PINMUX_IPSR_MSEL(IP8_7_6, VI0_DATA4_VI0_B4, SEL_VI0_0),
- PINMUX_IPSR_DATA(IP8_7_6, ATAG0_N),
- PINMUX_IPSR_DATA(IP8_7_6, AVB_RXD6),
+ PINMUX_IPSR_GPSR(IP8_7_6, ATAG0_N),
+ PINMUX_IPSR_GPSR(IP8_7_6, AVB_RXD6),
PINMUX_IPSR_MSEL(IP8_9_8, VI0_DATA5_VI0_B5, SEL_VI0_0),
- PINMUX_IPSR_DATA(IP8_9_8, EX_WAIT1),
- PINMUX_IPSR_DATA(IP8_9_8, AVB_RXD7),
+ PINMUX_IPSR_GPSR(IP8_9_8, EX_WAIT1),
+ PINMUX_IPSR_GPSR(IP8_9_8, AVB_RXD7),
PINMUX_IPSR_MSEL(IP8_11_10, VI0_DATA6_VI0_B6, SEL_VI0_0),
- PINMUX_IPSR_DATA(IP8_11_10, AVB_RX_ER),
+ PINMUX_IPSR_GPSR(IP8_11_10, AVB_RX_ER),
PINMUX_IPSR_MSEL(IP8_13_12, VI0_DATA7_VI0_B7, SEL_VI0_0),
- PINMUX_IPSR_DATA(IP8_13_12, AVB_RX_CLK),
+ PINMUX_IPSR_GPSR(IP8_13_12, AVB_RX_CLK),
PINMUX_IPSR_MSEL(IP8_15_14, VI1_CLK, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP8_15_14, AVB_RX_DV),
+ PINMUX_IPSR_GPSR(IP8_15_14, AVB_RX_DV),
PINMUX_IPSR_MSEL(IP8_17_16, VI1_DATA0_VI1_B0, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP8_17_16, SCIFA1_SCK_D, SEL_SCIFA1_3),
- PINMUX_IPSR_DATA(IP8_17_16, AVB_CRS),
+ PINMUX_IPSR_GPSR(IP8_17_16, AVB_CRS),
PINMUX_IPSR_MSEL(IP8_19_18, VI1_DATA1_VI1_B1, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP8_19_18, SCIFA1_RXD_D, SEL_SCIFA1_3),
- PINMUX_IPSR_DATA(IP8_19_18, AVB_MDC),
+ PINMUX_IPSR_GPSR(IP8_19_18, AVB_MDC),
PINMUX_IPSR_MSEL(IP8_21_20, VI1_DATA2_VI1_B2, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP8_21_20, SCIFA1_TXD_D, SEL_SCIFA1_3),
- PINMUX_IPSR_DATA(IP8_21_20, AVB_MDIO),
+ PINMUX_IPSR_GPSR(IP8_21_20, AVB_MDIO),
PINMUX_IPSR_MSEL(IP8_23_22, VI1_DATA3_VI1_B3, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP8_23_22, SCIFA1_CTS_N_D, SEL_SCIFA1_3),
- PINMUX_IPSR_DATA(IP8_23_22, AVB_GTX_CLK),
+ PINMUX_IPSR_GPSR(IP8_23_22, AVB_GTX_CLK),
PINMUX_IPSR_MSEL(IP8_25_24, VI1_DATA4_VI1_B4, SEL_VI1_0),
PINMUX_IPSR_MSEL(IP8_25_24, SCIFA1_RTS_N_D, SEL_SCIFA1_3),
- PINMUX_IPSR_DATA(IP8_25_24, AVB_MAGIC),
+ PINMUX_IPSR_GPSR(IP8_25_24, AVB_MAGIC),
PINMUX_IPSR_MSEL(IP8_26, VI1_DATA5_VI1_B5, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP8_26, AVB_PHY_INT),
+ PINMUX_IPSR_GPSR(IP8_26, AVB_PHY_INT),
PINMUX_IPSR_MSEL(IP8_27, VI1_DATA6_VI1_B6, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP8_27, AVB_GTXREFCLK),
- PINMUX_IPSR_DATA(IP8_28, SD0_CLK),
+ PINMUX_IPSR_GPSR(IP8_27, AVB_GTXREFCLK),
+ PINMUX_IPSR_GPSR(IP8_28, SD0_CLK),
PINMUX_IPSR_MSEL(IP8_28, VI1_DATA0_VI1_B0_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP8_30_29, SD0_CMD),
+ PINMUX_IPSR_GPSR(IP8_30_29, SD0_CMD),
PINMUX_IPSR_MSEL(IP8_30_29, SCIFB1_SCK_B, SEL_SCIFB1_1),
PINMUX_IPSR_MSEL(IP8_30_29, VI1_DATA1_VI1_B1_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP9_1_0, SD0_DAT0),
+ PINMUX_IPSR_GPSR(IP9_1_0, SD0_DAT0),
PINMUX_IPSR_MSEL(IP9_1_0, SCIFB1_RXD_B, SEL_SCIFB1_1),
PINMUX_IPSR_MSEL(IP9_1_0, VI1_DATA2_VI1_B2_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP9_3_2, SD0_DAT1),
+ PINMUX_IPSR_GPSR(IP9_3_2, SD0_DAT1),
PINMUX_IPSR_MSEL(IP9_3_2, SCIFB1_TXD_B, SEL_SCIFB1_1),
PINMUX_IPSR_MSEL(IP9_3_2, VI1_DATA3_VI1_B3_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP9_5_4, SD0_DAT2),
+ PINMUX_IPSR_GPSR(IP9_5_4, SD0_DAT2),
PINMUX_IPSR_MSEL(IP9_5_4, SCIFB1_CTS_N_B, SEL_SCIFB1_1),
PINMUX_IPSR_MSEL(IP9_5_4, VI1_DATA4_VI1_B4_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP9_7_6, SD0_DAT3),
+ PINMUX_IPSR_GPSR(IP9_7_6, SD0_DAT3),
PINMUX_IPSR_MSEL(IP9_7_6, SCIFB1_RTS_N_B, SEL_SCIFB1_1),
PINMUX_IPSR_MSEL(IP9_7_6, VI1_DATA5_VI1_B5_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP9_11_8, SD0_CD),
- PINMUX_IPSR_DATA(IP9_11_8, MMC0_D6),
+ PINMUX_IPSR_GPSR(IP9_11_8, SD0_CD),
+ PINMUX_IPSR_GPSR(IP9_11_8, MMC0_D6),
PINMUX_IPSR_MSEL(IP9_11_8, TS_SDEN0_B, SEL_TSIF0_1),
- PINMUX_IPSR_DATA(IP9_11_8, USB0_EXTP),
+ PINMUX_IPSR_GPSR(IP9_11_8, USB0_EXTP),
PINMUX_IPSR_MSEL(IP9_11_8, GLO_SCLK, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP9_11_8, VI1_DATA6_VI1_B6_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP9_11_8, IIC1_SCL_B, SEL_IIC1_1),
PINMUX_IPSR_MSEL(IP9_11_8, I2C1_SCL_B, SEL_I2C1_1),
PINMUX_IPSR_MSEL(IP9_11_8, VI2_DATA6_VI2_B6_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP9_15_12, SD0_WP),
- PINMUX_IPSR_DATA(IP9_15_12, MMC0_D7),
+ PINMUX_IPSR_GPSR(IP9_15_12, SD0_WP),
+ PINMUX_IPSR_GPSR(IP9_15_12, MMC0_D7),
PINMUX_IPSR_MSEL(IP9_15_12, TS_SPSYNC0_B, SEL_TSIF0_1),
- PINMUX_IPSR_DATA(IP9_15_12, USB0_IDIN),
+ PINMUX_IPSR_GPSR(IP9_15_12, USB0_IDIN),
PINMUX_IPSR_MSEL(IP9_15_12, GLO_SDATA, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP9_15_12, VI1_DATA7_VI1_B7_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP9_15_12, IIC1_SDA_B, SEL_IIC1_1),
PINMUX_IPSR_MSEL(IP9_15_12, I2C1_SDA_B, SEL_I2C1_1),
PINMUX_IPSR_MSEL(IP9_15_12, VI2_DATA7_VI2_B7_B, SEL_VI2_1),
- PINMUX_IPSR_DATA(IP9_17_16, SD1_CLK),
- PINMUX_IPSR_DATA(IP9_17_16, AVB_TX_EN),
- PINMUX_IPSR_DATA(IP9_19_18, SD1_CMD),
- PINMUX_IPSR_DATA(IP9_19_18, AVB_TX_ER),
+ PINMUX_IPSR_GPSR(IP9_17_16, SD1_CLK),
+ PINMUX_IPSR_GPSR(IP9_17_16, AVB_TX_EN),
+ PINMUX_IPSR_GPSR(IP9_19_18, SD1_CMD),
+ PINMUX_IPSR_GPSR(IP9_19_18, AVB_TX_ER),
PINMUX_IPSR_MSEL(IP9_19_18, SCIFB0_SCK_B, SEL_SCIFB_1),
- PINMUX_IPSR_DATA(IP9_21_20, SD1_DAT0),
- PINMUX_IPSR_DATA(IP9_21_20, AVB_TX_CLK),
+ PINMUX_IPSR_GPSR(IP9_21_20, SD1_DAT0),
+ PINMUX_IPSR_GPSR(IP9_21_20, AVB_TX_CLK),
PINMUX_IPSR_MSEL(IP9_21_20, SCIFB0_RXD_B, SEL_SCIFB_1),
- PINMUX_IPSR_DATA(IP9_23_22, SD1_DAT1),
- PINMUX_IPSR_DATA(IP9_23_22, AVB_LINK),
+ PINMUX_IPSR_GPSR(IP9_23_22, SD1_DAT1),
+ PINMUX_IPSR_GPSR(IP9_23_22, AVB_LINK),
PINMUX_IPSR_MSEL(IP9_23_22, SCIFB0_TXD_B, SEL_SCIFB_1),
- PINMUX_IPSR_DATA(IP9_25_24, SD1_DAT2),
- PINMUX_IPSR_DATA(IP9_25_24, AVB_COL),
+ PINMUX_IPSR_GPSR(IP9_25_24, SD1_DAT2),
+ PINMUX_IPSR_GPSR(IP9_25_24, AVB_COL),
PINMUX_IPSR_MSEL(IP9_25_24, SCIFB0_CTS_N_B, SEL_SCIFB_1),
- PINMUX_IPSR_DATA(IP9_27_26, SD1_DAT3),
- PINMUX_IPSR_DATA(IP9_27_26, AVB_RXD0),
+ PINMUX_IPSR_GPSR(IP9_27_26, SD1_DAT3),
+ PINMUX_IPSR_GPSR(IP9_27_26, AVB_RXD0),
PINMUX_IPSR_MSEL(IP9_27_26, SCIFB0_RTS_N_B, SEL_SCIFB_1),
- PINMUX_IPSR_DATA(IP9_31_28, SD1_CD),
- PINMUX_IPSR_DATA(IP9_31_28, MMC1_D6),
+ PINMUX_IPSR_GPSR(IP9_31_28, SD1_CD),
+ PINMUX_IPSR_GPSR(IP9_31_28, MMC1_D6),
PINMUX_IPSR_MSEL(IP9_31_28, TS_SDEN1, SEL_TSIF1_0),
- PINMUX_IPSR_DATA(IP9_31_28, USB1_EXTP),
+ PINMUX_IPSR_GPSR(IP9_31_28, USB1_EXTP),
PINMUX_IPSR_MSEL(IP9_31_28, GLO_SS, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP9_31_28, VI0_CLK_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP9_31_28, IIC2_SCL_D, SEL_IIC2_3),
@@ -1330,24 +1330,24 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP9_31_28, SIM0_CLK_B, SEL_SIM_1),
PINMUX_IPSR_MSEL(IP9_31_28, VI3_CLK_B, SEL_VI3_1),
- PINMUX_IPSR_DATA(IP10_3_0, SD1_WP),
- PINMUX_IPSR_DATA(IP10_3_0, MMC1_D7),
+ PINMUX_IPSR_GPSR(IP10_3_0, SD1_WP),
+ PINMUX_IPSR_GPSR(IP10_3_0, MMC1_D7),
PINMUX_IPSR_MSEL(IP10_3_0, TS_SPSYNC1, SEL_TSIF1_0),
- PINMUX_IPSR_DATA(IP10_3_0, USB1_IDIN),
+ PINMUX_IPSR_GPSR(IP10_3_0, USB1_IDIN),
PINMUX_IPSR_MSEL(IP10_3_0, GLO_RFON, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP10_3_0, VI1_CLK_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP10_3_0, IIC2_SDA_D, SEL_IIC2_3),
PINMUX_IPSR_MSEL(IP10_3_0, I2C2_SDA_D, SEL_I2C2_3),
PINMUX_IPSR_MSEL(IP10_3_0, SIM0_D_B, SEL_SIM_1),
- PINMUX_IPSR_DATA(IP10_6_4, SD2_CLK),
- PINMUX_IPSR_DATA(IP10_6_4, MMC0_CLK),
+ PINMUX_IPSR_GPSR(IP10_6_4, SD2_CLK),
+ PINMUX_IPSR_GPSR(IP10_6_4, MMC0_CLK),
PINMUX_IPSR_MSEL(IP10_6_4, SIM0_CLK, SEL_SIM_0),
PINMUX_IPSR_MSEL(IP10_6_4, VI0_DATA0_VI0_B0_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP10_6_4, TS_SDEN0_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP10_6_4, GLO_SCLK_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_6_4, VI3_DATA0_B, SEL_VI3_1),
- PINMUX_IPSR_DATA(IP10_10_7, SD2_CMD),
- PINMUX_IPSR_DATA(IP10_10_7, MMC0_CMD),
+ PINMUX_IPSR_GPSR(IP10_10_7, SD2_CMD),
+ PINMUX_IPSR_GPSR(IP10_10_7, MMC0_CMD),
PINMUX_IPSR_MSEL(IP10_10_7, SIM0_D, SEL_SIM_0),
PINMUX_IPSR_MSEL(IP10_10_7, VI0_DATA1_VI0_B1_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP10_10_7, SCIFB1_SCK_E, SEL_SCIFB1_4),
@@ -1355,8 +1355,8 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP10_10_7, TS_SPSYNC0_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP10_10_7, GLO_SDATA_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_10_7, VI3_DATA1_B, SEL_VI3_1),
- PINMUX_IPSR_DATA(IP10_14_11, SD2_DAT0),
- PINMUX_IPSR_DATA(IP10_14_11, MMC0_D0),
+ PINMUX_IPSR_GPSR(IP10_14_11, SD2_DAT0),
+ PINMUX_IPSR_GPSR(IP10_14_11, MMC0_D0),
PINMUX_IPSR_MSEL(IP10_14_11, FMCLK_B, SEL_FM_1),
PINMUX_IPSR_MSEL(IP10_14_11, VI0_DATA2_VI0_B2_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP10_14_11, SCIFB1_RXD_E, SEL_SCIFB1_4),
@@ -1364,8 +1364,8 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP10_14_11, TS_SDAT0_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP10_14_11, GLO_SS_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_14_11, VI3_DATA2_B, SEL_VI3_1),
- PINMUX_IPSR_DATA(IP10_18_15, SD2_DAT1),
- PINMUX_IPSR_DATA(IP10_18_15, MMC0_D1),
+ PINMUX_IPSR_GPSR(IP10_18_15, SD2_DAT1),
+ PINMUX_IPSR_GPSR(IP10_18_15, MMC0_D1),
PINMUX_IPSR_MSEL(IP10_18_15, FMIN_B, SEL_FM_1),
PINMUX_IPSR_MSEL(IP10_18_15, VI0_DATA3_VI0_B3_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP10_18_15, SCIFB1_TXD_E, SEL_SCIFB1_4),
@@ -1373,26 +1373,26 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP10_18_15, TS_SCK0_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP10_18_15, GLO_RFON_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_18_15, VI3_DATA3_B, SEL_VI3_1),
- PINMUX_IPSR_DATA(IP10_22_19, SD2_DAT2),
- PINMUX_IPSR_DATA(IP10_22_19, MMC0_D2),
+ PINMUX_IPSR_GPSR(IP10_22_19, SD2_DAT2),
+ PINMUX_IPSR_GPSR(IP10_22_19, MMC0_D2),
PINMUX_IPSR_MSEL(IP10_22_19, BPFCLK_B, SEL_FM_1),
PINMUX_IPSR_MSEL(IP10_22_19, VI0_DATA4_VI0_B4_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP10_22_19, HRX0_D, SEL_HSCIF0_3),
PINMUX_IPSR_MSEL(IP10_22_19, TS_SDEN1_B, SEL_TSIF1_1),
PINMUX_IPSR_MSEL(IP10_22_19, GLO_Q0_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_22_19, VI3_DATA4_B, SEL_VI3_1),
- PINMUX_IPSR_DATA(IP10_25_23, SD2_DAT3),
- PINMUX_IPSR_DATA(IP10_25_23, MMC0_D3),
+ PINMUX_IPSR_GPSR(IP10_25_23, SD2_DAT3),
+ PINMUX_IPSR_GPSR(IP10_25_23, MMC0_D3),
PINMUX_IPSR_MSEL(IP10_25_23, SIM0_RST, SEL_SIM_0),
PINMUX_IPSR_MSEL(IP10_25_23, VI0_DATA5_VI0_B5_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP10_25_23, HTX0_D, SEL_HSCIF0_3),
PINMUX_IPSR_MSEL(IP10_25_23, TS_SPSYNC1_B, SEL_TSIF1_1),
PINMUX_IPSR_MSEL(IP10_25_23, GLO_Q1_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_25_23, VI3_DATA5_B, SEL_VI3_1),
- PINMUX_IPSR_DATA(IP10_29_26, SD2_CD),
- PINMUX_IPSR_DATA(IP10_29_26, MMC0_D4),
+ PINMUX_IPSR_GPSR(IP10_29_26, SD2_CD),
+ PINMUX_IPSR_GPSR(IP10_29_26, MMC0_D4),
PINMUX_IPSR_MSEL(IP10_29_26, TS_SDAT0_B, SEL_TSIF0_1),
- PINMUX_IPSR_DATA(IP10_29_26, USB2_EXTP),
+ PINMUX_IPSR_GPSR(IP10_29_26, USB2_EXTP),
PINMUX_IPSR_MSEL(IP10_29_26, GLO_I0, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP10_29_26, VI0_DATA6_VI0_B6_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP10_29_26, HCTS0_N_D, SEL_HSCIF0_3),
@@ -1400,164 +1400,164 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP10_29_26, GLO_I0_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_29_26, VI3_DATA6_B, SEL_VI3_1),
- PINMUX_IPSR_DATA(IP11_3_0, SD2_WP),
- PINMUX_IPSR_DATA(IP11_3_0, MMC0_D5),
+ PINMUX_IPSR_GPSR(IP11_3_0, SD2_WP),
+ PINMUX_IPSR_GPSR(IP11_3_0, MMC0_D5),
PINMUX_IPSR_MSEL(IP11_3_0, TS_SCK0_B, SEL_TSIF0_1),
- PINMUX_IPSR_DATA(IP11_3_0, USB2_IDIN),
+ PINMUX_IPSR_GPSR(IP11_3_0, USB2_IDIN),
PINMUX_IPSR_MSEL(IP11_3_0, GLO_I1, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP11_3_0, VI0_DATA7_VI0_B7_B, SEL_VI0_1),
PINMUX_IPSR_MSEL(IP11_3_0, HRTS0_N_D, SEL_HSCIF0_3),
PINMUX_IPSR_MSEL(IP11_3_0, TS_SCK1_B, SEL_TSIF1_1),
PINMUX_IPSR_MSEL(IP11_3_0, GLO_I1_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP11_3_0, VI3_DATA7_B, SEL_VI3_1),
- PINMUX_IPSR_DATA(IP11_4, SD3_CLK),
- PINMUX_IPSR_DATA(IP11_4, MMC1_CLK),
- PINMUX_IPSR_DATA(IP11_6_5, SD3_CMD),
- PINMUX_IPSR_DATA(IP11_6_5, MMC1_CMD),
- PINMUX_IPSR_DATA(IP11_6_5, MTS_N),
- PINMUX_IPSR_DATA(IP11_8_7, SD3_DAT0),
- PINMUX_IPSR_DATA(IP11_8_7, MMC1_D0),
- PINMUX_IPSR_DATA(IP11_8_7, STM_N),
- PINMUX_IPSR_DATA(IP11_10_9, SD3_DAT1),
- PINMUX_IPSR_DATA(IP11_10_9, MMC1_D1),
- PINMUX_IPSR_DATA(IP11_10_9, MDATA),
- PINMUX_IPSR_DATA(IP11_12_11, SD3_DAT2),
- PINMUX_IPSR_DATA(IP11_12_11, MMC1_D2),
- PINMUX_IPSR_DATA(IP11_12_11, SDATA),
- PINMUX_IPSR_DATA(IP11_14_13, SD3_DAT3),
- PINMUX_IPSR_DATA(IP11_14_13, MMC1_D3),
- PINMUX_IPSR_DATA(IP11_14_13, SCKZ),
- PINMUX_IPSR_DATA(IP11_17_15, SD3_CD),
- PINMUX_IPSR_DATA(IP11_17_15, MMC1_D4),
+ PINMUX_IPSR_GPSR(IP11_4, SD3_CLK),
+ PINMUX_IPSR_GPSR(IP11_4, MMC1_CLK),
+ PINMUX_IPSR_GPSR(IP11_6_5, SD3_CMD),
+ PINMUX_IPSR_GPSR(IP11_6_5, MMC1_CMD),
+ PINMUX_IPSR_GPSR(IP11_6_5, MTS_N),
+ PINMUX_IPSR_GPSR(IP11_8_7, SD3_DAT0),
+ PINMUX_IPSR_GPSR(IP11_8_7, MMC1_D0),
+ PINMUX_IPSR_GPSR(IP11_8_7, STM_N),
+ PINMUX_IPSR_GPSR(IP11_10_9, SD3_DAT1),
+ PINMUX_IPSR_GPSR(IP11_10_9, MMC1_D1),
+ PINMUX_IPSR_GPSR(IP11_10_9, MDATA),
+ PINMUX_IPSR_GPSR(IP11_12_11, SD3_DAT2),
+ PINMUX_IPSR_GPSR(IP11_12_11, MMC1_D2),
+ PINMUX_IPSR_GPSR(IP11_12_11, SDATA),
+ PINMUX_IPSR_GPSR(IP11_14_13, SD3_DAT3),
+ PINMUX_IPSR_GPSR(IP11_14_13, MMC1_D3),
+ PINMUX_IPSR_GPSR(IP11_14_13, SCKZ),
+ PINMUX_IPSR_GPSR(IP11_17_15, SD3_CD),
+ PINMUX_IPSR_GPSR(IP11_17_15, MMC1_D4),
PINMUX_IPSR_MSEL(IP11_17_15, TS_SDAT1, SEL_TSIF1_0),
- PINMUX_IPSR_DATA(IP11_17_15, VSP),
+ PINMUX_IPSR_GPSR(IP11_17_15, VSP),
PINMUX_IPSR_MSEL(IP11_17_15, GLO_Q0, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP11_17_15, SIM0_RST_B, SEL_SIM_1),
- PINMUX_IPSR_DATA(IP11_21_18, SD3_WP),
- PINMUX_IPSR_DATA(IP11_21_18, MMC1_D5),
+ PINMUX_IPSR_GPSR(IP11_21_18, SD3_WP),
+ PINMUX_IPSR_GPSR(IP11_21_18, MMC1_D5),
PINMUX_IPSR_MSEL(IP11_21_18, TS_SCK1, SEL_TSIF1_0),
PINMUX_IPSR_MSEL(IP11_21_18, GLO_Q1, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP11_21_18, FMIN_C, SEL_FM_2),
PINMUX_IPSR_MSEL(IP11_21_18, FMIN_E, SEL_FM_4),
PINMUX_IPSR_MSEL(IP11_21_18, FMIN_F, SEL_FM_5),
- PINMUX_IPSR_DATA(IP11_23_22, MLB_CLK),
+ PINMUX_IPSR_GPSR(IP11_23_22, MLB_CLK),
PINMUX_IPSR_MSEL(IP11_23_22, IIC2_SCL_B, SEL_IIC2_1),
PINMUX_IPSR_MSEL(IP11_23_22, I2C2_SCL_B, SEL_I2C2_1),
- PINMUX_IPSR_DATA(IP11_26_24, MLB_SIG),
+ PINMUX_IPSR_GPSR(IP11_26_24, MLB_SIG),
PINMUX_IPSR_MSEL(IP11_26_24, SCIFB1_RXD_D, SEL_SCIFB1_3),
PINMUX_IPSR_MSEL(IP11_26_24, RX1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP11_26_24, IIC2_SDA_B, SEL_IIC2_1),
PINMUX_IPSR_MSEL(IP11_26_24, I2C2_SDA_B, SEL_I2C2_1),
- PINMUX_IPSR_DATA(IP11_29_27, MLB_DAT),
+ PINMUX_IPSR_GPSR(IP11_29_27, MLB_DAT),
PINMUX_IPSR_MSEL(IP11_29_27, SCIFB1_TXD_D, SEL_SCIFB1_3),
PINMUX_IPSR_MSEL(IP11_29_27, TX1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP11_29_27, BPFCLK_C, SEL_FM_2),
- PINMUX_IPSR_DATA(IP11_31_30, SSI_SCK0129),
+ PINMUX_IPSR_GPSR(IP11_31_30, SSI_SCK0129),
PINMUX_IPSR_MSEL(IP11_31_30, CAN_CLK_B, SEL_CANCLK_1),
- PINMUX_IPSR_DATA(IP11_31_30, MOUT0),
+ PINMUX_IPSR_GPSR(IP11_31_30, MOUT0),
- PINMUX_IPSR_DATA(IP12_1_0, SSI_WS0129),
+ PINMUX_IPSR_GPSR(IP12_1_0, SSI_WS0129),
PINMUX_IPSR_MSEL(IP12_1_0, CAN0_TX_B, SEL_CAN0_1),
- PINMUX_IPSR_DATA(IP12_1_0, MOUT1),
- PINMUX_IPSR_DATA(IP12_3_2, SSI_SDATA0),
+ PINMUX_IPSR_GPSR(IP12_1_0, MOUT1),
+ PINMUX_IPSR_GPSR(IP12_3_2, SSI_SDATA0),
PINMUX_IPSR_MSEL(IP12_3_2, CAN0_RX_B, SEL_CAN0_1),
- PINMUX_IPSR_DATA(IP12_3_2, MOUT2),
- PINMUX_IPSR_DATA(IP12_5_4, SSI_SDATA1),
+ PINMUX_IPSR_GPSR(IP12_3_2, MOUT2),
+ PINMUX_IPSR_GPSR(IP12_5_4, SSI_SDATA1),
PINMUX_IPSR_MSEL(IP12_5_4, CAN1_TX_B, SEL_CAN1_1),
- PINMUX_IPSR_DATA(IP12_5_4, MOUT5),
- PINMUX_IPSR_DATA(IP12_7_6, SSI_SDATA2),
+ PINMUX_IPSR_GPSR(IP12_5_4, MOUT5),
+ PINMUX_IPSR_GPSR(IP12_7_6, SSI_SDATA2),
PINMUX_IPSR_MSEL(IP12_7_6, CAN1_RX_B, SEL_CAN1_1),
- PINMUX_IPSR_DATA(IP12_7_6, SSI_SCK1),
- PINMUX_IPSR_DATA(IP12_7_6, MOUT6),
- PINMUX_IPSR_DATA(IP12_10_8, SSI_SCK34),
- PINMUX_IPSR_DATA(IP12_10_8, STP_OPWM_0),
+ PINMUX_IPSR_GPSR(IP12_7_6, SSI_SCK1),
+ PINMUX_IPSR_GPSR(IP12_7_6, MOUT6),
+ PINMUX_IPSR_GPSR(IP12_10_8, SSI_SCK34),
+ PINMUX_IPSR_GPSR(IP12_10_8, STP_OPWM_0),
PINMUX_IPSR_MSEL(IP12_10_8, SCIFB0_SCK, SEL_SCIFB_0),
PINMUX_IPSR_MSEL(IP12_10_8, MSIOF1_SCK, SEL_SOF1_0),
- PINMUX_IPSR_DATA(IP12_10_8, CAN_DEBUG_HW_TRIGGER),
- PINMUX_IPSR_DATA(IP12_13_11, SSI_WS34),
+ PINMUX_IPSR_GPSR(IP12_10_8, CAN_DEBUG_HW_TRIGGER),
+ PINMUX_IPSR_GPSR(IP12_13_11, SSI_WS34),
PINMUX_IPSR_MSEL(IP12_13_11, STP_IVCXO27_0, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP12_13_11, SCIFB0_RXD, SEL_SCIFB_0),
- PINMUX_IPSR_DATA(IP12_13_11, MSIOF1_SYNC),
- PINMUX_IPSR_DATA(IP12_13_11, CAN_STEP0),
- PINMUX_IPSR_DATA(IP12_16_14, SSI_SDATA3),
+ PINMUX_IPSR_GPSR(IP12_13_11, MSIOF1_SYNC),
+ PINMUX_IPSR_GPSR(IP12_13_11, CAN_STEP0),
+ PINMUX_IPSR_GPSR(IP12_16_14, SSI_SDATA3),
PINMUX_IPSR_MSEL(IP12_16_14, STP_ISCLK_0, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP12_16_14, SCIFB0_TXD, SEL_SCIFB_0),
PINMUX_IPSR_MSEL(IP12_16_14, MSIOF1_SS1, SEL_SOF1_0),
- PINMUX_IPSR_DATA(IP12_16_14, CAN_TXCLK),
- PINMUX_IPSR_DATA(IP12_19_17, SSI_SCK4),
+ PINMUX_IPSR_GPSR(IP12_16_14, CAN_TXCLK),
+ PINMUX_IPSR_GPSR(IP12_19_17, SSI_SCK4),
PINMUX_IPSR_MSEL(IP12_19_17, STP_ISD_0, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP12_19_17, SCIFB0_CTS_N, SEL_SCIFB_0),
PINMUX_IPSR_MSEL(IP12_19_17, MSIOF1_SS2, SEL_SOF1_0),
PINMUX_IPSR_MSEL(IP12_19_17, SSI_SCK5_C, SEL_SSI5_2),
- PINMUX_IPSR_DATA(IP12_19_17, CAN_DEBUGOUT0),
- PINMUX_IPSR_DATA(IP12_22_20, SSI_WS4),
+ PINMUX_IPSR_GPSR(IP12_19_17, CAN_DEBUGOUT0),
+ PINMUX_IPSR_GPSR(IP12_22_20, SSI_WS4),
PINMUX_IPSR_MSEL(IP12_22_20, STP_ISEN_0, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP12_22_20, SCIFB0_RTS_N, SEL_SCIFB_0),
PINMUX_IPSR_MSEL(IP12_22_20, MSIOF1_TXD, SEL_SOF1_0),
PINMUX_IPSR_MSEL(IP12_22_20, SSI_WS5_C, SEL_SSI5_2),
- PINMUX_IPSR_DATA(IP12_22_20, CAN_DEBUGOUT1),
- PINMUX_IPSR_DATA(IP12_24_23, SSI_SDATA4),
+ PINMUX_IPSR_GPSR(IP12_22_20, CAN_DEBUGOUT1),
+ PINMUX_IPSR_GPSR(IP12_24_23, SSI_SDATA4),
PINMUX_IPSR_MSEL(IP12_24_23, STP_ISSYNC_0, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP12_24_23, MSIOF1_RXD, SEL_SOF1_0),
- PINMUX_IPSR_DATA(IP12_24_23, CAN_DEBUGOUT2),
+ PINMUX_IPSR_GPSR(IP12_24_23, CAN_DEBUGOUT2),
PINMUX_IPSR_MSEL(IP12_27_25, SSI_SCK5, SEL_SSI5_0),
PINMUX_IPSR_MSEL(IP12_27_25, SCIFB1_SCK, SEL_SCIFB1_0),
PINMUX_IPSR_MSEL(IP12_27_25, IERX_B, SEL_IEB_1),
- PINMUX_IPSR_DATA(IP12_27_25, DU2_EXHSYNC_DU2_HSYNC),
- PINMUX_IPSR_DATA(IP12_27_25, QSTH_QHS),
- PINMUX_IPSR_DATA(IP12_27_25, CAN_DEBUGOUT3),
+ PINMUX_IPSR_GPSR(IP12_27_25, DU2_EXHSYNC_DU2_HSYNC),
+ PINMUX_IPSR_GPSR(IP12_27_25, QSTH_QHS),
+ PINMUX_IPSR_GPSR(IP12_27_25, CAN_DEBUGOUT3),
PINMUX_IPSR_MSEL(IP12_30_28, SSI_WS5, SEL_SSI5_0),
PINMUX_IPSR_MSEL(IP12_30_28, SCIFB1_RXD, SEL_SCIFB1_0),
PINMUX_IPSR_MSEL(IP12_30_28, IECLK_B, SEL_IEB_1),
- PINMUX_IPSR_DATA(IP12_30_28, DU2_EXVSYNC_DU2_VSYNC),
- PINMUX_IPSR_DATA(IP12_30_28, QSTB_QHE),
- PINMUX_IPSR_DATA(IP12_30_28, CAN_DEBUGOUT4),
+ PINMUX_IPSR_GPSR(IP12_30_28, DU2_EXVSYNC_DU2_VSYNC),
+ PINMUX_IPSR_GPSR(IP12_30_28, QSTB_QHE),
+ PINMUX_IPSR_GPSR(IP12_30_28, CAN_DEBUGOUT4),
PINMUX_IPSR_MSEL(IP13_2_0, SSI_SDATA5, SEL_SSI5_0),
PINMUX_IPSR_MSEL(IP13_2_0, SCIFB1_TXD, SEL_SCIFB1_0),
PINMUX_IPSR_MSEL(IP13_2_0, IETX_B, SEL_IEB_1),
- PINMUX_IPSR_DATA(IP13_2_0, DU2_DR2),
- PINMUX_IPSR_DATA(IP13_2_0, LCDOUT2),
- PINMUX_IPSR_DATA(IP13_2_0, CAN_DEBUGOUT5),
+ PINMUX_IPSR_GPSR(IP13_2_0, DU2_DR2),
+ PINMUX_IPSR_GPSR(IP13_2_0, LCDOUT2),
+ PINMUX_IPSR_GPSR(IP13_2_0, CAN_DEBUGOUT5),
PINMUX_IPSR_MSEL(IP13_6_3, SSI_SCK6, SEL_SSI6_0),
PINMUX_IPSR_MSEL(IP13_6_3, SCIFB1_CTS_N, SEL_SCIFB1_0),
PINMUX_IPSR_MSEL(IP13_6_3, BPFCLK_D, SEL_FM_3),
- PINMUX_IPSR_DATA(IP13_6_3, DU2_DR3),
- PINMUX_IPSR_DATA(IP13_6_3, LCDOUT3),
- PINMUX_IPSR_DATA(IP13_6_3, CAN_DEBUGOUT6),
+ PINMUX_IPSR_GPSR(IP13_6_3, DU2_DR3),
+ PINMUX_IPSR_GPSR(IP13_6_3, LCDOUT3),
+ PINMUX_IPSR_GPSR(IP13_6_3, CAN_DEBUGOUT6),
PINMUX_IPSR_MSEL(IP13_6_3, BPFCLK_F, SEL_FM_5),
PINMUX_IPSR_MSEL(IP13_9_7, SSI_WS6, SEL_SSI6_0),
PINMUX_IPSR_MSEL(IP13_9_7, SCIFB1_RTS_N, SEL_SCIFB1_0),
PINMUX_IPSR_MSEL(IP13_9_7, CAN0_TX_D, SEL_CAN0_3),
- PINMUX_IPSR_DATA(IP13_9_7, DU2_DR4),
- PINMUX_IPSR_DATA(IP13_9_7, LCDOUT4),
- PINMUX_IPSR_DATA(IP13_9_7, CAN_DEBUGOUT7),
+ PINMUX_IPSR_GPSR(IP13_9_7, DU2_DR4),
+ PINMUX_IPSR_GPSR(IP13_9_7, LCDOUT4),
+ PINMUX_IPSR_GPSR(IP13_9_7, CAN_DEBUGOUT7),
PINMUX_IPSR_MSEL(IP13_12_10, SSI_SDATA6, SEL_SSI6_0),
PINMUX_IPSR_MSEL(IP13_12_10, FMIN_D, SEL_FM_3),
- PINMUX_IPSR_DATA(IP13_12_10, DU2_DR5),
- PINMUX_IPSR_DATA(IP13_12_10, LCDOUT5),
- PINMUX_IPSR_DATA(IP13_12_10, CAN_DEBUGOUT8),
+ PINMUX_IPSR_GPSR(IP13_12_10, DU2_DR5),
+ PINMUX_IPSR_GPSR(IP13_12_10, LCDOUT5),
+ PINMUX_IPSR_GPSR(IP13_12_10, CAN_DEBUGOUT8),
PINMUX_IPSR_MSEL(IP13_15_13, SSI_SCK78, SEL_SSI7_0),
PINMUX_IPSR_MSEL(IP13_15_13, STP_IVCXO27_1, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP13_15_13, SCK1, SEL_SCIF1_0),
PINMUX_IPSR_MSEL(IP13_15_13, SCIFA1_SCK, SEL_SCIFA1_0),
- PINMUX_IPSR_DATA(IP13_15_13, DU2_DR6),
- PINMUX_IPSR_DATA(IP13_15_13, LCDOUT6),
- PINMUX_IPSR_DATA(IP13_15_13, CAN_DEBUGOUT9),
+ PINMUX_IPSR_GPSR(IP13_15_13, DU2_DR6),
+ PINMUX_IPSR_GPSR(IP13_15_13, LCDOUT6),
+ PINMUX_IPSR_GPSR(IP13_15_13, CAN_DEBUGOUT9),
PINMUX_IPSR_MSEL(IP13_18_16, SSI_WS78, SEL_SSI7_0),
PINMUX_IPSR_MSEL(IP13_18_16, STP_ISCLK_1, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP13_18_16, SCIFB2_SCK, SEL_SCIFB2_0),
- PINMUX_IPSR_DATA(IP13_18_16, SCIFA2_CTS_N),
- PINMUX_IPSR_DATA(IP13_18_16, DU2_DR7),
- PINMUX_IPSR_DATA(IP13_18_16, LCDOUT7),
- PINMUX_IPSR_DATA(IP13_18_16, CAN_DEBUGOUT10),
+ PINMUX_IPSR_GPSR(IP13_18_16, SCIFA2_CTS_N),
+ PINMUX_IPSR_GPSR(IP13_18_16, DU2_DR7),
+ PINMUX_IPSR_GPSR(IP13_18_16, LCDOUT7),
+ PINMUX_IPSR_GPSR(IP13_18_16, CAN_DEBUGOUT10),
PINMUX_IPSR_MSEL(IP13_22_19, SSI_SDATA7, SEL_SSI7_0),
PINMUX_IPSR_MSEL(IP13_22_19, STP_ISD_1, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP13_22_19, SCIFB2_RXD, SEL_SCIFB2_0),
- PINMUX_IPSR_DATA(IP13_22_19, SCIFA2_RTS_N),
- PINMUX_IPSR_DATA(IP13_22_19, TCLK2),
- PINMUX_IPSR_DATA(IP13_22_19, QSTVA_QVS),
- PINMUX_IPSR_DATA(IP13_22_19, CAN_DEBUGOUT11),
+ PINMUX_IPSR_GPSR(IP13_22_19, SCIFA2_RTS_N),
+ PINMUX_IPSR_GPSR(IP13_22_19, TCLK2),
+ PINMUX_IPSR_GPSR(IP13_22_19, QSTVA_QVS),
+ PINMUX_IPSR_GPSR(IP13_22_19, CAN_DEBUGOUT11),
PINMUX_IPSR_MSEL(IP13_22_19, BPFCLK_E, SEL_FM_4),
PINMUX_IPSR_MSEL(IP13_22_19, SSI_SDATA7_B, SEL_SSI7_1),
PINMUX_IPSR_MSEL(IP13_22_19, FMIN_G, SEL_FM_6),
@@ -1565,161 +1565,161 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP13_25_23, STP_ISEN_1, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP13_25_23, SCIFB2_TXD, SEL_SCIFB2_0),
PINMUX_IPSR_MSEL(IP13_25_23, CAN0_TX_C, SEL_CAN0_2),
- PINMUX_IPSR_DATA(IP13_25_23, CAN_DEBUGOUT12),
+ PINMUX_IPSR_GPSR(IP13_25_23, CAN_DEBUGOUT12),
PINMUX_IPSR_MSEL(IP13_25_23, SSI_SDATA8_B, SEL_SSI8_1),
- PINMUX_IPSR_DATA(IP13_28_26, SSI_SDATA9),
+ PINMUX_IPSR_GPSR(IP13_28_26, SSI_SDATA9),
PINMUX_IPSR_MSEL(IP13_28_26, STP_ISSYNC_1, SEL_SSP_0),
PINMUX_IPSR_MSEL(IP13_28_26, SCIFB2_CTS_N, SEL_SCIFB2_0),
- PINMUX_IPSR_DATA(IP13_28_26, SSI_WS1),
+ PINMUX_IPSR_GPSR(IP13_28_26, SSI_WS1),
PINMUX_IPSR_MSEL(IP13_28_26, SSI_SDATA5_C, SEL_SSI5_2),
- PINMUX_IPSR_DATA(IP13_28_26, CAN_DEBUGOUT13),
- PINMUX_IPSR_DATA(IP13_30_29, AUDIO_CLKA),
+ PINMUX_IPSR_GPSR(IP13_28_26, CAN_DEBUGOUT13),
+ PINMUX_IPSR_GPSR(IP13_30_29, AUDIO_CLKA),
PINMUX_IPSR_MSEL(IP13_30_29, SCIFB2_RTS_N, SEL_SCIFB2_0),
- PINMUX_IPSR_DATA(IP13_30_29, CAN_DEBUGOUT14),
+ PINMUX_IPSR_GPSR(IP13_30_29, CAN_DEBUGOUT14),
- PINMUX_IPSR_DATA(IP14_2_0, AUDIO_CLKB),
+ PINMUX_IPSR_GPSR(IP14_2_0, AUDIO_CLKB),
PINMUX_IPSR_MSEL(IP14_2_0, SCIF_CLK, SEL_SCIFCLK_0),
PINMUX_IPSR_MSEL(IP14_2_0, CAN0_RX_D, SEL_CAN0_3),
- PINMUX_IPSR_DATA(IP14_2_0, DVC_MUTE),
+ PINMUX_IPSR_GPSR(IP14_2_0, DVC_MUTE),
PINMUX_IPSR_MSEL(IP14_2_0, CAN0_RX_C, SEL_CAN0_2),
- PINMUX_IPSR_DATA(IP14_2_0, CAN_DEBUGOUT15),
- PINMUX_IPSR_DATA(IP14_2_0, REMOCON),
+ PINMUX_IPSR_GPSR(IP14_2_0, CAN_DEBUGOUT15),
+ PINMUX_IPSR_GPSR(IP14_2_0, REMOCON),
PINMUX_IPSR_MSEL(IP14_5_3, SCIFA0_SCK, SEL_SCFA_0),
PINMUX_IPSR_MSEL(IP14_5_3, HSCK1, SEL_HSCIF1_0),
- PINMUX_IPSR_DATA(IP14_5_3, SCK0),
- PINMUX_IPSR_DATA(IP14_5_3, MSIOF3_SS2),
- PINMUX_IPSR_DATA(IP14_5_3, DU2_DG2),
- PINMUX_IPSR_DATA(IP14_5_3, LCDOUT10),
+ PINMUX_IPSR_GPSR(IP14_5_3, SCK0),
+ PINMUX_IPSR_GPSR(IP14_5_3, MSIOF3_SS2),
+ PINMUX_IPSR_GPSR(IP14_5_3, DU2_DG2),
+ PINMUX_IPSR_GPSR(IP14_5_3, LCDOUT10),
PINMUX_IPSR_MSEL(IP14_5_3, IIC1_SDA_C, SEL_IIC1_2),
PINMUX_IPSR_MSEL(IP14_5_3, I2C1_SDA_C, SEL_I2C1_2),
PINMUX_IPSR_MSEL(IP14_8_6, SCIFA0_RXD, SEL_SCFA_0),
PINMUX_IPSR_MSEL(IP14_8_6, HRX1, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP14_8_6, RX0, SEL_SCIF0_0),
- PINMUX_IPSR_DATA(IP14_8_6, DU2_DR0),
- PINMUX_IPSR_DATA(IP14_8_6, LCDOUT0),
+ PINMUX_IPSR_GPSR(IP14_8_6, DU2_DR0),
+ PINMUX_IPSR_GPSR(IP14_8_6, LCDOUT0),
PINMUX_IPSR_MSEL(IP14_11_9, SCIFA0_TXD, SEL_SCFA_0),
PINMUX_IPSR_MSEL(IP14_11_9, HTX1, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP14_11_9, TX0, SEL_SCIF0_0),
- PINMUX_IPSR_DATA(IP14_11_9, DU2_DR1),
- PINMUX_IPSR_DATA(IP14_11_9, LCDOUT1),
+ PINMUX_IPSR_GPSR(IP14_11_9, DU2_DR1),
+ PINMUX_IPSR_GPSR(IP14_11_9, LCDOUT1),
PINMUX_IPSR_MSEL(IP14_15_12, SCIFA0_CTS_N, SEL_SCFA_0),
PINMUX_IPSR_MSEL(IP14_15_12, HCTS1_N, SEL_HSCIF1_0),
- PINMUX_IPSR_DATA(IP14_15_12, CTS0_N),
+ PINMUX_IPSR_GPSR(IP14_15_12, CTS0_N),
PINMUX_IPSR_MSEL(IP14_15_12, MSIOF3_SYNC, SEL_SOF3_0),
- PINMUX_IPSR_DATA(IP14_15_12, DU2_DG3),
- PINMUX_IPSR_DATA(IP14_15_12, LCDOUT11),
- PINMUX_IPSR_DATA(IP14_15_12, PWM0_B),
+ PINMUX_IPSR_GPSR(IP14_15_12, DU2_DG3),
+ PINMUX_IPSR_GPSR(IP14_15_12, LCDOUT11),
+ PINMUX_IPSR_GPSR(IP14_15_12, PWM0_B),
PINMUX_IPSR_MSEL(IP14_15_12, IIC1_SCL_C, SEL_IIC1_2),
PINMUX_IPSR_MSEL(IP14_15_12, I2C1_SCL_C, SEL_I2C1_2),
PINMUX_IPSR_MSEL(IP14_18_16, SCIFA0_RTS_N, SEL_SCFA_0),
PINMUX_IPSR_MSEL(IP14_18_16, HRTS1_N, SEL_HSCIF1_0),
- PINMUX_IPSR_DATA(IP14_18_16, RTS0_N),
- PINMUX_IPSR_DATA(IP14_18_16, MSIOF3_SS1),
- PINMUX_IPSR_DATA(IP14_18_16, DU2_DG0),
- PINMUX_IPSR_DATA(IP14_18_16, LCDOUT8),
- PINMUX_IPSR_DATA(IP14_18_16, PWM1_B),
+ PINMUX_IPSR_GPSR(IP14_18_16, RTS0_N),
+ PINMUX_IPSR_GPSR(IP14_18_16, MSIOF3_SS1),
+ PINMUX_IPSR_GPSR(IP14_18_16, DU2_DG0),
+ PINMUX_IPSR_GPSR(IP14_18_16, LCDOUT8),
+ PINMUX_IPSR_GPSR(IP14_18_16, PWM1_B),
PINMUX_IPSR_MSEL(IP14_21_19, SCIFA1_RXD, SEL_SCIFA1_0),
PINMUX_IPSR_MSEL(IP14_21_19, AD_DI, SEL_ADI_0),
PINMUX_IPSR_MSEL(IP14_21_19, RX1, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP14_21_19, DU2_EXODDF_DU2_ODDF_DISP_CDE),
- PINMUX_IPSR_DATA(IP14_21_19, QCPV_QDE),
+ PINMUX_IPSR_GPSR(IP14_21_19, DU2_EXODDF_DU2_ODDF_DISP_CDE),
+ PINMUX_IPSR_GPSR(IP14_21_19, QCPV_QDE),
PINMUX_IPSR_MSEL(IP14_24_22, SCIFA1_TXD, SEL_SCIFA1_0),
PINMUX_IPSR_MSEL(IP14_24_22, AD_DO, SEL_ADI_0),
PINMUX_IPSR_MSEL(IP14_24_22, TX1, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP14_24_22, DU2_DG1),
- PINMUX_IPSR_DATA(IP14_24_22, LCDOUT9),
+ PINMUX_IPSR_GPSR(IP14_24_22, DU2_DG1),
+ PINMUX_IPSR_GPSR(IP14_24_22, LCDOUT9),
PINMUX_IPSR_MSEL(IP14_27_25, SCIFA1_CTS_N, SEL_SCIFA1_0),
PINMUX_IPSR_MSEL(IP14_27_25, AD_CLK, SEL_ADI_0),
- PINMUX_IPSR_DATA(IP14_27_25, CTS1_N),
+ PINMUX_IPSR_GPSR(IP14_27_25, CTS1_N),
PINMUX_IPSR_MSEL(IP14_27_25, MSIOF3_RXD, SEL_SOF3_0),
- PINMUX_IPSR_DATA(IP14_27_25, DU0_DOTCLKOUT),
- PINMUX_IPSR_DATA(IP14_27_25, QCLK),
+ PINMUX_IPSR_GPSR(IP14_27_25, DU0_DOTCLKOUT),
+ PINMUX_IPSR_GPSR(IP14_27_25, QCLK),
PINMUX_IPSR_MSEL(IP14_30_28, SCIFA1_RTS_N, SEL_SCIFA1_0),
PINMUX_IPSR_MSEL(IP14_30_28, AD_NCS_N, SEL_ADI_0),
- PINMUX_IPSR_DATA(IP14_30_28, RTS1_N),
+ PINMUX_IPSR_GPSR(IP14_30_28, RTS1_N),
PINMUX_IPSR_MSEL(IP14_30_28, MSIOF3_TXD, SEL_SOF3_0),
- PINMUX_IPSR_DATA(IP14_30_28, DU1_DOTCLKOUT),
- PINMUX_IPSR_DATA(IP14_30_28, QSTVB_QVE),
+ PINMUX_IPSR_GPSR(IP14_30_28, DU1_DOTCLKOUT),
+ PINMUX_IPSR_GPSR(IP14_30_28, QSTVB_QVE),
PINMUX_IPSR_MSEL(IP14_30_28, HRTS0_N_C, SEL_HSCIF0_2),
PINMUX_IPSR_MSEL(IP15_2_0, SCIFA2_SCK, SEL_SCIFA2_0),
PINMUX_IPSR_MSEL(IP15_2_0, FMCLK, SEL_FM_0),
- PINMUX_IPSR_DATA(IP15_2_0, SCK2),
+ PINMUX_IPSR_GPSR(IP15_2_0, SCK2),
PINMUX_IPSR_MSEL(IP15_2_0, MSIOF3_SCK, SEL_SOF3_0),
- PINMUX_IPSR_DATA(IP15_2_0, DU2_DG7),
- PINMUX_IPSR_DATA(IP15_2_0, LCDOUT15),
+ PINMUX_IPSR_GPSR(IP15_2_0, DU2_DG7),
+ PINMUX_IPSR_GPSR(IP15_2_0, LCDOUT15),
PINMUX_IPSR_MSEL(IP15_2_0, SCIF_CLK_B, SEL_SCIFCLK_1),
PINMUX_IPSR_MSEL(IP15_5_3, SCIFA2_RXD, SEL_SCIFA2_0),
PINMUX_IPSR_MSEL(IP15_5_3, FMIN, SEL_FM_0),
PINMUX_IPSR_MSEL(IP15_5_3, TX2, SEL_SCIF2_0),
- PINMUX_IPSR_DATA(IP15_5_3, DU2_DB0),
- PINMUX_IPSR_DATA(IP15_5_3, LCDOUT16),
+ PINMUX_IPSR_GPSR(IP15_5_3, DU2_DB0),
+ PINMUX_IPSR_GPSR(IP15_5_3, LCDOUT16),
PINMUX_IPSR_MSEL(IP15_5_3, IIC2_SCL, SEL_IIC2_0),
PINMUX_IPSR_MSEL(IP15_5_3, I2C2_SCL, SEL_I2C2_0),
PINMUX_IPSR_MSEL(IP15_8_6, SCIFA2_TXD, SEL_SCIFA2_0),
PINMUX_IPSR_MSEL(IP15_8_6, BPFCLK, SEL_FM_0),
PINMUX_IPSR_MSEL(IP15_8_6, RX2, SEL_SCIF2_0),
- PINMUX_IPSR_DATA(IP15_8_6, DU2_DB1),
- PINMUX_IPSR_DATA(IP15_8_6, LCDOUT17),
+ PINMUX_IPSR_GPSR(IP15_8_6, DU2_DB1),
+ PINMUX_IPSR_GPSR(IP15_8_6, LCDOUT17),
PINMUX_IPSR_MSEL(IP15_8_6, IIC2_SDA, SEL_IIC2_0),
PINMUX_IPSR_MSEL(IP15_8_6, I2C2_SDA, SEL_I2C2_0),
- PINMUX_IPSR_DATA(IP15_11_9, HSCK0),
+ PINMUX_IPSR_GPSR(IP15_11_9, HSCK0),
PINMUX_IPSR_MSEL(IP15_11_9, TS_SDEN0, SEL_TSIF0_0),
- PINMUX_IPSR_DATA(IP15_11_9, DU2_DG4),
- PINMUX_IPSR_DATA(IP15_11_9, LCDOUT12),
+ PINMUX_IPSR_GPSR(IP15_11_9, DU2_DG4),
+ PINMUX_IPSR_GPSR(IP15_11_9, LCDOUT12),
PINMUX_IPSR_MSEL(IP15_11_9, HCTS0_N_C, SEL_HSCIF0_2),
PINMUX_IPSR_MSEL(IP15_13_12, HRX0, SEL_HSCIF0_0),
- PINMUX_IPSR_DATA(IP15_13_12, DU2_DB2),
- PINMUX_IPSR_DATA(IP15_13_12, LCDOUT18),
+ PINMUX_IPSR_GPSR(IP15_13_12, DU2_DB2),
+ PINMUX_IPSR_GPSR(IP15_13_12, LCDOUT18),
PINMUX_IPSR_MSEL(IP15_15_14, HTX0, SEL_HSCIF0_0),
- PINMUX_IPSR_DATA(IP15_15_14, DU2_DB3),
- PINMUX_IPSR_DATA(IP15_15_14, LCDOUT19),
+ PINMUX_IPSR_GPSR(IP15_15_14, DU2_DB3),
+ PINMUX_IPSR_GPSR(IP15_15_14, LCDOUT19),
PINMUX_IPSR_MSEL(IP15_17_16, HCTS0_N, SEL_HSCIF0_0),
- PINMUX_IPSR_DATA(IP15_17_16, SSI_SCK9),
- PINMUX_IPSR_DATA(IP15_17_16, DU2_DB4),
- PINMUX_IPSR_DATA(IP15_17_16, LCDOUT20),
+ PINMUX_IPSR_GPSR(IP15_17_16, SSI_SCK9),
+ PINMUX_IPSR_GPSR(IP15_17_16, DU2_DB4),
+ PINMUX_IPSR_GPSR(IP15_17_16, LCDOUT20),
PINMUX_IPSR_MSEL(IP15_19_18, HRTS0_N, SEL_HSCIF0_0),
- PINMUX_IPSR_DATA(IP15_19_18, SSI_WS9),
- PINMUX_IPSR_DATA(IP15_19_18, DU2_DB5),
- PINMUX_IPSR_DATA(IP15_19_18, LCDOUT21),
+ PINMUX_IPSR_GPSR(IP15_19_18, SSI_WS9),
+ PINMUX_IPSR_GPSR(IP15_19_18, DU2_DB5),
+ PINMUX_IPSR_GPSR(IP15_19_18, LCDOUT21),
PINMUX_IPSR_MSEL(IP15_22_20, MSIOF0_SCK, SEL_SOF0_0),
PINMUX_IPSR_MSEL(IP15_22_20, TS_SDAT0, SEL_TSIF0_0),
- PINMUX_IPSR_DATA(IP15_22_20, ADICLK),
- PINMUX_IPSR_DATA(IP15_22_20, DU2_DB6),
- PINMUX_IPSR_DATA(IP15_22_20, LCDOUT22),
- PINMUX_IPSR_DATA(IP15_25_23, MSIOF0_SYNC),
+ PINMUX_IPSR_GPSR(IP15_22_20, ADICLK),
+ PINMUX_IPSR_GPSR(IP15_22_20, DU2_DB6),
+ PINMUX_IPSR_GPSR(IP15_22_20, LCDOUT22),
+ PINMUX_IPSR_GPSR(IP15_25_23, MSIOF0_SYNC),
PINMUX_IPSR_MSEL(IP15_25_23, TS_SCK0, SEL_TSIF0_0),
- PINMUX_IPSR_DATA(IP15_25_23, SSI_SCK2),
- PINMUX_IPSR_DATA(IP15_25_23, ADIDATA),
- PINMUX_IPSR_DATA(IP15_25_23, DU2_DB7),
- PINMUX_IPSR_DATA(IP15_25_23, LCDOUT23),
+ PINMUX_IPSR_GPSR(IP15_25_23, SSI_SCK2),
+ PINMUX_IPSR_GPSR(IP15_25_23, ADIDATA),
+ PINMUX_IPSR_GPSR(IP15_25_23, DU2_DB7),
+ PINMUX_IPSR_GPSR(IP15_25_23, LCDOUT23),
PINMUX_IPSR_MSEL(IP15_25_23, HRX0_C, SEL_SCIFA2_1),
PINMUX_IPSR_MSEL(IP15_27_26, MSIOF0_SS1, SEL_SOF0_0),
- PINMUX_IPSR_DATA(IP15_27_26, ADICHS0),
- PINMUX_IPSR_DATA(IP15_27_26, DU2_DG5),
- PINMUX_IPSR_DATA(IP15_27_26, LCDOUT13),
+ PINMUX_IPSR_GPSR(IP15_27_26, ADICHS0),
+ PINMUX_IPSR_GPSR(IP15_27_26, DU2_DG5),
+ PINMUX_IPSR_GPSR(IP15_27_26, LCDOUT13),
PINMUX_IPSR_MSEL(IP15_29_28, MSIOF0_TXD, SEL_SOF0_0),
- PINMUX_IPSR_DATA(IP15_29_28, ADICHS1),
- PINMUX_IPSR_DATA(IP15_29_28, DU2_DG6),
- PINMUX_IPSR_DATA(IP15_29_28, LCDOUT14),
+ PINMUX_IPSR_GPSR(IP15_29_28, ADICHS1),
+ PINMUX_IPSR_GPSR(IP15_29_28, DU2_DG6),
+ PINMUX_IPSR_GPSR(IP15_29_28, LCDOUT14),
PINMUX_IPSR_MSEL(IP16_2_0, MSIOF0_SS2, SEL_SOF0_0),
- PINMUX_IPSR_DATA(IP16_2_0, AUDIO_CLKOUT),
- PINMUX_IPSR_DATA(IP16_2_0, ADICHS2),
- PINMUX_IPSR_DATA(IP16_2_0, DU2_DISP),
- PINMUX_IPSR_DATA(IP16_2_0, QPOLA),
+ PINMUX_IPSR_GPSR(IP16_2_0, AUDIO_CLKOUT),
+ PINMUX_IPSR_GPSR(IP16_2_0, ADICHS2),
+ PINMUX_IPSR_GPSR(IP16_2_0, DU2_DISP),
+ PINMUX_IPSR_GPSR(IP16_2_0, QPOLA),
PINMUX_IPSR_MSEL(IP16_2_0, HTX0_C, SEL_HSCIF0_2),
PINMUX_IPSR_MSEL(IP16_2_0, SCIFA2_TXD_B, SEL_SCIFA2_1),
PINMUX_IPSR_MSEL(IP16_5_3, MSIOF0_RXD, SEL_SOF0_0),
PINMUX_IPSR_MSEL(IP16_5_3, TS_SPSYNC0, SEL_TSIF0_0),
- PINMUX_IPSR_DATA(IP16_5_3, SSI_WS2),
- PINMUX_IPSR_DATA(IP16_5_3, ADICS_SAMP),
- PINMUX_IPSR_DATA(IP16_5_3, DU2_CDE),
- PINMUX_IPSR_DATA(IP16_5_3, QPOLB),
+ PINMUX_IPSR_GPSR(IP16_5_3, SSI_WS2),
+ PINMUX_IPSR_GPSR(IP16_5_3, ADICS_SAMP),
+ PINMUX_IPSR_GPSR(IP16_5_3, DU2_CDE),
+ PINMUX_IPSR_GPSR(IP16_5_3, QPOLB),
PINMUX_IPSR_MSEL(IP16_5_3, SCIFA2_RXD_B, SEL_HSCIF0_2),
- PINMUX_IPSR_DATA(IP16_6, USB1_PWEN),
- PINMUX_IPSR_DATA(IP16_6, AUDIO_CLKOUT_D),
- PINMUX_IPSR_DATA(IP16_7, USB1_OVC),
+ PINMUX_IPSR_GPSR(IP16_6, USB1_PWEN),
+ PINMUX_IPSR_GPSR(IP16_6, AUDIO_CLKOUT_D),
+ PINMUX_IPSR_GPSR(IP16_7, USB1_OVC),
PINMUX_IPSR_MSEL(IP16_7, TCLK1_B, SEL_TMU1_1),
PINMUX_DATA(IIC0_SCL_MARK, FN_SEL_IIC0_0),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
index 4cfbb94ad5d0..01abbd5b4e49 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -792,171 +792,171 @@ static const u16 pinmux_data[] = {
PINMUX_SINGLE(SD1_CLK),
/* IPSR0 */
- PINMUX_IPSR_DATA(IP0_0, D0),
- PINMUX_IPSR_DATA(IP0_1, D1),
- PINMUX_IPSR_DATA(IP0_2, D2),
- PINMUX_IPSR_DATA(IP0_3, D3),
- PINMUX_IPSR_DATA(IP0_4, D4),
- PINMUX_IPSR_DATA(IP0_5, D5),
- PINMUX_IPSR_DATA(IP0_6, D6),
- PINMUX_IPSR_DATA(IP0_7, D7),
- PINMUX_IPSR_DATA(IP0_8, D8),
- PINMUX_IPSR_DATA(IP0_9, D9),
- PINMUX_IPSR_DATA(IP0_10, D10),
- PINMUX_IPSR_DATA(IP0_11, D11),
- PINMUX_IPSR_DATA(IP0_12, D12),
- PINMUX_IPSR_DATA(IP0_13, D13),
- PINMUX_IPSR_DATA(IP0_14, D14),
- PINMUX_IPSR_DATA(IP0_15, D15),
- PINMUX_IPSR_DATA(IP0_18_16, A0),
+ PINMUX_IPSR_GPSR(IP0_0, D0),
+ PINMUX_IPSR_GPSR(IP0_1, D1),
+ PINMUX_IPSR_GPSR(IP0_2, D2),
+ PINMUX_IPSR_GPSR(IP0_3, D3),
+ PINMUX_IPSR_GPSR(IP0_4, D4),
+ PINMUX_IPSR_GPSR(IP0_5, D5),
+ PINMUX_IPSR_GPSR(IP0_6, D6),
+ PINMUX_IPSR_GPSR(IP0_7, D7),
+ PINMUX_IPSR_GPSR(IP0_8, D8),
+ PINMUX_IPSR_GPSR(IP0_9, D9),
+ PINMUX_IPSR_GPSR(IP0_10, D10),
+ PINMUX_IPSR_GPSR(IP0_11, D11),
+ PINMUX_IPSR_GPSR(IP0_12, D12),
+ PINMUX_IPSR_GPSR(IP0_13, D13),
+ PINMUX_IPSR_GPSR(IP0_14, D14),
+ PINMUX_IPSR_GPSR(IP0_15, D15),
+ PINMUX_IPSR_GPSR(IP0_18_16, A0),
PINMUX_IPSR_MSEL(IP0_18_16, ATAWR0_N_C, SEL_LBS_2),
PINMUX_IPSR_MSEL(IP0_18_16, MSIOF0_SCK_B, SEL_SOF0_1),
PINMUX_IPSR_MSEL(IP0_18_16, SCL0_C, SEL_IIC0_2),
- PINMUX_IPSR_DATA(IP0_18_16, PWM2_B),
- PINMUX_IPSR_DATA(IP0_20_19, A1),
+ PINMUX_IPSR_GPSR(IP0_18_16, PWM2_B),
+ PINMUX_IPSR_GPSR(IP0_20_19, A1),
PINMUX_IPSR_MSEL(IP0_20_19, MSIOF0_SYNC_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP0_22_21, A2),
+ PINMUX_IPSR_GPSR(IP0_22_21, A2),
PINMUX_IPSR_MSEL(IP0_22_21, MSIOF0_SS1_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP0_24_23, A3),
+ PINMUX_IPSR_GPSR(IP0_24_23, A3),
PINMUX_IPSR_MSEL(IP0_24_23, MSIOF0_SS2_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP0_26_25, A4),
+ PINMUX_IPSR_GPSR(IP0_26_25, A4),
PINMUX_IPSR_MSEL(IP0_26_25, MSIOF0_TXD_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP0_28_27, A5),
+ PINMUX_IPSR_GPSR(IP0_28_27, A5),
PINMUX_IPSR_MSEL(IP0_28_27, MSIOF0_RXD_B, SEL_SOF0_1),
- PINMUX_IPSR_DATA(IP0_30_29, A6),
+ PINMUX_IPSR_GPSR(IP0_30_29, A6),
PINMUX_IPSR_MSEL(IP0_30_29, MSIOF1_SCK, SEL_SOF1_0),
/* IPSR1 */
- PINMUX_IPSR_DATA(IP1_1_0, A7),
+ PINMUX_IPSR_GPSR(IP1_1_0, A7),
PINMUX_IPSR_MSEL(IP1_1_0, MSIOF1_SYNC, SEL_SOF1_0),
- PINMUX_IPSR_DATA(IP1_3_2, A8),
+ PINMUX_IPSR_GPSR(IP1_3_2, A8),
PINMUX_IPSR_MSEL(IP1_3_2, MSIOF1_SS1, SEL_SOF1_0),
PINMUX_IPSR_MSEL(IP1_3_2, SCL0, SEL_IIC0_0),
- PINMUX_IPSR_DATA(IP1_5_4, A9),
+ PINMUX_IPSR_GPSR(IP1_5_4, A9),
PINMUX_IPSR_MSEL(IP1_5_4, MSIOF1_SS2, SEL_SOF1_0),
PINMUX_IPSR_MSEL(IP1_5_4, SDA0, SEL_IIC0_0),
- PINMUX_IPSR_DATA(IP1_7_6, A10),
+ PINMUX_IPSR_GPSR(IP1_7_6, A10),
PINMUX_IPSR_MSEL(IP1_7_6, MSIOF1_TXD, SEL_SOF1_0),
PINMUX_IPSR_MSEL(IP1_7_6, MSIOF1_TXD_D, SEL_SOF1_3),
- PINMUX_IPSR_DATA(IP1_10_8, A11),
+ PINMUX_IPSR_GPSR(IP1_10_8, A11),
PINMUX_IPSR_MSEL(IP1_10_8, MSIOF1_RXD, SEL_SOF1_0),
PINMUX_IPSR_MSEL(IP1_10_8, SCL3_D, SEL_IIC3_3),
PINMUX_IPSR_MSEL(IP1_10_8, MSIOF1_RXD_D, SEL_SOF1_3),
- PINMUX_IPSR_DATA(IP1_13_11, A12),
+ PINMUX_IPSR_GPSR(IP1_13_11, A12),
PINMUX_IPSR_MSEL(IP1_13_11, FMCLK, SEL_FM_0),
PINMUX_IPSR_MSEL(IP1_13_11, SDA3_D, SEL_IIC3_3),
PINMUX_IPSR_MSEL(IP1_13_11, MSIOF1_SCK_D, SEL_SOF1_3),
- PINMUX_IPSR_DATA(IP1_16_14, A13),
+ PINMUX_IPSR_GPSR(IP1_16_14, A13),
PINMUX_IPSR_MSEL(IP1_16_14, ATAG0_N_C, SEL_LBS_2),
PINMUX_IPSR_MSEL(IP1_16_14, BPFCLK, SEL_FM_0),
PINMUX_IPSR_MSEL(IP1_16_14, MSIOF1_SS1_D, SEL_SOF1_3),
- PINMUX_IPSR_DATA(IP1_19_17, A14),
+ PINMUX_IPSR_GPSR(IP1_19_17, A14),
PINMUX_IPSR_MSEL(IP1_19_17, ATADIR0_N_C, SEL_LBS_2),
PINMUX_IPSR_MSEL(IP1_19_17, FMIN, SEL_FM_0),
PINMUX_IPSR_MSEL(IP1_19_17, FMIN_C, SEL_FM_2),
PINMUX_IPSR_MSEL(IP1_19_17, MSIOF1_SYNC_D, SEL_SOF1_3),
- PINMUX_IPSR_DATA(IP1_22_20, A15),
+ PINMUX_IPSR_GPSR(IP1_22_20, A15),
PINMUX_IPSR_MSEL(IP1_22_20, BPFCLK_C, SEL_FM_2),
- PINMUX_IPSR_DATA(IP1_25_23, A16),
+ PINMUX_IPSR_GPSR(IP1_25_23, A16),
PINMUX_IPSR_MSEL(IP1_25_23, DREQ2_B, SEL_LBS_1),
PINMUX_IPSR_MSEL(IP1_25_23, FMCLK_C, SEL_FM_2),
PINMUX_IPSR_MSEL(IP1_25_23, SCIFA1_SCK_B, SEL_SCIFA1_1),
- PINMUX_IPSR_DATA(IP1_28_26, A17),
+ PINMUX_IPSR_GPSR(IP1_28_26, A17),
PINMUX_IPSR_MSEL(IP1_28_26, DACK2_B, SEL_LBS_1),
PINMUX_IPSR_MSEL(IP1_28_26, SDA0_C, SEL_IIC0_2),
- PINMUX_IPSR_DATA(IP1_31_29, A18),
+ PINMUX_IPSR_GPSR(IP1_31_29, A18),
PINMUX_IPSR_MSEL(IP1_31_29, DREQ1, SEL_LBS_0),
PINMUX_IPSR_MSEL(IP1_31_29, SCIFA1_RXD_C, SEL_SCIFA1_2),
PINMUX_IPSR_MSEL(IP1_31_29, SCIFB1_RXD_C, SEL_SCIFB1_2),
/* IPSR2 */
- PINMUX_IPSR_DATA(IP2_2_0, A19),
- PINMUX_IPSR_DATA(IP2_2_0, DACK1),
+ PINMUX_IPSR_GPSR(IP2_2_0, A19),
+ PINMUX_IPSR_GPSR(IP2_2_0, DACK1),
PINMUX_IPSR_MSEL(IP2_2_0, SCIFA1_TXD_C, SEL_SCIFA1_2),
PINMUX_IPSR_MSEL(IP2_2_0, SCIFB1_TXD_C, SEL_SCIFB1_2),
PINMUX_IPSR_MSEL(IP2_2_0, SCIFB1_SCK_B, SEL_SCIFB1_1),
- PINMUX_IPSR_DATA(IP2_2_0, A20),
+ PINMUX_IPSR_GPSR(IP2_2_0, A20),
PINMUX_IPSR_MSEL(IP2_4_3, SPCLK, SEL_QSP_0),
- PINMUX_IPSR_DATA(IP2_6_5, A21),
+ PINMUX_IPSR_GPSR(IP2_6_5, A21),
PINMUX_IPSR_MSEL(IP2_6_5, ATAWR0_N_B, SEL_LBS_1),
PINMUX_IPSR_MSEL(IP2_6_5, MOSI_IO0, SEL_QSP_0),
- PINMUX_IPSR_DATA(IP2_9_7, A22),
+ PINMUX_IPSR_GPSR(IP2_9_7, A22),
PINMUX_IPSR_MSEL(IP2_9_7, MISO_IO1, SEL_QSP_0),
PINMUX_IPSR_MSEL(IP2_9_7, FMCLK_B, SEL_FM_1),
PINMUX_IPSR_MSEL(IP2_9_7, TX0, SEL_SCIF0_0),
PINMUX_IPSR_MSEL(IP2_9_7, SCIFA0_TXD, SEL_SCFA_0),
- PINMUX_IPSR_DATA(IP2_12_10, A23),
+ PINMUX_IPSR_GPSR(IP2_12_10, A23),
PINMUX_IPSR_MSEL(IP2_12_10, IO2, SEL_QSP_0),
PINMUX_IPSR_MSEL(IP2_12_10, BPFCLK_B, SEL_FM_1),
PINMUX_IPSR_MSEL(IP2_12_10, RX0, SEL_SCIF0_0),
PINMUX_IPSR_MSEL(IP2_12_10, SCIFA0_RXD, SEL_SCFA_0),
- PINMUX_IPSR_DATA(IP2_15_13, A24),
+ PINMUX_IPSR_GPSR(IP2_15_13, A24),
PINMUX_IPSR_MSEL(IP2_15_13, DREQ2, SEL_LBS_0),
PINMUX_IPSR_MSEL(IP2_15_13, IO3, SEL_QSP_0),
PINMUX_IPSR_MSEL(IP2_15_13, TX1, SEL_SCIF1_0),
PINMUX_IPSR_MSEL(IP2_15_13, SCIFA1_TXD, SEL_SCIFA1_0),
- PINMUX_IPSR_DATA(IP2_18_16, A25),
+ PINMUX_IPSR_GPSR(IP2_18_16, A25),
PINMUX_IPSR_MSEL(IP2_18_16, DACK2, SEL_LBS_0),
PINMUX_IPSR_MSEL(IP2_18_16, SSL, SEL_QSP_0),
PINMUX_IPSR_MSEL(IP2_18_16, DREQ1_C, SEL_LBS_2),
PINMUX_IPSR_MSEL(IP2_18_16, RX1, SEL_SCIF1_0),
PINMUX_IPSR_MSEL(IP2_18_16, SCIFA1_RXD, SEL_SCIFA1_0),
- PINMUX_IPSR_DATA(IP2_20_19, CS0_N),
+ PINMUX_IPSR_GPSR(IP2_20_19, CS0_N),
PINMUX_IPSR_MSEL(IP2_20_19, ATAG0_N_B, SEL_LBS_1),
PINMUX_IPSR_MSEL(IP2_20_19, SCL1, SEL_IIC1_0),
- PINMUX_IPSR_DATA(IP2_22_21, CS1_N_A26),
+ PINMUX_IPSR_GPSR(IP2_22_21, CS1_N_A26),
PINMUX_IPSR_MSEL(IP2_22_21, ATADIR0_N_B, SEL_LBS_1),
PINMUX_IPSR_MSEL(IP2_22_21, SDA1, SEL_IIC1_0),
- PINMUX_IPSR_DATA(IP2_24_23, EX_CS1_N),
+ PINMUX_IPSR_GPSR(IP2_24_23, EX_CS1_N),
PINMUX_IPSR_MSEL(IP2_24_23, MSIOF2_SCK, SEL_SOF2_0),
- PINMUX_IPSR_DATA(IP2_26_25, EX_CS2_N),
+ PINMUX_IPSR_GPSR(IP2_26_25, EX_CS2_N),
PINMUX_IPSR_MSEL(IP2_26_25, ATAWR0_N, SEL_LBS_0),
PINMUX_IPSR_MSEL(IP2_26_25, MSIOF2_SYNC, SEL_SOF2_0),
- PINMUX_IPSR_DATA(IP2_29_27, EX_CS3_N),
+ PINMUX_IPSR_GPSR(IP2_29_27, EX_CS3_N),
PINMUX_IPSR_MSEL(IP2_29_27, ATADIR0_N, SEL_LBS_0),
PINMUX_IPSR_MSEL(IP2_29_27, MSIOF2_TXD, SEL_SOF2_0),
PINMUX_IPSR_MSEL(IP2_29_27, ATAG0_N, SEL_LBS_0),
- PINMUX_IPSR_DATA(IP2_29_27, EX_WAIT1),
+ PINMUX_IPSR_GPSR(IP2_29_27, EX_WAIT1),
/* IPSR3 */
- PINMUX_IPSR_DATA(IP3_2_0, EX_CS4_N),
+ PINMUX_IPSR_GPSR(IP3_2_0, EX_CS4_N),
PINMUX_IPSR_MSEL(IP3_2_0, ATARD0_N, SEL_LBS_0),
PINMUX_IPSR_MSEL(IP3_2_0, MSIOF2_RXD, SEL_SOF2_0),
- PINMUX_IPSR_DATA(IP3_2_0, EX_WAIT2),
- PINMUX_IPSR_DATA(IP3_5_3, EX_CS5_N),
- PINMUX_IPSR_DATA(IP3_5_3, ATACS00_N),
+ PINMUX_IPSR_GPSR(IP3_2_0, EX_WAIT2),
+ PINMUX_IPSR_GPSR(IP3_5_3, EX_CS5_N),
+ PINMUX_IPSR_GPSR(IP3_5_3, ATACS00_N),
PINMUX_IPSR_MSEL(IP3_5_3, MSIOF2_SS1, SEL_SOF2_0),
PINMUX_IPSR_MSEL(IP3_5_3, HRX1_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP3_5_3, SCIFB1_RXD_B, SEL_SCIFB1_1),
- PINMUX_IPSR_DATA(IP3_5_3, PWM1),
- PINMUX_IPSR_DATA(IP3_5_3, TPU_TO1),
- PINMUX_IPSR_DATA(IP3_8_6, BS_N),
- PINMUX_IPSR_DATA(IP3_8_6, ATACS10_N),
+ PINMUX_IPSR_GPSR(IP3_5_3, PWM1),
+ PINMUX_IPSR_GPSR(IP3_5_3, TPU_TO1),
+ PINMUX_IPSR_GPSR(IP3_8_6, BS_N),
+ PINMUX_IPSR_GPSR(IP3_8_6, ATACS10_N),
PINMUX_IPSR_MSEL(IP3_8_6, MSIOF2_SS2, SEL_SOF2_0),
PINMUX_IPSR_MSEL(IP3_8_6, HTX1_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP3_8_6, SCIFB1_TXD_B, SEL_SCIFB1_1),
- PINMUX_IPSR_DATA(IP3_8_6, PWM2),
- PINMUX_IPSR_DATA(IP3_8_6, TPU_TO2),
- PINMUX_IPSR_DATA(IP3_11_9, RD_WR_N),
+ PINMUX_IPSR_GPSR(IP3_8_6, PWM2),
+ PINMUX_IPSR_GPSR(IP3_8_6, TPU_TO2),
+ PINMUX_IPSR_GPSR(IP3_11_9, RD_WR_N),
PINMUX_IPSR_MSEL(IP3_11_9, HRX2_B, SEL_HSCIF2_1),
PINMUX_IPSR_MSEL(IP3_11_9, FMIN_B, SEL_FM_1),
PINMUX_IPSR_MSEL(IP3_11_9, SCIFB0_RXD_B, SEL_SCIFB_1),
PINMUX_IPSR_MSEL(IP3_11_9, DREQ1_D, SEL_LBS_1),
- PINMUX_IPSR_DATA(IP3_13_12, WE0_N),
+ PINMUX_IPSR_GPSR(IP3_13_12, WE0_N),
PINMUX_IPSR_MSEL(IP3_13_12, HCTS2_N_B, SEL_HSCIF2_1),
PINMUX_IPSR_MSEL(IP3_13_12, SCIFB0_TXD_B, SEL_SCIFB_1),
- PINMUX_IPSR_DATA(IP3_15_14, WE1_N),
+ PINMUX_IPSR_GPSR(IP3_15_14, WE1_N),
PINMUX_IPSR_MSEL(IP3_15_14, ATARD0_N_B, SEL_LBS_1),
PINMUX_IPSR_MSEL(IP3_15_14, HTX2_B, SEL_HSCIF2_1),
PINMUX_IPSR_MSEL(IP3_15_14, SCIFB0_RTS_N_B, SEL_SCIFB_1),
- PINMUX_IPSR_DATA(IP3_17_16, EX_WAIT0),
+ PINMUX_IPSR_GPSR(IP3_17_16, EX_WAIT0),
PINMUX_IPSR_MSEL(IP3_17_16, HRTS2_N_B, SEL_HSCIF2_1),
PINMUX_IPSR_MSEL(IP3_17_16, SCIFB0_CTS_N_B, SEL_SCIFB_1),
- PINMUX_IPSR_DATA(IP3_19_18, DREQ0),
- PINMUX_IPSR_DATA(IP3_19_18, PWM3),
- PINMUX_IPSR_DATA(IP3_19_18, TPU_TO3),
- PINMUX_IPSR_DATA(IP3_21_20, DACK0),
- PINMUX_IPSR_DATA(IP3_21_20, DRACK0),
+ PINMUX_IPSR_GPSR(IP3_19_18, DREQ0),
+ PINMUX_IPSR_GPSR(IP3_19_18, PWM3),
+ PINMUX_IPSR_GPSR(IP3_19_18, TPU_TO3),
+ PINMUX_IPSR_GPSR(IP3_21_20, DACK0),
+ PINMUX_IPSR_GPSR(IP3_21_20, DRACK0),
PINMUX_IPSR_MSEL(IP3_21_20, REMOCON, SEL_RCN_0),
PINMUX_IPSR_MSEL(IP3_24_22, SPEEDIN, SEL_RSP_0),
PINMUX_IPSR_MSEL(IP3_24_22, HSCK0_C, SEL_HSCIF0_2),
@@ -995,61 +995,61 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP4_9_8, SDA1_B, SEL_IIC1_1),
PINMUX_IPSR_MSEL(IP4_9_8, SDA8_B, SEL_IIC8_1),
PINMUX_IPSR_MSEL(IP4_9_8, MSIOF2_RXD_C, SEL_SOF2_2),
- PINMUX_IPSR_DATA(IP4_12_10, SSI_SCK2),
+ PINMUX_IPSR_GPSR(IP4_12_10, SSI_SCK2),
PINMUX_IPSR_MSEL(IP4_12_10, SCL2, SEL_IIC2_0),
PINMUX_IPSR_MSEL(IP4_12_10, GPS_CLK_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP4_12_10, GLO_Q0_D, SEL_GPS_3),
- PINMUX_IPSR_DATA(IP4_15_13, SSI_WS2),
+ PINMUX_IPSR_GPSR(IP4_15_13, SSI_WS2),
PINMUX_IPSR_MSEL(IP4_15_13, SDA2, SEL_IIC2_0),
PINMUX_IPSR_MSEL(IP4_15_13, GPS_SIGN_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP4_15_13, RX2_E, SEL_SCIF2_4),
PINMUX_IPSR_MSEL(IP4_15_13, GLO_Q1_D, SEL_GPS_3),
- PINMUX_IPSR_DATA(IP4_18_16, SSI_SDATA2),
+ PINMUX_IPSR_GPSR(IP4_18_16, SSI_SDATA2),
PINMUX_IPSR_MSEL(IP4_18_16, GPS_MAG_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP4_18_16, TX2_E, SEL_SCIF2_4),
- PINMUX_IPSR_DATA(IP4_19, SSI_SCK34),
- PINMUX_IPSR_DATA(IP4_20, SSI_WS34),
- PINMUX_IPSR_DATA(IP4_21, SSI_SDATA3),
- PINMUX_IPSR_DATA(IP4_23_22, SSI_SCK4),
+ PINMUX_IPSR_GPSR(IP4_19, SSI_SCK34),
+ PINMUX_IPSR_GPSR(IP4_20, SSI_WS34),
+ PINMUX_IPSR_GPSR(IP4_21, SSI_SDATA3),
+ PINMUX_IPSR_GPSR(IP4_23_22, SSI_SCK4),
PINMUX_IPSR_MSEL(IP4_23_22, GLO_SS_D, SEL_GPS_3),
- PINMUX_IPSR_DATA(IP4_25_24, SSI_WS4),
+ PINMUX_IPSR_GPSR(IP4_25_24, SSI_WS4),
PINMUX_IPSR_MSEL(IP4_25_24, GLO_RFON_D, SEL_GPS_3),
- PINMUX_IPSR_DATA(IP4_27_26, SSI_SDATA4),
+ PINMUX_IPSR_GPSR(IP4_27_26, SSI_SDATA4),
PINMUX_IPSR_MSEL(IP4_27_26, MSIOF2_SCK_D, SEL_SOF2_3),
- PINMUX_IPSR_DATA(IP4_30_28, SSI_SCK5),
+ PINMUX_IPSR_GPSR(IP4_30_28, SSI_SCK5),
PINMUX_IPSR_MSEL(IP4_30_28, MSIOF1_SCK_C, SEL_SOF1_2),
PINMUX_IPSR_MSEL(IP4_30_28, TS_SDATA0, SEL_TSIF0_0),
PINMUX_IPSR_MSEL(IP4_30_28, GLO_I0, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP4_30_28, MSIOF2_SYNC_D, SEL_SOF2_3),
- PINMUX_IPSR_DATA(IP4_30_28, VI1_R2_B),
+ PINMUX_IPSR_GPSR(IP4_30_28, VI1_R2_B),
/* IPSR5 */
- PINMUX_IPSR_DATA(IP5_2_0, SSI_WS5),
+ PINMUX_IPSR_GPSR(IP5_2_0, SSI_WS5),
PINMUX_IPSR_MSEL(IP5_2_0, MSIOF1_SYNC_C, SEL_SOF1_2),
PINMUX_IPSR_MSEL(IP5_2_0, TS_SCK0, SEL_TSIF0_0),
PINMUX_IPSR_MSEL(IP5_2_0, GLO_I1, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP5_2_0, MSIOF2_TXD_D, SEL_SOF2_3),
- PINMUX_IPSR_DATA(IP5_2_0, VI1_R3_B),
- PINMUX_IPSR_DATA(IP5_5_3, SSI_SDATA5),
+ PINMUX_IPSR_GPSR(IP5_2_0, VI1_R3_B),
+ PINMUX_IPSR_GPSR(IP5_5_3, SSI_SDATA5),
PINMUX_IPSR_MSEL(IP5_5_3, MSIOF1_TXD_C, SEL_SOF1_2),
PINMUX_IPSR_MSEL(IP5_5_3, TS_SDEN0, SEL_TSIF0_0),
PINMUX_IPSR_MSEL(IP5_5_3, GLO_Q0, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP5_5_3, MSIOF2_SS1_D, SEL_SOF2_3),
- PINMUX_IPSR_DATA(IP5_5_3, VI1_R4_B),
- PINMUX_IPSR_DATA(IP5_8_6, SSI_SCK6),
+ PINMUX_IPSR_GPSR(IP5_5_3, VI1_R4_B),
+ PINMUX_IPSR_GPSR(IP5_8_6, SSI_SCK6),
PINMUX_IPSR_MSEL(IP5_8_6, MSIOF1_RXD_C, SEL_SOF1_2),
PINMUX_IPSR_MSEL(IP5_8_6, TS_SPSYNC0, SEL_TSIF0_0),
PINMUX_IPSR_MSEL(IP5_8_6, GLO_Q1, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP5_8_6, MSIOF2_RXD_D, SEL_SOF2_3),
- PINMUX_IPSR_DATA(IP5_8_6, VI1_R5_B),
- PINMUX_IPSR_DATA(IP5_11_9, SSI_WS6),
+ PINMUX_IPSR_GPSR(IP5_8_6, VI1_R5_B),
+ PINMUX_IPSR_GPSR(IP5_11_9, SSI_WS6),
PINMUX_IPSR_MSEL(IP5_11_9, GLO_SCLK, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP5_11_9, MSIOF2_SS2_D, SEL_SOF2_3),
- PINMUX_IPSR_DATA(IP5_11_9, VI1_R6_B),
- PINMUX_IPSR_DATA(IP5_14_12, SSI_SDATA6),
+ PINMUX_IPSR_GPSR(IP5_11_9, VI1_R6_B),
+ PINMUX_IPSR_GPSR(IP5_14_12, SSI_SDATA6),
PINMUX_IPSR_MSEL(IP5_14_12, STP_IVCXO27_0_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP5_14_12, GLO_SDATA, SEL_GPS_0),
- PINMUX_IPSR_DATA(IP5_14_12, VI1_R7_B),
+ PINMUX_IPSR_GPSR(IP5_14_12, VI1_R7_B),
PINMUX_IPSR_MSEL(IP5_16_15, SSI_SCK78, SEL_SSI7_0),
PINMUX_IPSR_MSEL(IP5_16_15, STP_ISCLK_0_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP5_16_15, GLO_SS, SEL_GPS_0),
@@ -1080,307 +1080,307 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP6_2_0, MSIOF1_SCK_B, SEL_SOF1_1),
PINMUX_IPSR_MSEL(IP6_2_0, SCIF_CLK, SEL_SCIF_0),
PINMUX_IPSR_MSEL(IP6_2_0, BPFCLK_E, SEL_FM_4),
- PINMUX_IPSR_DATA(IP6_5_3, AUDIO_CLKC),
+ PINMUX_IPSR_GPSR(IP6_5_3, AUDIO_CLKC),
PINMUX_IPSR_MSEL(IP6_5_3, SCIFB0_SCK_C, SEL_SCIFB_2),
PINMUX_IPSR_MSEL(IP6_5_3, MSIOF1_SYNC_B, SEL_SOF1_1),
PINMUX_IPSR_MSEL(IP6_5_3, RX2, SEL_SCIF2_0),
PINMUX_IPSR_MSEL(IP6_5_3, SCIFA2_RXD, SEL_SCIFA2_0),
PINMUX_IPSR_MSEL(IP6_5_3, FMIN_E, SEL_FM_4),
- PINMUX_IPSR_DATA(IP6_7_6, AUDIO_CLKOUT),
+ PINMUX_IPSR_GPSR(IP6_7_6, AUDIO_CLKOUT),
PINMUX_IPSR_MSEL(IP6_7_6, MSIOF1_SS1_B, SEL_SOF1_1),
PINMUX_IPSR_MSEL(IP6_5_3, TX2, SEL_SCIF2_0),
PINMUX_IPSR_MSEL(IP6_7_6, SCIFA2_TXD, SEL_SCIFA2_0),
- PINMUX_IPSR_DATA(IP6_9_8, IRQ0),
+ PINMUX_IPSR_GPSR(IP6_9_8, IRQ0),
PINMUX_IPSR_MSEL(IP6_9_8, SCIFB1_RXD_D, SEL_SCIFB1_3),
- PINMUX_IPSR_DATA(IP6_9_8, INTC_IRQ0_N),
- PINMUX_IPSR_DATA(IP6_11_10, IRQ1),
+ PINMUX_IPSR_GPSR(IP6_9_8, INTC_IRQ0_N),
+ PINMUX_IPSR_GPSR(IP6_11_10, IRQ1),
PINMUX_IPSR_MSEL(IP6_11_10, SCIFB1_SCK_C, SEL_SCIFB1_2),
- PINMUX_IPSR_DATA(IP6_11_10, INTC_IRQ1_N),
- PINMUX_IPSR_DATA(IP6_13_12, IRQ2),
+ PINMUX_IPSR_GPSR(IP6_11_10, INTC_IRQ1_N),
+ PINMUX_IPSR_GPSR(IP6_13_12, IRQ2),
PINMUX_IPSR_MSEL(IP6_13_12, SCIFB1_TXD_D, SEL_SCIFB1_3),
- PINMUX_IPSR_DATA(IP6_13_12, INTC_IRQ2_N),
- PINMUX_IPSR_DATA(IP6_15_14, IRQ3),
+ PINMUX_IPSR_GPSR(IP6_13_12, INTC_IRQ2_N),
+ PINMUX_IPSR_GPSR(IP6_15_14, IRQ3),
PINMUX_IPSR_MSEL(IP6_15_14, SCL4_C, SEL_IIC4_2),
PINMUX_IPSR_MSEL(IP6_15_14, MSIOF2_TXD_E, SEL_SOF2_4),
- PINMUX_IPSR_DATA(IP6_15_14, INTC_IRQ4_N),
- PINMUX_IPSR_DATA(IP6_18_16, IRQ4),
+ PINMUX_IPSR_GPSR(IP6_15_14, INTC_IRQ4_N),
+ PINMUX_IPSR_GPSR(IP6_18_16, IRQ4),
PINMUX_IPSR_MSEL(IP6_18_16, HRX1_C, SEL_HSCIF1_2),
PINMUX_IPSR_MSEL(IP6_18_16, SDA4_C, SEL_IIC4_2),
PINMUX_IPSR_MSEL(IP6_18_16, MSIOF2_RXD_E, SEL_SOF2_4),
- PINMUX_IPSR_DATA(IP6_18_16, INTC_IRQ4_N),
- PINMUX_IPSR_DATA(IP6_20_19, IRQ5),
+ PINMUX_IPSR_GPSR(IP6_18_16, INTC_IRQ4_N),
+ PINMUX_IPSR_GPSR(IP6_20_19, IRQ5),
PINMUX_IPSR_MSEL(IP6_20_19, HTX1_C, SEL_HSCIF1_2),
PINMUX_IPSR_MSEL(IP6_20_19, SCL1_E, SEL_IIC1_4),
PINMUX_IPSR_MSEL(IP6_20_19, MSIOF2_SCK_E, SEL_SOF2_4),
- PINMUX_IPSR_DATA(IP6_23_21, IRQ6),
+ PINMUX_IPSR_GPSR(IP6_23_21, IRQ6),
PINMUX_IPSR_MSEL(IP6_23_21, HSCK1_C, SEL_HSCIF1_2),
PINMUX_IPSR_MSEL(IP6_23_21, MSIOF1_SS2_B, SEL_SOF1_1),
PINMUX_IPSR_MSEL(IP6_23_21, SDA1_E, SEL_IIC1_4),
PINMUX_IPSR_MSEL(IP6_23_21, MSIOF2_SYNC_E, SEL_SOF2_4),
- PINMUX_IPSR_DATA(IP6_26_24, IRQ7),
+ PINMUX_IPSR_GPSR(IP6_26_24, IRQ7),
PINMUX_IPSR_MSEL(IP6_26_24, HCTS1_N_C, SEL_HSCIF1_2),
PINMUX_IPSR_MSEL(IP6_26_24, MSIOF1_TXD_B, SEL_SOF1_1),
PINMUX_IPSR_MSEL(IP6_26_24, GPS_CLK_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP6_26_24, GPS_CLK_D, SEL_GPS_3),
- PINMUX_IPSR_DATA(IP6_29_27, IRQ8),
+ PINMUX_IPSR_GPSR(IP6_29_27, IRQ8),
PINMUX_IPSR_MSEL(IP6_29_27, HRTS1_N_C, SEL_HSCIF1_2),
PINMUX_IPSR_MSEL(IP6_29_27, MSIOF1_RXD_B, SEL_SOF1_1),
PINMUX_IPSR_MSEL(IP6_29_27, GPS_SIGN_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP6_29_27, GPS_SIGN_D, SEL_GPS_3),
/* IPSR7 */
- PINMUX_IPSR_DATA(IP7_2_0, IRQ9),
+ PINMUX_IPSR_GPSR(IP7_2_0, IRQ9),
PINMUX_IPSR_MSEL(IP7_2_0, DU1_DOTCLKIN_B, SEL_DIS_1),
PINMUX_IPSR_MSEL(IP7_2_0, CAN_CLK_D, SEL_CANCLK_3),
PINMUX_IPSR_MSEL(IP7_2_0, GPS_MAG_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP7_2_0, SCIF_CLK_B, SEL_SCIF_1),
PINMUX_IPSR_MSEL(IP7_2_0, GPS_MAG_D, SEL_GPS_3),
- PINMUX_IPSR_DATA(IP7_5_3, DU1_DR0),
- PINMUX_IPSR_DATA(IP7_5_3, LCDOUT0),
+ PINMUX_IPSR_GPSR(IP7_5_3, DU1_DR0),
+ PINMUX_IPSR_GPSR(IP7_5_3, LCDOUT0),
PINMUX_IPSR_MSEL(IP7_5_3, VI1_DATA0_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP7_5_3, TX0_B, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP7_5_3, SCIFA0_TXD_B, SEL_SCFA_1),
PINMUX_IPSR_MSEL(IP7_5_3, MSIOF2_SCK_B, SEL_SOF2_1),
- PINMUX_IPSR_DATA(IP7_8_6, DU1_DR1),
- PINMUX_IPSR_DATA(IP7_8_6, LCDOUT1),
+ PINMUX_IPSR_GPSR(IP7_8_6, DU1_DR1),
+ PINMUX_IPSR_GPSR(IP7_8_6, LCDOUT1),
PINMUX_IPSR_MSEL(IP7_8_6, VI1_DATA1_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP7_8_6, RX0_B, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP7_8_6, SCIFA0_RXD_B, SEL_SCFA_1),
PINMUX_IPSR_MSEL(IP7_8_6, MSIOF2_SYNC_B, SEL_SOF2_1),
- PINMUX_IPSR_DATA(IP7_10_9, DU1_DR2),
- PINMUX_IPSR_DATA(IP7_10_9, LCDOUT2),
+ PINMUX_IPSR_GPSR(IP7_10_9, DU1_DR2),
+ PINMUX_IPSR_GPSR(IP7_10_9, LCDOUT2),
PINMUX_IPSR_MSEL(IP7_10_9, SSI_SCK0129_B, SEL_SSI0_1),
- PINMUX_IPSR_DATA(IP7_12_11, DU1_DR3),
- PINMUX_IPSR_DATA(IP7_12_11, LCDOUT3),
+ PINMUX_IPSR_GPSR(IP7_12_11, DU1_DR3),
+ PINMUX_IPSR_GPSR(IP7_12_11, LCDOUT3),
PINMUX_IPSR_MSEL(IP7_12_11, SSI_WS0129_B, SEL_SSI0_1),
- PINMUX_IPSR_DATA(IP7_14_13, DU1_DR4),
- PINMUX_IPSR_DATA(IP7_14_13, LCDOUT4),
+ PINMUX_IPSR_GPSR(IP7_14_13, DU1_DR4),
+ PINMUX_IPSR_GPSR(IP7_14_13, LCDOUT4),
PINMUX_IPSR_MSEL(IP7_14_13, SSI_SDATA0_B, SEL_SSI0_1),
- PINMUX_IPSR_DATA(IP7_16_15, DU1_DR5),
- PINMUX_IPSR_DATA(IP7_16_15, LCDOUT5),
+ PINMUX_IPSR_GPSR(IP7_16_15, DU1_DR5),
+ PINMUX_IPSR_GPSR(IP7_16_15, LCDOUT5),
PINMUX_IPSR_MSEL(IP7_16_15, SSI_SCK1_B, SEL_SSI1_1),
- PINMUX_IPSR_DATA(IP7_18_17, DU1_DR6),
- PINMUX_IPSR_DATA(IP7_18_17, LCDOUT6),
+ PINMUX_IPSR_GPSR(IP7_18_17, DU1_DR6),
+ PINMUX_IPSR_GPSR(IP7_18_17, LCDOUT6),
PINMUX_IPSR_MSEL(IP7_18_17, SSI_WS1_B, SEL_SSI1_1),
- PINMUX_IPSR_DATA(IP7_20_19, DU1_DR7),
- PINMUX_IPSR_DATA(IP7_20_19, LCDOUT7),
+ PINMUX_IPSR_GPSR(IP7_20_19, DU1_DR7),
+ PINMUX_IPSR_GPSR(IP7_20_19, LCDOUT7),
PINMUX_IPSR_MSEL(IP7_20_19, SSI_SDATA1_B, SEL_SSI1_1),
- PINMUX_IPSR_DATA(IP7_23_21, DU1_DG0),
- PINMUX_IPSR_DATA(IP7_23_21, LCDOUT8),
+ PINMUX_IPSR_GPSR(IP7_23_21, DU1_DG0),
+ PINMUX_IPSR_GPSR(IP7_23_21, LCDOUT8),
PINMUX_IPSR_MSEL(IP7_23_21, VI1_DATA2_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP7_23_21, TX1_B, SEL_SCIF1_1),
PINMUX_IPSR_MSEL(IP7_23_21, SCIFA1_TXD_B, SEL_SCIFA1_1),
PINMUX_IPSR_MSEL(IP7_23_21, MSIOF2_SS1_B, SEL_SOF2_1),
- PINMUX_IPSR_DATA(IP7_26_24, DU1_DG1),
- PINMUX_IPSR_DATA(IP7_26_24, LCDOUT9),
+ PINMUX_IPSR_GPSR(IP7_26_24, DU1_DG1),
+ PINMUX_IPSR_GPSR(IP7_26_24, LCDOUT9),
PINMUX_IPSR_MSEL(IP7_26_24, VI1_DATA3_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP7_26_24, RX1_B, SEL_SCIF1_1),
PINMUX_IPSR_MSEL(IP7_26_24, SCIFA1_RXD_B, SEL_SCIFA1_1),
PINMUX_IPSR_MSEL(IP7_26_24, MSIOF2_SS2_B, SEL_SOF2_1),
- PINMUX_IPSR_DATA(IP7_29_27, DU1_DG2),
- PINMUX_IPSR_DATA(IP7_29_27, LCDOUT10),
+ PINMUX_IPSR_GPSR(IP7_29_27, DU1_DG2),
+ PINMUX_IPSR_GPSR(IP7_29_27, LCDOUT10),
PINMUX_IPSR_MSEL(IP7_29_27, VI1_DATA4_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP7_29_27, SCIF1_SCK_B),
+ PINMUX_IPSR_GPSR(IP7_29_27, SCIF1_SCK_B),
PINMUX_IPSR_MSEL(IP7_29_27, SCIFA1_SCK, SEL_SCIFA1_0),
PINMUX_IPSR_MSEL(IP7_29_27, SSI_SCK78_B, SEL_SSI7_1),
/* IPSR8 */
- PINMUX_IPSR_DATA(IP8_2_0, DU1_DG3),
- PINMUX_IPSR_DATA(IP8_2_0, LCDOUT11),
+ PINMUX_IPSR_GPSR(IP8_2_0, DU1_DG3),
+ PINMUX_IPSR_GPSR(IP8_2_0, LCDOUT11),
PINMUX_IPSR_MSEL(IP8_2_0, VI1_DATA5_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP8_2_0, SSI_WS78_B, SEL_SSI7_1),
- PINMUX_IPSR_DATA(IP8_5_3, DU1_DG4),
- PINMUX_IPSR_DATA(IP8_5_3, LCDOUT12),
+ PINMUX_IPSR_GPSR(IP8_5_3, DU1_DG4),
+ PINMUX_IPSR_GPSR(IP8_5_3, LCDOUT12),
PINMUX_IPSR_MSEL(IP8_5_3, VI1_DATA6_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP8_5_3, HRX0_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP8_5_3, SCIFB2_RXD_B, SEL_SCIFB2_1),
PINMUX_IPSR_MSEL(IP8_5_3, SSI_SDATA7_B, SEL_SSI7_1),
- PINMUX_IPSR_DATA(IP8_8_6, DU1_DG5),
- PINMUX_IPSR_DATA(IP8_8_6, LCDOUT13),
+ PINMUX_IPSR_GPSR(IP8_8_6, DU1_DG5),
+ PINMUX_IPSR_GPSR(IP8_8_6, LCDOUT13),
PINMUX_IPSR_MSEL(IP8_8_6, VI1_DATA7_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP8_8_6, HCTS0_N_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP8_8_6, SCIFB2_TXD_B, SEL_SCIFB2_1),
PINMUX_IPSR_MSEL(IP8_8_6, SSI_SDATA8_B, SEL_SSI8_1),
- PINMUX_IPSR_DATA(IP8_11_9, DU1_DG6),
- PINMUX_IPSR_DATA(IP8_11_9, LCDOUT14),
+ PINMUX_IPSR_GPSR(IP8_11_9, DU1_DG6),
+ PINMUX_IPSR_GPSR(IP8_11_9, LCDOUT14),
PINMUX_IPSR_MSEL(IP8_11_9, HRTS0_N_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP8_11_9, SCIFB2_CTS_N_B, SEL_SCIFB2_1),
PINMUX_IPSR_MSEL(IP8_11_9, SSI_SCK9_B, SEL_SSI9_1),
- PINMUX_IPSR_DATA(IP8_14_12, DU1_DG7),
- PINMUX_IPSR_DATA(IP8_14_12, LCDOUT15),
+ PINMUX_IPSR_GPSR(IP8_14_12, DU1_DG7),
+ PINMUX_IPSR_GPSR(IP8_14_12, LCDOUT15),
PINMUX_IPSR_MSEL(IP8_14_12, HTX0_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP8_14_12, SCIFB2_RTS_N_B, SEL_SCIFB2_1),
PINMUX_IPSR_MSEL(IP8_14_12, SSI_WS9_B, SEL_SSI9_1),
- PINMUX_IPSR_DATA(IP8_17_15, DU1_DB0),
- PINMUX_IPSR_DATA(IP8_17_15, LCDOUT16),
+ PINMUX_IPSR_GPSR(IP8_17_15, DU1_DB0),
+ PINMUX_IPSR_GPSR(IP8_17_15, LCDOUT16),
PINMUX_IPSR_MSEL(IP8_17_15, VI1_CLK_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP8_17_15, TX2_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP8_17_15, SCIFA2_TXD_B, SEL_SCIFA2_1),
PINMUX_IPSR_MSEL(IP8_17_15, MSIOF2_TXD_B, SEL_SOF2_1),
- PINMUX_IPSR_DATA(IP8_20_18, DU1_DB1),
- PINMUX_IPSR_DATA(IP8_20_18, LCDOUT17),
+ PINMUX_IPSR_GPSR(IP8_20_18, DU1_DB1),
+ PINMUX_IPSR_GPSR(IP8_20_18, LCDOUT17),
PINMUX_IPSR_MSEL(IP8_20_18, VI1_HSYNC_N_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP8_20_18, RX2_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP8_20_18, SCIFA2_RXD_B, SEL_SCIFA2_1),
PINMUX_IPSR_MSEL(IP8_20_18, MSIOF2_RXD_B, SEL_SOF2_1),
- PINMUX_IPSR_DATA(IP8_23_21, DU1_DB2),
- PINMUX_IPSR_DATA(IP8_23_21, LCDOUT18),
+ PINMUX_IPSR_GPSR(IP8_23_21, DU1_DB2),
+ PINMUX_IPSR_GPSR(IP8_23_21, LCDOUT18),
PINMUX_IPSR_MSEL(IP8_23_21, VI1_VSYNC_N_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP8_23_21, SCIF2_SCK_B),
+ PINMUX_IPSR_GPSR(IP8_23_21, SCIF2_SCK_B),
PINMUX_IPSR_MSEL(IP8_23_21, SCIFA2_SCK, SEL_SCIFA2_1),
PINMUX_IPSR_MSEL(IP8_23_21, SSI_SDATA9_B, SEL_SSI9_1),
- PINMUX_IPSR_DATA(IP8_25_24, DU1_DB3),
- PINMUX_IPSR_DATA(IP8_25_24, LCDOUT19),
+ PINMUX_IPSR_GPSR(IP8_25_24, DU1_DB3),
+ PINMUX_IPSR_GPSR(IP8_25_24, LCDOUT19),
PINMUX_IPSR_MSEL(IP8_25_24, VI1_CLKENB_B, SEL_VI1_1),
- PINMUX_IPSR_DATA(IP8_27_26, DU1_DB4),
- PINMUX_IPSR_DATA(IP8_27_26, LCDOUT20),
+ PINMUX_IPSR_GPSR(IP8_27_26, DU1_DB4),
+ PINMUX_IPSR_GPSR(IP8_27_26, LCDOUT20),
PINMUX_IPSR_MSEL(IP8_27_26, VI1_FIELD_B, SEL_VI1_1),
PINMUX_IPSR_MSEL(IP8_27_26, CAN1_RX, SEL_CAN1_0),
- PINMUX_IPSR_DATA(IP8_30_28, DU1_DB5),
- PINMUX_IPSR_DATA(IP8_30_28, LCDOUT21),
+ PINMUX_IPSR_GPSR(IP8_30_28, DU1_DB5),
+ PINMUX_IPSR_GPSR(IP8_30_28, LCDOUT21),
PINMUX_IPSR_MSEL(IP8_30_28, TX3, SEL_SCIF3_0),
PINMUX_IPSR_MSEL(IP8_30_28, SCIFA3_TXD, SEL_SCIFA3_0),
PINMUX_IPSR_MSEL(IP8_30_28, CAN1_TX, SEL_CAN1_0),
/* IPSR9 */
- PINMUX_IPSR_DATA(IP9_2_0, DU1_DB6),
- PINMUX_IPSR_DATA(IP9_2_0, LCDOUT22),
+ PINMUX_IPSR_GPSR(IP9_2_0, DU1_DB6),
+ PINMUX_IPSR_GPSR(IP9_2_0, LCDOUT22),
PINMUX_IPSR_MSEL(IP9_2_0, SCL3_C, SEL_IIC3_2),
PINMUX_IPSR_MSEL(IP9_2_0, RX3, SEL_SCIF3_0),
PINMUX_IPSR_MSEL(IP9_2_0, SCIFA3_RXD, SEL_SCIFA3_0),
- PINMUX_IPSR_DATA(IP9_5_3, DU1_DB7),
- PINMUX_IPSR_DATA(IP9_5_3, LCDOUT23),
+ PINMUX_IPSR_GPSR(IP9_5_3, DU1_DB7),
+ PINMUX_IPSR_GPSR(IP9_5_3, LCDOUT23),
PINMUX_IPSR_MSEL(IP9_5_3, SDA3_C, SEL_IIC3_2),
PINMUX_IPSR_MSEL(IP9_5_3, SCIF3_SCK, SEL_SCIF3_0),
PINMUX_IPSR_MSEL(IP9_5_3, SCIFA3_SCK, SEL_SCIFA3_0),
PINMUX_IPSR_MSEL(IP9_6, DU1_DOTCLKIN, SEL_DIS_0),
- PINMUX_IPSR_DATA(IP9_6, QSTVA_QVS),
- PINMUX_IPSR_DATA(IP9_7, DU1_DOTCLKOUT0),
- PINMUX_IPSR_DATA(IP9_7, QCLK),
- PINMUX_IPSR_DATA(IP9_10_8, DU1_DOTCLKOUT1),
- PINMUX_IPSR_DATA(IP9_10_8, QSTVB_QVE),
+ PINMUX_IPSR_GPSR(IP9_6, QSTVA_QVS),
+ PINMUX_IPSR_GPSR(IP9_7, DU1_DOTCLKOUT0),
+ PINMUX_IPSR_GPSR(IP9_7, QCLK),
+ PINMUX_IPSR_GPSR(IP9_10_8, DU1_DOTCLKOUT1),
+ PINMUX_IPSR_GPSR(IP9_10_8, QSTVB_QVE),
PINMUX_IPSR_MSEL(IP9_10_8, CAN0_TX, SEL_CAN0_0),
PINMUX_IPSR_MSEL(IP9_10_8, TX3_B, SEL_SCIF3_1),
PINMUX_IPSR_MSEL(IP9_10_8, SCL2_B, SEL_IIC2_1),
- PINMUX_IPSR_DATA(IP9_10_8, PWM4),
- PINMUX_IPSR_DATA(IP9_11, DU1_EXHSYNC_DU1_HSYNC),
- PINMUX_IPSR_DATA(IP9_11, QSTH_QHS),
- PINMUX_IPSR_DATA(IP9_12, DU1_EXVSYNC_DU1_VSYNC),
- PINMUX_IPSR_DATA(IP9_12, QSTB_QHE),
- PINMUX_IPSR_DATA(IP9_15_13, DU1_EXODDF_DU1_ODDF_DISP_CDE),
- PINMUX_IPSR_DATA(IP9_15_13, QCPV_QDE),
+ PINMUX_IPSR_GPSR(IP9_10_8, PWM4),
+ PINMUX_IPSR_GPSR(IP9_11, DU1_EXHSYNC_DU1_HSYNC),
+ PINMUX_IPSR_GPSR(IP9_11, QSTH_QHS),
+ PINMUX_IPSR_GPSR(IP9_12, DU1_EXVSYNC_DU1_VSYNC),
+ PINMUX_IPSR_GPSR(IP9_12, QSTB_QHE),
+ PINMUX_IPSR_GPSR(IP9_15_13, DU1_EXODDF_DU1_ODDF_DISP_CDE),
+ PINMUX_IPSR_GPSR(IP9_15_13, QCPV_QDE),
PINMUX_IPSR_MSEL(IP9_15_13, CAN0_RX, SEL_CAN0_0),
PINMUX_IPSR_MSEL(IP9_15_13, RX3_B, SEL_SCIF3_1),
PINMUX_IPSR_MSEL(IP9_15_13, SDA2_B, SEL_IIC2_1),
- PINMUX_IPSR_DATA(IP9_16, DU1_DISP),
- PINMUX_IPSR_DATA(IP9_16, QPOLA),
- PINMUX_IPSR_DATA(IP9_18_17, DU1_CDE),
- PINMUX_IPSR_DATA(IP9_18_17, QPOLB),
- PINMUX_IPSR_DATA(IP9_18_17, PWM4_B),
- PINMUX_IPSR_DATA(IP9_20_19, VI0_CLKENB),
+ PINMUX_IPSR_GPSR(IP9_16, DU1_DISP),
+ PINMUX_IPSR_GPSR(IP9_16, QPOLA),
+ PINMUX_IPSR_GPSR(IP9_18_17, DU1_CDE),
+ PINMUX_IPSR_GPSR(IP9_18_17, QPOLB),
+ PINMUX_IPSR_GPSR(IP9_18_17, PWM4_B),
+ PINMUX_IPSR_GPSR(IP9_20_19, VI0_CLKENB),
PINMUX_IPSR_MSEL(IP9_20_19, TX4, SEL_SCIF4_0),
PINMUX_IPSR_MSEL(IP9_20_19, SCIFA4_TXD, SEL_SCIFA4_0),
PINMUX_IPSR_MSEL(IP9_20_19, TS_SDATA0_D, SEL_TSIF0_3),
- PINMUX_IPSR_DATA(IP9_22_21, VI0_FIELD),
+ PINMUX_IPSR_GPSR(IP9_22_21, VI0_FIELD),
PINMUX_IPSR_MSEL(IP9_22_21, RX4, SEL_SCIF4_0),
PINMUX_IPSR_MSEL(IP9_22_21, SCIFA4_RXD, SEL_SCIFA4_0),
PINMUX_IPSR_MSEL(IP9_22_21, TS_SCK0_D, SEL_TSIF0_3),
- PINMUX_IPSR_DATA(IP9_24_23, VI0_HSYNC_N),
+ PINMUX_IPSR_GPSR(IP9_24_23, VI0_HSYNC_N),
PINMUX_IPSR_MSEL(IP9_24_23, TX5, SEL_SCIF5_0),
PINMUX_IPSR_MSEL(IP9_24_23, SCIFA5_TXD, SEL_SCIFA5_0),
PINMUX_IPSR_MSEL(IP9_24_23, TS_SDEN0_D, SEL_TSIF0_3),
- PINMUX_IPSR_DATA(IP9_26_25, VI0_VSYNC_N),
+ PINMUX_IPSR_GPSR(IP9_26_25, VI0_VSYNC_N),
PINMUX_IPSR_MSEL(IP9_26_25, RX5, SEL_SCIF5_0),
PINMUX_IPSR_MSEL(IP9_26_25, SCIFA5_RXD, SEL_SCIFA5_0),
PINMUX_IPSR_MSEL(IP9_26_25, TS_SPSYNC0_D, SEL_TSIF0_3),
- PINMUX_IPSR_DATA(IP9_28_27, VI0_DATA3_VI0_B3),
+ PINMUX_IPSR_GPSR(IP9_28_27, VI0_DATA3_VI0_B3),
PINMUX_IPSR_MSEL(IP9_28_27, SCIF3_SCK_B, SEL_SCIF3_1),
PINMUX_IPSR_MSEL(IP9_28_27, SCIFA3_SCK_B, SEL_SCIFA3_1),
- PINMUX_IPSR_DATA(IP9_31_29, VI0_G0),
+ PINMUX_IPSR_GPSR(IP9_31_29, VI0_G0),
PINMUX_IPSR_MSEL(IP9_31_29, SCL8, SEL_IIC8_0),
PINMUX_IPSR_MSEL(IP9_31_29, STP_IVCXO27_0_C, SEL_SSP_2),
PINMUX_IPSR_MSEL(IP9_31_29, SCL4, SEL_IIC4_0),
PINMUX_IPSR_MSEL(IP9_31_29, HCTS2_N, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP9_31_29, SCIFB2_CTS_N, SEL_SCIFB2_0),
- PINMUX_IPSR_DATA(IP9_31_29, ATAWR1_N),
+ PINMUX_IPSR_GPSR(IP9_31_29, ATAWR1_N),
/* IPSR10 */
- PINMUX_IPSR_DATA(IP10_2_0, VI0_G1),
+ PINMUX_IPSR_GPSR(IP10_2_0, VI0_G1),
PINMUX_IPSR_MSEL(IP10_2_0, SDA8, SEL_IIC8_0),
PINMUX_IPSR_MSEL(IP10_2_0, STP_ISCLK_0_C, SEL_SSP_2),
PINMUX_IPSR_MSEL(IP10_2_0, SDA4, SEL_IIC4_0),
PINMUX_IPSR_MSEL(IP10_2_0, HRTS2_N, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP10_2_0, SCIFB2_RTS_N, SEL_SCIFB2_0),
- PINMUX_IPSR_DATA(IP10_2_0, ATADIR1_N),
- PINMUX_IPSR_DATA(IP10_5_3, VI0_G2),
- PINMUX_IPSR_DATA(IP10_5_3, VI2_HSYNC_N),
+ PINMUX_IPSR_GPSR(IP10_2_0, ATADIR1_N),
+ PINMUX_IPSR_GPSR(IP10_5_3, VI0_G2),
+ PINMUX_IPSR_GPSR(IP10_5_3, VI2_HSYNC_N),
PINMUX_IPSR_MSEL(IP10_5_3, STP_ISD_0_C, SEL_SSP_2),
PINMUX_IPSR_MSEL(IP10_5_3, SCL3_B, SEL_IIC3_1),
PINMUX_IPSR_MSEL(IP10_5_3, HSCK2, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP10_5_3, SCIFB2_SCK, SEL_SCIFB2_0),
- PINMUX_IPSR_DATA(IP10_5_3, ATARD1_N),
- PINMUX_IPSR_DATA(IP10_8_6, VI0_G3),
- PINMUX_IPSR_DATA(IP10_8_6, VI2_VSYNC_N),
+ PINMUX_IPSR_GPSR(IP10_5_3, ATARD1_N),
+ PINMUX_IPSR_GPSR(IP10_8_6, VI0_G3),
+ PINMUX_IPSR_GPSR(IP10_8_6, VI2_VSYNC_N),
PINMUX_IPSR_MSEL(IP10_8_6, STP_ISEN_0_C, SEL_SSP_2),
PINMUX_IPSR_MSEL(IP10_8_6, SDA3_B, SEL_IIC3_1),
PINMUX_IPSR_MSEL(IP10_8_6, HRX2, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP10_8_6, SCIFB2_RXD, SEL_SCIFB2_0),
- PINMUX_IPSR_DATA(IP10_8_6, ATACS01_N),
- PINMUX_IPSR_DATA(IP10_11_9, VI0_G4),
- PINMUX_IPSR_DATA(IP10_11_9, VI2_CLKENB),
+ PINMUX_IPSR_GPSR(IP10_8_6, ATACS01_N),
+ PINMUX_IPSR_GPSR(IP10_11_9, VI0_G4),
+ PINMUX_IPSR_GPSR(IP10_11_9, VI2_CLKENB),
PINMUX_IPSR_MSEL(IP10_11_9, STP_ISSYNC_0_C, SEL_SSP_2),
PINMUX_IPSR_MSEL(IP10_11_9, HTX2, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP10_11_9, SCIFB2_TXD, SEL_SCIFB2_0),
PINMUX_IPSR_MSEL(IP10_11_9, SCIFB0_SCK_D, SEL_SCIFB_3),
- PINMUX_IPSR_DATA(IP10_14_12, VI0_G5),
- PINMUX_IPSR_DATA(IP10_14_12, VI2_FIELD),
+ PINMUX_IPSR_GPSR(IP10_14_12, VI0_G5),
+ PINMUX_IPSR_GPSR(IP10_14_12, VI2_FIELD),
PINMUX_IPSR_MSEL(IP10_14_12, STP_OPWM_0_C, SEL_SSP_2),
PINMUX_IPSR_MSEL(IP10_14_12, FMCLK_D, SEL_FM_3),
PINMUX_IPSR_MSEL(IP10_14_12, CAN0_TX_E, SEL_CAN0_4),
PINMUX_IPSR_MSEL(IP10_14_12, HTX1_D, SEL_HSCIF1_3),
PINMUX_IPSR_MSEL(IP10_14_12, SCIFB0_TXD_D, SEL_SCIFB_3),
- PINMUX_IPSR_DATA(IP10_16_15, VI0_G6),
- PINMUX_IPSR_DATA(IP10_16_15, VI2_CLK),
+ PINMUX_IPSR_GPSR(IP10_16_15, VI0_G6),
+ PINMUX_IPSR_GPSR(IP10_16_15, VI2_CLK),
PINMUX_IPSR_MSEL(IP10_16_15, BPFCLK_D, SEL_FM_3),
- PINMUX_IPSR_DATA(IP10_18_17, VI0_G7),
- PINMUX_IPSR_DATA(IP10_18_17, VI2_DATA0),
+ PINMUX_IPSR_GPSR(IP10_18_17, VI0_G7),
+ PINMUX_IPSR_GPSR(IP10_18_17, VI2_DATA0),
PINMUX_IPSR_MSEL(IP10_18_17, FMIN_D, SEL_FM_3),
- PINMUX_IPSR_DATA(IP10_21_19, VI0_R0),
- PINMUX_IPSR_DATA(IP10_21_19, VI2_DATA1),
+ PINMUX_IPSR_GPSR(IP10_21_19, VI0_R0),
+ PINMUX_IPSR_GPSR(IP10_21_19, VI2_DATA1),
PINMUX_IPSR_MSEL(IP10_21_19, GLO_I0_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_21_19, TS_SDATA0_C, SEL_TSIF0_2),
- PINMUX_IPSR_DATA(IP10_21_19, ATACS11_N),
- PINMUX_IPSR_DATA(IP10_24_22, VI0_R1),
- PINMUX_IPSR_DATA(IP10_24_22, VI2_DATA2),
+ PINMUX_IPSR_GPSR(IP10_21_19, ATACS11_N),
+ PINMUX_IPSR_GPSR(IP10_24_22, VI0_R1),
+ PINMUX_IPSR_GPSR(IP10_24_22, VI2_DATA2),
PINMUX_IPSR_MSEL(IP10_24_22, GLO_I1_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_24_22, TS_SCK0_C, SEL_TSIF0_2),
- PINMUX_IPSR_DATA(IP10_24_22, ATAG1_N),
- PINMUX_IPSR_DATA(IP10_26_25, VI0_R2),
- PINMUX_IPSR_DATA(IP10_26_25, VI2_DATA3),
+ PINMUX_IPSR_GPSR(IP10_24_22, ATAG1_N),
+ PINMUX_IPSR_GPSR(IP10_26_25, VI0_R2),
+ PINMUX_IPSR_GPSR(IP10_26_25, VI2_DATA3),
PINMUX_IPSR_MSEL(IP10_26_25, GLO_Q0_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_26_25, TS_SDEN0_C, SEL_TSIF0_2),
- PINMUX_IPSR_DATA(IP10_28_27, VI0_R3),
- PINMUX_IPSR_DATA(IP10_28_27, VI2_DATA4),
+ PINMUX_IPSR_GPSR(IP10_28_27, VI0_R3),
+ PINMUX_IPSR_GPSR(IP10_28_27, VI2_DATA4),
PINMUX_IPSR_MSEL(IP10_28_27, GLO_Q1_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_28_27, TS_SPSYNC0_C, SEL_TSIF0_2),
- PINMUX_IPSR_DATA(IP10_31_29, VI0_R4),
- PINMUX_IPSR_DATA(IP10_31_29, VI2_DATA5),
+ PINMUX_IPSR_GPSR(IP10_31_29, VI0_R4),
+ PINMUX_IPSR_GPSR(IP10_31_29, VI2_DATA5),
PINMUX_IPSR_MSEL(IP10_31_29, GLO_SCLK_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP10_31_29, TX0_C, SEL_SCIF0_2),
PINMUX_IPSR_MSEL(IP10_31_29, SCL1_D, SEL_IIC1_3),
/* IPSR11 */
- PINMUX_IPSR_DATA(IP11_2_0, VI0_R5),
- PINMUX_IPSR_DATA(IP11_2_0, VI2_DATA6),
+ PINMUX_IPSR_GPSR(IP11_2_0, VI0_R5),
+ PINMUX_IPSR_GPSR(IP11_2_0, VI2_DATA6),
PINMUX_IPSR_MSEL(IP11_2_0, GLO_SDATA_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP11_2_0, RX0_C, SEL_SCIF0_2),
PINMUX_IPSR_MSEL(IP11_2_0, SDA1_D, SEL_IIC1_3),
- PINMUX_IPSR_DATA(IP11_5_3, VI0_R6),
- PINMUX_IPSR_DATA(IP11_5_3, VI2_DATA7),
+ PINMUX_IPSR_GPSR(IP11_5_3, VI0_R6),
+ PINMUX_IPSR_GPSR(IP11_5_3, VI2_DATA7),
PINMUX_IPSR_MSEL(IP11_5_3, GLO_SS_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP11_5_3, TX1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP11_5_3, SCL4_B, SEL_IIC4_1),
- PINMUX_IPSR_DATA(IP11_8_6, VI0_R7),
+ PINMUX_IPSR_GPSR(IP11_8_6, VI0_R7),
PINMUX_IPSR_MSEL(IP11_8_6, GLO_RFON_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP11_8_6, RX1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP11_8_6, CAN0_RX_E, SEL_CAN0_4),
@@ -1388,180 +1388,180 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP11_8_6, HRX1_D, SEL_HSCIF1_3),
PINMUX_IPSR_MSEL(IP11_8_6, SCIFB0_RXD_D, SEL_SCIFB_3),
PINMUX_IPSR_MSEL(IP11_11_9, VI1_HSYNC_N, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_11_9, AVB_RXD0),
+ PINMUX_IPSR_GPSR(IP11_11_9, AVB_RXD0),
PINMUX_IPSR_MSEL(IP11_11_9, TS_SDATA0_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP11_11_9, TX4_B, SEL_SCIF4_1),
PINMUX_IPSR_MSEL(IP11_11_9, SCIFA4_TXD_B, SEL_SCIFA4_1),
PINMUX_IPSR_MSEL(IP11_14_12, VI1_VSYNC_N, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_14_12, AVB_RXD1),
+ PINMUX_IPSR_GPSR(IP11_14_12, AVB_RXD1),
PINMUX_IPSR_MSEL(IP11_14_12, TS_SCK0_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP11_14_12, RX4_B, SEL_SCIF4_1),
PINMUX_IPSR_MSEL(IP11_14_12, SCIFA4_RXD_B, SEL_SCIFA4_1),
PINMUX_IPSR_MSEL(IP11_16_15, VI1_CLKENB, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_16_15, AVB_RXD2),
+ PINMUX_IPSR_GPSR(IP11_16_15, AVB_RXD2),
PINMUX_IPSR_MSEL(IP11_16_15, TS_SDEN0_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP11_18_17, VI1_FIELD, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_18_17, AVB_RXD3),
+ PINMUX_IPSR_GPSR(IP11_18_17, AVB_RXD3),
PINMUX_IPSR_MSEL(IP11_18_17, TS_SPSYNC0_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP11_19, VI1_CLK, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_19, AVB_RXD4),
+ PINMUX_IPSR_GPSR(IP11_19, AVB_RXD4),
PINMUX_IPSR_MSEL(IP11_20, VI1_DATA0, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_20, AVB_RXD5),
+ PINMUX_IPSR_GPSR(IP11_20, AVB_RXD5),
PINMUX_IPSR_MSEL(IP11_21, VI1_DATA1, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_21, AVB_RXD6),
+ PINMUX_IPSR_GPSR(IP11_21, AVB_RXD6),
PINMUX_IPSR_MSEL(IP11_22, VI1_DATA2, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_22, AVB_RXD7),
+ PINMUX_IPSR_GPSR(IP11_22, AVB_RXD7),
PINMUX_IPSR_MSEL(IP11_23, VI1_DATA3, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_23, AVB_RX_ER),
+ PINMUX_IPSR_GPSR(IP11_23, AVB_RX_ER),
PINMUX_IPSR_MSEL(IP11_24, VI1_DATA4, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_24, AVB_MDIO),
+ PINMUX_IPSR_GPSR(IP11_24, AVB_MDIO),
PINMUX_IPSR_MSEL(IP11_25, VI1_DATA5, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_25, AVB_RX_DV),
+ PINMUX_IPSR_GPSR(IP11_25, AVB_RX_DV),
PINMUX_IPSR_MSEL(IP11_26, VI1_DATA6, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_26, AVB_MAGIC),
+ PINMUX_IPSR_GPSR(IP11_26, AVB_MAGIC),
PINMUX_IPSR_MSEL(IP11_27, VI1_DATA7, SEL_VI1_0),
- PINMUX_IPSR_DATA(IP11_27, AVB_MDC),
- PINMUX_IPSR_DATA(IP11_29_28, ETH_MDIO),
- PINMUX_IPSR_DATA(IP11_29_28, AVB_RX_CLK),
+ PINMUX_IPSR_GPSR(IP11_27, AVB_MDC),
+ PINMUX_IPSR_GPSR(IP11_29_28, ETH_MDIO),
+ PINMUX_IPSR_GPSR(IP11_29_28, AVB_RX_CLK),
PINMUX_IPSR_MSEL(IP11_29_28, SCL2_C, SEL_IIC2_2),
- PINMUX_IPSR_DATA(IP11_31_30, ETH_CRS_DV),
- PINMUX_IPSR_DATA(IP11_31_30, AVB_LINK),
+ PINMUX_IPSR_GPSR(IP11_31_30, ETH_CRS_DV),
+ PINMUX_IPSR_GPSR(IP11_31_30, AVB_LINK),
PINMUX_IPSR_MSEL(IP11_31_30, SDA2_C, SEL_IIC2_2),
/* IPSR12 */
- PINMUX_IPSR_DATA(IP12_1_0, ETH_RX_ER),
- PINMUX_IPSR_DATA(IP12_1_0, AVB_CRS),
+ PINMUX_IPSR_GPSR(IP12_1_0, ETH_RX_ER),
+ PINMUX_IPSR_GPSR(IP12_1_0, AVB_CRS),
PINMUX_IPSR_MSEL(IP12_1_0, SCL3, SEL_IIC3_0),
PINMUX_IPSR_MSEL(IP12_1_0, SCL7, SEL_IIC7_0),
- PINMUX_IPSR_DATA(IP12_3_2, ETH_RXD0),
- PINMUX_IPSR_DATA(IP12_3_2, AVB_PHY_INT),
+ PINMUX_IPSR_GPSR(IP12_3_2, ETH_RXD0),
+ PINMUX_IPSR_GPSR(IP12_3_2, AVB_PHY_INT),
PINMUX_IPSR_MSEL(IP12_3_2, SDA3, SEL_IIC3_0),
PINMUX_IPSR_MSEL(IP12_3_2, SDA7, SEL_IIC7_0),
- PINMUX_IPSR_DATA(IP12_6_4, ETH_RXD1),
- PINMUX_IPSR_DATA(IP12_6_4, AVB_GTXREFCLK),
+ PINMUX_IPSR_GPSR(IP12_6_4, ETH_RXD1),
+ PINMUX_IPSR_GPSR(IP12_6_4, AVB_GTXREFCLK),
PINMUX_IPSR_MSEL(IP12_6_4, CAN0_TX_C, SEL_CAN0_2),
PINMUX_IPSR_MSEL(IP12_6_4, SCL2_D, SEL_IIC2_3),
PINMUX_IPSR_MSEL(IP12_6_4, MSIOF1_RXD_E, SEL_SOF1_4),
- PINMUX_IPSR_DATA(IP12_9_7, ETH_LINK),
- PINMUX_IPSR_DATA(IP12_9_7, AVB_TXD0),
+ PINMUX_IPSR_GPSR(IP12_9_7, ETH_LINK),
+ PINMUX_IPSR_GPSR(IP12_9_7, AVB_TXD0),
PINMUX_IPSR_MSEL(IP12_9_7, CAN0_RX_C, SEL_CAN0_2),
PINMUX_IPSR_MSEL(IP12_9_7, SDA2_D, SEL_IIC2_3),
PINMUX_IPSR_MSEL(IP12_9_7, MSIOF1_SCK_E, SEL_SOF1_4),
- PINMUX_IPSR_DATA(IP12_12_10, ETH_REFCLK),
- PINMUX_IPSR_DATA(IP12_12_10, AVB_TXD1),
+ PINMUX_IPSR_GPSR(IP12_12_10, ETH_REFCLK),
+ PINMUX_IPSR_GPSR(IP12_12_10, AVB_TXD1),
PINMUX_IPSR_MSEL(IP12_12_10, SCIFA3_RXD_B, SEL_SCIFA3_1),
PINMUX_IPSR_MSEL(IP12_12_10, CAN1_RX_C, SEL_CAN1_2),
PINMUX_IPSR_MSEL(IP12_12_10, MSIOF1_SYNC_E, SEL_SOF1_4),
- PINMUX_IPSR_DATA(IP12_15_13, ETH_TXD1),
- PINMUX_IPSR_DATA(IP12_15_13, AVB_TXD2),
+ PINMUX_IPSR_GPSR(IP12_15_13, ETH_TXD1),
+ PINMUX_IPSR_GPSR(IP12_15_13, AVB_TXD2),
PINMUX_IPSR_MSEL(IP12_15_13, SCIFA3_TXD_B, SEL_SCIFA3_1),
PINMUX_IPSR_MSEL(IP12_15_13, CAN1_TX_C, SEL_CAN1_2),
PINMUX_IPSR_MSEL(IP12_15_13, MSIOF1_TXD_E, SEL_SOF1_4),
- PINMUX_IPSR_DATA(IP12_17_16, ETH_TX_EN),
- PINMUX_IPSR_DATA(IP12_17_16, AVB_TXD3),
+ PINMUX_IPSR_GPSR(IP12_17_16, ETH_TX_EN),
+ PINMUX_IPSR_GPSR(IP12_17_16, AVB_TXD3),
PINMUX_IPSR_MSEL(IP12_17_16, TCLK1_B, SEL_TMU1_0),
PINMUX_IPSR_MSEL(IP12_17_16, CAN_CLK_B, SEL_CANCLK_1),
- PINMUX_IPSR_DATA(IP12_19_18, ETH_MAGIC),
- PINMUX_IPSR_DATA(IP12_19_18, AVB_TXD4),
+ PINMUX_IPSR_GPSR(IP12_19_18, ETH_MAGIC),
+ PINMUX_IPSR_GPSR(IP12_19_18, AVB_TXD4),
PINMUX_IPSR_MSEL(IP12_19_18, IETX_C, SEL_IEB_2),
- PINMUX_IPSR_DATA(IP12_21_20, ETH_TXD0),
- PINMUX_IPSR_DATA(IP12_21_20, AVB_TXD5),
+ PINMUX_IPSR_GPSR(IP12_21_20, ETH_TXD0),
+ PINMUX_IPSR_GPSR(IP12_21_20, AVB_TXD5),
PINMUX_IPSR_MSEL(IP12_21_20, IECLK_C, SEL_IEB_2),
- PINMUX_IPSR_DATA(IP12_23_22, ETH_MDC),
- PINMUX_IPSR_DATA(IP12_23_22, AVB_TXD6),
+ PINMUX_IPSR_GPSR(IP12_23_22, ETH_MDC),
+ PINMUX_IPSR_GPSR(IP12_23_22, AVB_TXD6),
PINMUX_IPSR_MSEL(IP12_23_22, IERX_C, SEL_IEB_2),
PINMUX_IPSR_MSEL(IP12_26_24, STP_IVCXO27_0, SEL_SSP_0),
- PINMUX_IPSR_DATA(IP12_26_24, AVB_TXD7),
+ PINMUX_IPSR_GPSR(IP12_26_24, AVB_TXD7),
PINMUX_IPSR_MSEL(IP12_26_24, SCIFB2_TXD_D, SEL_SCIFB2_3),
PINMUX_IPSR_MSEL(IP12_26_24, ADIDATA_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP12_26_24, MSIOF0_SYNC_C, SEL_SOF0_2),
PINMUX_IPSR_MSEL(IP12_29_27, STP_ISCLK_0, SEL_SSP_0),
- PINMUX_IPSR_DATA(IP12_29_27, AVB_TX_EN),
+ PINMUX_IPSR_GPSR(IP12_29_27, AVB_TX_EN),
PINMUX_IPSR_MSEL(IP12_29_27, SCIFB2_RXD_D, SEL_SCIFB2_3),
PINMUX_IPSR_MSEL(IP12_29_27, ADICS_SAMP_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP12_29_27, MSIOF0_SCK_C, SEL_SOF0_2),
/* IPSR13 */
PINMUX_IPSR_MSEL(IP13_2_0, STP_ISD_0, SEL_SSP_0),
- PINMUX_IPSR_DATA(IP13_2_0, AVB_TX_ER),
+ PINMUX_IPSR_GPSR(IP13_2_0, AVB_TX_ER),
PINMUX_IPSR_MSEL(IP13_2_0, SCIFB2_SCK_C, SEL_SCIFB2_2),
PINMUX_IPSR_MSEL(IP13_2_0, ADICLK_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP13_2_0, MSIOF0_SS1_C, SEL_SOF0_2),
PINMUX_IPSR_MSEL(IP13_4_3, STP_ISEN_0, SEL_SSP_0),
- PINMUX_IPSR_DATA(IP13_4_3, AVB_TX_CLK),
+ PINMUX_IPSR_GPSR(IP13_4_3, AVB_TX_CLK),
PINMUX_IPSR_MSEL(IP13_4_3, ADICHS0_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP13_4_3, MSIOF0_SS2_C, SEL_SOF0_2),
PINMUX_IPSR_MSEL(IP13_6_5, STP_ISSYNC_0, SEL_SSP_0),
- PINMUX_IPSR_DATA(IP13_6_5, AVB_COL),
+ PINMUX_IPSR_GPSR(IP13_6_5, AVB_COL),
PINMUX_IPSR_MSEL(IP13_6_5, ADICHS1_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP13_6_5, MSIOF0_RXD_C, SEL_SOF0_2),
PINMUX_IPSR_MSEL(IP13_9_7, STP_OPWM_0, SEL_SSP_0),
- PINMUX_IPSR_DATA(IP13_9_7, AVB_GTX_CLK),
- PINMUX_IPSR_DATA(IP13_9_7, PWM0_B),
+ PINMUX_IPSR_GPSR(IP13_9_7, AVB_GTX_CLK),
+ PINMUX_IPSR_GPSR(IP13_9_7, PWM0_B),
PINMUX_IPSR_MSEL(IP13_9_7, ADICHS2_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP13_9_7, MSIOF0_TXD_C, SEL_SOF0_2),
- PINMUX_IPSR_DATA(IP13_10, SD0_CLK),
+ PINMUX_IPSR_GPSR(IP13_10, SD0_CLK),
PINMUX_IPSR_MSEL(IP13_10, SPCLK_B, SEL_QSP_1),
- PINMUX_IPSR_DATA(IP13_11, SD0_CMD),
+ PINMUX_IPSR_GPSR(IP13_11, SD0_CMD),
PINMUX_IPSR_MSEL(IP13_11, MOSI_IO0_B, SEL_QSP_1),
- PINMUX_IPSR_DATA(IP13_12, SD0_DATA0),
+ PINMUX_IPSR_GPSR(IP13_12, SD0_DATA0),
PINMUX_IPSR_MSEL(IP13_12, MISO_IO1_B, SEL_QSP_1),
- PINMUX_IPSR_DATA(IP13_13, SD0_DATA1),
+ PINMUX_IPSR_GPSR(IP13_13, SD0_DATA1),
PINMUX_IPSR_MSEL(IP13_13, IO2_B, SEL_QSP_1),
- PINMUX_IPSR_DATA(IP13_14, SD0_DATA2),
+ PINMUX_IPSR_GPSR(IP13_14, SD0_DATA2),
PINMUX_IPSR_MSEL(IP13_14, IO3_B, SEL_QSP_1),
- PINMUX_IPSR_DATA(IP13_15, SD0_DATA3),
+ PINMUX_IPSR_GPSR(IP13_15, SD0_DATA3),
PINMUX_IPSR_MSEL(IP13_15, SSL_B, SEL_QSP_1),
- PINMUX_IPSR_DATA(IP13_18_16, SD0_CD),
+ PINMUX_IPSR_GPSR(IP13_18_16, SD0_CD),
PINMUX_IPSR_MSEL(IP13_18_16, MMC_D6_B, SEL_MMC_1),
PINMUX_IPSR_MSEL(IP13_18_16, SIM0_RST_B, SEL_SIM_1),
PINMUX_IPSR_MSEL(IP13_18_16, CAN0_RX_F, SEL_CAN0_5),
PINMUX_IPSR_MSEL(IP13_18_16, SCIFA5_TXD_B, SEL_SCIFA5_1),
PINMUX_IPSR_MSEL(IP13_18_16, TX3_C, SEL_SCIF3_2),
- PINMUX_IPSR_DATA(IP13_21_19, SD0_WP),
+ PINMUX_IPSR_GPSR(IP13_21_19, SD0_WP),
PINMUX_IPSR_MSEL(IP13_21_19, MMC_D7_B, SEL_MMC_1),
PINMUX_IPSR_MSEL(IP13_21_19, SIM0_D_B, SEL_SIM_1),
PINMUX_IPSR_MSEL(IP13_21_19, CAN0_TX_F, SEL_CAN0_5),
PINMUX_IPSR_MSEL(IP13_21_19, SCIFA5_RXD_B, SEL_SCIFA5_1),
PINMUX_IPSR_MSEL(IP13_21_19, RX3_C, SEL_SCIF3_2),
- PINMUX_IPSR_DATA(IP13_22, SD1_CMD),
+ PINMUX_IPSR_GPSR(IP13_22, SD1_CMD),
PINMUX_IPSR_MSEL(IP13_22, REMOCON_B, SEL_RCN_1),
- PINMUX_IPSR_DATA(IP13_24_23, SD1_DATA0),
+ PINMUX_IPSR_GPSR(IP13_24_23, SD1_DATA0),
PINMUX_IPSR_MSEL(IP13_24_23, SPEEDIN_B, SEL_RSP_1),
- PINMUX_IPSR_DATA(IP13_25, SD1_DATA1),
+ PINMUX_IPSR_GPSR(IP13_25, SD1_DATA1),
PINMUX_IPSR_MSEL(IP13_25, IETX_B, SEL_IEB_1),
- PINMUX_IPSR_DATA(IP13_26, SD1_DATA2),
+ PINMUX_IPSR_GPSR(IP13_26, SD1_DATA2),
PINMUX_IPSR_MSEL(IP13_26, IECLK_B, SEL_IEB_1),
- PINMUX_IPSR_DATA(IP13_27, SD1_DATA3),
+ PINMUX_IPSR_GPSR(IP13_27, SD1_DATA3),
PINMUX_IPSR_MSEL(IP13_27, IERX_B, SEL_IEB_1),
- PINMUX_IPSR_DATA(IP13_30_28, SD1_CD),
- PINMUX_IPSR_DATA(IP13_30_28, PWM0),
- PINMUX_IPSR_DATA(IP13_30_28, TPU_TO0),
+ PINMUX_IPSR_GPSR(IP13_30_28, SD1_CD),
+ PINMUX_IPSR_GPSR(IP13_30_28, PWM0),
+ PINMUX_IPSR_GPSR(IP13_30_28, TPU_TO0),
PINMUX_IPSR_MSEL(IP13_30_28, SCL1_C, SEL_IIC1_2),
/* IPSR14 */
- PINMUX_IPSR_DATA(IP14_1_0, SD1_WP),
- PINMUX_IPSR_DATA(IP14_1_0, PWM1_B),
+ PINMUX_IPSR_GPSR(IP14_1_0, SD1_WP),
+ PINMUX_IPSR_GPSR(IP14_1_0, PWM1_B),
PINMUX_IPSR_MSEL(IP14_1_0, SDA1_C, SEL_IIC1_2),
- PINMUX_IPSR_DATA(IP14_2, SD2_CLK),
- PINMUX_IPSR_DATA(IP14_2, MMC_CLK),
- PINMUX_IPSR_DATA(IP14_3, SD2_CMD),
- PINMUX_IPSR_DATA(IP14_3, MMC_CMD),
- PINMUX_IPSR_DATA(IP14_4, SD2_DATA0),
- PINMUX_IPSR_DATA(IP14_4, MMC_D0),
- PINMUX_IPSR_DATA(IP14_5, SD2_DATA1),
- PINMUX_IPSR_DATA(IP14_5, MMC_D1),
- PINMUX_IPSR_DATA(IP14_6, SD2_DATA2),
- PINMUX_IPSR_DATA(IP14_6, MMC_D2),
- PINMUX_IPSR_DATA(IP14_7, SD2_DATA3),
- PINMUX_IPSR_DATA(IP14_7, MMC_D3),
- PINMUX_IPSR_DATA(IP14_10_8, SD2_CD),
- PINMUX_IPSR_DATA(IP14_10_8, MMC_D4),
+ PINMUX_IPSR_GPSR(IP14_2, SD2_CLK),
+ PINMUX_IPSR_GPSR(IP14_2, MMC_CLK),
+ PINMUX_IPSR_GPSR(IP14_3, SD2_CMD),
+ PINMUX_IPSR_GPSR(IP14_3, MMC_CMD),
+ PINMUX_IPSR_GPSR(IP14_4, SD2_DATA0),
+ PINMUX_IPSR_GPSR(IP14_4, MMC_D0),
+ PINMUX_IPSR_GPSR(IP14_5, SD2_DATA1),
+ PINMUX_IPSR_GPSR(IP14_5, MMC_D1),
+ PINMUX_IPSR_GPSR(IP14_6, SD2_DATA2),
+ PINMUX_IPSR_GPSR(IP14_6, MMC_D2),
+ PINMUX_IPSR_GPSR(IP14_7, SD2_DATA3),
+ PINMUX_IPSR_GPSR(IP14_7, MMC_D3),
+ PINMUX_IPSR_GPSR(IP14_10_8, SD2_CD),
+ PINMUX_IPSR_GPSR(IP14_10_8, MMC_D4),
PINMUX_IPSR_MSEL(IP14_10_8, SCL8_C, SEL_IIC8_2),
PINMUX_IPSR_MSEL(IP14_10_8, TX5_B, SEL_SCIF5_1),
PINMUX_IPSR_MSEL(IP14_10_8, SCIFA5_TXD_C, SEL_SCIFA5_2),
- PINMUX_IPSR_DATA(IP14_13_11, SD2_WP),
- PINMUX_IPSR_DATA(IP14_13_11, MMC_D5),
+ PINMUX_IPSR_GPSR(IP14_13_11, SD2_WP),
+ PINMUX_IPSR_GPSR(IP14_13_11, MMC_D5),
PINMUX_IPSR_MSEL(IP14_13_11, SDA8_C, SEL_IIC8_2),
PINMUX_IPSR_MSEL(IP14_13_11, RX5_B, SEL_SCIF5_1),
PINMUX_IPSR_MSEL(IP14_13_11, SCIFA5_RXD_C, SEL_SCIFA5_2),
@@ -1569,40 +1569,40 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP14_16_14, RX2_C, SEL_SCIF2_2),
PINMUX_IPSR_MSEL(IP14_16_14, ADIDATA, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP14_16_14, VI1_CLK_C, SEL_VI1_2),
- PINMUX_IPSR_DATA(IP14_16_14, VI1_G0_B),
+ PINMUX_IPSR_GPSR(IP14_16_14, VI1_G0_B),
PINMUX_IPSR_MSEL(IP14_19_17, MSIOF0_SYNC, SEL_SOF0_0),
PINMUX_IPSR_MSEL(IP14_19_17, TX2_C, SEL_SCIF2_2),
PINMUX_IPSR_MSEL(IP14_19_17, ADICS_SAMP, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP14_19_17, VI1_CLKENB_C, SEL_VI1_2),
- PINMUX_IPSR_DATA(IP14_19_17, VI1_G1_B),
+ PINMUX_IPSR_GPSR(IP14_19_17, VI1_G1_B),
PINMUX_IPSR_MSEL(IP14_22_20, MSIOF0_TXD, SEL_SOF0_0),
PINMUX_IPSR_MSEL(IP14_22_20, ADICLK, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP14_22_20, VI1_FIELD_C, SEL_VI1_2),
- PINMUX_IPSR_DATA(IP14_22_20, VI1_G2_B),
+ PINMUX_IPSR_GPSR(IP14_22_20, VI1_G2_B),
PINMUX_IPSR_MSEL(IP14_25_23, MSIOF0_RXD, SEL_SOF0_0),
PINMUX_IPSR_MSEL(IP14_25_23, ADICHS0, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP14_25_23, VI1_DATA0_C, SEL_VI1_2),
- PINMUX_IPSR_DATA(IP14_25_23, VI1_G3_B),
+ PINMUX_IPSR_GPSR(IP14_25_23, VI1_G3_B),
PINMUX_IPSR_MSEL(IP14_28_26, MSIOF0_SS1, SEL_SOF0_0),
PINMUX_IPSR_MSEL(IP14_28_26, MMC_D6, SEL_MMC_0),
PINMUX_IPSR_MSEL(IP14_28_26, ADICHS1, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP14_28_26, TX0_E, SEL_SCIF0_4),
PINMUX_IPSR_MSEL(IP14_28_26, VI1_HSYNC_N_C, SEL_VI1_2),
PINMUX_IPSR_MSEL(IP14_28_26, SCL7_C, SEL_IIC7_2),
- PINMUX_IPSR_DATA(IP14_28_26, VI1_G4_B),
+ PINMUX_IPSR_GPSR(IP14_28_26, VI1_G4_B),
PINMUX_IPSR_MSEL(IP14_31_29, MSIOF0_SS2, SEL_SOF0_0),
PINMUX_IPSR_MSEL(IP14_31_29, MMC_D7, SEL_MMC_0),
PINMUX_IPSR_MSEL(IP14_31_29, ADICHS2, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP14_31_29, RX0_E, SEL_SCIF0_4),
PINMUX_IPSR_MSEL(IP14_31_29, VI1_VSYNC_N_C, SEL_VI1_2),
PINMUX_IPSR_MSEL(IP14_31_29, SDA7_C, SEL_IIC7_2),
- PINMUX_IPSR_DATA(IP14_31_29, VI1_G5_B),
+ PINMUX_IPSR_GPSR(IP14_31_29, VI1_G5_B),
/* IPSR15 */
PINMUX_IPSR_MSEL(IP15_1_0, SIM0_RST, SEL_SIM_0),
PINMUX_IPSR_MSEL(IP15_1_0, IETX, SEL_IEB_0),
PINMUX_IPSR_MSEL(IP15_1_0, CAN1_TX_D, SEL_CAN1_3),
- PINMUX_IPSR_DATA(IP15_3_2, SIM0_CLK),
+ PINMUX_IPSR_GPSR(IP15_3_2, SIM0_CLK),
PINMUX_IPSR_MSEL(IP15_3_2, IECLK, SEL_IEB_0),
PINMUX_IPSR_MSEL(IP15_3_2, CAN_CLK_C, SEL_CANCLK_2),
PINMUX_IPSR_MSEL(IP15_5_4, SIM0_D, SEL_SIM_0),
@@ -1611,19 +1611,19 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP15_8_6, GPS_CLK, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP15_8_6, DU1_DOTCLKIN_C, SEL_DIS_2),
PINMUX_IPSR_MSEL(IP15_8_6, AUDIO_CLKB_B, SEL_ADG_1),
- PINMUX_IPSR_DATA(IP15_8_6, PWM5_B),
+ PINMUX_IPSR_GPSR(IP15_8_6, PWM5_B),
PINMUX_IPSR_MSEL(IP15_8_6, SCIFA3_TXD_C, SEL_SCIFA3_2),
PINMUX_IPSR_MSEL(IP15_11_9, GPS_SIGN, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP15_11_9, TX4_C, SEL_SCIF4_2),
PINMUX_IPSR_MSEL(IP15_11_9, SCIFA4_TXD_C, SEL_SCIFA4_2),
- PINMUX_IPSR_DATA(IP15_11_9, PWM5),
- PINMUX_IPSR_DATA(IP15_11_9, VI1_G6_B),
+ PINMUX_IPSR_GPSR(IP15_11_9, PWM5),
+ PINMUX_IPSR_GPSR(IP15_11_9, VI1_G6_B),
PINMUX_IPSR_MSEL(IP15_11_9, SCIFA3_RXD_C, SEL_SCIFA3_2),
PINMUX_IPSR_MSEL(IP15_14_12, GPS_MAG, SEL_GPS_0),
PINMUX_IPSR_MSEL(IP15_14_12, RX4_C, SEL_SCIF4_2),
PINMUX_IPSR_MSEL(IP15_14_12, SCIFA4_RXD_C, SEL_SCIFA4_2),
- PINMUX_IPSR_DATA(IP15_14_12, PWM6),
- PINMUX_IPSR_DATA(IP15_14_12, VI1_G7_B),
+ PINMUX_IPSR_GPSR(IP15_14_12, PWM6),
+ PINMUX_IPSR_GPSR(IP15_14_12, VI1_G7_B),
PINMUX_IPSR_MSEL(IP15_14_12, SCIFA3_SCK_C, SEL_SCIFA3_2),
PINMUX_IPSR_MSEL(IP15_17_15, HCTS0_N, SEL_HSCIF0_0),
PINMUX_IPSR_MSEL(IP15_17_15, SCIFB0_CTS_N, SEL_SCIFB_0),
@@ -1638,7 +1638,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP15_23_21, SCIFB0_SCK, SEL_SCIFB_0),
PINMUX_IPSR_MSEL(IP15_23_21, GLO_Q0_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP15_23_21, CAN_CLK, SEL_CANCLK_0),
- PINMUX_IPSR_DATA(IP15_23_21, TCLK2),
+ PINMUX_IPSR_GPSR(IP15_23_21, TCLK2),
PINMUX_IPSR_MSEL(IP15_23_21, VI1_DATA3_C, SEL_VI1_2),
PINMUX_IPSR_MSEL(IP15_26_24, HRX0, SEL_HSCIF0_0),
PINMUX_IPSR_MSEL(IP15_26_24, SCIFB0_RXD, SEL_SCIFB_0),
@@ -1654,25 +1654,25 @@ static const u16 pinmux_data[] = {
/* IPSR16 */
PINMUX_IPSR_MSEL(IP16_2_0, HRX1, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP16_2_0, SCIFB1_RXD, SEL_SCIFB1_0),
- PINMUX_IPSR_DATA(IP16_2_0, VI1_R0_B),
+ PINMUX_IPSR_GPSR(IP16_2_0, VI1_R0_B),
PINMUX_IPSR_MSEL(IP16_2_0, GLO_SDATA_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP16_2_0, VI1_DATA6_C, SEL_VI1_2),
PINMUX_IPSR_MSEL(IP16_5_3, HTX1, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP16_5_3, SCIFB1_TXD, SEL_SCIFB1_0),
- PINMUX_IPSR_DATA(IP16_5_3, VI1_R1_B),
+ PINMUX_IPSR_GPSR(IP16_5_3, VI1_R1_B),
PINMUX_IPSR_MSEL(IP16_5_3, GLO_SS_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP16_5_3, VI1_DATA7_C, SEL_VI1_2),
PINMUX_IPSR_MSEL(IP16_7_6, HSCK1, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP16_7_6, SCIFB1_SCK, SEL_SCIFB1_0),
- PINMUX_IPSR_DATA(IP16_7_6, MLB_CLK),
+ PINMUX_IPSR_GPSR(IP16_7_6, MLB_CLK),
PINMUX_IPSR_MSEL(IP16_7_6, GLO_RFON_C, SEL_GPS_2),
PINMUX_IPSR_MSEL(IP16_9_8, HCTS1_N, SEL_HSCIF1_0),
- PINMUX_IPSR_DATA(IP16_9_8, SCIFB1_CTS_N),
- PINMUX_IPSR_DATA(IP16_9_8, MLB_SIG),
+ PINMUX_IPSR_GPSR(IP16_9_8, SCIFB1_CTS_N),
+ PINMUX_IPSR_GPSR(IP16_9_8, MLB_SIG),
PINMUX_IPSR_MSEL(IP16_9_8, CAN1_TX_B, SEL_CAN1_1),
PINMUX_IPSR_MSEL(IP16_11_10, HRTS1_N, SEL_HSCIF1_0),
- PINMUX_IPSR_DATA(IP16_11_10, SCIFB1_RTS_N),
- PINMUX_IPSR_DATA(IP16_11_10, MLB_DAT),
+ PINMUX_IPSR_GPSR(IP16_11_10, SCIFB1_RTS_N),
+ PINMUX_IPSR_GPSR(IP16_11_10, MLB_DAT),
PINMUX_IPSR_MSEL(IP16_11_10, CAN1_RX_B, SEL_CAN1_1),
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
index 3718c7846bfd..38912cff597b 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
@@ -1,9 +1,9 @@
/*
* r8a7794 processor support - PFC hardware block.
*
- * Copyright (C) 2014 Renesas Electronics Corporation
+ * Copyright (C) 2014-2015 Renesas Electronics Corporation
* Copyright (C) 2015 Renesas Solutions Corp.
- * Copyright (C) 2015 Cogent Embedded, Inc., <source@cogentembedded.com>
+ * Copyright (C) 2015-2016 Cogent Embedded, Inc., <source@cogentembedded.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -623,848 +623,848 @@ static const u16 pinmux_data[] = {
PINMUX_SINGLE(SD1_DATA3),
/* IPSR0 */
- PINMUX_IPSR_DATA(IP0_0, SD1_CD),
+ PINMUX_IPSR_GPSR(IP0_0, SD1_CD),
PINMUX_IPSR_MSEL(IP0_0, CAN0_RX, SEL_CAN0_0),
- PINMUX_IPSR_DATA(IP0_9_8, SD1_WP),
- PINMUX_IPSR_DATA(IP0_9_8, IRQ7),
+ PINMUX_IPSR_GPSR(IP0_9_8, SD1_WP),
+ PINMUX_IPSR_GPSR(IP0_9_8, IRQ7),
PINMUX_IPSR_MSEL(IP0_9_8, CAN0_TX, SEL_CAN0_0),
- PINMUX_IPSR_DATA(IP0_10, MMC_CLK),
- PINMUX_IPSR_DATA(IP0_10, SD2_CLK),
- PINMUX_IPSR_DATA(IP0_11, MMC_CMD),
- PINMUX_IPSR_DATA(IP0_11, SD2_CMD),
- PINMUX_IPSR_DATA(IP0_12, MMC_D0),
- PINMUX_IPSR_DATA(IP0_12, SD2_DATA0),
- PINMUX_IPSR_DATA(IP0_13, MMC_D1),
- PINMUX_IPSR_DATA(IP0_13, SD2_DATA1),
- PINMUX_IPSR_DATA(IP0_14, MMC_D2),
- PINMUX_IPSR_DATA(IP0_14, SD2_DATA2),
- PINMUX_IPSR_DATA(IP0_15, MMC_D3),
- PINMUX_IPSR_DATA(IP0_15, SD2_DATA3),
- PINMUX_IPSR_DATA(IP0_16, MMC_D4),
- PINMUX_IPSR_DATA(IP0_16, SD2_CD),
- PINMUX_IPSR_DATA(IP0_17, MMC_D5),
- PINMUX_IPSR_DATA(IP0_17, SD2_WP),
- PINMUX_IPSR_DATA(IP0_19_18, MMC_D6),
+ PINMUX_IPSR_GPSR(IP0_10, MMC_CLK),
+ PINMUX_IPSR_GPSR(IP0_10, SD2_CLK),
+ PINMUX_IPSR_GPSR(IP0_11, MMC_CMD),
+ PINMUX_IPSR_GPSR(IP0_11, SD2_CMD),
+ PINMUX_IPSR_GPSR(IP0_12, MMC_D0),
+ PINMUX_IPSR_GPSR(IP0_12, SD2_DATA0),
+ PINMUX_IPSR_GPSR(IP0_13, MMC_D1),
+ PINMUX_IPSR_GPSR(IP0_13, SD2_DATA1),
+ PINMUX_IPSR_GPSR(IP0_14, MMC_D2),
+ PINMUX_IPSR_GPSR(IP0_14, SD2_DATA2),
+ PINMUX_IPSR_GPSR(IP0_15, MMC_D3),
+ PINMUX_IPSR_GPSR(IP0_15, SD2_DATA3),
+ PINMUX_IPSR_GPSR(IP0_16, MMC_D4),
+ PINMUX_IPSR_GPSR(IP0_16, SD2_CD),
+ PINMUX_IPSR_GPSR(IP0_17, MMC_D5),
+ PINMUX_IPSR_GPSR(IP0_17, SD2_WP),
+ PINMUX_IPSR_GPSR(IP0_19_18, MMC_D6),
PINMUX_IPSR_MSEL(IP0_19_18, SCIF0_RXD, SEL_SCIF0_0),
PINMUX_IPSR_MSEL(IP0_19_18, I2C2_SCL_B, SEL_I2C02_1),
PINMUX_IPSR_MSEL(IP0_19_18, CAN1_RX, SEL_CAN1_0),
- PINMUX_IPSR_DATA(IP0_21_20, MMC_D7),
+ PINMUX_IPSR_GPSR(IP0_21_20, MMC_D7),
PINMUX_IPSR_MSEL(IP0_21_20, SCIF0_TXD, SEL_SCIF0_0),
PINMUX_IPSR_MSEL(IP0_21_20, I2C2_SDA_B, SEL_I2C02_1),
PINMUX_IPSR_MSEL(IP0_21_20, CAN1_TX, SEL_CAN1_0),
- PINMUX_IPSR_DATA(IP0_23_22, D0),
+ PINMUX_IPSR_GPSR(IP0_23_22, D0),
PINMUX_IPSR_MSEL(IP0_23_22, SCIFA3_SCK_B, SEL_SCIFA3_1),
- PINMUX_IPSR_DATA(IP0_23_22, IRQ4),
- PINMUX_IPSR_DATA(IP0_24, D1),
+ PINMUX_IPSR_GPSR(IP0_23_22, IRQ4),
+ PINMUX_IPSR_GPSR(IP0_24, D1),
PINMUX_IPSR_MSEL(IP0_24, SCIFA3_RXD_B, SEL_SCIFA3_1),
- PINMUX_IPSR_DATA(IP0_25, D2),
+ PINMUX_IPSR_GPSR(IP0_25, D2),
PINMUX_IPSR_MSEL(IP0_25, SCIFA3_TXD_B, SEL_SCIFA3_1),
- PINMUX_IPSR_DATA(IP0_27_26, D3),
+ PINMUX_IPSR_GPSR(IP0_27_26, D3),
PINMUX_IPSR_MSEL(IP0_27_26, I2C3_SCL_B, SEL_I2C03_1),
PINMUX_IPSR_MSEL(IP0_27_26, SCIF5_RXD_B, SEL_SCIF5_1),
- PINMUX_IPSR_DATA(IP0_29_28, D4),
+ PINMUX_IPSR_GPSR(IP0_29_28, D4),
PINMUX_IPSR_MSEL(IP0_29_28, I2C3_SDA_B, SEL_I2C03_1),
PINMUX_IPSR_MSEL(IP0_29_28, SCIF5_TXD_B, SEL_SCIF5_1),
- PINMUX_IPSR_DATA(IP0_31_30, D5),
+ PINMUX_IPSR_GPSR(IP0_31_30, D5),
PINMUX_IPSR_MSEL(IP0_31_30, SCIF4_RXD_B, SEL_SCIF4_1),
PINMUX_IPSR_MSEL(IP0_31_30, I2C0_SCL_D, SEL_I2C00_3),
/* IPSR1 */
- PINMUX_IPSR_DATA(IP1_1_0, D6),
+ PINMUX_IPSR_GPSR(IP1_1_0, D6),
PINMUX_IPSR_MSEL(IP1_1_0, SCIF4_TXD_B, SEL_SCIF4_1),
PINMUX_IPSR_MSEL(IP1_1_0, I2C0_SDA_D, SEL_I2C00_3),
- PINMUX_IPSR_DATA(IP1_3_2, D7),
- PINMUX_IPSR_DATA(IP1_3_2, IRQ3),
+ PINMUX_IPSR_GPSR(IP1_3_2, D7),
+ PINMUX_IPSR_GPSR(IP1_3_2, IRQ3),
PINMUX_IPSR_MSEL(IP1_3_2, TCLK1, SEL_TMU_0),
- PINMUX_IPSR_DATA(IP1_3_2, PWM6_B),
- PINMUX_IPSR_DATA(IP1_5_4, D8),
- PINMUX_IPSR_DATA(IP1_5_4, HSCIF2_HRX),
+ PINMUX_IPSR_GPSR(IP1_3_2, PWM6_B),
+ PINMUX_IPSR_GPSR(IP1_5_4, D8),
+ PINMUX_IPSR_GPSR(IP1_5_4, HSCIF2_HRX),
PINMUX_IPSR_MSEL(IP1_5_4, I2C1_SCL_B, SEL_I2C01_1),
- PINMUX_IPSR_DATA(IP1_7_6, D9),
- PINMUX_IPSR_DATA(IP1_7_6, HSCIF2_HTX),
+ PINMUX_IPSR_GPSR(IP1_7_6, D9),
+ PINMUX_IPSR_GPSR(IP1_7_6, HSCIF2_HTX),
PINMUX_IPSR_MSEL(IP1_7_6, I2C1_SDA_B, SEL_I2C01_1),
- PINMUX_IPSR_DATA(IP1_10_8, D10),
- PINMUX_IPSR_DATA(IP1_10_8, HSCIF2_HSCK),
+ PINMUX_IPSR_GPSR(IP1_10_8, D10),
+ PINMUX_IPSR_GPSR(IP1_10_8, HSCIF2_HSCK),
PINMUX_IPSR_MSEL(IP1_10_8, SCIF1_SCK_C, SEL_SCIF1_2),
- PINMUX_IPSR_DATA(IP1_10_8, IRQ6),
- PINMUX_IPSR_DATA(IP1_10_8, PWM5_C),
- PINMUX_IPSR_DATA(IP1_12_11, D11),
- PINMUX_IPSR_DATA(IP1_12_11, HSCIF2_HCTS_N),
+ PINMUX_IPSR_GPSR(IP1_10_8, IRQ6),
+ PINMUX_IPSR_GPSR(IP1_10_8, PWM5_C),
+ PINMUX_IPSR_GPSR(IP1_12_11, D11),
+ PINMUX_IPSR_GPSR(IP1_12_11, HSCIF2_HCTS_N),
PINMUX_IPSR_MSEL(IP1_12_11, SCIF1_RXD_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP1_12_11, I2C1_SCL_D, SEL_I2C01_3),
- PINMUX_IPSR_DATA(IP1_14_13, D12),
- PINMUX_IPSR_DATA(IP1_14_13, HSCIF2_HRTS_N),
+ PINMUX_IPSR_GPSR(IP1_14_13, D12),
+ PINMUX_IPSR_GPSR(IP1_14_13, HSCIF2_HRTS_N),
PINMUX_IPSR_MSEL(IP1_14_13, SCIF1_TXD_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP1_14_13, I2C1_SDA_D, SEL_I2C01_3),
- PINMUX_IPSR_DATA(IP1_17_15, D13),
+ PINMUX_IPSR_GPSR(IP1_17_15, D13),
PINMUX_IPSR_MSEL(IP1_17_15, SCIFA1_SCK, SEL_SCIFA1_0),
- PINMUX_IPSR_DATA(IP1_17_15, TANS1),
- PINMUX_IPSR_DATA(IP1_17_15, PWM2_C),
+ PINMUX_IPSR_GPSR(IP1_17_15, TANS1),
+ PINMUX_IPSR_GPSR(IP1_17_15, PWM2_C),
PINMUX_IPSR_MSEL(IP1_17_15, TCLK2_B, SEL_TMU_1),
- PINMUX_IPSR_DATA(IP1_19_18, D14),
+ PINMUX_IPSR_GPSR(IP1_19_18, D14),
PINMUX_IPSR_MSEL(IP1_19_18, SCIFA1_RXD, SEL_SCIFA1_0),
PINMUX_IPSR_MSEL(IP1_19_18, IIC0_SCL_B, SEL_IIC00_1),
- PINMUX_IPSR_DATA(IP1_21_20, D15),
+ PINMUX_IPSR_GPSR(IP1_21_20, D15),
PINMUX_IPSR_MSEL(IP1_21_20, SCIFA1_TXD, SEL_SCIFA1_0),
PINMUX_IPSR_MSEL(IP1_21_20, IIC0_SDA_B, SEL_IIC00_1),
- PINMUX_IPSR_DATA(IP1_23_22, A0),
- PINMUX_IPSR_DATA(IP1_23_22, SCIFB1_SCK),
- PINMUX_IPSR_DATA(IP1_23_22, PWM3_B),
- PINMUX_IPSR_DATA(IP1_24, A1),
- PINMUX_IPSR_DATA(IP1_24, SCIFB1_TXD),
- PINMUX_IPSR_DATA(IP1_26, A3),
- PINMUX_IPSR_DATA(IP1_26, SCIFB0_SCK),
- PINMUX_IPSR_DATA(IP1_27, A4),
- PINMUX_IPSR_DATA(IP1_27, SCIFB0_TXD),
- PINMUX_IPSR_DATA(IP1_29_28, A5),
- PINMUX_IPSR_DATA(IP1_29_28, SCIFB0_RXD),
- PINMUX_IPSR_DATA(IP1_29_28, PWM4_B),
- PINMUX_IPSR_DATA(IP1_29_28, TPUTO3_C),
- PINMUX_IPSR_DATA(IP1_31_30, A6),
- PINMUX_IPSR_DATA(IP1_31_30, SCIFB0_CTS_N),
+ PINMUX_IPSR_GPSR(IP1_23_22, A0),
+ PINMUX_IPSR_GPSR(IP1_23_22, SCIFB1_SCK),
+ PINMUX_IPSR_GPSR(IP1_23_22, PWM3_B),
+ PINMUX_IPSR_GPSR(IP1_24, A1),
+ PINMUX_IPSR_GPSR(IP1_24, SCIFB1_TXD),
+ PINMUX_IPSR_GPSR(IP1_26, A3),
+ PINMUX_IPSR_GPSR(IP1_26, SCIFB0_SCK),
+ PINMUX_IPSR_GPSR(IP1_27, A4),
+ PINMUX_IPSR_GPSR(IP1_27, SCIFB0_TXD),
+ PINMUX_IPSR_GPSR(IP1_29_28, A5),
+ PINMUX_IPSR_GPSR(IP1_29_28, SCIFB0_RXD),
+ PINMUX_IPSR_GPSR(IP1_29_28, PWM4_B),
+ PINMUX_IPSR_GPSR(IP1_29_28, TPUTO3_C),
+ PINMUX_IPSR_GPSR(IP1_31_30, A6),
+ PINMUX_IPSR_GPSR(IP1_31_30, SCIFB0_CTS_N),
PINMUX_IPSR_MSEL(IP1_31_30, SCIFA4_RXD_B, SEL_SCIFA4_1),
- PINMUX_IPSR_DATA(IP1_31_30, TPUTO2_C),
+ PINMUX_IPSR_GPSR(IP1_31_30, TPUTO2_C),
/* IPSR2 */
- PINMUX_IPSR_DATA(IP2_1_0, A7),
- PINMUX_IPSR_DATA(IP2_1_0, SCIFB0_RTS_N),
+ PINMUX_IPSR_GPSR(IP2_1_0, A7),
+ PINMUX_IPSR_GPSR(IP2_1_0, SCIFB0_RTS_N),
PINMUX_IPSR_MSEL(IP2_1_0, SCIFA4_TXD_B, SEL_SCIFA4_1),
- PINMUX_IPSR_DATA(IP2_3_2, A8),
+ PINMUX_IPSR_GPSR(IP2_3_2, A8),
PINMUX_IPSR_MSEL(IP2_3_2, MSIOF1_RXD, SEL_MSI1_0),
PINMUX_IPSR_MSEL(IP2_3_2, SCIFA0_RXD_B, SEL_SCIFA0_1),
- PINMUX_IPSR_DATA(IP2_5_4, A9),
+ PINMUX_IPSR_GPSR(IP2_5_4, A9),
PINMUX_IPSR_MSEL(IP2_5_4, MSIOF1_TXD, SEL_MSI1_0),
PINMUX_IPSR_MSEL(IP2_5_4, SCIFA0_TXD_B, SEL_SCIFA0_1),
- PINMUX_IPSR_DATA(IP2_7_6, A10),
+ PINMUX_IPSR_GPSR(IP2_7_6, A10),
PINMUX_IPSR_MSEL(IP2_7_6, MSIOF1_SCK, SEL_MSI1_0),
PINMUX_IPSR_MSEL(IP2_7_6, IIC1_SCL_B, SEL_IIC01_1),
- PINMUX_IPSR_DATA(IP2_9_8, A11),
+ PINMUX_IPSR_GPSR(IP2_9_8, A11),
PINMUX_IPSR_MSEL(IP2_9_8, MSIOF1_SYNC, SEL_MSI1_0),
PINMUX_IPSR_MSEL(IP2_9_8, IIC1_SDA_B, SEL_IIC01_1),
- PINMUX_IPSR_DATA(IP2_11_10, A12),
+ PINMUX_IPSR_GPSR(IP2_11_10, A12),
PINMUX_IPSR_MSEL(IP2_11_10, MSIOF1_SS1, SEL_MSI1_0),
PINMUX_IPSR_MSEL(IP2_11_10, SCIFA5_RXD_B, SEL_SCIFA5_1),
- PINMUX_IPSR_DATA(IP2_13_12, A13),
+ PINMUX_IPSR_GPSR(IP2_13_12, A13),
PINMUX_IPSR_MSEL(IP2_13_12, MSIOF1_SS2, SEL_MSI1_0),
PINMUX_IPSR_MSEL(IP2_13_12, SCIFA5_TXD_B, SEL_SCIFA5_1),
- PINMUX_IPSR_DATA(IP2_15_14, A14),
+ PINMUX_IPSR_GPSR(IP2_15_14, A14),
PINMUX_IPSR_MSEL(IP2_15_14, MSIOF2_RXD, SEL_MSI2_0),
PINMUX_IPSR_MSEL(IP2_15_14, HSCIF0_HRX_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP2_15_14, DREQ1_N, SEL_LBS_0),
- PINMUX_IPSR_DATA(IP2_17_16, A15),
+ PINMUX_IPSR_GPSR(IP2_17_16, A15),
PINMUX_IPSR_MSEL(IP2_17_16, MSIOF2_TXD, SEL_MSI2_0),
PINMUX_IPSR_MSEL(IP2_17_16, HSCIF0_HTX_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP2_17_16, DACK1, SEL_LBS_0),
- PINMUX_IPSR_DATA(IP2_20_18, A16),
+ PINMUX_IPSR_GPSR(IP2_20_18, A16),
PINMUX_IPSR_MSEL(IP2_20_18, MSIOF2_SCK, SEL_MSI2_0),
PINMUX_IPSR_MSEL(IP2_20_18, HSCIF0_HSCK_B, SEL_HSCIF0_1),
PINMUX_IPSR_MSEL(IP2_20_18, SPEEDIN, SEL_RSP_0),
PINMUX_IPSR_MSEL(IP2_20_18, VSP, SEL_SPDM_0),
PINMUX_IPSR_MSEL(IP2_20_18, CAN_CLK_C, SEL_CAN_2),
- PINMUX_IPSR_DATA(IP2_20_18, TPUTO2_B),
- PINMUX_IPSR_DATA(IP2_23_21, A17),
+ PINMUX_IPSR_GPSR(IP2_20_18, TPUTO2_B),
+ PINMUX_IPSR_GPSR(IP2_23_21, A17),
PINMUX_IPSR_MSEL(IP2_23_21, MSIOF2_SYNC, SEL_MSI2_0),
PINMUX_IPSR_MSEL(IP2_23_21, SCIF4_RXD_E, SEL_SCIF4_4),
PINMUX_IPSR_MSEL(IP2_23_21, CAN1_RX_B, SEL_CAN1_1),
PINMUX_IPSR_MSEL(IP2_23_21, AVB_AVTP_CAPTURE_B, SEL_AVB_1),
- PINMUX_IPSR_DATA(IP2_26_24, A18),
+ PINMUX_IPSR_GPSR(IP2_26_24, A18),
PINMUX_IPSR_MSEL(IP2_26_24, MSIOF2_SS1, SEL_MSI2_0),
PINMUX_IPSR_MSEL(IP2_26_24, SCIF4_TXD_E, SEL_SCIF4_4),
PINMUX_IPSR_MSEL(IP2_26_24, CAN1_TX_B, SEL_CAN1_1),
PINMUX_IPSR_MSEL(IP2_26_24, AVB_AVTP_MATCH_B, SEL_AVB_1),
- PINMUX_IPSR_DATA(IP2_29_27, A19),
+ PINMUX_IPSR_GPSR(IP2_29_27, A19),
PINMUX_IPSR_MSEL(IP2_29_27, MSIOF2_SS2, SEL_MSI2_0),
- PINMUX_IPSR_DATA(IP2_29_27, PWM4),
- PINMUX_IPSR_DATA(IP2_29_27, TPUTO2),
- PINMUX_IPSR_DATA(IP2_29_27, MOUT0),
- PINMUX_IPSR_DATA(IP2_31_30, A20),
- PINMUX_IPSR_DATA(IP2_31_30, SPCLK),
- PINMUX_IPSR_DATA(IP2_29_27, MOUT1),
+ PINMUX_IPSR_GPSR(IP2_29_27, PWM4),
+ PINMUX_IPSR_GPSR(IP2_29_27, TPUTO2),
+ PINMUX_IPSR_GPSR(IP2_29_27, MOUT0),
+ PINMUX_IPSR_GPSR(IP2_31_30, A20),
+ PINMUX_IPSR_GPSR(IP2_31_30, SPCLK),
+ PINMUX_IPSR_GPSR(IP2_29_27, MOUT1),
/* IPSR3 */
- PINMUX_IPSR_DATA(IP3_1_0, A21),
- PINMUX_IPSR_DATA(IP3_1_0, MOSI_IO0),
- PINMUX_IPSR_DATA(IP3_1_0, MOUT2),
- PINMUX_IPSR_DATA(IP3_3_2, A22),
- PINMUX_IPSR_DATA(IP3_3_2, MISO_IO1),
- PINMUX_IPSR_DATA(IP3_3_2, MOUT5),
- PINMUX_IPSR_DATA(IP3_3_2, ATADIR1_N),
- PINMUX_IPSR_DATA(IP3_5_4, A23),
- PINMUX_IPSR_DATA(IP3_5_4, IO2),
- PINMUX_IPSR_DATA(IP3_5_4, MOUT6),
- PINMUX_IPSR_DATA(IP3_5_4, ATAWR1_N),
- PINMUX_IPSR_DATA(IP3_7_6, A24),
- PINMUX_IPSR_DATA(IP3_7_6, IO3),
- PINMUX_IPSR_DATA(IP3_7_6, EX_WAIT2),
- PINMUX_IPSR_DATA(IP3_9_8, A25),
- PINMUX_IPSR_DATA(IP3_9_8, SSL),
- PINMUX_IPSR_DATA(IP3_9_8, ATARD1_N),
- PINMUX_IPSR_DATA(IP3_10, CS0_N),
- PINMUX_IPSR_DATA(IP3_10, VI1_DATA8),
- PINMUX_IPSR_DATA(IP3_11, CS1_N_A26),
- PINMUX_IPSR_DATA(IP3_11, VI1_DATA9),
- PINMUX_IPSR_DATA(IP3_12, EX_CS0_N),
- PINMUX_IPSR_DATA(IP3_12, VI1_DATA10),
- PINMUX_IPSR_DATA(IP3_14_13, EX_CS1_N),
- PINMUX_IPSR_DATA(IP3_14_13, TPUTO3_B),
- PINMUX_IPSR_DATA(IP3_14_13, SCIFB2_RXD),
- PINMUX_IPSR_DATA(IP3_14_13, VI1_DATA11),
- PINMUX_IPSR_DATA(IP3_17_15, EX_CS2_N),
- PINMUX_IPSR_DATA(IP3_17_15, PWM0),
+ PINMUX_IPSR_GPSR(IP3_1_0, A21),
+ PINMUX_IPSR_GPSR(IP3_1_0, MOSI_IO0),
+ PINMUX_IPSR_GPSR(IP3_1_0, MOUT2),
+ PINMUX_IPSR_GPSR(IP3_3_2, A22),
+ PINMUX_IPSR_GPSR(IP3_3_2, MISO_IO1),
+ PINMUX_IPSR_GPSR(IP3_3_2, MOUT5),
+ PINMUX_IPSR_GPSR(IP3_3_2, ATADIR1_N),
+ PINMUX_IPSR_GPSR(IP3_5_4, A23),
+ PINMUX_IPSR_GPSR(IP3_5_4, IO2),
+ PINMUX_IPSR_GPSR(IP3_5_4, MOUT6),
+ PINMUX_IPSR_GPSR(IP3_5_4, ATAWR1_N),
+ PINMUX_IPSR_GPSR(IP3_7_6, A24),
+ PINMUX_IPSR_GPSR(IP3_7_6, IO3),
+ PINMUX_IPSR_GPSR(IP3_7_6, EX_WAIT2),
+ PINMUX_IPSR_GPSR(IP3_9_8, A25),
+ PINMUX_IPSR_GPSR(IP3_9_8, SSL),
+ PINMUX_IPSR_GPSR(IP3_9_8, ATARD1_N),
+ PINMUX_IPSR_GPSR(IP3_10, CS0_N),
+ PINMUX_IPSR_GPSR(IP3_10, VI1_DATA8),
+ PINMUX_IPSR_GPSR(IP3_11, CS1_N_A26),
+ PINMUX_IPSR_GPSR(IP3_11, VI1_DATA9),
+ PINMUX_IPSR_GPSR(IP3_12, EX_CS0_N),
+ PINMUX_IPSR_GPSR(IP3_12, VI1_DATA10),
+ PINMUX_IPSR_GPSR(IP3_14_13, EX_CS1_N),
+ PINMUX_IPSR_GPSR(IP3_14_13, TPUTO3_B),
+ PINMUX_IPSR_GPSR(IP3_14_13, SCIFB2_RXD),
+ PINMUX_IPSR_GPSR(IP3_14_13, VI1_DATA11),
+ PINMUX_IPSR_GPSR(IP3_17_15, EX_CS2_N),
+ PINMUX_IPSR_GPSR(IP3_17_15, PWM0),
PINMUX_IPSR_MSEL(IP3_17_15, SCIF4_RXD_C, SEL_SCIF4_2),
PINMUX_IPSR_MSEL(IP3_17_15, TS_SDATA_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP3_17_15, RIF0_SYNC, SEL_DR0_0),
- PINMUX_IPSR_DATA(IP3_17_15, TPUTO3),
- PINMUX_IPSR_DATA(IP3_17_15, SCIFB2_TXD),
+ PINMUX_IPSR_GPSR(IP3_17_15, TPUTO3),
+ PINMUX_IPSR_GPSR(IP3_17_15, SCIFB2_TXD),
PINMUX_IPSR_MSEL(IP3_17_15, SDATA_B, SEL_FSN_1),
- PINMUX_IPSR_DATA(IP3_20_18, EX_CS3_N),
+ PINMUX_IPSR_GPSR(IP3_20_18, EX_CS3_N),
PINMUX_IPSR_MSEL(IP3_20_18, SCIFA2_SCK, SEL_SCIFA2_0),
PINMUX_IPSR_MSEL(IP3_20_18, SCIF4_TXD_C, SEL_SCIF4_2),
PINMUX_IPSR_MSEL(IP3_20_18, TS_SCK_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP3_20_18, RIF0_CLK, SEL_DR0_0),
PINMUX_IPSR_MSEL(IP3_20_18, BPFCLK, SEL_DARC_0),
- PINMUX_IPSR_DATA(IP3_20_18, SCIFB2_SCK),
+ PINMUX_IPSR_GPSR(IP3_20_18, SCIFB2_SCK),
PINMUX_IPSR_MSEL(IP3_20_18, MDATA_B, SEL_FSN_1),
- PINMUX_IPSR_DATA(IP3_23_21, EX_CS4_N),
+ PINMUX_IPSR_GPSR(IP3_23_21, EX_CS4_N),
PINMUX_IPSR_MSEL(IP3_23_21, SCIFA2_RXD, SEL_SCIFA2_0),
PINMUX_IPSR_MSEL(IP3_23_21, I2C2_SCL_E, SEL_I2C02_4),
PINMUX_IPSR_MSEL(IP3_23_21, TS_SDEN_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP3_23_21, RIF0_D0, SEL_DR0_0),
PINMUX_IPSR_MSEL(IP3_23_21, FMCLK, SEL_DARC_0),
- PINMUX_IPSR_DATA(IP3_23_21, SCIFB2_CTS_N),
+ PINMUX_IPSR_GPSR(IP3_23_21, SCIFB2_CTS_N),
PINMUX_IPSR_MSEL(IP3_23_21, SCKZ_B, SEL_FSN_1),
- PINMUX_IPSR_DATA(IP3_26_24, EX_CS5_N),
+ PINMUX_IPSR_GPSR(IP3_26_24, EX_CS5_N),
PINMUX_IPSR_MSEL(IP3_26_24, SCIFA2_TXD, SEL_SCIFA2_0),
PINMUX_IPSR_MSEL(IP3_26_24, I2C2_SDA_E, SEL_I2C02_4),
PINMUX_IPSR_MSEL(IP3_26_24, TS_SPSYNC_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP3_26_24, RIF0_D1, SEL_DR1_0),
PINMUX_IPSR_MSEL(IP3_26_24, FMIN, SEL_DARC_0),
- PINMUX_IPSR_DATA(IP3_26_24, SCIFB2_RTS_N),
+ PINMUX_IPSR_GPSR(IP3_26_24, SCIFB2_RTS_N),
PINMUX_IPSR_MSEL(IP3_26_24, STM_N_B, SEL_FSN_1),
- PINMUX_IPSR_DATA(IP3_29_27, BS_N),
- PINMUX_IPSR_DATA(IP3_29_27, DRACK0),
- PINMUX_IPSR_DATA(IP3_29_27, PWM1_C),
- PINMUX_IPSR_DATA(IP3_29_27, TPUTO0_C),
- PINMUX_IPSR_DATA(IP3_29_27, ATACS01_N),
+ PINMUX_IPSR_GPSR(IP3_29_27, BS_N),
+ PINMUX_IPSR_GPSR(IP3_29_27, DRACK0),
+ PINMUX_IPSR_GPSR(IP3_29_27, PWM1_C),
+ PINMUX_IPSR_GPSR(IP3_29_27, TPUTO0_C),
+ PINMUX_IPSR_GPSR(IP3_29_27, ATACS01_N),
PINMUX_IPSR_MSEL(IP3_29_27, MTS_N_B, SEL_FSN_1),
- PINMUX_IPSR_DATA(IP3_30, RD_N),
- PINMUX_IPSR_DATA(IP3_30, ATACS11_N),
- PINMUX_IPSR_DATA(IP3_31, RD_WR_N),
- PINMUX_IPSR_DATA(IP3_31, ATAG1_N),
+ PINMUX_IPSR_GPSR(IP3_30, RD_N),
+ PINMUX_IPSR_GPSR(IP3_30, ATACS11_N),
+ PINMUX_IPSR_GPSR(IP3_31, RD_WR_N),
+ PINMUX_IPSR_GPSR(IP3_31, ATAG1_N),
/* IPSR4 */
- PINMUX_IPSR_DATA(IP4_1_0, EX_WAIT0),
+ PINMUX_IPSR_GPSR(IP4_1_0, EX_WAIT0),
PINMUX_IPSR_MSEL(IP4_1_0, CAN_CLK_B, SEL_CAN_1),
PINMUX_IPSR_MSEL(IP4_1_0, SCIF_CLK, SEL_SCIF0_0),
- PINMUX_IPSR_DATA(IP4_1_0, PWMFSW0),
- PINMUX_IPSR_DATA(IP4_4_2, DU0_DR0),
- PINMUX_IPSR_DATA(IP4_4_2, LCDOUT16),
+ PINMUX_IPSR_GPSR(IP4_1_0, PWMFSW0),
+ PINMUX_IPSR_GPSR(IP4_4_2, DU0_DR0),
+ PINMUX_IPSR_GPSR(IP4_4_2, LCDOUT16),
PINMUX_IPSR_MSEL(IP4_4_2, SCIF5_RXD_C, SEL_SCIF5_2),
PINMUX_IPSR_MSEL(IP4_4_2, I2C2_SCL_D, SEL_I2C02_3),
- PINMUX_IPSR_DATA(IP4_4_2, CC50_STATE0),
- PINMUX_IPSR_DATA(IP4_7_5, DU0_DR1),
- PINMUX_IPSR_DATA(IP4_7_5, LCDOUT17),
+ PINMUX_IPSR_GPSR(IP4_4_2, CC50_STATE0),
+ PINMUX_IPSR_GPSR(IP4_7_5, DU0_DR1),
+ PINMUX_IPSR_GPSR(IP4_7_5, LCDOUT17),
PINMUX_IPSR_MSEL(IP4_7_5, SCIF5_TXD_C, SEL_SCIF5_2),
PINMUX_IPSR_MSEL(IP4_7_5, I2C2_SDA_D, SEL_I2C02_3),
- PINMUX_IPSR_DATA(IP4_9_8, CC50_STATE1),
- PINMUX_IPSR_DATA(IP4_9_8, DU0_DR2),
- PINMUX_IPSR_DATA(IP4_9_8, LCDOUT18),
- PINMUX_IPSR_DATA(IP4_9_8, CC50_STATE2),
- PINMUX_IPSR_DATA(IP4_11_10, DU0_DR3),
- PINMUX_IPSR_DATA(IP4_11_10, LCDOUT19),
- PINMUX_IPSR_DATA(IP4_11_10, CC50_STATE3),
- PINMUX_IPSR_DATA(IP4_13_12, DU0_DR4),
- PINMUX_IPSR_DATA(IP4_13_12, LCDOUT20),
- PINMUX_IPSR_DATA(IP4_13_12, CC50_STATE4),
- PINMUX_IPSR_DATA(IP4_15_14, DU0_DR5),
- PINMUX_IPSR_DATA(IP4_15_14, LCDOUT21),
- PINMUX_IPSR_DATA(IP4_15_14, CC50_STATE5),
- PINMUX_IPSR_DATA(IP4_17_16, DU0_DR6),
- PINMUX_IPSR_DATA(IP4_17_16, LCDOUT22),
- PINMUX_IPSR_DATA(IP4_17_16, CC50_STATE6),
- PINMUX_IPSR_DATA(IP4_19_18, DU0_DR7),
- PINMUX_IPSR_DATA(IP4_19_18, LCDOUT23),
- PINMUX_IPSR_DATA(IP4_19_18, CC50_STATE7),
- PINMUX_IPSR_DATA(IP4_22_20, DU0_DG0),
- PINMUX_IPSR_DATA(IP4_22_20, LCDOUT8),
+ PINMUX_IPSR_GPSR(IP4_9_8, CC50_STATE1),
+ PINMUX_IPSR_GPSR(IP4_9_8, DU0_DR2),
+ PINMUX_IPSR_GPSR(IP4_9_8, LCDOUT18),
+ PINMUX_IPSR_GPSR(IP4_9_8, CC50_STATE2),
+ PINMUX_IPSR_GPSR(IP4_11_10, DU0_DR3),
+ PINMUX_IPSR_GPSR(IP4_11_10, LCDOUT19),
+ PINMUX_IPSR_GPSR(IP4_11_10, CC50_STATE3),
+ PINMUX_IPSR_GPSR(IP4_13_12, DU0_DR4),
+ PINMUX_IPSR_GPSR(IP4_13_12, LCDOUT20),
+ PINMUX_IPSR_GPSR(IP4_13_12, CC50_STATE4),
+ PINMUX_IPSR_GPSR(IP4_15_14, DU0_DR5),
+ PINMUX_IPSR_GPSR(IP4_15_14, LCDOUT21),
+ PINMUX_IPSR_GPSR(IP4_15_14, CC50_STATE5),
+ PINMUX_IPSR_GPSR(IP4_17_16, DU0_DR6),
+ PINMUX_IPSR_GPSR(IP4_17_16, LCDOUT22),
+ PINMUX_IPSR_GPSR(IP4_17_16, CC50_STATE6),
+ PINMUX_IPSR_GPSR(IP4_19_18, DU0_DR7),
+ PINMUX_IPSR_GPSR(IP4_19_18, LCDOUT23),
+ PINMUX_IPSR_GPSR(IP4_19_18, CC50_STATE7),
+ PINMUX_IPSR_GPSR(IP4_22_20, DU0_DG0),
+ PINMUX_IPSR_GPSR(IP4_22_20, LCDOUT8),
PINMUX_IPSR_MSEL(IP4_22_20, SCIFA0_RXD_C, SEL_SCIFA0_2),
PINMUX_IPSR_MSEL(IP4_22_20, I2C3_SCL_D, SEL_I2C03_3),
- PINMUX_IPSR_DATA(IP4_22_20, CC50_STATE8),
- PINMUX_IPSR_DATA(IP4_25_23, DU0_DG1),
- PINMUX_IPSR_DATA(IP4_25_23, LCDOUT9),
+ PINMUX_IPSR_GPSR(IP4_22_20, CC50_STATE8),
+ PINMUX_IPSR_GPSR(IP4_25_23, DU0_DG1),
+ PINMUX_IPSR_GPSR(IP4_25_23, LCDOUT9),
PINMUX_IPSR_MSEL(IP4_25_23, SCIFA0_TXD_C, SEL_SCIFA0_2),
PINMUX_IPSR_MSEL(IP4_25_23, I2C3_SDA_D, SEL_I2C03_3),
- PINMUX_IPSR_DATA(IP4_25_23, CC50_STATE9),
- PINMUX_IPSR_DATA(IP4_27_26, DU0_DG2),
- PINMUX_IPSR_DATA(IP4_27_26, LCDOUT10),
- PINMUX_IPSR_DATA(IP4_27_26, CC50_STATE10),
- PINMUX_IPSR_DATA(IP4_29_28, DU0_DG3),
- PINMUX_IPSR_DATA(IP4_29_28, LCDOUT11),
- PINMUX_IPSR_DATA(IP4_29_28, CC50_STATE11),
- PINMUX_IPSR_DATA(IP4_31_30, DU0_DG4),
- PINMUX_IPSR_DATA(IP4_31_30, LCDOUT12),
- PINMUX_IPSR_DATA(IP4_31_30, CC50_STATE12),
+ PINMUX_IPSR_GPSR(IP4_25_23, CC50_STATE9),
+ PINMUX_IPSR_GPSR(IP4_27_26, DU0_DG2),
+ PINMUX_IPSR_GPSR(IP4_27_26, LCDOUT10),
+ PINMUX_IPSR_GPSR(IP4_27_26, CC50_STATE10),
+ PINMUX_IPSR_GPSR(IP4_29_28, DU0_DG3),
+ PINMUX_IPSR_GPSR(IP4_29_28, LCDOUT11),
+ PINMUX_IPSR_GPSR(IP4_29_28, CC50_STATE11),
+ PINMUX_IPSR_GPSR(IP4_31_30, DU0_DG4),
+ PINMUX_IPSR_GPSR(IP4_31_30, LCDOUT12),
+ PINMUX_IPSR_GPSR(IP4_31_30, CC50_STATE12),
/* IPSR5 */
- PINMUX_IPSR_DATA(IP5_1_0, DU0_DG5),
- PINMUX_IPSR_DATA(IP5_1_0, LCDOUT13),
- PINMUX_IPSR_DATA(IP5_1_0, CC50_STATE13),
- PINMUX_IPSR_DATA(IP5_3_2, DU0_DG6),
- PINMUX_IPSR_DATA(IP5_3_2, LCDOUT14),
- PINMUX_IPSR_DATA(IP5_3_2, CC50_STATE14),
- PINMUX_IPSR_DATA(IP5_5_4, DU0_DG7),
- PINMUX_IPSR_DATA(IP5_5_4, LCDOUT15),
- PINMUX_IPSR_DATA(IP5_5_4, CC50_STATE15),
- PINMUX_IPSR_DATA(IP5_8_6, DU0_DB0),
- PINMUX_IPSR_DATA(IP5_8_6, LCDOUT0),
+ PINMUX_IPSR_GPSR(IP5_1_0, DU0_DG5),
+ PINMUX_IPSR_GPSR(IP5_1_0, LCDOUT13),
+ PINMUX_IPSR_GPSR(IP5_1_0, CC50_STATE13),
+ PINMUX_IPSR_GPSR(IP5_3_2, DU0_DG6),
+ PINMUX_IPSR_GPSR(IP5_3_2, LCDOUT14),
+ PINMUX_IPSR_GPSR(IP5_3_2, CC50_STATE14),
+ PINMUX_IPSR_GPSR(IP5_5_4, DU0_DG7),
+ PINMUX_IPSR_GPSR(IP5_5_4, LCDOUT15),
+ PINMUX_IPSR_GPSR(IP5_5_4, CC50_STATE15),
+ PINMUX_IPSR_GPSR(IP5_8_6, DU0_DB0),
+ PINMUX_IPSR_GPSR(IP5_8_6, LCDOUT0),
PINMUX_IPSR_MSEL(IP5_8_6, SCIFA4_RXD_C, SEL_SCIFA4_2),
PINMUX_IPSR_MSEL(IP5_8_6, I2C4_SCL_D, SEL_I2C04_3),
PINMUX_IPSR_MSEL(IP7_8_6, CAN0_RX_C, SEL_CAN0_2),
- PINMUX_IPSR_DATA(IP5_8_6, CC50_STATE16),
- PINMUX_IPSR_DATA(IP5_11_9, DU0_DB1),
- PINMUX_IPSR_DATA(IP5_11_9, LCDOUT1),
+ PINMUX_IPSR_GPSR(IP5_8_6, CC50_STATE16),
+ PINMUX_IPSR_GPSR(IP5_11_9, DU0_DB1),
+ PINMUX_IPSR_GPSR(IP5_11_9, LCDOUT1),
PINMUX_IPSR_MSEL(IP5_11_9, SCIFA4_TXD_C, SEL_SCIFA4_2),
PINMUX_IPSR_MSEL(IP5_11_9, I2C4_SDA_D, SEL_I2C04_3),
PINMUX_IPSR_MSEL(IP5_11_9, CAN0_TX_C, SEL_CAN0_2),
- PINMUX_IPSR_DATA(IP5_11_9, CC50_STATE17),
- PINMUX_IPSR_DATA(IP5_13_12, DU0_DB2),
- PINMUX_IPSR_DATA(IP5_13_12, LCDOUT2),
- PINMUX_IPSR_DATA(IP5_13_12, CC50_STATE18),
- PINMUX_IPSR_DATA(IP5_15_14, DU0_DB3),
- PINMUX_IPSR_DATA(IP5_15_14, LCDOUT3),
- PINMUX_IPSR_DATA(IP5_15_14, CC50_STATE19),
- PINMUX_IPSR_DATA(IP5_17_16, DU0_DB4),
- PINMUX_IPSR_DATA(IP5_17_16, LCDOUT4),
- PINMUX_IPSR_DATA(IP5_17_16, CC50_STATE20),
- PINMUX_IPSR_DATA(IP5_19_18, DU0_DB5),
- PINMUX_IPSR_DATA(IP5_19_18, LCDOUT5),
- PINMUX_IPSR_DATA(IP5_19_18, CC50_STATE21),
- PINMUX_IPSR_DATA(IP5_21_20, DU0_DB6),
- PINMUX_IPSR_DATA(IP5_21_20, LCDOUT6),
- PINMUX_IPSR_DATA(IP5_21_20, CC50_STATE22),
- PINMUX_IPSR_DATA(IP5_23_22, DU0_DB7),
- PINMUX_IPSR_DATA(IP5_23_22, LCDOUT7),
- PINMUX_IPSR_DATA(IP5_23_22, CC50_STATE23),
- PINMUX_IPSR_DATA(IP5_25_24, DU0_DOTCLKIN),
- PINMUX_IPSR_DATA(IP5_25_24, QSTVA_QVS),
- PINMUX_IPSR_DATA(IP5_25_24, CC50_STATE24),
- PINMUX_IPSR_DATA(IP5_27_26, DU0_DOTCLKOUT0),
- PINMUX_IPSR_DATA(IP5_27_26, QCLK),
- PINMUX_IPSR_DATA(IP5_27_26, CC50_STATE25),
- PINMUX_IPSR_DATA(IP5_29_28, DU0_DOTCLKOUT1),
- PINMUX_IPSR_DATA(IP5_29_28, QSTVB_QVE),
- PINMUX_IPSR_DATA(IP5_29_28, CC50_STATE26),
- PINMUX_IPSR_DATA(IP5_31_30, DU0_EXHSYNC_DU0_HSYNC),
- PINMUX_IPSR_DATA(IP5_31_30, QSTH_QHS),
- PINMUX_IPSR_DATA(IP5_31_30, CC50_STATE27),
+ PINMUX_IPSR_GPSR(IP5_11_9, CC50_STATE17),
+ PINMUX_IPSR_GPSR(IP5_13_12, DU0_DB2),
+ PINMUX_IPSR_GPSR(IP5_13_12, LCDOUT2),
+ PINMUX_IPSR_GPSR(IP5_13_12, CC50_STATE18),
+ PINMUX_IPSR_GPSR(IP5_15_14, DU0_DB3),
+ PINMUX_IPSR_GPSR(IP5_15_14, LCDOUT3),
+ PINMUX_IPSR_GPSR(IP5_15_14, CC50_STATE19),
+ PINMUX_IPSR_GPSR(IP5_17_16, DU0_DB4),
+ PINMUX_IPSR_GPSR(IP5_17_16, LCDOUT4),
+ PINMUX_IPSR_GPSR(IP5_17_16, CC50_STATE20),
+ PINMUX_IPSR_GPSR(IP5_19_18, DU0_DB5),
+ PINMUX_IPSR_GPSR(IP5_19_18, LCDOUT5),
+ PINMUX_IPSR_GPSR(IP5_19_18, CC50_STATE21),
+ PINMUX_IPSR_GPSR(IP5_21_20, DU0_DB6),
+ PINMUX_IPSR_GPSR(IP5_21_20, LCDOUT6),
+ PINMUX_IPSR_GPSR(IP5_21_20, CC50_STATE22),
+ PINMUX_IPSR_GPSR(IP5_23_22, DU0_DB7),
+ PINMUX_IPSR_GPSR(IP5_23_22, LCDOUT7),
+ PINMUX_IPSR_GPSR(IP5_23_22, CC50_STATE23),
+ PINMUX_IPSR_GPSR(IP5_25_24, DU0_DOTCLKIN),
+ PINMUX_IPSR_GPSR(IP5_25_24, QSTVA_QVS),
+ PINMUX_IPSR_GPSR(IP5_25_24, CC50_STATE24),
+ PINMUX_IPSR_GPSR(IP5_27_26, DU0_DOTCLKOUT0),
+ PINMUX_IPSR_GPSR(IP5_27_26, QCLK),
+ PINMUX_IPSR_GPSR(IP5_27_26, CC50_STATE25),
+ PINMUX_IPSR_GPSR(IP5_29_28, DU0_DOTCLKOUT1),
+ PINMUX_IPSR_GPSR(IP5_29_28, QSTVB_QVE),
+ PINMUX_IPSR_GPSR(IP5_29_28, CC50_STATE26),
+ PINMUX_IPSR_GPSR(IP5_31_30, DU0_EXHSYNC_DU0_HSYNC),
+ PINMUX_IPSR_GPSR(IP5_31_30, QSTH_QHS),
+ PINMUX_IPSR_GPSR(IP5_31_30, CC50_STATE27),
/* IPSR6 */
- PINMUX_IPSR_DATA(IP6_1_0, DU0_EXVSYNC_DU0_VSYNC),
- PINMUX_IPSR_DATA(IP6_1_0, QSTB_QHE),
- PINMUX_IPSR_DATA(IP6_1_0, CC50_STATE28),
- PINMUX_IPSR_DATA(IP6_3_2, DU0_EXODDF_DU0_ODDF_DISP_CDE),
- PINMUX_IPSR_DATA(IP6_3_2, QCPV_QDE),
- PINMUX_IPSR_DATA(IP6_3_2, CC50_STATE29),
- PINMUX_IPSR_DATA(IP6_5_4, DU0_DISP),
- PINMUX_IPSR_DATA(IP6_5_4, QPOLA),
- PINMUX_IPSR_DATA(IP6_5_4, CC50_STATE30),
- PINMUX_IPSR_DATA(IP6_7_6, DU0_CDE),
- PINMUX_IPSR_DATA(IP6_7_6, QPOLB),
- PINMUX_IPSR_DATA(IP6_7_6, CC50_STATE31),
- PINMUX_IPSR_DATA(IP6_8, VI0_CLK),
- PINMUX_IPSR_DATA(IP6_8, AVB_RX_CLK),
- PINMUX_IPSR_DATA(IP6_9, VI0_DATA0_VI0_B0),
- PINMUX_IPSR_DATA(IP6_9, AVB_RX_DV),
- PINMUX_IPSR_DATA(IP6_10, VI0_DATA1_VI0_B1),
- PINMUX_IPSR_DATA(IP6_10, AVB_RXD0),
- PINMUX_IPSR_DATA(IP6_11, VI0_DATA2_VI0_B2),
- PINMUX_IPSR_DATA(IP6_11, AVB_RXD1),
- PINMUX_IPSR_DATA(IP6_12, VI0_DATA3_VI0_B3),
- PINMUX_IPSR_DATA(IP6_12, AVB_RXD2),
- PINMUX_IPSR_DATA(IP6_13, VI0_DATA4_VI0_B4),
- PINMUX_IPSR_DATA(IP6_13, AVB_RXD3),
- PINMUX_IPSR_DATA(IP6_14, VI0_DATA5_VI0_B5),
- PINMUX_IPSR_DATA(IP6_14, AVB_RXD4),
- PINMUX_IPSR_DATA(IP6_15, VI0_DATA6_VI0_B6),
- PINMUX_IPSR_DATA(IP6_15, AVB_RXD5),
- PINMUX_IPSR_DATA(IP6_16, VI0_DATA7_VI0_B7),
- PINMUX_IPSR_DATA(IP6_16, AVB_RXD6),
- PINMUX_IPSR_DATA(IP6_19_17, VI0_CLKENB),
+ PINMUX_IPSR_GPSR(IP6_1_0, DU0_EXVSYNC_DU0_VSYNC),
+ PINMUX_IPSR_GPSR(IP6_1_0, QSTB_QHE),
+ PINMUX_IPSR_GPSR(IP6_1_0, CC50_STATE28),
+ PINMUX_IPSR_GPSR(IP6_3_2, DU0_EXODDF_DU0_ODDF_DISP_CDE),
+ PINMUX_IPSR_GPSR(IP6_3_2, QCPV_QDE),
+ PINMUX_IPSR_GPSR(IP6_3_2, CC50_STATE29),
+ PINMUX_IPSR_GPSR(IP6_5_4, DU0_DISP),
+ PINMUX_IPSR_GPSR(IP6_5_4, QPOLA),
+ PINMUX_IPSR_GPSR(IP6_5_4, CC50_STATE30),
+ PINMUX_IPSR_GPSR(IP6_7_6, DU0_CDE),
+ PINMUX_IPSR_GPSR(IP6_7_6, QPOLB),
+ PINMUX_IPSR_GPSR(IP6_7_6, CC50_STATE31),
+ PINMUX_IPSR_GPSR(IP6_8, VI0_CLK),
+ PINMUX_IPSR_GPSR(IP6_8, AVB_RX_CLK),
+ PINMUX_IPSR_GPSR(IP6_9, VI0_DATA0_VI0_B0),
+ PINMUX_IPSR_GPSR(IP6_9, AVB_RX_DV),
+ PINMUX_IPSR_GPSR(IP6_10, VI0_DATA1_VI0_B1),
+ PINMUX_IPSR_GPSR(IP6_10, AVB_RXD0),
+ PINMUX_IPSR_GPSR(IP6_11, VI0_DATA2_VI0_B2),
+ PINMUX_IPSR_GPSR(IP6_11, AVB_RXD1),
+ PINMUX_IPSR_GPSR(IP6_12, VI0_DATA3_VI0_B3),
+ PINMUX_IPSR_GPSR(IP6_12, AVB_RXD2),
+ PINMUX_IPSR_GPSR(IP6_13, VI0_DATA4_VI0_B4),
+ PINMUX_IPSR_GPSR(IP6_13, AVB_RXD3),
+ PINMUX_IPSR_GPSR(IP6_14, VI0_DATA5_VI0_B5),
+ PINMUX_IPSR_GPSR(IP6_14, AVB_RXD4),
+ PINMUX_IPSR_GPSR(IP6_15, VI0_DATA6_VI0_B6),
+ PINMUX_IPSR_GPSR(IP6_15, AVB_RXD5),
+ PINMUX_IPSR_GPSR(IP6_16, VI0_DATA7_VI0_B7),
+ PINMUX_IPSR_GPSR(IP6_16, AVB_RXD6),
+ PINMUX_IPSR_GPSR(IP6_19_17, VI0_CLKENB),
PINMUX_IPSR_MSEL(IP6_19_17, I2C3_SCL, SEL_I2C03_0),
PINMUX_IPSR_MSEL(IP6_19_17, SCIFA5_RXD_C, SEL_SCIFA5_2),
PINMUX_IPSR_MSEL(IP6_19_17, IETX_C, SEL_IEB_2),
- PINMUX_IPSR_DATA(IP6_19_17, AVB_RXD7),
- PINMUX_IPSR_DATA(IP6_22_20, VI0_FIELD),
+ PINMUX_IPSR_GPSR(IP6_19_17, AVB_RXD7),
+ PINMUX_IPSR_GPSR(IP6_22_20, VI0_FIELD),
PINMUX_IPSR_MSEL(IP6_22_20, I2C3_SDA, SEL_I2C03_0),
PINMUX_IPSR_MSEL(IP6_22_20, SCIFA5_TXD_C, SEL_SCIFA5_2),
PINMUX_IPSR_MSEL(IP6_22_20, IECLK_C, SEL_IEB_2),
- PINMUX_IPSR_DATA(IP6_22_20, AVB_RX_ER),
- PINMUX_IPSR_DATA(IP6_25_23, VI0_HSYNC_N),
+ PINMUX_IPSR_GPSR(IP6_22_20, AVB_RX_ER),
+ PINMUX_IPSR_GPSR(IP6_25_23, VI0_HSYNC_N),
PINMUX_IPSR_MSEL(IP6_25_23, SCIF0_RXD_B, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP6_25_23, I2C0_SCL_C, SEL_I2C00_2),
PINMUX_IPSR_MSEL(IP6_25_23, IERX_C, SEL_IEB_2),
- PINMUX_IPSR_DATA(IP6_25_23, AVB_COL),
- PINMUX_IPSR_DATA(IP6_28_26, VI0_VSYNC_N),
+ PINMUX_IPSR_GPSR(IP6_25_23, AVB_COL),
+ PINMUX_IPSR_GPSR(IP6_28_26, VI0_VSYNC_N),
PINMUX_IPSR_MSEL(IP6_28_26, SCIF0_TXD_B, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP6_28_26, I2C0_SDA_C, SEL_I2C00_2),
PINMUX_IPSR_MSEL(IP6_28_26, AUDIO_CLKOUT_B, SEL_ADG_1),
- PINMUX_IPSR_DATA(IP6_28_26, AVB_TX_EN),
+ PINMUX_IPSR_GPSR(IP6_28_26, AVB_TX_EN),
PINMUX_IPSR_MSEL(IP6_31_29, ETH_MDIO, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP6_31_29, VI0_G0),
+ PINMUX_IPSR_GPSR(IP6_31_29, VI0_G0),
PINMUX_IPSR_MSEL(IP6_31_29, MSIOF2_RXD_B, SEL_MSI2_1),
PINMUX_IPSR_MSEL(IP6_31_29, IIC0_SCL_D, SEL_IIC00_3),
- PINMUX_IPSR_DATA(IP6_31_29, AVB_TX_CLK),
+ PINMUX_IPSR_GPSR(IP6_31_29, AVB_TX_CLK),
PINMUX_IPSR_MSEL(IP6_31_29, ADIDATA, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP6_31_29, AD_DI, SEL_ADI_0),
/* IPSR7 */
PINMUX_IPSR_MSEL(IP7_2_0, ETH_CRS_DV, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_2_0, VI0_G1),
+ PINMUX_IPSR_GPSR(IP7_2_0, VI0_G1),
PINMUX_IPSR_MSEL(IP7_2_0, MSIOF2_TXD_B, SEL_MSI2_1),
PINMUX_IPSR_MSEL(IP7_2_0, IIC0_SDA_D, SEL_IIC00_3),
- PINMUX_IPSR_DATA(IP7_2_0, AVB_TXD0),
+ PINMUX_IPSR_GPSR(IP7_2_0, AVB_TXD0),
PINMUX_IPSR_MSEL(IP7_2_0, ADICS_SAMP, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP7_2_0, AD_DO, SEL_ADI_0),
PINMUX_IPSR_MSEL(IP7_5_3, ETH_RX_ER, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_5_3, VI0_G2),
+ PINMUX_IPSR_GPSR(IP7_5_3, VI0_G2),
PINMUX_IPSR_MSEL(IP7_5_3, MSIOF2_SCK_B, SEL_MSI2_1),
PINMUX_IPSR_MSEL(IP7_5_3, CAN0_RX_B, SEL_CAN0_1),
- PINMUX_IPSR_DATA(IP7_5_3, AVB_TXD1),
+ PINMUX_IPSR_GPSR(IP7_5_3, AVB_TXD1),
PINMUX_IPSR_MSEL(IP7_5_3, ADICLK, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP7_5_3, AD_CLK, SEL_ADI_0),
PINMUX_IPSR_MSEL(IP7_8_6, ETH_RXD0, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_8_6, VI0_G3),
+ PINMUX_IPSR_GPSR(IP7_8_6, VI0_G3),
PINMUX_IPSR_MSEL(IP7_8_6, MSIOF2_SYNC_B, SEL_MSI2_1),
PINMUX_IPSR_MSEL(IP7_8_6, CAN0_TX_B, SEL_CAN0_1),
- PINMUX_IPSR_DATA(IP7_8_6, AVB_TXD2),
+ PINMUX_IPSR_GPSR(IP7_8_6, AVB_TXD2),
PINMUX_IPSR_MSEL(IP7_8_6, ADICHS0, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP7_8_6, AD_NCS_N, SEL_ADI_0),
PINMUX_IPSR_MSEL(IP7_11_9, ETH_RXD1, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_11_9, VI0_G4),
+ PINMUX_IPSR_GPSR(IP7_11_9, VI0_G4),
PINMUX_IPSR_MSEL(IP7_11_9, MSIOF2_SS1_B, SEL_MSI2_1),
PINMUX_IPSR_MSEL(IP7_11_9, SCIF4_RXD_D, SEL_SCIF4_3),
- PINMUX_IPSR_DATA(IP7_11_9, AVB_TXD3),
+ PINMUX_IPSR_GPSR(IP7_11_9, AVB_TXD3),
PINMUX_IPSR_MSEL(IP7_11_9, ADICHS1, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP7_14_12, ETH_LINK, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_14_12, VI0_G5),
+ PINMUX_IPSR_GPSR(IP7_14_12, VI0_G5),
PINMUX_IPSR_MSEL(IP7_14_12, MSIOF2_SS2_B, SEL_MSI2_1),
PINMUX_IPSR_MSEL(IP7_14_12, SCIF4_TXD_D, SEL_SCIF4_3),
- PINMUX_IPSR_DATA(IP7_14_12, AVB_TXD4),
+ PINMUX_IPSR_GPSR(IP7_14_12, AVB_TXD4),
PINMUX_IPSR_MSEL(IP7_14_12, ADICHS2, SEL_RAD_0),
PINMUX_IPSR_MSEL(IP7_17_15, ETH_REFCLK, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_17_15, VI0_G6),
+ PINMUX_IPSR_GPSR(IP7_17_15, VI0_G6),
PINMUX_IPSR_MSEL(IP7_17_15, SCIF2_SCK_C, SEL_SCIF2_2),
- PINMUX_IPSR_DATA(IP7_17_15, AVB_TXD5),
+ PINMUX_IPSR_GPSR(IP7_17_15, AVB_TXD5),
PINMUX_IPSR_MSEL(IP7_17_15, SSI_SCK5_B, SEL_SSI5_1),
PINMUX_IPSR_MSEL(IP7_20_18, ETH_TXD1, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_20_18, VI0_G7),
+ PINMUX_IPSR_GPSR(IP7_20_18, VI0_G7),
PINMUX_IPSR_MSEL(IP7_20_18, SCIF2_RXD_C, SEL_SCIF2_2),
PINMUX_IPSR_MSEL(IP7_20_18, IIC1_SCL_D, SEL_IIC01_3),
- PINMUX_IPSR_DATA(IP7_20_18, AVB_TXD6),
+ PINMUX_IPSR_GPSR(IP7_20_18, AVB_TXD6),
PINMUX_IPSR_MSEL(IP7_20_18, SSI_WS5_B, SEL_SSI5_1),
PINMUX_IPSR_MSEL(IP7_23_21, ETH_TX_EN, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_23_21, VI0_R0),
+ PINMUX_IPSR_GPSR(IP7_23_21, VI0_R0),
PINMUX_IPSR_MSEL(IP7_23_21, SCIF2_TXD_C, SEL_SCIF2_2),
PINMUX_IPSR_MSEL(IP7_23_21, IIC1_SDA_D, SEL_IIC01_3),
- PINMUX_IPSR_DATA(IP7_23_21, AVB_TXD7),
+ PINMUX_IPSR_GPSR(IP7_23_21, AVB_TXD7),
PINMUX_IPSR_MSEL(IP7_23_21, SSI_SDATA5_B, SEL_SSI5_1),
PINMUX_IPSR_MSEL(IP7_26_24, ETH_MAGIC, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_26_24, VI0_R1),
+ PINMUX_IPSR_GPSR(IP7_26_24, VI0_R1),
PINMUX_IPSR_MSEL(IP7_26_24, SCIF3_SCK_B, SEL_SCIF3_1),
- PINMUX_IPSR_DATA(IP7_26_24, AVB_TX_ER),
+ PINMUX_IPSR_GPSR(IP7_26_24, AVB_TX_ER),
PINMUX_IPSR_MSEL(IP7_26_24, SSI_SCK6_B, SEL_SSI6_1),
PINMUX_IPSR_MSEL(IP7_29_27, ETH_TXD0, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP7_29_27, VI0_R2),
+ PINMUX_IPSR_GPSR(IP7_29_27, VI0_R2),
PINMUX_IPSR_MSEL(IP7_29_27, SCIF3_RXD_B, SEL_SCIF3_1),
PINMUX_IPSR_MSEL(IP7_29_27, I2C4_SCL_E, SEL_I2C04_4),
- PINMUX_IPSR_DATA(IP7_29_27, AVB_GTX_CLK),
+ PINMUX_IPSR_GPSR(IP7_29_27, AVB_GTX_CLK),
PINMUX_IPSR_MSEL(IP7_29_27, SSI_WS6_B, SEL_SSI6_1),
- PINMUX_IPSR_DATA(IP7_31, DREQ0_N),
- PINMUX_IPSR_DATA(IP7_31, SCIFB1_RXD),
+ PINMUX_IPSR_GPSR(IP7_31, DREQ0_N),
+ PINMUX_IPSR_GPSR(IP7_31, SCIFB1_RXD),
/* IPSR8 */
PINMUX_IPSR_MSEL(IP8_2_0, ETH_MDC, SEL_ETH_0),
- PINMUX_IPSR_DATA(IP8_2_0, VI0_R3),
+ PINMUX_IPSR_GPSR(IP8_2_0, VI0_R3),
PINMUX_IPSR_MSEL(IP8_2_0, SCIF3_TXD_B, SEL_SCIF3_1),
PINMUX_IPSR_MSEL(IP8_2_0, I2C4_SDA_E, SEL_I2C04_4),
- PINMUX_IPSR_DATA(IP8_2_0, AVB_MDC),
+ PINMUX_IPSR_GPSR(IP8_2_0, AVB_MDC),
PINMUX_IPSR_MSEL(IP8_2_0, SSI_SDATA6_B, SEL_SSI6_1),
PINMUX_IPSR_MSEL(IP8_5_3, HSCIF0_HRX, SEL_HSCIF0_0),
- PINMUX_IPSR_DATA(IP8_5_3, VI0_R4),
+ PINMUX_IPSR_GPSR(IP8_5_3, VI0_R4),
PINMUX_IPSR_MSEL(IP8_5_3, I2C1_SCL_C, SEL_I2C01_2),
PINMUX_IPSR_MSEL(IP8_5_3, AUDIO_CLKA_B, SEL_ADG_1),
- PINMUX_IPSR_DATA(IP8_5_3, AVB_MDIO),
+ PINMUX_IPSR_GPSR(IP8_5_3, AVB_MDIO),
PINMUX_IPSR_MSEL(IP8_5_3, SSI_SCK78_B, SEL_SSI7_1),
PINMUX_IPSR_MSEL(IP8_8_6, HSCIF0_HTX, SEL_HSCIF0_0),
- PINMUX_IPSR_DATA(IP8_8_6, VI0_R5),
+ PINMUX_IPSR_GPSR(IP8_8_6, VI0_R5),
PINMUX_IPSR_MSEL(IP8_8_6, I2C1_SDA_C, SEL_I2C01_2),
PINMUX_IPSR_MSEL(IP8_8_6, AUDIO_CLKB_B, SEL_ADG_1),
- PINMUX_IPSR_DATA(IP8_5_3, AVB_LINK),
+ PINMUX_IPSR_GPSR(IP8_5_3, AVB_LINK),
PINMUX_IPSR_MSEL(IP8_8_6, SSI_WS78_B, SEL_SSI7_1),
- PINMUX_IPSR_DATA(IP8_11_9, HSCIF0_HCTS_N),
- PINMUX_IPSR_DATA(IP8_11_9, VI0_R6),
+ PINMUX_IPSR_GPSR(IP8_11_9, HSCIF0_HCTS_N),
+ PINMUX_IPSR_GPSR(IP8_11_9, VI0_R6),
PINMUX_IPSR_MSEL(IP8_11_9, SCIF0_RXD_D, SEL_SCIF0_3),
PINMUX_IPSR_MSEL(IP8_11_9, I2C0_SCL_E, SEL_I2C00_4),
- PINMUX_IPSR_DATA(IP8_11_9, AVB_MAGIC),
+ PINMUX_IPSR_GPSR(IP8_11_9, AVB_MAGIC),
PINMUX_IPSR_MSEL(IP8_11_9, SSI_SDATA7_B, SEL_SSI7_1),
- PINMUX_IPSR_DATA(IP8_14_12, HSCIF0_HRTS_N),
- PINMUX_IPSR_DATA(IP8_14_12, VI0_R7),
+ PINMUX_IPSR_GPSR(IP8_14_12, HSCIF0_HRTS_N),
+ PINMUX_IPSR_GPSR(IP8_14_12, VI0_R7),
PINMUX_IPSR_MSEL(IP8_14_12, SCIF0_TXD_D, SEL_SCIF0_3),
PINMUX_IPSR_MSEL(IP8_14_12, I2C0_SDA_E, SEL_I2C00_4),
- PINMUX_IPSR_DATA(IP8_14_12, AVB_PHY_INT),
+ PINMUX_IPSR_GPSR(IP8_14_12, AVB_PHY_INT),
PINMUX_IPSR_MSEL(IP8_14_12, SSI_SDATA8_B, SEL_SSI8_1),
PINMUX_IPSR_MSEL(IP8_16_15, HSCIF0_HSCK, SEL_HSCIF0_0),
PINMUX_IPSR_MSEL(IP8_16_15, SCIF_CLK_B, SEL_SCIF0_1),
- PINMUX_IPSR_DATA(IP8_16_15, AVB_CRS),
+ PINMUX_IPSR_GPSR(IP8_16_15, AVB_CRS),
PINMUX_IPSR_MSEL(IP8_16_15, AUDIO_CLKC_B, SEL_ADG_1),
PINMUX_IPSR_MSEL(IP8_19_17, I2C0_SCL, SEL_I2C00_0),
PINMUX_IPSR_MSEL(IP8_19_17, SCIF0_RXD_C, SEL_SCIF0_2),
- PINMUX_IPSR_DATA(IP8_19_17, PWM5),
+ PINMUX_IPSR_GPSR(IP8_19_17, PWM5),
PINMUX_IPSR_MSEL(IP8_19_17, TCLK1_B, SEL_TMU_1),
- PINMUX_IPSR_DATA(IP8_19_17, AVB_GTXREFCLK),
+ PINMUX_IPSR_GPSR(IP8_19_17, AVB_GTXREFCLK),
PINMUX_IPSR_MSEL(IP8_19_17, CAN1_RX_D, SEL_CAN1_3),
- PINMUX_IPSR_DATA(IP8_19_17, TPUTO0_B),
+ PINMUX_IPSR_GPSR(IP8_19_17, TPUTO0_B),
PINMUX_IPSR_MSEL(IP8_22_20, I2C0_SDA, SEL_I2C00_0),
PINMUX_IPSR_MSEL(IP8_22_20, SCIF0_TXD_C, SEL_SCIF0_2),
- PINMUX_IPSR_DATA(IP8_22_20, TPUTO0),
+ PINMUX_IPSR_GPSR(IP8_22_20, TPUTO0),
PINMUX_IPSR_MSEL(IP8_22_20, CAN_CLK, SEL_CAN_0),
- PINMUX_IPSR_DATA(IP8_22_20, DVC_MUTE),
+ PINMUX_IPSR_GPSR(IP8_22_20, DVC_MUTE),
PINMUX_IPSR_MSEL(IP8_22_20, CAN1_TX_D, SEL_CAN1_3),
PINMUX_IPSR_MSEL(IP8_25_23, I2C1_SCL, SEL_I2C01_0),
PINMUX_IPSR_MSEL(IP8_25_23, SCIF4_RXD, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP8_25_23, PWM5_B),
- PINMUX_IPSR_DATA(IP8_25_23, DU1_DR0),
+ PINMUX_IPSR_GPSR(IP8_25_23, PWM5_B),
+ PINMUX_IPSR_GPSR(IP8_25_23, DU1_DR0),
PINMUX_IPSR_MSEL(IP8_25_23, RIF1_SYNC_B, SEL_DR2_1),
PINMUX_IPSR_MSEL(IP8_25_23, TS_SDATA_D, SEL_TSIF0_3),
- PINMUX_IPSR_DATA(IP8_25_23, TPUTO1_B),
+ PINMUX_IPSR_GPSR(IP8_25_23, TPUTO1_B),
PINMUX_IPSR_MSEL(IP8_28_26, I2C1_SDA, SEL_I2C01_0),
PINMUX_IPSR_MSEL(IP8_28_26, SCIF4_TXD, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP8_28_26, IRQ5),
- PINMUX_IPSR_DATA(IP8_28_26, DU1_DR1),
+ PINMUX_IPSR_GPSR(IP8_28_26, IRQ5),
+ PINMUX_IPSR_GPSR(IP8_28_26, DU1_DR1),
PINMUX_IPSR_MSEL(IP8_28_26, RIF1_CLK_B, SEL_DR2_1),
PINMUX_IPSR_MSEL(IP8_28_26, TS_SCK_D, SEL_TSIF0_3),
PINMUX_IPSR_MSEL(IP8_28_26, BPFCLK_C, SEL_DARC_2),
- PINMUX_IPSR_DATA(IP8_31_29, MSIOF0_RXD),
+ PINMUX_IPSR_GPSR(IP8_31_29, MSIOF0_RXD),
PINMUX_IPSR_MSEL(IP8_31_29, SCIF5_RXD, SEL_SCIF5_0),
PINMUX_IPSR_MSEL(IP8_31_29, I2C2_SCL_C, SEL_I2C02_2),
- PINMUX_IPSR_DATA(IP8_31_29, DU1_DR2),
+ PINMUX_IPSR_GPSR(IP8_31_29, DU1_DR2),
PINMUX_IPSR_MSEL(IP8_31_29, RIF1_D0_B, SEL_DR2_1),
PINMUX_IPSR_MSEL(IP8_31_29, TS_SDEN_D, SEL_TSIF0_3),
PINMUX_IPSR_MSEL(IP8_31_29, FMCLK_C, SEL_DARC_2),
PINMUX_IPSR_MSEL(IP8_31_29, RDS_CLK, SEL_RDS_0),
/* IPSR9 */
- PINMUX_IPSR_DATA(IP9_2_0, MSIOF0_TXD),
+ PINMUX_IPSR_GPSR(IP9_2_0, MSIOF0_TXD),
PINMUX_IPSR_MSEL(IP9_2_0, SCIF5_TXD, SEL_SCIF5_0),
PINMUX_IPSR_MSEL(IP9_2_0, I2C2_SDA_C, SEL_I2C02_2),
- PINMUX_IPSR_DATA(IP9_2_0, DU1_DR3),
+ PINMUX_IPSR_GPSR(IP9_2_0, DU1_DR3),
PINMUX_IPSR_MSEL(IP9_2_0, RIF1_D1_B, SEL_DR3_1),
PINMUX_IPSR_MSEL(IP9_2_0, TS_SPSYNC_D, SEL_TSIF0_3),
PINMUX_IPSR_MSEL(IP9_2_0, FMIN_C, SEL_DARC_2),
PINMUX_IPSR_MSEL(IP9_2_0, RDS_DATA, SEL_RDS_0),
- PINMUX_IPSR_DATA(IP9_5_3, MSIOF0_SCK),
- PINMUX_IPSR_DATA(IP9_5_3, IRQ0),
+ PINMUX_IPSR_GPSR(IP9_5_3, MSIOF0_SCK),
+ PINMUX_IPSR_GPSR(IP9_5_3, IRQ0),
PINMUX_IPSR_MSEL(IP9_5_3, TS_SDATA, SEL_TSIF0_0),
- PINMUX_IPSR_DATA(IP9_5_3, DU1_DR4),
+ PINMUX_IPSR_GPSR(IP9_5_3, DU1_DR4),
PINMUX_IPSR_MSEL(IP9_5_3, RIF1_SYNC, SEL_DR2_0),
- PINMUX_IPSR_DATA(IP9_5_3, TPUTO1_C),
- PINMUX_IPSR_DATA(IP9_8_6, MSIOF0_SYNC),
- PINMUX_IPSR_DATA(IP9_8_6, PWM1),
+ PINMUX_IPSR_GPSR(IP9_5_3, TPUTO1_C),
+ PINMUX_IPSR_GPSR(IP9_8_6, MSIOF0_SYNC),
+ PINMUX_IPSR_GPSR(IP9_8_6, PWM1),
PINMUX_IPSR_MSEL(IP9_8_6, TS_SCK, SEL_TSIF0_0),
- PINMUX_IPSR_DATA(IP9_8_6, DU1_DR5),
+ PINMUX_IPSR_GPSR(IP9_8_6, DU1_DR5),
PINMUX_IPSR_MSEL(IP9_8_6, RIF1_CLK, SEL_DR2_0),
PINMUX_IPSR_MSEL(IP9_8_6, BPFCLK_B, SEL_DARC_1),
- PINMUX_IPSR_DATA(IP9_11_9, MSIOF0_SS1),
+ PINMUX_IPSR_GPSR(IP9_11_9, MSIOF0_SS1),
PINMUX_IPSR_MSEL(IP9_11_9, SCIFA0_RXD, SEL_SCIFA0_0),
PINMUX_IPSR_MSEL(IP9_11_9, TS_SDEN, SEL_TSIF0_0),
- PINMUX_IPSR_DATA(IP9_11_9, DU1_DR6),
+ PINMUX_IPSR_GPSR(IP9_11_9, DU1_DR6),
PINMUX_IPSR_MSEL(IP9_11_9, RIF1_D0, SEL_DR2_0),
PINMUX_IPSR_MSEL(IP9_11_9, FMCLK_B, SEL_DARC_1),
PINMUX_IPSR_MSEL(IP9_11_9, RDS_CLK_B, SEL_RDS_1),
- PINMUX_IPSR_DATA(IP9_14_12, MSIOF0_SS2),
+ PINMUX_IPSR_GPSR(IP9_14_12, MSIOF0_SS2),
PINMUX_IPSR_MSEL(IP9_14_12, SCIFA0_TXD, SEL_SCIFA0_0),
PINMUX_IPSR_MSEL(IP9_14_12, TS_SPSYNC, SEL_TSIF0_0),
- PINMUX_IPSR_DATA(IP9_14_12, DU1_DR7),
+ PINMUX_IPSR_GPSR(IP9_14_12, DU1_DR7),
PINMUX_IPSR_MSEL(IP9_14_12, RIF1_D1, SEL_DR3_0),
PINMUX_IPSR_MSEL(IP9_14_12, FMIN_B, SEL_DARC_1),
PINMUX_IPSR_MSEL(IP9_14_12, RDS_DATA_B, SEL_RDS_1),
PINMUX_IPSR_MSEL(IP9_16_15, HSCIF1_HRX, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP9_16_15, I2C4_SCL, SEL_I2C04_0),
- PINMUX_IPSR_DATA(IP9_16_15, PWM6),
- PINMUX_IPSR_DATA(IP9_16_15, DU1_DG0),
+ PINMUX_IPSR_GPSR(IP9_16_15, PWM6),
+ PINMUX_IPSR_GPSR(IP9_16_15, DU1_DG0),
PINMUX_IPSR_MSEL(IP9_18_17, HSCIF1_HTX, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP9_18_17, I2C4_SDA, SEL_I2C04_0),
- PINMUX_IPSR_DATA(IP9_18_17, TPUTO1),
- PINMUX_IPSR_DATA(IP9_18_17, DU1_DG1),
- PINMUX_IPSR_DATA(IP9_21_19, HSCIF1_HSCK),
- PINMUX_IPSR_DATA(IP9_21_19, PWM2),
+ PINMUX_IPSR_GPSR(IP9_18_17, TPUTO1),
+ PINMUX_IPSR_GPSR(IP9_18_17, DU1_DG1),
+ PINMUX_IPSR_GPSR(IP9_21_19, HSCIF1_HSCK),
+ PINMUX_IPSR_GPSR(IP9_21_19, PWM2),
PINMUX_IPSR_MSEL(IP9_21_19, IETX, SEL_IEB_0),
- PINMUX_IPSR_DATA(IP9_21_19, DU1_DG2),
+ PINMUX_IPSR_GPSR(IP9_21_19, DU1_DG2),
PINMUX_IPSR_MSEL(IP9_21_19, REMOCON_B, SEL_RCN_1),
PINMUX_IPSR_MSEL(IP9_21_19, SPEEDIN_B, SEL_RSP_1),
PINMUX_IPSR_MSEL(IP9_21_19, VSP_B, SEL_SPDM_1),
PINMUX_IPSR_MSEL(IP9_24_22, HSCIF1_HCTS_N, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP9_24_22, SCIFA4_RXD, SEL_SCIFA4_0),
PINMUX_IPSR_MSEL(IP9_24_22, IECLK, SEL_IEB_0),
- PINMUX_IPSR_DATA(IP9_24_22, DU1_DG3),
+ PINMUX_IPSR_GPSR(IP9_24_22, DU1_DG3),
PINMUX_IPSR_MSEL(IP9_24_22, SSI_SCK1_B, SEL_SSI1_1),
- PINMUX_IPSR_DATA(IP9_24_22, CAN_DEBUG_HW_TRIGGER),
- PINMUX_IPSR_DATA(IP9_24_22, CC50_STATE32),
+ PINMUX_IPSR_GPSR(IP9_24_22, CAN_DEBUG_HW_TRIGGER),
+ PINMUX_IPSR_GPSR(IP9_24_22, CC50_STATE32),
PINMUX_IPSR_MSEL(IP9_27_25, HSCIF1_HRTS_N, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP9_27_25, SCIFA4_TXD, SEL_SCIFA4_0),
PINMUX_IPSR_MSEL(IP9_27_25, IERX, SEL_IEB_0),
- PINMUX_IPSR_DATA(IP9_27_25, DU1_DG4),
+ PINMUX_IPSR_GPSR(IP9_27_25, DU1_DG4),
PINMUX_IPSR_MSEL(IP9_27_25, SSI_WS1_B, SEL_SSI1_1),
- PINMUX_IPSR_DATA(IP9_27_25, CAN_STEP0),
- PINMUX_IPSR_DATA(IP9_27_25, CC50_STATE33),
+ PINMUX_IPSR_GPSR(IP9_27_25, CAN_STEP0),
+ PINMUX_IPSR_GPSR(IP9_27_25, CC50_STATE33),
PINMUX_IPSR_MSEL(IP9_30_28, SCIF1_SCK, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP9_30_28, PWM3),
+ PINMUX_IPSR_GPSR(IP9_30_28, PWM3),
PINMUX_IPSR_MSEL(IP9_30_28, TCLK2, SEL_TMU_0),
- PINMUX_IPSR_DATA(IP9_30_28, DU1_DG5),
+ PINMUX_IPSR_GPSR(IP9_30_28, DU1_DG5),
PINMUX_IPSR_MSEL(IP9_30_28, SSI_SDATA1_B, SEL_SSI1_1),
- PINMUX_IPSR_DATA(IP9_30_28, CAN_TXCLK),
- PINMUX_IPSR_DATA(IP9_30_28, CC50_STATE34),
+ PINMUX_IPSR_GPSR(IP9_30_28, CAN_TXCLK),
+ PINMUX_IPSR_GPSR(IP9_30_28, CC50_STATE34),
/* IPSR10 */
PINMUX_IPSR_MSEL(IP10_2_0, SCIF1_RXD, SEL_SCIF1_0),
PINMUX_IPSR_MSEL(IP10_2_0, IIC0_SCL, SEL_IIC00_0),
- PINMUX_IPSR_DATA(IP10_2_0, DU1_DG6),
+ PINMUX_IPSR_GPSR(IP10_2_0, DU1_DG6),
PINMUX_IPSR_MSEL(IP10_2_0, SSI_SCK2_B, SEL_SSI2_1),
- PINMUX_IPSR_DATA(IP10_2_0, CAN_DEBUGOUT0),
- PINMUX_IPSR_DATA(IP10_2_0, CC50_STATE35),
+ PINMUX_IPSR_GPSR(IP10_2_0, CAN_DEBUGOUT0),
+ PINMUX_IPSR_GPSR(IP10_2_0, CC50_STATE35),
PINMUX_IPSR_MSEL(IP10_5_3, SCIF1_TXD, SEL_SCIF1_0),
PINMUX_IPSR_MSEL(IP10_5_3, IIC0_SDA, SEL_IIC00_0),
- PINMUX_IPSR_DATA(IP10_5_3, DU1_DG7),
+ PINMUX_IPSR_GPSR(IP10_5_3, DU1_DG7),
PINMUX_IPSR_MSEL(IP10_5_3, SSI_WS2_B, SEL_SSI2_1),
- PINMUX_IPSR_DATA(IP10_5_3, CAN_DEBUGOUT1),
- PINMUX_IPSR_DATA(IP10_5_3, CC50_STATE36),
+ PINMUX_IPSR_GPSR(IP10_5_3, CAN_DEBUGOUT1),
+ PINMUX_IPSR_GPSR(IP10_5_3, CC50_STATE36),
PINMUX_IPSR_MSEL(IP10_8_6, SCIF2_RXD, SEL_SCIF2_0),
PINMUX_IPSR_MSEL(IP10_8_6, IIC1_SCL, SEL_IIC01_0),
- PINMUX_IPSR_DATA(IP10_8_6, DU1_DB0),
+ PINMUX_IPSR_GPSR(IP10_8_6, DU1_DB0),
PINMUX_IPSR_MSEL(IP10_8_6, SSI_SDATA2_B, SEL_SSI2_1),
- PINMUX_IPSR_DATA(IP10_8_6, USB0_EXTLP),
- PINMUX_IPSR_DATA(IP10_8_6, CAN_DEBUGOUT2),
- PINMUX_IPSR_DATA(IP10_8_6, CC50_STATE37),
+ PINMUX_IPSR_GPSR(IP10_8_6, USB0_EXTLP),
+ PINMUX_IPSR_GPSR(IP10_8_6, CAN_DEBUGOUT2),
+ PINMUX_IPSR_GPSR(IP10_8_6, CC50_STATE37),
PINMUX_IPSR_MSEL(IP10_11_9, SCIF2_TXD, SEL_SCIF2_0),
PINMUX_IPSR_MSEL(IP10_11_9, IIC1_SDA, SEL_IIC01_0),
- PINMUX_IPSR_DATA(IP10_11_9, DU1_DB1),
+ PINMUX_IPSR_GPSR(IP10_11_9, DU1_DB1),
PINMUX_IPSR_MSEL(IP10_11_9, SSI_SCK9_B, SEL_SSI9_1),
- PINMUX_IPSR_DATA(IP10_11_9, USB0_OVC1),
- PINMUX_IPSR_DATA(IP10_11_9, CAN_DEBUGOUT3),
- PINMUX_IPSR_DATA(IP10_11_9, CC50_STATE38),
+ PINMUX_IPSR_GPSR(IP10_11_9, USB0_OVC1),
+ PINMUX_IPSR_GPSR(IP10_11_9, CAN_DEBUGOUT3),
+ PINMUX_IPSR_GPSR(IP10_11_9, CC50_STATE38),
PINMUX_IPSR_MSEL(IP10_14_12, SCIF2_SCK, SEL_SCIF2_0),
- PINMUX_IPSR_DATA(IP10_14_12, IRQ1),
- PINMUX_IPSR_DATA(IP10_14_12, DU1_DB2),
+ PINMUX_IPSR_GPSR(IP10_14_12, IRQ1),
+ PINMUX_IPSR_GPSR(IP10_14_12, DU1_DB2),
PINMUX_IPSR_MSEL(IP10_14_12, SSI_WS9_B, SEL_SSI9_1),
- PINMUX_IPSR_DATA(IP10_14_12, USB0_IDIN),
- PINMUX_IPSR_DATA(IP10_14_12, CAN_DEBUGOUT4),
- PINMUX_IPSR_DATA(IP10_14_12, CC50_STATE39),
+ PINMUX_IPSR_GPSR(IP10_14_12, USB0_IDIN),
+ PINMUX_IPSR_GPSR(IP10_14_12, CAN_DEBUGOUT4),
+ PINMUX_IPSR_GPSR(IP10_14_12, CC50_STATE39),
PINMUX_IPSR_MSEL(IP10_17_15, SCIF3_SCK, SEL_SCIF3_0),
- PINMUX_IPSR_DATA(IP10_17_15, IRQ2),
+ PINMUX_IPSR_GPSR(IP10_17_15, IRQ2),
PINMUX_IPSR_MSEL(IP10_17_15, BPFCLK_D, SEL_DARC_3),
- PINMUX_IPSR_DATA(IP10_17_15, DU1_DB3),
+ PINMUX_IPSR_GPSR(IP10_17_15, DU1_DB3),
PINMUX_IPSR_MSEL(IP10_17_15, SSI_SDATA9_B, SEL_SSI9_1),
- PINMUX_IPSR_DATA(IP10_17_15, TANS2),
- PINMUX_IPSR_DATA(IP10_17_15, CAN_DEBUGOUT5),
- PINMUX_IPSR_DATA(IP10_17_15, CC50_OSCOUT),
+ PINMUX_IPSR_GPSR(IP10_17_15, TANS2),
+ PINMUX_IPSR_GPSR(IP10_17_15, CAN_DEBUGOUT5),
+ PINMUX_IPSR_GPSR(IP10_17_15, CC50_OSCOUT),
PINMUX_IPSR_MSEL(IP10_20_18, SCIF3_RXD, SEL_SCIF3_0),
PINMUX_IPSR_MSEL(IP10_20_18, I2C1_SCL_E, SEL_I2C01_4),
PINMUX_IPSR_MSEL(IP10_20_18, FMCLK_D, SEL_DARC_3),
- PINMUX_IPSR_DATA(IP10_20_18, DU1_DB4),
+ PINMUX_IPSR_GPSR(IP10_20_18, DU1_DB4),
PINMUX_IPSR_MSEL(IP10_20_18, AUDIO_CLKA_C, SEL_ADG_2),
PINMUX_IPSR_MSEL(IP10_20_18, SSI_SCK4_B, SEL_SSI4_1),
- PINMUX_IPSR_DATA(IP10_20_18, CAN_DEBUGOUT6),
+ PINMUX_IPSR_GPSR(IP10_20_18, CAN_DEBUGOUT6),
PINMUX_IPSR_MSEL(IP10_20_18, RDS_CLK_C, SEL_RDS_2),
PINMUX_IPSR_MSEL(IP10_23_21, SCIF3_TXD, SEL_SCIF3_0),
PINMUX_IPSR_MSEL(IP10_23_21, I2C1_SDA_E, SEL_I2C01_4),
PINMUX_IPSR_MSEL(IP10_23_21, FMIN_D, SEL_DARC_3),
- PINMUX_IPSR_DATA(IP10_23_21, DU1_DB5),
+ PINMUX_IPSR_GPSR(IP10_23_21, DU1_DB5),
PINMUX_IPSR_MSEL(IP10_23_21, AUDIO_CLKB_C, SEL_ADG_2),
PINMUX_IPSR_MSEL(IP10_23_21, SSI_WS4_B, SEL_SSI4_1),
- PINMUX_IPSR_DATA(IP10_23_21, CAN_DEBUGOUT7),
+ PINMUX_IPSR_GPSR(IP10_23_21, CAN_DEBUGOUT7),
PINMUX_IPSR_MSEL(IP10_23_21, RDS_DATA_C, SEL_RDS_2),
PINMUX_IPSR_MSEL(IP10_26_24, I2C2_SCL, SEL_I2C02_0),
PINMUX_IPSR_MSEL(IP10_26_24, SCIFA5_RXD, SEL_SCIFA5_0),
- PINMUX_IPSR_DATA(IP10_26_24, DU1_DB6),
+ PINMUX_IPSR_GPSR(IP10_26_24, DU1_DB6),
PINMUX_IPSR_MSEL(IP10_26_24, AUDIO_CLKC_C, SEL_ADG_2),
PINMUX_IPSR_MSEL(IP10_26_24, SSI_SDATA4_B, SEL_SSI4_1),
- PINMUX_IPSR_DATA(IP10_26_24, CAN_DEBUGOUT8),
+ PINMUX_IPSR_GPSR(IP10_26_24, CAN_DEBUGOUT8),
PINMUX_IPSR_MSEL(IP10_29_27, I2C2_SDA, SEL_I2C02_0),
PINMUX_IPSR_MSEL(IP10_29_27, SCIFA5_TXD, SEL_SCIFA5_0),
- PINMUX_IPSR_DATA(IP10_29_27, DU1_DB7),
+ PINMUX_IPSR_GPSR(IP10_29_27, DU1_DB7),
PINMUX_IPSR_MSEL(IP10_29_27, AUDIO_CLKOUT_C, SEL_ADG_2),
- PINMUX_IPSR_DATA(IP10_29_27, CAN_DEBUGOUT9),
+ PINMUX_IPSR_GPSR(IP10_29_27, CAN_DEBUGOUT9),
PINMUX_IPSR_MSEL(IP10_31_30, SSI_SCK5, SEL_SSI5_0),
PINMUX_IPSR_MSEL(IP10_31_30, SCIFA3_SCK, SEL_SCIFA3_0),
- PINMUX_IPSR_DATA(IP10_31_30, DU1_DOTCLKIN),
- PINMUX_IPSR_DATA(IP10_31_30, CAN_DEBUGOUT10),
+ PINMUX_IPSR_GPSR(IP10_31_30, DU1_DOTCLKIN),
+ PINMUX_IPSR_GPSR(IP10_31_30, CAN_DEBUGOUT10),
/* IPSR11 */
PINMUX_IPSR_MSEL(IP11_2_0, SSI_WS5, SEL_SSI5_0),
PINMUX_IPSR_MSEL(IP11_2_0, SCIFA3_RXD, SEL_SCIFA3_0),
PINMUX_IPSR_MSEL(IP11_2_0, I2C3_SCL_C, SEL_I2C03_2),
- PINMUX_IPSR_DATA(IP11_2_0, DU1_DOTCLKOUT0),
- PINMUX_IPSR_DATA(IP11_2_0, CAN_DEBUGOUT11),
+ PINMUX_IPSR_GPSR(IP11_2_0, DU1_DOTCLKOUT0),
+ PINMUX_IPSR_GPSR(IP11_2_0, CAN_DEBUGOUT11),
PINMUX_IPSR_MSEL(IP11_5_3, SSI_SDATA5, SEL_SSI5_0),
PINMUX_IPSR_MSEL(IP11_5_3, SCIFA3_TXD, SEL_SCIFA3_0),
PINMUX_IPSR_MSEL(IP11_5_3, I2C3_SDA_C, SEL_I2C03_2),
- PINMUX_IPSR_DATA(IP11_5_3, DU1_DOTCLKOUT1),
- PINMUX_IPSR_DATA(IP11_5_3, CAN_DEBUGOUT12),
+ PINMUX_IPSR_GPSR(IP11_5_3, DU1_DOTCLKOUT1),
+ PINMUX_IPSR_GPSR(IP11_5_3, CAN_DEBUGOUT12),
PINMUX_IPSR_MSEL(IP11_7_6, SSI_SCK6, SEL_SSI6_0),
PINMUX_IPSR_MSEL(IP11_7_6, SCIFA1_SCK_B, SEL_SCIFA1_1),
- PINMUX_IPSR_DATA(IP11_7_6, DU1_EXHSYNC_DU1_HSYNC),
- PINMUX_IPSR_DATA(IP11_7_6, CAN_DEBUGOUT13),
+ PINMUX_IPSR_GPSR(IP11_7_6, DU1_EXHSYNC_DU1_HSYNC),
+ PINMUX_IPSR_GPSR(IP11_7_6, CAN_DEBUGOUT13),
PINMUX_IPSR_MSEL(IP11_10_8, SSI_WS6, SEL_SSI6_0),
PINMUX_IPSR_MSEL(IP11_10_8, SCIFA1_RXD_B, SEL_SCIFA1_1),
PINMUX_IPSR_MSEL(IP11_10_8, I2C4_SCL_C, SEL_I2C04_2),
- PINMUX_IPSR_DATA(IP11_10_8, DU1_EXVSYNC_DU1_VSYNC),
- PINMUX_IPSR_DATA(IP11_10_8, CAN_DEBUGOUT14),
+ PINMUX_IPSR_GPSR(IP11_10_8, DU1_EXVSYNC_DU1_VSYNC),
+ PINMUX_IPSR_GPSR(IP11_10_8, CAN_DEBUGOUT14),
PINMUX_IPSR_MSEL(IP11_13_11, SSI_SDATA6, SEL_SSI6_0),
PINMUX_IPSR_MSEL(IP11_13_11, SCIFA1_TXD_B, SEL_SCIFA1_1),
PINMUX_IPSR_MSEL(IP11_13_11, I2C4_SDA_C, SEL_I2C04_2),
- PINMUX_IPSR_DATA(IP11_13_11, DU1_EXODDF_DU1_ODDF_DISP_CDE),
- PINMUX_IPSR_DATA(IP11_13_11, CAN_DEBUGOUT15),
+ PINMUX_IPSR_GPSR(IP11_13_11, DU1_EXODDF_DU1_ODDF_DISP_CDE),
+ PINMUX_IPSR_GPSR(IP11_13_11, CAN_DEBUGOUT15),
PINMUX_IPSR_MSEL(IP11_15_14, SSI_SCK78, SEL_SSI7_0),
PINMUX_IPSR_MSEL(IP11_15_14, SCIFA2_SCK_B, SEL_SCIFA2_1),
PINMUX_IPSR_MSEL(IP11_15_14, IIC0_SDA_C, SEL_IIC00_2),
- PINMUX_IPSR_DATA(IP11_15_14, DU1_DISP),
+ PINMUX_IPSR_GPSR(IP11_15_14, DU1_DISP),
PINMUX_IPSR_MSEL(IP11_17_16, SSI_WS78, SEL_SSI7_0),
PINMUX_IPSR_MSEL(IP11_17_16, SCIFA2_RXD_B, SEL_SCIFA2_1),
PINMUX_IPSR_MSEL(IP11_17_16, IIC0_SCL_C, SEL_IIC00_2),
- PINMUX_IPSR_DATA(IP11_17_16, DU1_CDE),
+ PINMUX_IPSR_GPSR(IP11_17_16, DU1_CDE),
PINMUX_IPSR_MSEL(IP11_20_18, SSI_SDATA7, SEL_SSI7_0),
PINMUX_IPSR_MSEL(IP11_20_18, SCIFA2_TXD_B, SEL_SCIFA2_1),
- PINMUX_IPSR_DATA(IP11_20_18, IRQ8),
+ PINMUX_IPSR_GPSR(IP11_20_18, IRQ8),
PINMUX_IPSR_MSEL(IP11_20_18, AUDIO_CLKA_D, SEL_ADG_3),
PINMUX_IPSR_MSEL(IP11_20_18, CAN_CLK_D, SEL_CAN_3),
- PINMUX_IPSR_DATA(IP11_20_18, PCMOE_N),
- PINMUX_IPSR_DATA(IP11_23_21, SSI_SCK0129),
+ PINMUX_IPSR_GPSR(IP11_20_18, PCMOE_N),
+ PINMUX_IPSR_GPSR(IP11_23_21, SSI_SCK0129),
PINMUX_IPSR_MSEL(IP11_23_21, MSIOF1_RXD_B, SEL_MSI1_1),
PINMUX_IPSR_MSEL(IP11_23_21, SCIF5_RXD_D, SEL_SCIF5_3),
PINMUX_IPSR_MSEL(IP11_23_21, ADIDATA_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP11_23_21, AD_DI_B, SEL_ADI_1),
- PINMUX_IPSR_DATA(IP11_23_21, PCMWE_N),
- PINMUX_IPSR_DATA(IP11_26_24, SSI_WS0129),
+ PINMUX_IPSR_GPSR(IP11_23_21, PCMWE_N),
+ PINMUX_IPSR_GPSR(IP11_26_24, SSI_WS0129),
PINMUX_IPSR_MSEL(IP11_26_24, MSIOF1_TXD_B, SEL_MSI1_1),
PINMUX_IPSR_MSEL(IP11_26_24, SCIF5_TXD_D, SEL_SCIF5_3),
PINMUX_IPSR_MSEL(IP11_26_24, ADICS_SAMP_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP11_26_24, AD_DO_B, SEL_ADI_1),
- PINMUX_IPSR_DATA(IP11_29_27, SSI_SDATA0),
+ PINMUX_IPSR_GPSR(IP11_29_27, SSI_SDATA0),
PINMUX_IPSR_MSEL(IP11_29_27, MSIOF1_SCK_B, SEL_MSI1_1),
- PINMUX_IPSR_DATA(IP11_29_27, PWM0_B),
+ PINMUX_IPSR_GPSR(IP11_29_27, PWM0_B),
PINMUX_IPSR_MSEL(IP11_29_27, ADICLK_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP11_29_27, AD_CLK_B, SEL_ADI_1),
/* IPSR12 */
- PINMUX_IPSR_DATA(IP12_2_0, SSI_SCK34),
+ PINMUX_IPSR_GPSR(IP12_2_0, SSI_SCK34),
PINMUX_IPSR_MSEL(IP12_2_0, MSIOF1_SYNC_B, SEL_MSI1_1),
PINMUX_IPSR_MSEL(IP12_2_0, SCIFA1_SCK_C, SEL_SCIFA1_2),
PINMUX_IPSR_MSEL(IP12_2_0, ADICHS0_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP12_2_0, AD_NCS_N_B, SEL_ADI_1),
PINMUX_IPSR_MSEL(IP12_2_0, DREQ1_N_B, SEL_LBS_1),
- PINMUX_IPSR_DATA(IP12_5_3, SSI_WS34),
+ PINMUX_IPSR_GPSR(IP12_5_3, SSI_WS34),
PINMUX_IPSR_MSEL(IP12_5_3, MSIOF1_SS1_B, SEL_MSI1_1),
PINMUX_IPSR_MSEL(IP12_5_3, SCIFA1_RXD_C, SEL_SCIFA1_2),
PINMUX_IPSR_MSEL(IP12_5_3, ADICHS1_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP12_5_3, CAN1_RX_C, SEL_CAN1_2),
PINMUX_IPSR_MSEL(IP12_5_3, DACK1_B, SEL_LBS_1),
- PINMUX_IPSR_DATA(IP12_8_6, SSI_SDATA3),
+ PINMUX_IPSR_GPSR(IP12_8_6, SSI_SDATA3),
PINMUX_IPSR_MSEL(IP12_8_6, MSIOF1_SS2_B, SEL_MSI1_1),
PINMUX_IPSR_MSEL(IP12_8_6, SCIFA1_TXD_C, SEL_SCIFA1_2),
PINMUX_IPSR_MSEL(IP12_8_6, ADICHS2_B, SEL_RAD_1),
PINMUX_IPSR_MSEL(IP12_8_6, CAN1_TX_C, SEL_CAN1_2),
- PINMUX_IPSR_DATA(IP12_8_6, DREQ2_N),
+ PINMUX_IPSR_GPSR(IP12_8_6, DREQ2_N),
PINMUX_IPSR_MSEL(IP12_10_9, SSI_SCK4, SEL_SSI4_0),
- PINMUX_IPSR_DATA(IP12_10_9, MLB_CLK),
+ PINMUX_IPSR_GPSR(IP12_10_9, MLB_CLK),
PINMUX_IPSR_MSEL(IP12_10_9, IETX_B, SEL_IEB_1),
- PINMUX_IPSR_DATA(IP12_10_9, IRD_TX),
+ PINMUX_IPSR_GPSR(IP12_10_9, IRD_TX),
PINMUX_IPSR_MSEL(IP12_12_11, SSI_WS4, SEL_SSI4_0),
- PINMUX_IPSR_DATA(IP12_12_11, MLB_SIG),
+ PINMUX_IPSR_GPSR(IP12_12_11, MLB_SIG),
PINMUX_IPSR_MSEL(IP12_12_11, IECLK_B, SEL_IEB_1),
- PINMUX_IPSR_DATA(IP12_12_11, IRD_RX),
+ PINMUX_IPSR_GPSR(IP12_12_11, IRD_RX),
PINMUX_IPSR_MSEL(IP12_14_13, SSI_SDATA4, SEL_SSI4_0),
- PINMUX_IPSR_DATA(IP12_14_13, MLB_DAT),
+ PINMUX_IPSR_GPSR(IP12_14_13, MLB_DAT),
PINMUX_IPSR_MSEL(IP12_14_13, IERX_B, SEL_IEB_1),
- PINMUX_IPSR_DATA(IP12_14_13, IRD_SCK),
+ PINMUX_IPSR_GPSR(IP12_14_13, IRD_SCK),
PINMUX_IPSR_MSEL(IP12_17_15, SSI_SDATA8, SEL_SSI8_0),
PINMUX_IPSR_MSEL(IP12_17_15, SCIF1_SCK_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP12_17_15, PWM1_B),
- PINMUX_IPSR_DATA(IP12_17_15, IRQ9),
+ PINMUX_IPSR_GPSR(IP12_17_15, PWM1_B),
+ PINMUX_IPSR_GPSR(IP12_17_15, IRQ9),
PINMUX_IPSR_MSEL(IP12_17_15, REMOCON, SEL_RCN_0),
- PINMUX_IPSR_DATA(IP12_17_15, DACK2),
+ PINMUX_IPSR_GPSR(IP12_17_15, DACK2),
PINMUX_IPSR_MSEL(IP12_17_15, ETH_MDIO_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP12_20_18, SSI_SCK1, SEL_SSI1_0),
PINMUX_IPSR_MSEL(IP12_20_18, SCIF1_RXD_B, SEL_SCIF1_1),
PINMUX_IPSR_MSEL(IP12_20_18, IIC1_SCL_C, SEL_IIC01_2),
- PINMUX_IPSR_DATA(IP12_20_18, VI1_CLK),
+ PINMUX_IPSR_GPSR(IP12_20_18, VI1_CLK),
PINMUX_IPSR_MSEL(IP12_20_18, CAN0_RX_D, SEL_CAN0_3),
PINMUX_IPSR_MSEL(IP12_20_18, AVB_AVTP_CAPTURE, SEL_AVB_0),
PINMUX_IPSR_MSEL(IP12_20_18, ETH_CRS_DV_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP12_23_21, SSI_WS1, SEL_SSI1_0),
PINMUX_IPSR_MSEL(IP12_23_21, SCIF1_TXD_B, SEL_SCIF1_1),
PINMUX_IPSR_MSEL(IP12_23_21, IIC1_SDA_C, SEL_IIC01_2),
- PINMUX_IPSR_DATA(IP12_23_21, VI1_DATA0),
+ PINMUX_IPSR_GPSR(IP12_23_21, VI1_DATA0),
PINMUX_IPSR_MSEL(IP12_23_21, CAN0_TX_D, SEL_CAN0_3),
PINMUX_IPSR_MSEL(IP12_23_21, AVB_AVTP_MATCH, SEL_AVB_0),
PINMUX_IPSR_MSEL(IP12_23_21, ETH_RX_ER_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP12_26_24, SSI_SDATA1, SEL_SSI1_0),
PINMUX_IPSR_MSEL(IP12_26_24, HSCIF1_HRX_B, SEL_HSCIF1_1),
- PINMUX_IPSR_DATA(IP12_26_24, VI1_DATA1),
+ PINMUX_IPSR_GPSR(IP12_26_24, VI1_DATA1),
PINMUX_IPSR_MSEL(IP12_26_24, SDATA, SEL_FSN_0),
- PINMUX_IPSR_DATA(IP12_26_24, ATAG0_N),
+ PINMUX_IPSR_GPSR(IP12_26_24, ATAG0_N),
PINMUX_IPSR_MSEL(IP12_26_24, ETH_RXD0_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP12_29_27, SSI_SCK2, SEL_SSI2_0),
PINMUX_IPSR_MSEL(IP12_29_27, HSCIF1_HTX_B, SEL_HSCIF1_1),
- PINMUX_IPSR_DATA(IP12_29_27, VI1_DATA2),
+ PINMUX_IPSR_GPSR(IP12_29_27, VI1_DATA2),
PINMUX_IPSR_MSEL(IP12_29_27, MDATA, SEL_FSN_0),
- PINMUX_IPSR_DATA(IP12_29_27, ATAWR0_N),
+ PINMUX_IPSR_GPSR(IP12_29_27, ATAWR0_N),
PINMUX_IPSR_MSEL(IP12_29_27, ETH_RXD1_B, SEL_ETH_1),
/* IPSR13 */
PINMUX_IPSR_MSEL(IP13_2_0, SSI_WS2, SEL_SSI2_0),
PINMUX_IPSR_MSEL(IP13_2_0, HSCIF1_HCTS_N_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP13_2_0, SCIFA0_RXD_D, SEL_SCIFA0_3),
- PINMUX_IPSR_DATA(IP13_2_0, VI1_DATA3),
+ PINMUX_IPSR_GPSR(IP13_2_0, VI1_DATA3),
PINMUX_IPSR_MSEL(IP13_2_0, SCKZ, SEL_FSN_0),
- PINMUX_IPSR_DATA(IP13_2_0, ATACS00_N),
+ PINMUX_IPSR_GPSR(IP13_2_0, ATACS00_N),
PINMUX_IPSR_MSEL(IP13_2_0, ETH_LINK_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP13_5_3, SSI_SDATA2, SEL_SSI2_0),
PINMUX_IPSR_MSEL(IP13_5_3, HSCIF1_HRTS_N_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP13_5_3, SCIFA0_TXD_D, SEL_SCIFA0_3),
- PINMUX_IPSR_DATA(IP13_5_3, VI1_DATA4),
+ PINMUX_IPSR_GPSR(IP13_5_3, VI1_DATA4),
PINMUX_IPSR_MSEL(IP13_5_3, STM_N, SEL_FSN_0),
- PINMUX_IPSR_DATA(IP13_5_3, ATACS10_N),
+ PINMUX_IPSR_GPSR(IP13_5_3, ATACS10_N),
PINMUX_IPSR_MSEL(IP13_5_3, ETH_REFCLK_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP13_8_6, SSI_SCK9, SEL_SSI9_0),
PINMUX_IPSR_MSEL(IP13_8_6, SCIF2_SCK_B, SEL_SCIF2_1),
- PINMUX_IPSR_DATA(IP13_8_6, PWM2_B),
- PINMUX_IPSR_DATA(IP13_8_6, VI1_DATA5),
+ PINMUX_IPSR_GPSR(IP13_8_6, PWM2_B),
+ PINMUX_IPSR_GPSR(IP13_8_6, VI1_DATA5),
PINMUX_IPSR_MSEL(IP13_8_6, MTS_N, SEL_FSN_0),
- PINMUX_IPSR_DATA(IP13_8_6, EX_WAIT1),
+ PINMUX_IPSR_GPSR(IP13_8_6, EX_WAIT1),
PINMUX_IPSR_MSEL(IP13_8_6, ETH_TXD1_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP13_11_9, SSI_WS9, SEL_SSI9_0),
PINMUX_IPSR_MSEL(IP13_11_9, SCIF2_RXD_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP13_11_9, I2C3_SCL_E, SEL_I2C03_4),
- PINMUX_IPSR_DATA(IP13_11_9, VI1_DATA6),
- PINMUX_IPSR_DATA(IP13_11_9, ATARD0_N),
+ PINMUX_IPSR_GPSR(IP13_11_9, VI1_DATA6),
+ PINMUX_IPSR_GPSR(IP13_11_9, ATARD0_N),
PINMUX_IPSR_MSEL(IP13_11_9, ETH_TX_EN_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP13_14_12, SSI_SDATA9, SEL_SSI9_0),
PINMUX_IPSR_MSEL(IP13_14_12, SCIF2_TXD_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP13_14_12, I2C3_SDA_E, SEL_I2C03_4),
- PINMUX_IPSR_DATA(IP13_14_12, VI1_DATA7),
- PINMUX_IPSR_DATA(IP13_14_12, ATADIR0_N),
+ PINMUX_IPSR_GPSR(IP13_14_12, VI1_DATA7),
+ PINMUX_IPSR_GPSR(IP13_14_12, ATADIR0_N),
PINMUX_IPSR_MSEL(IP13_14_12, ETH_MAGIC_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP13_17_15, AUDIO_CLKA, SEL_ADG_0),
PINMUX_IPSR_MSEL(IP13_17_15, I2C0_SCL_B, SEL_I2C00_1),
PINMUX_IPSR_MSEL(IP13_17_15, SCIFA4_RXD_D, SEL_SCIFA4_3),
- PINMUX_IPSR_DATA(IP13_17_15, VI1_CLKENB),
+ PINMUX_IPSR_GPSR(IP13_17_15, VI1_CLKENB),
PINMUX_IPSR_MSEL(IP13_17_15, TS_SDATA_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP13_17_15, RIF0_SYNC_B, SEL_DR0_1),
PINMUX_IPSR_MSEL(IP13_17_15, ETH_TXD0_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP13_20_18, AUDIO_CLKB, SEL_ADG_0),
PINMUX_IPSR_MSEL(IP13_20_18, I2C0_SDA_B, SEL_I2C00_1),
PINMUX_IPSR_MSEL(IP13_20_18, SCIFA4_TXD_D, SEL_SCIFA4_3),
- PINMUX_IPSR_DATA(IP13_20_18, VI1_FIELD),
+ PINMUX_IPSR_GPSR(IP13_20_18, VI1_FIELD),
PINMUX_IPSR_MSEL(IP13_20_18, TS_SCK_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP13_20_18, RIF0_CLK_B, SEL_DR0_1),
PINMUX_IPSR_MSEL(IP13_20_18, BPFCLK_E, SEL_DARC_4),
@@ -1472,7 +1472,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP13_23_21, AUDIO_CLKC, SEL_ADG_0),
PINMUX_IPSR_MSEL(IP13_23_21, I2C4_SCL_B, SEL_I2C04_1),
PINMUX_IPSR_MSEL(IP13_23_21, SCIFA5_RXD_D, SEL_SCIFA5_3),
- PINMUX_IPSR_DATA(IP13_23_21, VI1_HSYNC_N),
+ PINMUX_IPSR_GPSR(IP13_23_21, VI1_HSYNC_N),
PINMUX_IPSR_MSEL(IP13_23_21, TS_SDEN_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP13_23_21, RIF0_D0_B, SEL_DR0_1),
PINMUX_IPSR_MSEL(IP13_23_21, FMCLK_E, SEL_DARC_4),
@@ -1480,7 +1480,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP13_26_24, AUDIO_CLKOUT, SEL_ADG_0),
PINMUX_IPSR_MSEL(IP13_26_24, I2C4_SDA_B, SEL_I2C04_1),
PINMUX_IPSR_MSEL(IP13_26_24, SCIFA5_TXD_D, SEL_SCIFA5_3),
- PINMUX_IPSR_DATA(IP13_26_24, VI1_VSYNC_N),
+ PINMUX_IPSR_GPSR(IP13_26_24, VI1_VSYNC_N),
PINMUX_IPSR_MSEL(IP13_26_24, TS_SPSYNC_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP13_26_24, RIF0_D1_B, SEL_DR1_1),
PINMUX_IPSR_MSEL(IP13_26_24, FMIN_E, SEL_DARC_4),
@@ -1491,6 +1491,197 @@ static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_GPIO_GP_ALL(),
};
+/* - Audio Clock ------------------------------------------------------------ */
+static const unsigned int audio_clka_pins[] = {
+ /* CLKA */
+ RCAR_GP_PIN(5, 20),
+};
+static const unsigned int audio_clka_mux[] = {
+ AUDIO_CLKA_MARK,
+};
+static const unsigned int audio_clka_b_pins[] = {
+ /* CLKA */
+ RCAR_GP_PIN(3, 25),
+};
+static const unsigned int audio_clka_b_mux[] = {
+ AUDIO_CLKA_B_MARK,
+};
+static const unsigned int audio_clka_c_pins[] = {
+ /* CLKA */
+ RCAR_GP_PIN(4, 20),
+};
+static const unsigned int audio_clka_c_mux[] = {
+ AUDIO_CLKA_C_MARK,
+};
+static const unsigned int audio_clka_d_pins[] = {
+ /* CLKA */
+ RCAR_GP_PIN(5, 0),
+};
+static const unsigned int audio_clka_d_mux[] = {
+ AUDIO_CLKA_D_MARK,
+};
+static const unsigned int audio_clkb_pins[] = {
+ /* CLKB */
+ RCAR_GP_PIN(5, 21),
+};
+static const unsigned int audio_clkb_mux[] = {
+ AUDIO_CLKB_MARK,
+};
+static const unsigned int audio_clkb_b_pins[] = {
+ /* CLKB */
+ RCAR_GP_PIN(3, 26),
+};
+static const unsigned int audio_clkb_b_mux[] = {
+ AUDIO_CLKB_B_MARK,
+};
+static const unsigned int audio_clkb_c_pins[] = {
+ /* CLKB */
+ RCAR_GP_PIN(4, 21),
+};
+static const unsigned int audio_clkb_c_mux[] = {
+ AUDIO_CLKB_C_MARK,
+};
+static const unsigned int audio_clkc_pins[] = {
+ /* CLKC */
+ RCAR_GP_PIN(5, 22),
+};
+static const unsigned int audio_clkc_mux[] = {
+ AUDIO_CLKC_MARK,
+};
+static const unsigned int audio_clkc_b_pins[] = {
+ /* CLKC */
+ RCAR_GP_PIN(3, 29),
+};
+static const unsigned int audio_clkc_b_mux[] = {
+ AUDIO_CLKC_B_MARK,
+};
+static const unsigned int audio_clkc_c_pins[] = {
+ /* CLKC */
+ RCAR_GP_PIN(4, 22),
+};
+static const unsigned int audio_clkc_c_mux[] = {
+ AUDIO_CLKC_C_MARK,
+};
+static const unsigned int audio_clkout_pins[] = {
+ /* CLKOUT */
+ RCAR_GP_PIN(5, 23),
+};
+static const unsigned int audio_clkout_mux[] = {
+ AUDIO_CLKOUT_MARK,
+};
+static const unsigned int audio_clkout_b_pins[] = {
+ /* CLKOUT */
+ RCAR_GP_PIN(3, 12),
+};
+static const unsigned int audio_clkout_b_mux[] = {
+ AUDIO_CLKOUT_B_MARK,
+};
+static const unsigned int audio_clkout_c_pins[] = {
+ /* CLKOUT */
+ RCAR_GP_PIN(4, 23),
+};
+static const unsigned int audio_clkout_c_mux[] = {
+ AUDIO_CLKOUT_C_MARK,
+};
+/* - AVB -------------------------------------------------------------------- */
+static const unsigned int avb_link_pins[] = {
+ RCAR_GP_PIN(3, 26),
+};
+static const unsigned int avb_link_mux[] = {
+ AVB_LINK_MARK,
+};
+static const unsigned int avb_magic_pins[] = {
+ RCAR_GP_PIN(3, 27),
+};
+static const unsigned int avb_magic_mux[] = {
+ AVB_MAGIC_MARK,
+};
+static const unsigned int avb_phy_int_pins[] = {
+ RCAR_GP_PIN(3, 28),
+};
+static const unsigned int avb_phy_int_mux[] = {
+ AVB_PHY_INT_MARK,
+};
+static const unsigned int avb_mdio_pins[] = {
+ RCAR_GP_PIN(3, 24), RCAR_GP_PIN(3, 25),
+};
+static const unsigned int avb_mdio_mux[] = {
+ AVB_MDC_MARK, AVB_MDIO_MARK,
+};
+static const unsigned int avb_mii_pins[] = {
+ RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 16),
+ RCAR_GP_PIN(3, 17),
+
+ RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 4),
+ RCAR_GP_PIN(3, 5),
+
+ RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 1),
+ RCAR_GP_PIN(3, 29), RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 22),
+ RCAR_GP_PIN(3, 13), RCAR_GP_PIN(3, 11),
+};
+static const unsigned int avb_mii_mux[] = {
+ AVB_TXD0_MARK, AVB_TXD1_MARK, AVB_TXD2_MARK,
+ AVB_TXD3_MARK,
+
+ AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK,
+ AVB_RXD3_MARK,
+
+ AVB_RX_ER_MARK, AVB_RX_CLK_MARK, AVB_RX_DV_MARK,
+ AVB_CRS_MARK, AVB_TX_EN_MARK, AVB_TX_ER_MARK,
+ AVB_TX_CLK_MARK, AVB_COL_MARK,
+};
+static const unsigned int avb_gmii_pins[] = {
+ RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 16),
+ RCAR_GP_PIN(3, 17), RCAR_GP_PIN(3, 18), RCAR_GP_PIN(3, 19),
+ RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 21),
+
+ RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 4),
+ RCAR_GP_PIN(3, 5), RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7),
+ RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9),
+
+ RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 1),
+ RCAR_GP_PIN(3, 29), RCAR_GP_PIN(3, 23), RCAR_GP_PIN(3, 30),
+ RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 13),
+ RCAR_GP_PIN(3, 11),
+};
+static const unsigned int avb_gmii_mux[] = {
+ AVB_TXD0_MARK, AVB_TXD1_MARK, AVB_TXD2_MARK,
+ AVB_TXD3_MARK, AVB_TXD4_MARK, AVB_TXD5_MARK,
+ AVB_TXD6_MARK, AVB_TXD7_MARK,
+
+ AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK,
+ AVB_RXD3_MARK, AVB_RXD4_MARK, AVB_RXD5_MARK,
+ AVB_RXD6_MARK, AVB_RXD7_MARK,
+
+ AVB_RX_ER_MARK, AVB_RX_CLK_MARK, AVB_RX_DV_MARK,
+ AVB_CRS_MARK, AVB_GTX_CLK_MARK, AVB_GTXREFCLK_MARK,
+ AVB_TX_EN_MARK, AVB_TX_ER_MARK, AVB_TX_CLK_MARK,
+ AVB_COL_MARK,
+};
+static const unsigned int avb_avtp_capture_pins[] = {
+ RCAR_GP_PIN(5, 11),
+};
+static const unsigned int avb_avtp_capture_mux[] = {
+ AVB_AVTP_CAPTURE_MARK,
+};
+static const unsigned int avb_avtp_match_pins[] = {
+ RCAR_GP_PIN(5, 12),
+};
+static const unsigned int avb_avtp_match_mux[] = {
+ AVB_AVTP_MATCH_MARK,
+};
+static const unsigned int avb_avtp_capture_b_pins[] = {
+ RCAR_GP_PIN(1, 1),
+};
+static const unsigned int avb_avtp_capture_b_mux[] = {
+ AVB_AVTP_CAPTURE_B_MARK,
+};
+static const unsigned int avb_avtp_match_b_pins[] = {
+ RCAR_GP_PIN(1, 2),
+};
+static const unsigned int avb_avtp_match_b_mux[] = {
+ AVB_AVTP_MATCH_B_MARK,
+};
/* - ETH -------------------------------------------------------------------- */
static const unsigned int eth_link_pins[] = {
/* LINK */
@@ -2751,6 +2942,245 @@ static const unsigned int sdhi2_wp_pins[] = {
static const unsigned int sdhi2_wp_mux[] = {
SD2_WP_MARK,
};
+/* - SSI -------------------------------------------------------------------- */
+static const unsigned int ssi0_data_pins[] = {
+ /* SDATA0 */
+ RCAR_GP_PIN(5, 3),
+};
+static const unsigned int ssi0_data_mux[] = {
+ SSI_SDATA0_MARK,
+};
+static const unsigned int ssi0129_ctrl_pins[] = {
+ /* SCK0129, WS0129 */
+ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
+};
+static const unsigned int ssi0129_ctrl_mux[] = {
+ SSI_SCK0129_MARK, SSI_WS0129_MARK,
+};
+static const unsigned int ssi1_data_pins[] = {
+ /* SDATA1 */
+ RCAR_GP_PIN(5, 13),
+};
+static const unsigned int ssi1_data_mux[] = {
+ SSI_SDATA1_MARK,
+};
+static const unsigned int ssi1_ctrl_pins[] = {
+ /* SCK1, WS1 */
+ RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 12),
+};
+static const unsigned int ssi1_ctrl_mux[] = {
+ SSI_SCK1_MARK, SSI_WS1_MARK,
+};
+static const unsigned int ssi1_data_b_pins[] = {
+ /* SDATA1 */
+ RCAR_GP_PIN(4, 13),
+};
+static const unsigned int ssi1_data_b_mux[] = {
+ SSI_SDATA1_B_MARK,
+};
+static const unsigned int ssi1_ctrl_b_pins[] = {
+ /* SCK1, WS1 */
+ RCAR_GP_PIN(4, 11), RCAR_GP_PIN(4, 12),
+};
+static const unsigned int ssi1_ctrl_b_mux[] = {
+ SSI_SCK1_B_MARK, SSI_WS1_B_MARK,
+};
+static const unsigned int ssi2_data_pins[] = {
+ /* SDATA2 */
+ RCAR_GP_PIN(5, 16),
+};
+static const unsigned int ssi2_data_mux[] = {
+ SSI_SDATA2_MARK,
+};
+static const unsigned int ssi2_ctrl_pins[] = {
+ /* SCK2, WS2 */
+ RCAR_GP_PIN(5, 14), RCAR_GP_PIN(5, 15),
+};
+static const unsigned int ssi2_ctrl_mux[] = {
+ SSI_SCK2_MARK, SSI_WS2_MARK,
+};
+static const unsigned int ssi2_data_b_pins[] = {
+ /* SDATA2 */
+ RCAR_GP_PIN(4, 16),
+};
+static const unsigned int ssi2_data_b_mux[] = {
+ SSI_SDATA2_B_MARK,
+};
+static const unsigned int ssi2_ctrl_b_pins[] = {
+ /* SCK2, WS2 */
+ RCAR_GP_PIN(4, 14), RCAR_GP_PIN(4, 15),
+};
+static const unsigned int ssi2_ctrl_b_mux[] = {
+ SSI_SCK2_B_MARK, SSI_WS2_B_MARK,
+};
+static const unsigned int ssi3_data_pins[] = {
+ /* SDATA3 */
+ RCAR_GP_PIN(5, 6),
+};
+static const unsigned int ssi3_data_mux[] = {
+ SSI_SDATA3_MARK
+};
+static const unsigned int ssi34_ctrl_pins[] = {
+ /* SCK34, WS34 */
+ RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 5),
+};
+static const unsigned int ssi34_ctrl_mux[] = {
+ SSI_SCK34_MARK, SSI_WS34_MARK,
+};
+static const unsigned int ssi4_data_pins[] = {
+ /* SDATA4 */
+ RCAR_GP_PIN(5, 9),
+};
+static const unsigned int ssi4_data_mux[] = {
+ SSI_SDATA4_MARK,
+};
+static const unsigned int ssi4_ctrl_pins[] = {
+ /* SCK4, WS4 */
+ RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 8),
+};
+static const unsigned int ssi4_ctrl_mux[] = {
+ SSI_SCK4_MARK, SSI_WS4_MARK,
+};
+static const unsigned int ssi4_data_b_pins[] = {
+ /* SDATA4 */
+ RCAR_GP_PIN(4, 22),
+};
+static const unsigned int ssi4_data_b_mux[] = {
+ SSI_SDATA4_B_MARK,
+};
+static const unsigned int ssi4_ctrl_b_pins[] = {
+ /* SCK4, WS4 */
+ RCAR_GP_PIN(4, 20), RCAR_GP_PIN(4, 21),
+};
+static const unsigned int ssi4_ctrl_b_mux[] = {
+ SSI_SCK4_B_MARK, SSI_WS4_B_MARK,
+};
+static const unsigned int ssi5_data_pins[] = {
+ /* SDATA5 */
+ RCAR_GP_PIN(4, 26),
+};
+static const unsigned int ssi5_data_mux[] = {
+ SSI_SDATA5_MARK,
+};
+static const unsigned int ssi5_ctrl_pins[] = {
+ /* SCK5, WS5 */
+ RCAR_GP_PIN(4, 24), RCAR_GP_PIN(4, 25),
+};
+static const unsigned int ssi5_ctrl_mux[] = {
+ SSI_SCK5_MARK, SSI_WS5_MARK,
+};
+static const unsigned int ssi5_data_b_pins[] = {
+ /* SDATA5 */
+ RCAR_GP_PIN(3, 21),
+};
+static const unsigned int ssi5_data_b_mux[] = {
+ SSI_SDATA5_B_MARK,
+};
+static const unsigned int ssi5_ctrl_b_pins[] = {
+ /* SCK5, WS5 */
+ RCAR_GP_PIN(3, 19), RCAR_GP_PIN(3, 20),
+};
+static const unsigned int ssi5_ctrl_b_mux[] = {
+ SSI_SCK5_B_MARK, SSI_WS5_B_MARK,
+};
+static const unsigned int ssi6_data_pins[] = {
+ /* SDATA6 */
+ RCAR_GP_PIN(4, 29),
+};
+static const unsigned int ssi6_data_mux[] = {
+ SSI_SDATA6_MARK,
+};
+static const unsigned int ssi6_ctrl_pins[] = {
+ /* SCK6, WS6 */
+ RCAR_GP_PIN(4, 27), RCAR_GP_PIN(4, 28),
+};
+static const unsigned int ssi6_ctrl_mux[] = {
+ SSI_SCK6_MARK, SSI_WS6_MARK,
+};
+static const unsigned int ssi6_data_b_pins[] = {
+ /* SDATA6 */
+ RCAR_GP_PIN(3, 24),
+};
+static const unsigned int ssi6_data_b_mux[] = {
+ SSI_SDATA6_B_MARK,
+};
+static const unsigned int ssi6_ctrl_b_pins[] = {
+ /* SCK6, WS6 */
+ RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 23),
+};
+static const unsigned int ssi6_ctrl_b_mux[] = {
+ SSI_SCK6_B_MARK, SSI_WS6_B_MARK,
+};
+static const unsigned int ssi7_data_pins[] = {
+ /* SDATA7 */
+ RCAR_GP_PIN(5, 0),
+};
+static const unsigned int ssi7_data_mux[] = {
+ SSI_SDATA7_MARK,
+};
+static const unsigned int ssi78_ctrl_pins[] = {
+ /* SCK78, WS78 */
+ RCAR_GP_PIN(4, 30), RCAR_GP_PIN(4, 31),
+};
+static const unsigned int ssi78_ctrl_mux[] = {
+ SSI_SCK78_MARK, SSI_WS78_MARK,
+};
+static const unsigned int ssi7_data_b_pins[] = {
+ /* SDATA7 */
+ RCAR_GP_PIN(3, 27),
+};
+static const unsigned int ssi7_data_b_mux[] = {
+ SSI_SDATA7_B_MARK,
+};
+static const unsigned int ssi78_ctrl_b_pins[] = {
+ /* SCK78, WS78 */
+ RCAR_GP_PIN(3, 25), RCAR_GP_PIN(3, 26),
+};
+static const unsigned int ssi78_ctrl_b_mux[] = {
+ SSI_SCK78_B_MARK, SSI_WS78_B_MARK,
+};
+static const unsigned int ssi8_data_pins[] = {
+ /* SDATA8 */
+ RCAR_GP_PIN(5, 10),
+};
+static const unsigned int ssi8_data_mux[] = {
+ SSI_SDATA8_MARK,
+};
+static const unsigned int ssi8_data_b_pins[] = {
+ /* SDATA8 */
+ RCAR_GP_PIN(3, 28),
+};
+static const unsigned int ssi8_data_b_mux[] = {
+ SSI_SDATA8_B_MARK,
+};
+static const unsigned int ssi9_data_pins[] = {
+ /* SDATA9 */
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int ssi9_data_mux[] = {
+ SSI_SDATA9_MARK,
+};
+static const unsigned int ssi9_ctrl_pins[] = {
+ /* SCK9, WS9 */
+ RCAR_GP_PIN(5, 17), RCAR_GP_PIN(5, 18),
+};
+static const unsigned int ssi9_ctrl_mux[] = {
+ SSI_SCK9_MARK, SSI_WS9_MARK,
+};
+static const unsigned int ssi9_data_b_pins[] = {
+ /* SDATA9 */
+ RCAR_GP_PIN(4, 19),
+};
+static const unsigned int ssi9_data_b_mux[] = {
+ SSI_SDATA9_B_MARK,
+};
+static const unsigned int ssi9_ctrl_b_pins[] = {
+ /* SCK9, WS9 */
+ RCAR_GP_PIN(4, 17), RCAR_GP_PIN(4, 18),
+};
+static const unsigned int ssi9_ctrl_b_mux[] = {
+ SSI_SCK9_B_MARK, SSI_WS9_B_MARK,
+};
/* - USB0 ------------------------------------------------------------------- */
static const unsigned int usb0_pins[] = {
RCAR_GP_PIN(5, 24), /* PWEN */
@@ -2911,6 +3341,29 @@ static const unsigned int vin1_clk_mux[] = {
};
static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(audio_clka),
+ SH_PFC_PIN_GROUP(audio_clka_b),
+ SH_PFC_PIN_GROUP(audio_clka_c),
+ SH_PFC_PIN_GROUP(audio_clka_d),
+ SH_PFC_PIN_GROUP(audio_clkb),
+ SH_PFC_PIN_GROUP(audio_clkb_b),
+ SH_PFC_PIN_GROUP(audio_clkb_c),
+ SH_PFC_PIN_GROUP(audio_clkc),
+ SH_PFC_PIN_GROUP(audio_clkc_b),
+ SH_PFC_PIN_GROUP(audio_clkc_c),
+ SH_PFC_PIN_GROUP(audio_clkout),
+ SH_PFC_PIN_GROUP(audio_clkout_b),
+ SH_PFC_PIN_GROUP(audio_clkout_c),
+ SH_PFC_PIN_GROUP(avb_link),
+ SH_PFC_PIN_GROUP(avb_magic),
+ SH_PFC_PIN_GROUP(avb_phy_int),
+ SH_PFC_PIN_GROUP(avb_mdio),
+ SH_PFC_PIN_GROUP(avb_mii),
+ SH_PFC_PIN_GROUP(avb_gmii),
+ SH_PFC_PIN_GROUP(avb_avtp_capture),
+ SH_PFC_PIN_GROUP(avb_avtp_match),
+ SH_PFC_PIN_GROUP(avb_avtp_capture_b),
+ SH_PFC_PIN_GROUP(avb_avtp_match_b),
SH_PFC_PIN_GROUP(eth_link),
SH_PFC_PIN_GROUP(eth_magic),
SH_PFC_PIN_GROUP(eth_mdio),
@@ -3084,6 +3537,40 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(sdhi2_ctrl),
SH_PFC_PIN_GROUP(sdhi2_cd),
SH_PFC_PIN_GROUP(sdhi2_wp),
+ SH_PFC_PIN_GROUP(ssi0_data),
+ SH_PFC_PIN_GROUP(ssi0129_ctrl),
+ SH_PFC_PIN_GROUP(ssi1_data),
+ SH_PFC_PIN_GROUP(ssi1_ctrl),
+ SH_PFC_PIN_GROUP(ssi1_data_b),
+ SH_PFC_PIN_GROUP(ssi1_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi2_data),
+ SH_PFC_PIN_GROUP(ssi2_ctrl),
+ SH_PFC_PIN_GROUP(ssi2_data_b),
+ SH_PFC_PIN_GROUP(ssi2_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi3_data),
+ SH_PFC_PIN_GROUP(ssi34_ctrl),
+ SH_PFC_PIN_GROUP(ssi4_data),
+ SH_PFC_PIN_GROUP(ssi4_ctrl),
+ SH_PFC_PIN_GROUP(ssi4_data_b),
+ SH_PFC_PIN_GROUP(ssi4_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi5_data),
+ SH_PFC_PIN_GROUP(ssi5_ctrl),
+ SH_PFC_PIN_GROUP(ssi5_data_b),
+ SH_PFC_PIN_GROUP(ssi5_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi6_data),
+ SH_PFC_PIN_GROUP(ssi6_ctrl),
+ SH_PFC_PIN_GROUP(ssi6_data_b),
+ SH_PFC_PIN_GROUP(ssi6_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi7_data),
+ SH_PFC_PIN_GROUP(ssi78_ctrl),
+ SH_PFC_PIN_GROUP(ssi7_data_b),
+ SH_PFC_PIN_GROUP(ssi78_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi8_data),
+ SH_PFC_PIN_GROUP(ssi8_data_b),
+ SH_PFC_PIN_GROUP(ssi9_data),
+ SH_PFC_PIN_GROUP(ssi9_ctrl),
+ SH_PFC_PIN_GROUP(ssi9_data_b),
+ SH_PFC_PIN_GROUP(ssi9_ctrl_b),
SH_PFC_PIN_GROUP(usb0),
SH_PFC_PIN_GROUP(usb1),
VIN_DATA_PIN_GROUP(vin0_data, 24),
@@ -3106,6 +3593,35 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(vin1_clk),
};
+static const char * const audio_clk_groups[] = {
+ "audio_clka",
+ "audio_clka_b",
+ "audio_clka_c",
+ "audio_clka_d",
+ "audio_clkb",
+ "audio_clkb_b",
+ "audio_clkb_c",
+ "audio_clkc",
+ "audio_clkc_b",
+ "audio_clkc_c",
+ "audio_clkout",
+ "audio_clkout_b",
+ "audio_clkout_c",
+};
+
+static const char * const avb_groups[] = {
+ "avb_link",
+ "avb_magic",
+ "avb_phy_int",
+ "avb_mdio",
+ "avb_mii",
+ "avb_gmii",
+ "avb_avtp_capture",
+ "avb_avtp_match",
+ "avb_avtp_capture_b",
+ "avb_avtp_match_b",
+};
+
static const char * const eth_groups[] = {
"eth_link",
"eth_magic",
@@ -3381,6 +3897,43 @@ static const char * const sdhi2_groups[] = {
"sdhi2_wp",
};
+static const char * const ssi_groups[] = {
+ "ssi0_data",
+ "ssi0129_ctrl",
+ "ssi1_data",
+ "ssi1_ctrl",
+ "ssi1_data_b",
+ "ssi1_ctrl_b",
+ "ssi2_data",
+ "ssi2_ctrl",
+ "ssi2_data_b",
+ "ssi2_ctrl_b",
+ "ssi3_data",
+ "ssi34_ctrl",
+ "ssi4_data",
+ "ssi4_ctrl",
+ "ssi4_data_b",
+ "ssi4_ctrl_b",
+ "ssi5_data",
+ "ssi5_ctrl",
+ "ssi5_data_b",
+ "ssi5_ctrl_b",
+ "ssi6_data",
+ "ssi6_ctrl",
+ "ssi6_data_b",
+ "ssi6_ctrl_b",
+ "ssi7_data",
+ "ssi78_ctrl",
+ "ssi7_data_b",
+ "ssi78_ctrl_b",
+ "ssi8_data",
+ "ssi8_data_b",
+ "ssi9_data",
+ "ssi9_ctrl",
+ "ssi9_data_b",
+ "ssi9_ctrl_b",
+};
+
static const char * const usb0_groups[] = {
"usb0",
};
@@ -3414,6 +3967,8 @@ static const char * const vin1_groups[] = {
};
static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(audio_clk),
+ SH_PFC_FUNCTION(avb),
SH_PFC_FUNCTION(eth),
SH_PFC_FUNCTION(hscif0),
SH_PFC_FUNCTION(hscif1),
@@ -3448,6 +4003,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(sdhi0),
SH_PFC_FUNCTION(sdhi1),
SH_PFC_FUNCTION(sdhi2),
+ SH_PFC_FUNCTION(ssi),
SH_PFC_FUNCTION(usb0),
SH_PFC_FUNCTION(usb1),
SH_PFC_FUNCTION(vin0),
@@ -3974,6 +4530,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
FN_DU0_DISP, FN_QPOLA, FN_CC50_STATE30, 0,
/* IP6_3_2 [2] */
FN_DU0_EXODDF_DU0_ODDF_DISP_CDE, FN_QCPV_QDE, FN_CC50_STATE29,
+ 0,
/* IP6_1_0 [2] */
FN_DU0_EXVSYNC_DU0_VSYNC, FN_QSTB_QHE, FN_CC50_STATE28, 0, }
},
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
index ce4f5cdb0579..5979dabc02fa 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
@@ -189,8 +189,8 @@
#define GPSR6_4 F_(SSI_SDATA2_A, IP14_7_4)
#define GPSR6_3 F_(SSI_SDATA1_A, IP14_3_0)
#define GPSR6_2 F_(SSI_SDATA0, IP13_31_28)
-#define GPSR6_1 F_(SSI_WS0129, IP13_27_24)
-#define GPSR6_0 F_(SSI_SCK0129, IP13_23_20)
+#define GPSR6_1 F_(SSI_WS01239, IP13_27_24)
+#define GPSR6_0 F_(SSI_SCK01239, IP13_23_20)
/* GPSR7 */
#define GPSR7_3 FM(HDMI1_CEC)
@@ -315,8 +315,8 @@
#define IP13_11_8 FM(MLB_CLK) F_(0, 0) FM(MSIOF1_SCK_F) F_(0, 0) FM(SCL1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP13_15_12 FM(MLB_SIG) FM(RX1_B) FM(MSIOF1_SYNC_F) F_(0, 0) FM(SDA1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP13_19_16 FM(MLB_DAT) FM(TX1_B) FM(MSIOF1_RXD_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP13_23_20 FM(SSI_SCK0129) F_(0, 0) FM(MSIOF1_TXD_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP13_27_24 FM(SSI_WS0129) F_(0, 0) FM(MSIOF1_SS1_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP13_23_20 FM(SSI_SCK01239) F_(0, 0) FM(MSIOF1_TXD_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP13_27_24 FM(SSI_WS01239) F_(0, 0) FM(MSIOF1_SS1_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP13_31_28 FM(SSI_SDATA0) F_(0, 0) FM(MSIOF1_SS2_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP14_3_0 FM(SSI_SDATA1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP14_7_4 FM(SSI_SDATA2_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(SSI_SCK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
@@ -478,7 +478,6 @@ FM(IP16_31_28) IP16_31_28
#define MOD_SEL2_31 FM(I2C_SEL_5_0) FM(I2C_SEL_5_1)
#define MOD_SEL2_30 FM(I2C_SEL_3_0) FM(I2C_SEL_3_1)
#define MOD_SEL2_29 FM(I2C_SEL_0_0) FM(I2C_SEL_0_1)
-#define MOD_SEL2_2_1 FM(SEL_VSP_0) FM(SEL_VSP_1) FM(SEL_VSP_2) FM(SEL_VSP_3)
#define MOD_SEL2_0 FM(SEL_VIN4_0) FM(SEL_VIN4_1)
#define PINMUX_MOD_SELS\
@@ -512,7 +511,7 @@ MOD_SEL0_7_6 \
MOD_SEL0_5_4 MOD_SEL1_5 \
MOD_SEL1_4 \
MOD_SEL0_3 MOD_SEL1_3 \
-MOD_SEL0_2_1 MOD_SEL1_2 MOD_SEL2_2_1 \
+MOD_SEL0_2_1 MOD_SEL1_2 \
MOD_SEL1_1 \
MOD_SEL1_0 MOD_SEL2_0
@@ -569,18 +568,18 @@ static const u16 pinmux_data[] = {
PINMUX_SINGLE(SSI_WS5),
/* IPSR0 */
- PINMUX_IPSR_DATA(IP0_3_0, AVB_MDC),
+ PINMUX_IPSR_GPSR(IP0_3_0, AVB_MDC),
PINMUX_IPSR_MSEL(IP0_3_0, MSIOF2_SS2_C, SEL_MSIOF2_2),
- PINMUX_IPSR_DATA(IP0_7_4, AVB_MAGIC),
+ PINMUX_IPSR_GPSR(IP0_7_4, AVB_MAGIC),
PINMUX_IPSR_MSEL(IP0_7_4, MSIOF2_SS1_C, SEL_MSIOF2_2),
PINMUX_IPSR_MSEL(IP0_7_4, SCK4_A, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP0_11_8, AVB_PHY_INT),
+ PINMUX_IPSR_GPSR(IP0_11_8, AVB_PHY_INT),
PINMUX_IPSR_MSEL(IP0_11_8, MSIOF2_SYNC_C, SEL_MSIOF2_2),
PINMUX_IPSR_MSEL(IP0_11_8, RX4_A, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP0_15_12, AVB_LINK),
+ PINMUX_IPSR_GPSR(IP0_15_12, AVB_LINK),
PINMUX_IPSR_MSEL(IP0_15_12, MSIOF2_SCK_C, SEL_MSIOF2_2),
PINMUX_IPSR_MSEL(IP0_15_12, TX4_A, SEL_SCIF4_0),
@@ -592,126 +591,126 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP0_23_20, MSIOF2_TXD_C, SEL_MSIOF2_2),
PINMUX_IPSR_MSEL(IP0_23_20, RTS4_N_TANS_A, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP0_27_24, IRQ0),
- PINMUX_IPSR_DATA(IP0_27_24, QPOLB),
- PINMUX_IPSR_DATA(IP0_27_24, DU_CDE),
+ PINMUX_IPSR_GPSR(IP0_27_24, IRQ0),
+ PINMUX_IPSR_GPSR(IP0_27_24, QPOLB),
+ PINMUX_IPSR_GPSR(IP0_27_24, DU_CDE),
PINMUX_IPSR_MSEL(IP0_27_24, VI4_DATA0_B, SEL_VIN4_1),
PINMUX_IPSR_MSEL(IP0_27_24, CAN0_TX_B, SEL_RCAN0_1),
PINMUX_IPSR_MSEL(IP0_27_24, CANFD0_TX_B, SEL_CANFD0_1),
- PINMUX_IPSR_DATA(IP0_31_28, IRQ1),
- PINMUX_IPSR_DATA(IP0_31_28, QPOLA),
- PINMUX_IPSR_DATA(IP0_31_28, DU_DISP),
+ PINMUX_IPSR_GPSR(IP0_31_28, IRQ1),
+ PINMUX_IPSR_GPSR(IP0_31_28, QPOLA),
+ PINMUX_IPSR_GPSR(IP0_31_28, DU_DISP),
PINMUX_IPSR_MSEL(IP0_31_28, VI4_DATA1_B, SEL_VIN4_1),
PINMUX_IPSR_MSEL(IP0_31_28, CAN0_RX_B, SEL_RCAN0_1),
PINMUX_IPSR_MSEL(IP0_31_28, CANFD0_RX_B, SEL_CANFD0_1),
/* IPSR1 */
- PINMUX_IPSR_DATA(IP1_3_0, IRQ2),
- PINMUX_IPSR_DATA(IP1_3_0, QCPV_QDE),
- PINMUX_IPSR_DATA(IP1_3_0, DU_EXODDF_DU_ODDF_DISP_CDE),
+ PINMUX_IPSR_GPSR(IP1_3_0, IRQ2),
+ PINMUX_IPSR_GPSR(IP1_3_0, QCPV_QDE),
+ PINMUX_IPSR_GPSR(IP1_3_0, DU_EXODDF_DU_ODDF_DISP_CDE),
PINMUX_IPSR_MSEL(IP1_3_0, VI4_DATA2_B, SEL_VIN4_1),
PINMUX_IPSR_MSEL(IP1_3_0, PWM3_B, SEL_PWM3_1),
- PINMUX_IPSR_DATA(IP1_7_4, IRQ3),
- PINMUX_IPSR_DATA(IP1_7_4, QSTVB_QVE),
- PINMUX_IPSR_DATA(IP1_7_4, A25),
- PINMUX_IPSR_DATA(IP1_7_4, DU_DOTCLKOUT1),
+ PINMUX_IPSR_GPSR(IP1_7_4, IRQ3),
+ PINMUX_IPSR_GPSR(IP1_7_4, QSTVB_QVE),
+ PINMUX_IPSR_GPSR(IP1_7_4, A25),
+ PINMUX_IPSR_GPSR(IP1_7_4, DU_DOTCLKOUT1),
PINMUX_IPSR_MSEL(IP1_7_4, VI4_DATA3_B, SEL_VIN4_1),
PINMUX_IPSR_MSEL(IP1_7_4, PWM4_B, SEL_PWM4_1),
- PINMUX_IPSR_DATA(IP1_11_8, IRQ4),
- PINMUX_IPSR_DATA(IP1_11_8, QSTH_QHS),
- PINMUX_IPSR_DATA(IP1_11_8, A24),
- PINMUX_IPSR_DATA(IP1_11_8, DU_EXHSYNC_DU_HSYNC),
+ PINMUX_IPSR_GPSR(IP1_11_8, IRQ4),
+ PINMUX_IPSR_GPSR(IP1_11_8, QSTH_QHS),
+ PINMUX_IPSR_GPSR(IP1_11_8, A24),
+ PINMUX_IPSR_GPSR(IP1_11_8, DU_EXHSYNC_DU_HSYNC),
PINMUX_IPSR_MSEL(IP1_11_8, VI4_DATA4_B, SEL_VIN4_1),
PINMUX_IPSR_MSEL(IP1_11_8, PWM5_B, SEL_PWM5_1),
- PINMUX_IPSR_DATA(IP1_15_12, IRQ5),
- PINMUX_IPSR_DATA(IP1_15_12, QSTB_QHE),
- PINMUX_IPSR_DATA(IP1_15_12, A23),
- PINMUX_IPSR_DATA(IP1_15_12, DU_EXVSYNC_DU_VSYNC),
+ PINMUX_IPSR_GPSR(IP1_15_12, IRQ5),
+ PINMUX_IPSR_GPSR(IP1_15_12, QSTB_QHE),
+ PINMUX_IPSR_GPSR(IP1_15_12, A23),
+ PINMUX_IPSR_GPSR(IP1_15_12, DU_EXVSYNC_DU_VSYNC),
PINMUX_IPSR_MSEL(IP1_15_12, VI4_DATA5_B, SEL_VIN4_1),
PINMUX_IPSR_MSEL(IP1_15_12, PWM6_B, SEL_PWM6_1),
- PINMUX_IPSR_DATA(IP1_19_16, PWM0),
- PINMUX_IPSR_DATA(IP1_19_16, AVB_AVTP_PPS),
- PINMUX_IPSR_DATA(IP1_19_16, A22),
+ PINMUX_IPSR_GPSR(IP1_19_16, PWM0),
+ PINMUX_IPSR_GPSR(IP1_19_16, AVB_AVTP_PPS),
+ PINMUX_IPSR_GPSR(IP1_19_16, A22),
PINMUX_IPSR_MSEL(IP1_19_16, VI4_DATA6_B, SEL_VIN4_1),
PINMUX_IPSR_MSEL(IP1_19_16, IECLK_B, SEL_IEBUS_1),
PINMUX_IPSR_MSEL(IP1_23_20, PWM1_A, SEL_PWM1_0),
- PINMUX_IPSR_DATA(IP1_23_20, A21),
+ PINMUX_IPSR_GPSR(IP1_23_20, A21),
PINMUX_IPSR_MSEL(IP1_23_20, HRX3_D, SEL_HSCIF3_3),
PINMUX_IPSR_MSEL(IP1_23_20, VI4_DATA7_B, SEL_VIN4_1),
PINMUX_IPSR_MSEL(IP1_23_20, IERX_B, SEL_IEBUS_1),
PINMUX_IPSR_MSEL(IP1_27_24, PWM2_A, SEL_PWM2_0),
- PINMUX_IPSR_DATA(IP1_27_24, A20),
+ PINMUX_IPSR_GPSR(IP1_27_24, A20),
PINMUX_IPSR_MSEL(IP1_27_24, HTX3_D, SEL_HSCIF3_3),
PINMUX_IPSR_MSEL(IP1_27_24, IETX_B, SEL_IEBUS_1),
- PINMUX_IPSR_DATA(IP1_31_28, A0),
- PINMUX_IPSR_DATA(IP1_31_28, LCDOUT16),
+ PINMUX_IPSR_GPSR(IP1_31_28, A0),
+ PINMUX_IPSR_GPSR(IP1_31_28, LCDOUT16),
PINMUX_IPSR_MSEL(IP1_31_28, MSIOF3_SYNC_B, SEL_MSIOF3_1),
- PINMUX_IPSR_DATA(IP1_31_28, VI4_DATA8),
- PINMUX_IPSR_DATA(IP1_31_28, DU_DB0),
+ PINMUX_IPSR_GPSR(IP1_31_28, VI4_DATA8),
+ PINMUX_IPSR_GPSR(IP1_31_28, DU_DB0),
PINMUX_IPSR_MSEL(IP1_31_28, PWM3_A, SEL_PWM3_0),
/* IPSR2 */
- PINMUX_IPSR_DATA(IP2_3_0, A1),
- PINMUX_IPSR_DATA(IP2_3_0, LCDOUT17),
+ PINMUX_IPSR_GPSR(IP2_3_0, A1),
+ PINMUX_IPSR_GPSR(IP2_3_0, LCDOUT17),
PINMUX_IPSR_MSEL(IP2_3_0, MSIOF3_TXD_B, SEL_MSIOF3_1),
- PINMUX_IPSR_DATA(IP2_3_0, VI4_DATA9),
- PINMUX_IPSR_DATA(IP2_3_0, DU_DB1),
+ PINMUX_IPSR_GPSR(IP2_3_0, VI4_DATA9),
+ PINMUX_IPSR_GPSR(IP2_3_0, DU_DB1),
PINMUX_IPSR_MSEL(IP2_3_0, PWM4_A, SEL_PWM4_0),
- PINMUX_IPSR_DATA(IP2_7_4, A2),
- PINMUX_IPSR_DATA(IP2_7_4, LCDOUT18),
+ PINMUX_IPSR_GPSR(IP2_7_4, A2),
+ PINMUX_IPSR_GPSR(IP2_7_4, LCDOUT18),
PINMUX_IPSR_MSEL(IP2_7_4, MSIOF3_SCK_B, SEL_MSIOF3_1),
- PINMUX_IPSR_DATA(IP2_7_4, VI4_DATA10),
- PINMUX_IPSR_DATA(IP2_7_4, DU_DB2),
+ PINMUX_IPSR_GPSR(IP2_7_4, VI4_DATA10),
+ PINMUX_IPSR_GPSR(IP2_7_4, DU_DB2),
PINMUX_IPSR_MSEL(IP2_7_4, PWM5_A, SEL_PWM5_0),
- PINMUX_IPSR_DATA(IP2_11_8, A3),
- PINMUX_IPSR_DATA(IP2_11_8, LCDOUT19),
+ PINMUX_IPSR_GPSR(IP2_11_8, A3),
+ PINMUX_IPSR_GPSR(IP2_11_8, LCDOUT19),
PINMUX_IPSR_MSEL(IP2_11_8, MSIOF3_RXD_B, SEL_MSIOF3_1),
- PINMUX_IPSR_DATA(IP2_11_8, VI4_DATA11),
- PINMUX_IPSR_DATA(IP2_11_8, DU_DB3),
+ PINMUX_IPSR_GPSR(IP2_11_8, VI4_DATA11),
+ PINMUX_IPSR_GPSR(IP2_11_8, DU_DB3),
PINMUX_IPSR_MSEL(IP2_11_8, PWM6_A, SEL_PWM6_0),
- PINMUX_IPSR_DATA(IP2_15_12, A4),
- PINMUX_IPSR_DATA(IP2_15_12, LCDOUT20),
+ PINMUX_IPSR_GPSR(IP2_15_12, A4),
+ PINMUX_IPSR_GPSR(IP2_15_12, LCDOUT20),
PINMUX_IPSR_MSEL(IP2_15_12, MSIOF3_SS1_B, SEL_MSIOF3_1),
- PINMUX_IPSR_DATA(IP2_15_12, VI4_DATA12),
- PINMUX_IPSR_DATA(IP2_15_12, VI5_DATA12),
- PINMUX_IPSR_DATA(IP2_15_12, DU_DB4),
+ PINMUX_IPSR_GPSR(IP2_15_12, VI4_DATA12),
+ PINMUX_IPSR_GPSR(IP2_15_12, VI5_DATA12),
+ PINMUX_IPSR_GPSR(IP2_15_12, DU_DB4),
- PINMUX_IPSR_DATA(IP2_19_16, A5),
- PINMUX_IPSR_DATA(IP2_19_16, LCDOUT21),
+ PINMUX_IPSR_GPSR(IP2_19_16, A5),
+ PINMUX_IPSR_GPSR(IP2_19_16, LCDOUT21),
PINMUX_IPSR_MSEL(IP2_19_16, MSIOF3_SS2_B, SEL_MSIOF3_1),
PINMUX_IPSR_MSEL(IP2_19_16, SCK4_B, SEL_SCIF4_1),
- PINMUX_IPSR_DATA(IP2_19_16, VI4_DATA13),
- PINMUX_IPSR_DATA(IP2_19_16, VI5_DATA13),
- PINMUX_IPSR_DATA(IP2_19_16, DU_DB5),
+ PINMUX_IPSR_GPSR(IP2_19_16, VI4_DATA13),
+ PINMUX_IPSR_GPSR(IP2_19_16, VI5_DATA13),
+ PINMUX_IPSR_GPSR(IP2_19_16, DU_DB5),
- PINMUX_IPSR_DATA(IP2_23_20, A6),
- PINMUX_IPSR_DATA(IP2_23_20, LCDOUT22),
+ PINMUX_IPSR_GPSR(IP2_23_20, A6),
+ PINMUX_IPSR_GPSR(IP2_23_20, LCDOUT22),
PINMUX_IPSR_MSEL(IP2_23_20, MSIOF2_SS1_A, SEL_MSIOF2_0),
PINMUX_IPSR_MSEL(IP2_23_20, RX4_B, SEL_SCIF4_1),
- PINMUX_IPSR_DATA(IP2_23_20, VI4_DATA14),
- PINMUX_IPSR_DATA(IP2_23_20, VI5_DATA14),
- PINMUX_IPSR_DATA(IP2_23_20, DU_DB6),
+ PINMUX_IPSR_GPSR(IP2_23_20, VI4_DATA14),
+ PINMUX_IPSR_GPSR(IP2_23_20, VI5_DATA14),
+ PINMUX_IPSR_GPSR(IP2_23_20, DU_DB6),
- PINMUX_IPSR_DATA(IP2_27_24, A7),
- PINMUX_IPSR_DATA(IP2_27_24, LCDOUT23),
+ PINMUX_IPSR_GPSR(IP2_27_24, A7),
+ PINMUX_IPSR_GPSR(IP2_27_24, LCDOUT23),
PINMUX_IPSR_MSEL(IP2_27_24, MSIOF2_SS2_A, SEL_MSIOF2_0),
PINMUX_IPSR_MSEL(IP2_27_24, TX4_B, SEL_SCIF4_1),
- PINMUX_IPSR_DATA(IP2_27_24, VI4_DATA15),
- PINMUX_IPSR_DATA(IP2_27_24, VI5_DATA15),
- PINMUX_IPSR_DATA(IP2_27_24, DU_DB7),
+ PINMUX_IPSR_GPSR(IP2_27_24, VI4_DATA15),
+ PINMUX_IPSR_GPSR(IP2_27_24, VI5_DATA15),
+ PINMUX_IPSR_GPSR(IP2_27_24, DU_DB7),
- PINMUX_IPSR_DATA(IP2_31_28, A8),
+ PINMUX_IPSR_GPSR(IP2_31_28, A8),
PINMUX_IPSR_MSEL(IP2_31_28, RX3_B, SEL_SCIF3_1),
PINMUX_IPSR_MSEL(IP2_31_28, MSIOF2_SYNC_A, SEL_MSIOF2_0),
PINMUX_IPSR_MSEL(IP2_31_28, HRX4_B, SEL_HSCIF4_1),
@@ -720,99 +719,99 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP2_31_28, PWM1_B, SEL_PWM1_1),
/* IPSR3 */
- PINMUX_IPSR_DATA(IP3_3_0, A9),
+ PINMUX_IPSR_GPSR(IP3_3_0, A9),
PINMUX_IPSR_MSEL(IP3_3_0, MSIOF2_SCK_A, SEL_MSIOF2_0),
PINMUX_IPSR_MSEL(IP3_3_0, CTS4_N_B, SEL_SCIF4_1),
- PINMUX_IPSR_DATA(IP3_3_0, VI5_VSYNC_N),
+ PINMUX_IPSR_GPSR(IP3_3_0, VI5_VSYNC_N),
- PINMUX_IPSR_DATA(IP3_7_4, A10),
+ PINMUX_IPSR_GPSR(IP3_7_4, A10),
PINMUX_IPSR_MSEL(IP3_7_4, MSIOF2_RXD_A, SEL_MSIOF2_0),
PINMUX_IPSR_MSEL(IP3_7_4, RTS4_N_TANS_B, SEL_SCIF4_1),
- PINMUX_IPSR_DATA(IP3_7_4, VI5_HSYNC_N),
+ PINMUX_IPSR_GPSR(IP3_7_4, VI5_HSYNC_N),
- PINMUX_IPSR_DATA(IP3_11_8, A11),
+ PINMUX_IPSR_GPSR(IP3_11_8, A11),
PINMUX_IPSR_MSEL(IP3_11_8, TX3_B, SEL_SCIF3_1),
PINMUX_IPSR_MSEL(IP3_11_8, MSIOF2_TXD_A, SEL_MSIOF2_0),
PINMUX_IPSR_MSEL(IP3_11_8, HTX4_B, SEL_HSCIF4_1),
- PINMUX_IPSR_DATA(IP3_11_8, HSCK4),
- PINMUX_IPSR_DATA(IP3_11_8, VI5_FIELD),
+ PINMUX_IPSR_GPSR(IP3_11_8, HSCK4),
+ PINMUX_IPSR_GPSR(IP3_11_8, VI5_FIELD),
PINMUX_IPSR_MSEL(IP3_11_8, SCL6_A, SEL_I2C6_0),
PINMUX_IPSR_MSEL(IP3_11_8, AVB_AVTP_CAPTURE_B, SEL_ETHERAVB_1),
PINMUX_IPSR_MSEL(IP3_11_8, PWM2_B, SEL_PWM2_1),
- PINMUX_IPSR_DATA(IP3_15_12, A12),
- PINMUX_IPSR_DATA(IP3_15_12, LCDOUT12),
+ PINMUX_IPSR_GPSR(IP3_15_12, A12),
+ PINMUX_IPSR_GPSR(IP3_15_12, LCDOUT12),
PINMUX_IPSR_MSEL(IP3_15_12, MSIOF3_SCK_C, SEL_MSIOF3_2),
PINMUX_IPSR_MSEL(IP3_15_12, HRX4_A, SEL_HSCIF4_0),
- PINMUX_IPSR_DATA(IP3_15_12, VI5_DATA8),
- PINMUX_IPSR_DATA(IP3_15_12, DU_DG4),
+ PINMUX_IPSR_GPSR(IP3_15_12, VI5_DATA8),
+ PINMUX_IPSR_GPSR(IP3_15_12, DU_DG4),
- PINMUX_IPSR_DATA(IP3_19_16, A13),
- PINMUX_IPSR_DATA(IP3_19_16, LCDOUT13),
+ PINMUX_IPSR_GPSR(IP3_19_16, A13),
+ PINMUX_IPSR_GPSR(IP3_19_16, LCDOUT13),
PINMUX_IPSR_MSEL(IP3_19_16, MSIOF3_SYNC_C, SEL_MSIOF3_2),
PINMUX_IPSR_MSEL(IP3_19_16, HTX4_A, SEL_HSCIF4_0),
- PINMUX_IPSR_DATA(IP3_19_16, VI5_DATA9),
- PINMUX_IPSR_DATA(IP3_19_16, DU_DG5),
+ PINMUX_IPSR_GPSR(IP3_19_16, VI5_DATA9),
+ PINMUX_IPSR_GPSR(IP3_19_16, DU_DG5),
- PINMUX_IPSR_DATA(IP3_23_20, A14),
- PINMUX_IPSR_DATA(IP3_23_20, LCDOUT14),
+ PINMUX_IPSR_GPSR(IP3_23_20, A14),
+ PINMUX_IPSR_GPSR(IP3_23_20, LCDOUT14),
PINMUX_IPSR_MSEL(IP3_23_20, MSIOF3_RXD_C, SEL_MSIOF3_2),
- PINMUX_IPSR_DATA(IP3_23_20, HCTS4_N),
- PINMUX_IPSR_DATA(IP3_23_20, VI5_DATA10),
- PINMUX_IPSR_DATA(IP3_23_20, DU_DG6),
+ PINMUX_IPSR_GPSR(IP3_23_20, HCTS4_N),
+ PINMUX_IPSR_GPSR(IP3_23_20, VI5_DATA10),
+ PINMUX_IPSR_GPSR(IP3_23_20, DU_DG6),
- PINMUX_IPSR_DATA(IP3_27_24, A15),
- PINMUX_IPSR_DATA(IP3_27_24, LCDOUT15),
+ PINMUX_IPSR_GPSR(IP3_27_24, A15),
+ PINMUX_IPSR_GPSR(IP3_27_24, LCDOUT15),
PINMUX_IPSR_MSEL(IP3_27_24, MSIOF3_TXD_C, SEL_MSIOF3_2),
- PINMUX_IPSR_DATA(IP3_27_24, HRTS4_N),
- PINMUX_IPSR_DATA(IP3_27_24, VI5_DATA11),
- PINMUX_IPSR_DATA(IP3_27_24, DU_DG7),
+ PINMUX_IPSR_GPSR(IP3_27_24, HRTS4_N),
+ PINMUX_IPSR_GPSR(IP3_27_24, VI5_DATA11),
+ PINMUX_IPSR_GPSR(IP3_27_24, DU_DG7),
- PINMUX_IPSR_DATA(IP3_31_28, A16),
- PINMUX_IPSR_DATA(IP3_31_28, LCDOUT8),
- PINMUX_IPSR_DATA(IP3_31_28, VI4_FIELD),
- PINMUX_IPSR_DATA(IP3_31_28, DU_DG0),
+ PINMUX_IPSR_GPSR(IP3_31_28, A16),
+ PINMUX_IPSR_GPSR(IP3_31_28, LCDOUT8),
+ PINMUX_IPSR_GPSR(IP3_31_28, VI4_FIELD),
+ PINMUX_IPSR_GPSR(IP3_31_28, DU_DG0),
/* IPSR4 */
- PINMUX_IPSR_DATA(IP4_3_0, A17),
- PINMUX_IPSR_DATA(IP4_3_0, LCDOUT9),
- PINMUX_IPSR_DATA(IP4_3_0, VI4_VSYNC_N),
- PINMUX_IPSR_DATA(IP4_3_0, DU_DG1),
-
- PINMUX_IPSR_DATA(IP4_7_4, A18),
- PINMUX_IPSR_DATA(IP4_7_4, LCDOUT10),
- PINMUX_IPSR_DATA(IP4_7_4, VI4_HSYNC_N),
- PINMUX_IPSR_DATA(IP4_7_4, DU_DG2),
-
- PINMUX_IPSR_DATA(IP4_11_8, A19),
- PINMUX_IPSR_DATA(IP4_11_8, LCDOUT11),
- PINMUX_IPSR_DATA(IP4_11_8, VI4_CLKENB),
- PINMUX_IPSR_DATA(IP4_11_8, DU_DG3),
-
- PINMUX_IPSR_DATA(IP4_15_12, CS0_N),
- PINMUX_IPSR_DATA(IP4_15_12, VI5_CLKENB),
-
- PINMUX_IPSR_DATA(IP4_19_16, CS1_N_A26),
- PINMUX_IPSR_DATA(IP4_19_16, VI5_CLK),
+ PINMUX_IPSR_GPSR(IP4_3_0, A17),
+ PINMUX_IPSR_GPSR(IP4_3_0, LCDOUT9),
+ PINMUX_IPSR_GPSR(IP4_3_0, VI4_VSYNC_N),
+ PINMUX_IPSR_GPSR(IP4_3_0, DU_DG1),
+
+ PINMUX_IPSR_GPSR(IP4_7_4, A18),
+ PINMUX_IPSR_GPSR(IP4_7_4, LCDOUT10),
+ PINMUX_IPSR_GPSR(IP4_7_4, VI4_HSYNC_N),
+ PINMUX_IPSR_GPSR(IP4_7_4, DU_DG2),
+
+ PINMUX_IPSR_GPSR(IP4_11_8, A19),
+ PINMUX_IPSR_GPSR(IP4_11_8, LCDOUT11),
+ PINMUX_IPSR_GPSR(IP4_11_8, VI4_CLKENB),
+ PINMUX_IPSR_GPSR(IP4_11_8, DU_DG3),
+
+ PINMUX_IPSR_GPSR(IP4_15_12, CS0_N),
+ PINMUX_IPSR_GPSR(IP4_15_12, VI5_CLKENB),
+
+ PINMUX_IPSR_GPSR(IP4_19_16, CS1_N_A26),
+ PINMUX_IPSR_GPSR(IP4_19_16, VI5_CLK),
PINMUX_IPSR_MSEL(IP4_19_16, EX_WAIT0_B, SEL_LBSC_1),
- PINMUX_IPSR_DATA(IP4_23_20, BS_N),
- PINMUX_IPSR_DATA(IP4_23_20, QSTVA_QVS),
+ PINMUX_IPSR_GPSR(IP4_23_20, BS_N),
+ PINMUX_IPSR_GPSR(IP4_23_20, QSTVA_QVS),
PINMUX_IPSR_MSEL(IP4_23_20, MSIOF3_SCK_D, SEL_MSIOF3_3),
- PINMUX_IPSR_DATA(IP4_23_20, SCK3),
- PINMUX_IPSR_DATA(IP4_23_20, HSCK3),
- PINMUX_IPSR_DATA(IP4_23_20, CAN1_TX),
- PINMUX_IPSR_DATA(IP4_23_20, CANFD1_TX),
+ PINMUX_IPSR_GPSR(IP4_23_20, SCK3),
+ PINMUX_IPSR_GPSR(IP4_23_20, HSCK3),
+ PINMUX_IPSR_GPSR(IP4_23_20, CAN1_TX),
+ PINMUX_IPSR_GPSR(IP4_23_20, CANFD1_TX),
PINMUX_IPSR_MSEL(IP4_23_20, IETX_A, SEL_IEBUS_0),
- PINMUX_IPSR_DATA(IP4_27_24, RD_N),
+ PINMUX_IPSR_GPSR(IP4_27_24, RD_N),
PINMUX_IPSR_MSEL(IP4_27_24, MSIOF3_SYNC_D, SEL_MSIOF3_3),
PINMUX_IPSR_MSEL(IP4_27_24, RX3_A, SEL_SCIF3_0),
PINMUX_IPSR_MSEL(IP4_27_24, HRX3_A, SEL_HSCIF3_0),
PINMUX_IPSR_MSEL(IP4_27_24, CAN0_TX_A, SEL_RCAN0_0),
PINMUX_IPSR_MSEL(IP4_27_24, CANFD0_TX_A, SEL_CANFD0_0),
- PINMUX_IPSR_DATA(IP4_31_28, RD_WR_N),
+ PINMUX_IPSR_GPSR(IP4_31_28, RD_WR_N),
PINMUX_IPSR_MSEL(IP4_31_28, MSIOF3_RXD_D, SEL_MSIOF3_3),
PINMUX_IPSR_MSEL(IP4_31_28, TX3_A, SEL_SCIF3_0),
PINMUX_IPSR_MSEL(IP4_31_28, HTX3_A, SEL_HSCIF3_0),
@@ -820,236 +819,236 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP4_31_28, CANFD0_RX_A, SEL_CANFD0_0),
/* IPSR5 */
- PINMUX_IPSR_DATA(IP5_3_0, WE0_N),
+ PINMUX_IPSR_GPSR(IP5_3_0, WE0_N),
PINMUX_IPSR_MSEL(IP5_3_0, MSIOF3_TXD_D, SEL_MSIOF3_3),
- PINMUX_IPSR_DATA(IP5_3_0, CTS3_N),
- PINMUX_IPSR_DATA(IP5_3_0, HCTS3_N),
+ PINMUX_IPSR_GPSR(IP5_3_0, CTS3_N),
+ PINMUX_IPSR_GPSR(IP5_3_0, HCTS3_N),
PINMUX_IPSR_MSEL(IP5_3_0, SCL6_B, SEL_I2C6_1),
- PINMUX_IPSR_DATA(IP5_3_0, CAN_CLK),
+ PINMUX_IPSR_GPSR(IP5_3_0, CAN_CLK),
PINMUX_IPSR_MSEL(IP5_3_0, IECLK_A, SEL_IEBUS_0),
- PINMUX_IPSR_DATA(IP5_7_4, WE1_N),
+ PINMUX_IPSR_GPSR(IP5_7_4, WE1_N),
PINMUX_IPSR_MSEL(IP5_7_4, MSIOF3_SS1_D, SEL_MSIOF3_3),
- PINMUX_IPSR_DATA(IP5_7_4, RTS3_N_TANS),
- PINMUX_IPSR_DATA(IP5_7_4, HRTS3_N),
+ PINMUX_IPSR_GPSR(IP5_7_4, RTS3_N_TANS),
+ PINMUX_IPSR_GPSR(IP5_7_4, HRTS3_N),
PINMUX_IPSR_MSEL(IP5_7_4, SDA6_B, SEL_I2C6_1),
- PINMUX_IPSR_DATA(IP5_7_4, CAN1_RX),
- PINMUX_IPSR_DATA(IP5_7_4, CANFD1_RX),
+ PINMUX_IPSR_GPSR(IP5_7_4, CAN1_RX),
+ PINMUX_IPSR_GPSR(IP5_7_4, CANFD1_RX),
PINMUX_IPSR_MSEL(IP5_7_4, IERX_A, SEL_IEBUS_0),
PINMUX_IPSR_MSEL(IP5_11_8, EX_WAIT0_A, SEL_LBSC_0),
- PINMUX_IPSR_DATA(IP5_11_8, QCLK),
- PINMUX_IPSR_DATA(IP5_11_8, VI4_CLK),
- PINMUX_IPSR_DATA(IP5_11_8, DU_DOTCLKOUT0),
+ PINMUX_IPSR_GPSR(IP5_11_8, QCLK),
+ PINMUX_IPSR_GPSR(IP5_11_8, VI4_CLK),
+ PINMUX_IPSR_GPSR(IP5_11_8, DU_DOTCLKOUT0),
- PINMUX_IPSR_DATA(IP5_15_12, D0),
+ PINMUX_IPSR_GPSR(IP5_15_12, D0),
PINMUX_IPSR_MSEL(IP5_15_12, MSIOF2_SS1_B, SEL_MSIOF2_1),
PINMUX_IPSR_MSEL(IP5_15_12, MSIOF3_SCK_A, SEL_MSIOF3_0),
- PINMUX_IPSR_DATA(IP5_15_12, VI4_DATA16),
- PINMUX_IPSR_DATA(IP5_15_12, VI5_DATA0),
+ PINMUX_IPSR_GPSR(IP5_15_12, VI4_DATA16),
+ PINMUX_IPSR_GPSR(IP5_15_12, VI5_DATA0),
- PINMUX_IPSR_DATA(IP5_19_16, D1),
+ PINMUX_IPSR_GPSR(IP5_19_16, D1),
PINMUX_IPSR_MSEL(IP5_19_16, MSIOF2_SS2_B, SEL_MSIOF2_1),
PINMUX_IPSR_MSEL(IP5_19_16, MSIOF3_SYNC_A, SEL_MSIOF3_0),
- PINMUX_IPSR_DATA(IP5_19_16, VI4_DATA17),
- PINMUX_IPSR_DATA(IP5_19_16, VI5_DATA1),
+ PINMUX_IPSR_GPSR(IP5_19_16, VI4_DATA17),
+ PINMUX_IPSR_GPSR(IP5_19_16, VI5_DATA1),
- PINMUX_IPSR_DATA(IP5_23_20, D2),
+ PINMUX_IPSR_GPSR(IP5_23_20, D2),
PINMUX_IPSR_MSEL(IP5_23_20, MSIOF3_RXD_A, SEL_MSIOF3_0),
- PINMUX_IPSR_DATA(IP5_23_20, VI4_DATA18),
- PINMUX_IPSR_DATA(IP5_23_20, VI5_DATA2),
+ PINMUX_IPSR_GPSR(IP5_23_20, VI4_DATA18),
+ PINMUX_IPSR_GPSR(IP5_23_20, VI5_DATA2),
- PINMUX_IPSR_DATA(IP5_27_24, D3),
+ PINMUX_IPSR_GPSR(IP5_27_24, D3),
PINMUX_IPSR_MSEL(IP5_27_24, MSIOF3_TXD_A, SEL_MSIOF3_0),
- PINMUX_IPSR_DATA(IP5_27_24, VI4_DATA19),
- PINMUX_IPSR_DATA(IP5_27_24, VI5_DATA3),
+ PINMUX_IPSR_GPSR(IP5_27_24, VI4_DATA19),
+ PINMUX_IPSR_GPSR(IP5_27_24, VI5_DATA3),
- PINMUX_IPSR_DATA(IP5_31_28, D4),
+ PINMUX_IPSR_GPSR(IP5_31_28, D4),
PINMUX_IPSR_MSEL(IP5_31_28, MSIOF2_SCK_B, SEL_MSIOF2_1),
- PINMUX_IPSR_DATA(IP5_31_28, VI4_DATA20),
- PINMUX_IPSR_DATA(IP5_31_28, VI5_DATA4),
+ PINMUX_IPSR_GPSR(IP5_31_28, VI4_DATA20),
+ PINMUX_IPSR_GPSR(IP5_31_28, VI5_DATA4),
/* IPSR6 */
- PINMUX_IPSR_DATA(IP6_3_0, D5),
+ PINMUX_IPSR_GPSR(IP6_3_0, D5),
PINMUX_IPSR_MSEL(IP6_3_0, MSIOF2_SYNC_B, SEL_MSIOF2_1),
- PINMUX_IPSR_DATA(IP6_3_0, VI4_DATA21),
- PINMUX_IPSR_DATA(IP6_3_0, VI5_DATA5),
+ PINMUX_IPSR_GPSR(IP6_3_0, VI4_DATA21),
+ PINMUX_IPSR_GPSR(IP6_3_0, VI5_DATA5),
- PINMUX_IPSR_DATA(IP6_7_4, D6),
+ PINMUX_IPSR_GPSR(IP6_7_4, D6),
PINMUX_IPSR_MSEL(IP6_7_4, MSIOF2_RXD_B, SEL_MSIOF2_1),
- PINMUX_IPSR_DATA(IP6_7_4, VI4_DATA22),
- PINMUX_IPSR_DATA(IP6_7_4, VI5_DATA6),
+ PINMUX_IPSR_GPSR(IP6_7_4, VI4_DATA22),
+ PINMUX_IPSR_GPSR(IP6_7_4, VI5_DATA6),
- PINMUX_IPSR_DATA(IP6_11_8, D7),
+ PINMUX_IPSR_GPSR(IP6_11_8, D7),
PINMUX_IPSR_MSEL(IP6_11_8, MSIOF2_TXD_B, SEL_MSIOF2_1),
- PINMUX_IPSR_DATA(IP6_11_8, VI4_DATA23),
- PINMUX_IPSR_DATA(IP6_11_8, VI5_DATA7),
+ PINMUX_IPSR_GPSR(IP6_11_8, VI4_DATA23),
+ PINMUX_IPSR_GPSR(IP6_11_8, VI5_DATA7),
- PINMUX_IPSR_DATA(IP6_15_12, D8),
- PINMUX_IPSR_DATA(IP6_15_12, LCDOUT0),
+ PINMUX_IPSR_GPSR(IP6_15_12, D8),
+ PINMUX_IPSR_GPSR(IP6_15_12, LCDOUT0),
PINMUX_IPSR_MSEL(IP6_15_12, MSIOF2_SCK_D, SEL_MSIOF2_3),
PINMUX_IPSR_MSEL(IP6_15_12, SCK4_C, SEL_SCIF4_2),
PINMUX_IPSR_MSEL(IP6_15_12, VI4_DATA0_A, SEL_VIN4_0),
- PINMUX_IPSR_DATA(IP6_15_12, DU_DR0),
+ PINMUX_IPSR_GPSR(IP6_15_12, DU_DR0),
- PINMUX_IPSR_DATA(IP6_19_16, D9),
- PINMUX_IPSR_DATA(IP6_19_16, LCDOUT1),
+ PINMUX_IPSR_GPSR(IP6_19_16, D9),
+ PINMUX_IPSR_GPSR(IP6_19_16, LCDOUT1),
PINMUX_IPSR_MSEL(IP6_19_16, MSIOF2_SYNC_D, SEL_MSIOF2_3),
PINMUX_IPSR_MSEL(IP6_19_16, VI4_DATA1_A, SEL_VIN4_0),
- PINMUX_IPSR_DATA(IP6_19_16, DU_DR1),
+ PINMUX_IPSR_GPSR(IP6_19_16, DU_DR1),
- PINMUX_IPSR_DATA(IP6_23_20, D10),
- PINMUX_IPSR_DATA(IP6_23_20, LCDOUT2),
+ PINMUX_IPSR_GPSR(IP6_23_20, D10),
+ PINMUX_IPSR_GPSR(IP6_23_20, LCDOUT2),
PINMUX_IPSR_MSEL(IP6_23_20, MSIOF2_RXD_D, SEL_MSIOF2_3),
PINMUX_IPSR_MSEL(IP6_23_20, HRX3_B, SEL_HSCIF3_1),
PINMUX_IPSR_MSEL(IP6_23_20, VI4_DATA2_A, SEL_VIN4_0),
PINMUX_IPSR_MSEL(IP6_23_20, CTS4_N_C, SEL_SCIF4_2),
- PINMUX_IPSR_DATA(IP6_23_20, DU_DR2),
+ PINMUX_IPSR_GPSR(IP6_23_20, DU_DR2),
- PINMUX_IPSR_DATA(IP6_27_24, D11),
- PINMUX_IPSR_DATA(IP6_27_24, LCDOUT3),
+ PINMUX_IPSR_GPSR(IP6_27_24, D11),
+ PINMUX_IPSR_GPSR(IP6_27_24, LCDOUT3),
PINMUX_IPSR_MSEL(IP6_27_24, MSIOF2_TXD_D, SEL_MSIOF2_3),
PINMUX_IPSR_MSEL(IP6_27_24, HTX3_B, SEL_HSCIF3_1),
PINMUX_IPSR_MSEL(IP6_27_24, VI4_DATA3_A, SEL_VIN4_0),
PINMUX_IPSR_MSEL(IP6_27_24, RTS4_N_TANS_C, SEL_SCIF4_2),
- PINMUX_IPSR_DATA(IP6_27_24, DU_DR3),
+ PINMUX_IPSR_GPSR(IP6_27_24, DU_DR3),
- PINMUX_IPSR_DATA(IP6_31_28, D12),
- PINMUX_IPSR_DATA(IP6_31_28, LCDOUT4),
+ PINMUX_IPSR_GPSR(IP6_31_28, D12),
+ PINMUX_IPSR_GPSR(IP6_31_28, LCDOUT4),
PINMUX_IPSR_MSEL(IP6_31_28, MSIOF2_SS1_D, SEL_MSIOF2_3),
PINMUX_IPSR_MSEL(IP6_31_28, RX4_C, SEL_SCIF4_2),
PINMUX_IPSR_MSEL(IP6_31_28, VI4_DATA4_A, SEL_VIN4_0),
- PINMUX_IPSR_DATA(IP6_31_28, DU_DR4),
+ PINMUX_IPSR_GPSR(IP6_31_28, DU_DR4),
/* IPSR7 */
- PINMUX_IPSR_DATA(IP7_3_0, D13),
- PINMUX_IPSR_DATA(IP7_3_0, LCDOUT5),
+ PINMUX_IPSR_GPSR(IP7_3_0, D13),
+ PINMUX_IPSR_GPSR(IP7_3_0, LCDOUT5),
PINMUX_IPSR_MSEL(IP7_3_0, MSIOF2_SS2_D, SEL_MSIOF2_3),
PINMUX_IPSR_MSEL(IP7_3_0, TX4_C, SEL_SCIF4_2),
PINMUX_IPSR_MSEL(IP7_3_0, VI4_DATA5_A, SEL_VIN4_0),
- PINMUX_IPSR_DATA(IP7_3_0, DU_DR5),
+ PINMUX_IPSR_GPSR(IP7_3_0, DU_DR5),
- PINMUX_IPSR_DATA(IP7_7_4, D14),
- PINMUX_IPSR_DATA(IP7_7_4, LCDOUT6),
+ PINMUX_IPSR_GPSR(IP7_7_4, D14),
+ PINMUX_IPSR_GPSR(IP7_7_4, LCDOUT6),
PINMUX_IPSR_MSEL(IP7_7_4, MSIOF3_SS1_A, SEL_MSIOF3_0),
PINMUX_IPSR_MSEL(IP7_7_4, HRX3_C, SEL_HSCIF3_2),
PINMUX_IPSR_MSEL(IP7_7_4, VI4_DATA6_A, SEL_VIN4_0),
- PINMUX_IPSR_DATA(IP7_7_4, DU_DR6),
+ PINMUX_IPSR_GPSR(IP7_7_4, DU_DR6),
PINMUX_IPSR_MSEL(IP7_7_4, SCL6_C, SEL_I2C6_2),
- PINMUX_IPSR_DATA(IP7_11_8, D15),
- PINMUX_IPSR_DATA(IP7_11_8, LCDOUT7),
+ PINMUX_IPSR_GPSR(IP7_11_8, D15),
+ PINMUX_IPSR_GPSR(IP7_11_8, LCDOUT7),
PINMUX_IPSR_MSEL(IP7_11_8, MSIOF3_SS2_A, SEL_MSIOF3_0),
PINMUX_IPSR_MSEL(IP7_11_8, HTX3_C, SEL_HSCIF3_2),
PINMUX_IPSR_MSEL(IP7_11_8, VI4_DATA7_A, SEL_VIN4_0),
- PINMUX_IPSR_DATA(IP7_11_8, DU_DR7),
+ PINMUX_IPSR_GPSR(IP7_11_8, DU_DR7),
PINMUX_IPSR_MSEL(IP7_11_8, SDA6_C, SEL_I2C6_2),
- PINMUX_IPSR_DATA(IP7_15_12, FSCLKST),
+ PINMUX_IPSR_GPSR(IP7_15_12, FSCLKST),
- PINMUX_IPSR_DATA(IP7_19_16, SD0_CLK),
+ PINMUX_IPSR_GPSR(IP7_19_16, SD0_CLK),
PINMUX_IPSR_MSEL(IP7_19_16, MSIOF1_SCK_E, SEL_MSIOF1_4),
PINMUX_IPSR_MSEL(IP7_19_16, STP_OPWM_0_B, SEL_SSP1_0_1),
- PINMUX_IPSR_DATA(IP7_23_20, SD0_CMD),
+ PINMUX_IPSR_GPSR(IP7_23_20, SD0_CMD),
PINMUX_IPSR_MSEL(IP7_23_20, MSIOF1_SYNC_E, SEL_MSIOF1_4),
PINMUX_IPSR_MSEL(IP7_23_20, STP_IVCXO27_0_B, SEL_SSP1_0_1),
- PINMUX_IPSR_DATA(IP7_27_24, SD0_DAT0),
+ PINMUX_IPSR_GPSR(IP7_27_24, SD0_DAT0),
PINMUX_IPSR_MSEL(IP7_27_24, MSIOF1_RXD_E, SEL_MSIOF1_4),
PINMUX_IPSR_MSEL(IP7_27_24, TS_SCK0_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP7_27_24, STP_ISCLK_0_B, SEL_SSP1_0_1),
- PINMUX_IPSR_DATA(IP7_31_28, SD0_DAT1),
+ PINMUX_IPSR_GPSR(IP7_31_28, SD0_DAT1),
PINMUX_IPSR_MSEL(IP7_31_28, MSIOF1_TXD_E, SEL_MSIOF1_4),
PINMUX_IPSR_MSEL(IP7_31_28, TS_SPSYNC0_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP7_31_28, STP_ISSYNC_0_B, SEL_SSP1_0_1),
/* IPSR8 */
- PINMUX_IPSR_DATA(IP8_3_0, SD0_DAT2),
+ PINMUX_IPSR_GPSR(IP8_3_0, SD0_DAT2),
PINMUX_IPSR_MSEL(IP8_3_0, MSIOF1_SS1_E, SEL_MSIOF1_4),
PINMUX_IPSR_MSEL(IP8_3_0, TS_SDAT0_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP8_3_0, STP_ISD_0_B, SEL_SSP1_0_1),
- PINMUX_IPSR_DATA(IP8_7_4, SD0_DAT3),
+ PINMUX_IPSR_GPSR(IP8_7_4, SD0_DAT3),
PINMUX_IPSR_MSEL(IP8_7_4, MSIOF1_SS2_E, SEL_MSIOF1_4),
PINMUX_IPSR_MSEL(IP8_7_4, TS_SDEN0_B, SEL_TSIF0_1),
PINMUX_IPSR_MSEL(IP8_7_4, STP_ISEN_0_B, SEL_SSP1_0_1),
- PINMUX_IPSR_DATA(IP8_11_8, SD1_CLK),
+ PINMUX_IPSR_GPSR(IP8_11_8, SD1_CLK),
PINMUX_IPSR_MSEL(IP8_11_8, MSIOF1_SCK_G, SEL_MSIOF1_6),
PINMUX_IPSR_MSEL(IP8_11_8, SIM0_CLK_A, SEL_SIMCARD_0),
- PINMUX_IPSR_DATA(IP8_15_12, SD1_CMD),
+ PINMUX_IPSR_GPSR(IP8_15_12, SD1_CMD),
PINMUX_IPSR_MSEL(IP8_15_12, MSIOF1_SYNC_G, SEL_MSIOF1_6),
PINMUX_IPSR_MSEL(IP8_15_12, SIM0_D_A, SEL_SIMCARD_0),
PINMUX_IPSR_MSEL(IP8_15_12, STP_IVCXO27_1_B, SEL_SSP1_1_1),
- PINMUX_IPSR_DATA(IP8_19_16, SD1_DAT0),
- PINMUX_IPSR_DATA(IP8_19_16, SD2_DAT4),
+ PINMUX_IPSR_GPSR(IP8_19_16, SD1_DAT0),
+ PINMUX_IPSR_GPSR(IP8_19_16, SD2_DAT4),
PINMUX_IPSR_MSEL(IP8_19_16, MSIOF1_RXD_G, SEL_MSIOF1_6),
PINMUX_IPSR_MSEL(IP8_19_16, TS_SCK1_B, SEL_TSIF1_1),
PINMUX_IPSR_MSEL(IP8_19_16, STP_ISCLK_1_B, SEL_SSP1_1_1),
- PINMUX_IPSR_DATA(IP8_23_20, SD1_DAT1),
- PINMUX_IPSR_DATA(IP8_23_20, SD2_DAT5),
+ PINMUX_IPSR_GPSR(IP8_23_20, SD1_DAT1),
+ PINMUX_IPSR_GPSR(IP8_23_20, SD2_DAT5),
PINMUX_IPSR_MSEL(IP8_23_20, MSIOF1_TXD_G, SEL_MSIOF1_6),
PINMUX_IPSR_MSEL(IP8_23_20, TS_SPSYNC1_B, SEL_TSIF1_1),
PINMUX_IPSR_MSEL(IP8_23_20, STP_ISSYNC_1_B, SEL_SSP1_1_1),
- PINMUX_IPSR_DATA(IP8_27_24, SD1_DAT2),
- PINMUX_IPSR_DATA(IP8_27_24, SD2_DAT6),
+ PINMUX_IPSR_GPSR(IP8_27_24, SD1_DAT2),
+ PINMUX_IPSR_GPSR(IP8_27_24, SD2_DAT6),
PINMUX_IPSR_MSEL(IP8_27_24, MSIOF1_SS1_G, SEL_MSIOF1_6),
PINMUX_IPSR_MSEL(IP8_27_24, TS_SDAT1_B, SEL_TSIF1_1),
PINMUX_IPSR_MSEL(IP8_27_24, STP_ISD_1_B, SEL_SSP1_1_1),
- PINMUX_IPSR_DATA(IP8_31_28, SD1_DAT3),
- PINMUX_IPSR_DATA(IP8_31_28, SD2_DAT7),
+ PINMUX_IPSR_GPSR(IP8_31_28, SD1_DAT3),
+ PINMUX_IPSR_GPSR(IP8_31_28, SD2_DAT7),
PINMUX_IPSR_MSEL(IP8_31_28, MSIOF1_SS2_G, SEL_MSIOF1_6),
PINMUX_IPSR_MSEL(IP8_31_28, TS_SDEN1_B, SEL_TSIF1_1),
PINMUX_IPSR_MSEL(IP8_31_28, STP_ISEN_1_B, SEL_SSP1_1_1),
/* IPSR9 */
- PINMUX_IPSR_DATA(IP9_3_0, SD2_CLK),
+ PINMUX_IPSR_GPSR(IP9_3_0, SD2_CLK),
- PINMUX_IPSR_DATA(IP9_7_4, SD2_DAT0),
+ PINMUX_IPSR_GPSR(IP9_7_4, SD2_DAT0),
- PINMUX_IPSR_DATA(IP9_11_8, SD2_DAT1),
+ PINMUX_IPSR_GPSR(IP9_11_8, SD2_DAT1),
- PINMUX_IPSR_DATA(IP9_15_12, SD2_DAT2),
+ PINMUX_IPSR_GPSR(IP9_15_12, SD2_DAT2),
- PINMUX_IPSR_DATA(IP9_19_16, SD2_DAT3),
+ PINMUX_IPSR_GPSR(IP9_19_16, SD2_DAT3),
- PINMUX_IPSR_DATA(IP9_23_20, SD2_DS),
+ PINMUX_IPSR_GPSR(IP9_23_20, SD2_DS),
PINMUX_IPSR_MSEL(IP9_23_20, SATA_DEVSLP_B, SEL_SATA_1),
- PINMUX_IPSR_DATA(IP9_27_24, SD3_DAT4),
+ PINMUX_IPSR_GPSR(IP9_27_24, SD3_DAT4),
PINMUX_IPSR_MSEL(IP9_27_24, SD2_CD_A, SEL_SDHI2_0),
- PINMUX_IPSR_DATA(IP9_31_28, SD3_DAT5),
+ PINMUX_IPSR_GPSR(IP9_31_28, SD3_DAT5),
PINMUX_IPSR_MSEL(IP9_31_28, SD2_WP_A, SEL_SDHI2_0),
/* IPSR10 */
- PINMUX_IPSR_DATA(IP10_3_0, SD3_DAT6),
- PINMUX_IPSR_DATA(IP10_3_0, SD3_CD),
+ PINMUX_IPSR_GPSR(IP10_3_0, SD3_DAT6),
+ PINMUX_IPSR_GPSR(IP10_3_0, SD3_CD),
- PINMUX_IPSR_DATA(IP10_7_4, SD3_DAT7),
- PINMUX_IPSR_DATA(IP10_7_4, SD3_WP),
+ PINMUX_IPSR_GPSR(IP10_7_4, SD3_DAT7),
+ PINMUX_IPSR_GPSR(IP10_7_4, SD3_WP),
- PINMUX_IPSR_DATA(IP10_11_8, SD0_CD),
+ PINMUX_IPSR_GPSR(IP10_11_8, SD0_CD),
PINMUX_IPSR_MSEL(IP10_11_8, SCL2_B, SEL_I2C2_1),
PINMUX_IPSR_MSEL(IP10_11_8, SIM0_RST_A, SEL_SIMCARD_0),
- PINMUX_IPSR_DATA(IP10_15_12, SD0_WP),
+ PINMUX_IPSR_GPSR(IP10_15_12, SD0_WP),
PINMUX_IPSR_MSEL(IP10_15_12, SDA2_B, SEL_I2C2_1),
- PINMUX_IPSR_DATA(IP10_19_16, SD1_CD),
+ PINMUX_IPSR_GPSR(IP10_19_16, SD1_CD),
PINMUX_IPSR_MSEL(IP10_19_16, SIM0_CLK_B, SEL_SIMCARD_1),
- PINMUX_IPSR_DATA(IP10_23_20, SD1_WP),
+ PINMUX_IPSR_GPSR(IP10_23_20, SD1_WP),
PINMUX_IPSR_MSEL(IP10_23_20, SIM0_D_B, SEL_SIMCARD_1),
- PINMUX_IPSR_DATA(IP10_27_24, SCK0),
+ PINMUX_IPSR_GPSR(IP10_27_24, SCK0),
PINMUX_IPSR_MSEL(IP10_27_24, HSCK1_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP10_27_24, MSIOF1_SS2_B, SEL_MSIOF1_1),
PINMUX_IPSR_MSEL(IP10_27_24, AUDIO_CLKC_B, SEL_ADG_1),
@@ -1057,38 +1056,38 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP10_27_24, SIM0_RST_B, SEL_SIMCARD_1),
PINMUX_IPSR_MSEL(IP10_27_24, STP_OPWM_0_C, SEL_SSP1_0_2),
PINMUX_IPSR_MSEL(IP10_27_24, RIF0_CLK_B, SEL_DRIF0_1),
- PINMUX_IPSR_DATA(IP10_27_24, ADICHS2),
+ PINMUX_IPSR_GPSR(IP10_27_24, ADICHS2),
- PINMUX_IPSR_DATA(IP10_31_28, RX0),
+ PINMUX_IPSR_GPSR(IP10_31_28, RX0),
PINMUX_IPSR_MSEL(IP10_31_28, HRX1_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP10_31_28, TS_SCK0_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP10_31_28, STP_ISCLK_0_C, SEL_SSP1_0_2),
PINMUX_IPSR_MSEL(IP10_31_28, RIF0_D0_B, SEL_DRIF0_1),
/* IPSR11 */
- PINMUX_IPSR_DATA(IP11_3_0, TX0),
+ PINMUX_IPSR_GPSR(IP11_3_0, TX0),
PINMUX_IPSR_MSEL(IP11_3_0, HTX1_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP11_3_0, TS_SPSYNC0_C, SEL_TSIF0_2),
PINMUX_IPSR_MSEL(IP11_3_0, STP_ISSYNC_0_C, SEL_SSP1_0_2),
PINMUX_IPSR_MSEL(IP11_3_0, RIF0_D1_B, SEL_DRIF0_1),
- PINMUX_IPSR_DATA(IP11_7_4, CTS0_N),
+ PINMUX_IPSR_GPSR(IP11_7_4, CTS0_N),
PINMUX_IPSR_MSEL(IP11_7_4, HCTS1_N_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP11_7_4, MSIOF1_SYNC_B, SEL_MSIOF1_1),
PINMUX_IPSR_MSEL(IP11_7_4, TS_SPSYNC1_C, SEL_TSIF1_2),
PINMUX_IPSR_MSEL(IP11_7_4, STP_ISSYNC_1_C, SEL_SSP1_1_2),
PINMUX_IPSR_MSEL(IP11_7_4, RIF1_SYNC_B, SEL_DRIF1_1),
PINMUX_IPSR_MSEL(IP11_7_4, AUDIO_CLKOUT_C, SEL_ADG_2),
- PINMUX_IPSR_DATA(IP11_7_4, ADICS_SAMP),
+ PINMUX_IPSR_GPSR(IP11_7_4, ADICS_SAMP),
- PINMUX_IPSR_DATA(IP11_11_8, RTS0_N_TANS),
+ PINMUX_IPSR_GPSR(IP11_11_8, RTS0_N_TANS),
PINMUX_IPSR_MSEL(IP11_11_8, HRTS1_N_B, SEL_HSCIF1_1),
PINMUX_IPSR_MSEL(IP11_11_8, MSIOF1_SS1_B, SEL_MSIOF1_1),
PINMUX_IPSR_MSEL(IP11_11_8, AUDIO_CLKA_B, SEL_ADG_1),
PINMUX_IPSR_MSEL(IP11_11_8, SCL2_A, SEL_I2C2_0),
PINMUX_IPSR_MSEL(IP11_11_8, STP_IVCXO27_1_C, SEL_SSP1_1_2),
PINMUX_IPSR_MSEL(IP11_11_8, RIF0_SYNC_B, SEL_DRIF0_1),
- PINMUX_IPSR_DATA(IP11_11_8, ADICHS1),
+ PINMUX_IPSR_GPSR(IP11_11_8, ADICHS1),
PINMUX_IPSR_MSEL(IP11_15_12, RX1_A, SEL_SCIF1_0),
PINMUX_IPSR_MSEL(IP11_15_12, HRX1_A, SEL_HSCIF1_0),
@@ -1102,29 +1101,29 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP11_19_16, STP_ISEN_0_C, SEL_SSP1_0_2),
PINMUX_IPSR_MSEL(IP11_19_16, RIF1_D0_C, SEL_DRIF1_2),
- PINMUX_IPSR_DATA(IP11_23_20, CTS1_N),
+ PINMUX_IPSR_GPSR(IP11_23_20, CTS1_N),
PINMUX_IPSR_MSEL(IP11_23_20, HCTS1_N_A, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP11_23_20, MSIOF1_RXD_B, SEL_MSIOF1_1),
PINMUX_IPSR_MSEL(IP11_23_20, TS_SDEN1_C, SEL_TSIF1_2),
PINMUX_IPSR_MSEL(IP11_23_20, STP_ISEN_1_C, SEL_SSP1_1_2),
PINMUX_IPSR_MSEL(IP11_23_20, RIF1_D0_B, SEL_DRIF1_1),
- PINMUX_IPSR_DATA(IP11_23_20, ADIDATA),
+ PINMUX_IPSR_GPSR(IP11_23_20, ADIDATA),
- PINMUX_IPSR_DATA(IP11_27_24, RTS1_N_TANS),
+ PINMUX_IPSR_GPSR(IP11_27_24, RTS1_N_TANS),
PINMUX_IPSR_MSEL(IP11_27_24, HRTS1_N_A, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP11_27_24, MSIOF1_TXD_B, SEL_MSIOF1_1),
PINMUX_IPSR_MSEL(IP11_27_24, TS_SDAT1_C, SEL_TSIF1_2),
PINMUX_IPSR_MSEL(IP11_27_24, STP_ISD_1_C, SEL_SSP1_1_2),
PINMUX_IPSR_MSEL(IP11_27_24, RIF1_D1_B, SEL_DRIF1_1),
- PINMUX_IPSR_DATA(IP11_27_24, ADICHS0),
+ PINMUX_IPSR_GPSR(IP11_27_24, ADICHS0),
- PINMUX_IPSR_DATA(IP11_31_28, SCK2),
+ PINMUX_IPSR_GPSR(IP11_31_28, SCK2),
PINMUX_IPSR_MSEL(IP11_31_28, SCIF_CLK_B, SEL_SCIF1_1),
PINMUX_IPSR_MSEL(IP11_31_28, MSIOF1_SCK_B, SEL_MSIOF1_1),
PINMUX_IPSR_MSEL(IP11_31_28, TS_SCK1_C, SEL_TSIF1_2),
PINMUX_IPSR_MSEL(IP11_31_28, STP_ISCLK_1_C, SEL_SSP1_1_2),
PINMUX_IPSR_MSEL(IP11_31_28, RIF1_CLK_B, SEL_DRIF1_1),
- PINMUX_IPSR_DATA(IP11_31_28, ADICLK),
+ PINMUX_IPSR_GPSR(IP11_31_28, ADICLK),
/* IPSR12 */
PINMUX_IPSR_MSEL(IP12_3_0, TX2_A, SEL_SCIF2_0),
@@ -1141,7 +1140,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP12_7_4, RIF1_SYNC_C, SEL_DRIF1_2),
PINMUX_IPSR_MSEL(IP12_7_4, FSO_CFE_1_B, SEL_FSO_1),
- PINMUX_IPSR_DATA(IP12_11_8, HSCK0),
+ PINMUX_IPSR_GPSR(IP12_11_8, HSCK0),
PINMUX_IPSR_MSEL(IP12_11_8, MSIOF1_SCK_D, SEL_MSIOF1_3),
PINMUX_IPSR_MSEL(IP12_11_8, AUDIO_CLKB_A, SEL_ADG_0),
PINMUX_IPSR_MSEL(IP12_11_8, SSI_SDATA1_B, SEL_SSI_1),
@@ -1149,21 +1148,21 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP12_11_8, STP_ISCLK_0_D, SEL_SSP1_0_3),
PINMUX_IPSR_MSEL(IP12_11_8, RIF0_CLK_C, SEL_DRIF0_2),
- PINMUX_IPSR_DATA(IP12_15_12, HRX0),
+ PINMUX_IPSR_GPSR(IP12_15_12, HRX0),
PINMUX_IPSR_MSEL(IP12_15_12, MSIOF1_RXD_D, SEL_MSIOF1_3),
PINMUX_IPSR_MSEL(IP12_15_12, SSI_SDATA2_B, SEL_SSI_1),
PINMUX_IPSR_MSEL(IP12_15_12, TS_SDEN0_D, SEL_TSIF0_3),
PINMUX_IPSR_MSEL(IP12_15_12, STP_ISEN_0_D, SEL_SSP1_0_3),
PINMUX_IPSR_MSEL(IP12_15_12, RIF0_D0_C, SEL_DRIF0_2),
- PINMUX_IPSR_DATA(IP12_19_16, HTX0),
+ PINMUX_IPSR_GPSR(IP12_19_16, HTX0),
PINMUX_IPSR_MSEL(IP12_19_16, MSIOF1_TXD_D, SEL_MSIOF1_3),
PINMUX_IPSR_MSEL(IP12_19_16, SSI_SDATA9_B, SEL_SSI_1),
PINMUX_IPSR_MSEL(IP12_19_16, TS_SDAT0_D, SEL_TSIF0_3),
PINMUX_IPSR_MSEL(IP12_19_16, STP_ISD_0_D, SEL_SSP1_0_3),
PINMUX_IPSR_MSEL(IP12_19_16, RIF0_D1_C, SEL_DRIF0_2),
- PINMUX_IPSR_DATA(IP12_23_20, HCTS0_N),
+ PINMUX_IPSR_GPSR(IP12_23_20, HCTS0_N),
PINMUX_IPSR_MSEL(IP12_23_20, RX2_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP12_23_20, MSIOF1_SYNC_D, SEL_MSIOF1_3),
PINMUX_IPSR_MSEL(IP12_23_20, SSI_SCK9_A, SEL_SSI_0),
@@ -1172,7 +1171,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP12_23_20, RIF0_SYNC_C, SEL_DRIF0_2),
PINMUX_IPSR_MSEL(IP12_23_20, AUDIO_CLKOUT1_A, SEL_ADG_0),
- PINMUX_IPSR_DATA(IP12_27_24, HRTS0_N),
+ PINMUX_IPSR_GPSR(IP12_27_24, HRTS0_N),
PINMUX_IPSR_MSEL(IP12_27_24, TX2_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP12_27_24, MSIOF1_SS1_D, SEL_MSIOF1_3),
PINMUX_IPSR_MSEL(IP12_27_24, SSI_WS9_A, SEL_SSI_0),
@@ -1180,20 +1179,20 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP12_27_24, BPFCLK_A, SEL_FM_0),
PINMUX_IPSR_MSEL(IP12_27_24, AUDIO_CLKOUT2_A, SEL_ADG_0),
- PINMUX_IPSR_DATA(IP12_31_28, MSIOF0_SYNC),
+ PINMUX_IPSR_GPSR(IP12_31_28, MSIOF0_SYNC),
PINMUX_IPSR_MSEL(IP12_31_28, AUDIO_CLKOUT_A, SEL_ADG_0),
/* IPSR13 */
- PINMUX_IPSR_DATA(IP13_3_0, MSIOF0_SS1),
- PINMUX_IPSR_DATA(IP13_3_0, RX5),
+ PINMUX_IPSR_GPSR(IP13_3_0, MSIOF0_SS1),
+ PINMUX_IPSR_GPSR(IP13_3_0, RX5),
PINMUX_IPSR_MSEL(IP13_3_0, AUDIO_CLKA_C, SEL_ADG_2),
PINMUX_IPSR_MSEL(IP13_3_0, SSI_SCK2_A, SEL_SSI_0),
PINMUX_IPSR_MSEL(IP13_3_0, STP_IVCXO27_0_C, SEL_SSP1_0_2),
PINMUX_IPSR_MSEL(IP13_3_0, AUDIO_CLKOUT3_A, SEL_ADG_0),
PINMUX_IPSR_MSEL(IP13_3_0, TCLK1_B, SEL_TIMER_TMU_1),
- PINMUX_IPSR_DATA(IP13_7_4, MSIOF0_SS2),
- PINMUX_IPSR_DATA(IP13_7_4, TX5),
+ PINMUX_IPSR_GPSR(IP13_7_4, MSIOF0_SS2),
+ PINMUX_IPSR_GPSR(IP13_7_4, TX5),
PINMUX_IPSR_MSEL(IP13_7_4, MSIOF1_SS2_D, SEL_MSIOF1_3),
PINMUX_IPSR_MSEL(IP13_7_4, AUDIO_CLKC_A, SEL_ADG_0),
PINMUX_IPSR_MSEL(IP13_7_4, SSI_WS2_A, SEL_SSI_0),
@@ -1201,26 +1200,26 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP13_7_4, AUDIO_CLKOUT_D, SEL_ADG_3),
PINMUX_IPSR_MSEL(IP13_7_4, SPEEDIN_B, SEL_SPEED_PULSE_1),
- PINMUX_IPSR_DATA(IP13_11_8, MLB_CLK),
+ PINMUX_IPSR_GPSR(IP13_11_8, MLB_CLK),
PINMUX_IPSR_MSEL(IP13_11_8, MSIOF1_SCK_F, SEL_MSIOF1_5),
PINMUX_IPSR_MSEL(IP13_11_8, SCL1_B, SEL_I2C1_1),
- PINMUX_IPSR_DATA(IP13_15_12, MLB_SIG),
+ PINMUX_IPSR_GPSR(IP13_15_12, MLB_SIG),
PINMUX_IPSR_MSEL(IP13_15_12, RX1_B, SEL_SCIF1_1),
PINMUX_IPSR_MSEL(IP13_15_12, MSIOF1_SYNC_F, SEL_MSIOF1_5),
PINMUX_IPSR_MSEL(IP13_15_12, SDA1_B, SEL_I2C1_1),
- PINMUX_IPSR_DATA(IP13_19_16, MLB_DAT),
+ PINMUX_IPSR_GPSR(IP13_19_16, MLB_DAT),
PINMUX_IPSR_MSEL(IP13_19_16, TX1_B, SEL_SCIF1_1),
PINMUX_IPSR_MSEL(IP13_19_16, MSIOF1_RXD_F, SEL_MSIOF1_5),
- PINMUX_IPSR_DATA(IP13_23_20, SSI_SCK0129),
+ PINMUX_IPSR_GPSR(IP13_23_20, SSI_SCK01239),
PINMUX_IPSR_MSEL(IP13_23_20, MSIOF1_TXD_F, SEL_MSIOF1_5),
- PINMUX_IPSR_DATA(IP13_27_24, SSI_WS0129),
+ PINMUX_IPSR_GPSR(IP13_27_24, SSI_WS01239),
PINMUX_IPSR_MSEL(IP13_27_24, MSIOF1_SS1_F, SEL_MSIOF1_5),
- PINMUX_IPSR_DATA(IP13_31_28, SSI_SDATA0),
+ PINMUX_IPSR_GPSR(IP13_31_28, SSI_SDATA0),
PINMUX_IPSR_MSEL(IP13_31_28, MSIOF1_SS2_F, SEL_MSIOF1_5),
/* IPSR14 */
@@ -1229,16 +1228,16 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP14_7_4, SSI_SDATA2_A, SEL_SSI_0),
PINMUX_IPSR_MSEL(IP14_7_4, SSI_SCK1_B, SEL_SSI_1),
- PINMUX_IPSR_DATA(IP14_11_8, SSI_SCK34),
+ PINMUX_IPSR_GPSR(IP14_11_8, SSI_SCK34),
PINMUX_IPSR_MSEL(IP14_11_8, MSIOF1_SS1_A, SEL_MSIOF1_0),
PINMUX_IPSR_MSEL(IP14_11_8, STP_OPWM_0_A, SEL_SSP1_0_0),
- PINMUX_IPSR_DATA(IP14_15_12, SSI_WS34),
+ PINMUX_IPSR_GPSR(IP14_15_12, SSI_WS34),
PINMUX_IPSR_MSEL(IP14_15_12, HCTS2_N_A, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP14_15_12, MSIOF1_SS2_A, SEL_MSIOF1_0),
PINMUX_IPSR_MSEL(IP14_15_12, STP_IVCXO27_0_A, SEL_SSP1_0_0),
- PINMUX_IPSR_DATA(IP14_19_16, SSI_SDATA3),
+ PINMUX_IPSR_GPSR(IP14_19_16, SSI_SDATA3),
PINMUX_IPSR_MSEL(IP14_19_16, HRTS2_N_A, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP14_19_16, MSIOF1_TXD_A, SEL_MSIOF1_0),
PINMUX_IPSR_MSEL(IP14_19_16, TS_SCK0_A, SEL_TSIF0_0),
@@ -1246,7 +1245,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP14_19_16, RIF0_D1_A, SEL_DRIF0_0),
PINMUX_IPSR_MSEL(IP14_19_16, RIF2_D0_A, SEL_DRIF2_0),
- PINMUX_IPSR_DATA(IP14_23_20, SSI_SCK4),
+ PINMUX_IPSR_GPSR(IP14_23_20, SSI_SCK4),
PINMUX_IPSR_MSEL(IP14_23_20, HRX2_A, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP14_23_20, MSIOF1_SCK_A, SEL_MSIOF1_0),
PINMUX_IPSR_MSEL(IP14_23_20, TS_SDAT0_A, SEL_TSIF0_0),
@@ -1254,7 +1253,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP14_23_20, RIF0_CLK_A, SEL_DRIF0_0),
PINMUX_IPSR_MSEL(IP14_23_20, RIF2_CLK_A, SEL_DRIF2_0),
- PINMUX_IPSR_DATA(IP14_27_24, SSI_WS4),
+ PINMUX_IPSR_GPSR(IP14_27_24, SSI_WS4),
PINMUX_IPSR_MSEL(IP14_27_24, HTX2_A, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP14_27_24, MSIOF1_SYNC_A, SEL_MSIOF1_0),
PINMUX_IPSR_MSEL(IP14_27_24, TS_SDEN0_A, SEL_TSIF0_0),
@@ -1262,7 +1261,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP14_27_24, RIF0_SYNC_A, SEL_DRIF0_0),
PINMUX_IPSR_MSEL(IP14_27_24, RIF2_SYNC_A, SEL_DRIF2_0),
- PINMUX_IPSR_DATA(IP14_31_28, SSI_SDATA4),
+ PINMUX_IPSR_GPSR(IP14_31_28, SSI_SDATA4),
PINMUX_IPSR_MSEL(IP14_31_28, HSCK2_A, SEL_HSCIF2_0),
PINMUX_IPSR_MSEL(IP14_31_28, MSIOF1_RXD_A, SEL_MSIOF1_0),
PINMUX_IPSR_MSEL(IP14_31_28, TS_SPSYNC0_A, SEL_TSIF0_0),
@@ -1271,19 +1270,19 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP14_31_28, RIF2_D1_A, SEL_DRIF2_0),
/* IPSR15 */
- PINMUX_IPSR_DATA(IP15_3_0, SSI_SCK6),
- PINMUX_IPSR_DATA(IP15_3_0, USB2_PWEN),
+ PINMUX_IPSR_GPSR(IP15_3_0, SSI_SCK6),
+ PINMUX_IPSR_GPSR(IP15_3_0, USB2_PWEN),
PINMUX_IPSR_MSEL(IP15_3_0, SIM0_RST_D, SEL_SIMCARD_3),
- PINMUX_IPSR_DATA(IP15_7_4, SSI_WS6),
- PINMUX_IPSR_DATA(IP15_7_4, USB2_OVC),
+ PINMUX_IPSR_GPSR(IP15_7_4, SSI_WS6),
+ PINMUX_IPSR_GPSR(IP15_7_4, USB2_OVC),
PINMUX_IPSR_MSEL(IP15_7_4, SIM0_D_D, SEL_SIMCARD_3),
- PINMUX_IPSR_DATA(IP15_11_8, SSI_SDATA6),
+ PINMUX_IPSR_GPSR(IP15_11_8, SSI_SDATA6),
PINMUX_IPSR_MSEL(IP15_11_8, SIM0_CLK_D, SEL_SIMCARD_3),
PINMUX_IPSR_MSEL(IP15_11_8, SATA_DEVSLP_A, SEL_SATA_0),
- PINMUX_IPSR_DATA(IP15_15_12, SSI_SCK78),
+ PINMUX_IPSR_GPSR(IP15_15_12, SSI_SCK78),
PINMUX_IPSR_MSEL(IP15_15_12, HRX2_B, SEL_HSCIF2_1),
PINMUX_IPSR_MSEL(IP15_15_12, MSIOF1_SCK_C, SEL_MSIOF1_2),
PINMUX_IPSR_MSEL(IP15_15_12, TS_SCK1_A, SEL_TSIF1_0),
@@ -1291,7 +1290,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP15_15_12, RIF1_CLK_A, SEL_DRIF1_0),
PINMUX_IPSR_MSEL(IP15_15_12, RIF3_CLK_A, SEL_DRIF3_0),
- PINMUX_IPSR_DATA(IP15_19_16, SSI_WS78),
+ PINMUX_IPSR_GPSR(IP15_19_16, SSI_WS78),
PINMUX_IPSR_MSEL(IP15_19_16, HTX2_B, SEL_HSCIF2_1),
PINMUX_IPSR_MSEL(IP15_19_16, MSIOF1_SYNC_C, SEL_MSIOF1_2),
PINMUX_IPSR_MSEL(IP15_19_16, TS_SDAT1_A, SEL_TSIF1_0),
@@ -1299,7 +1298,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP15_19_16, RIF1_SYNC_A, SEL_DRIF1_0),
PINMUX_IPSR_MSEL(IP15_19_16, RIF3_SYNC_A, SEL_DRIF3_0),
- PINMUX_IPSR_DATA(IP15_23_20, SSI_SDATA7),
+ PINMUX_IPSR_GPSR(IP15_23_20, SSI_SDATA7),
PINMUX_IPSR_MSEL(IP15_23_20, HCTS2_N_B, SEL_HSCIF2_1),
PINMUX_IPSR_MSEL(IP15_23_20, MSIOF1_RXD_C, SEL_MSIOF1_2),
PINMUX_IPSR_MSEL(IP15_23_20, TS_SDEN1_A, SEL_TSIF1_0),
@@ -1308,7 +1307,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP15_23_20, RIF3_D0_A, SEL_DRIF3_0),
PINMUX_IPSR_MSEL(IP15_23_20, TCLK2_A, SEL_TIMER_TMU_0),
- PINMUX_IPSR_DATA(IP15_27_24, SSI_SDATA8),
+ PINMUX_IPSR_GPSR(IP15_27_24, SSI_SDATA8),
PINMUX_IPSR_MSEL(IP15_27_24, HRTS2_N_B, SEL_HSCIF2_1),
PINMUX_IPSR_MSEL(IP15_27_24, MSIOF1_TXD_C, SEL_MSIOF1_2),
PINMUX_IPSR_MSEL(IP15_27_24, TS_SPSYNC1_A, SEL_TSIF1_0),
@@ -1321,13 +1320,13 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP15_31_28, MSIOF1_SS1_C, SEL_MSIOF1_2),
PINMUX_IPSR_MSEL(IP15_31_28, HSCK1_A, SEL_HSCIF1_0),
PINMUX_IPSR_MSEL(IP15_31_28, SSI_WS1_B, SEL_SSI_1),
- PINMUX_IPSR_DATA(IP15_31_28, SCK1),
+ PINMUX_IPSR_GPSR(IP15_31_28, SCK1),
PINMUX_IPSR_MSEL(IP15_31_28, STP_IVCXO27_1_A, SEL_SSP1_1_0),
- PINMUX_IPSR_DATA(IP15_31_28, SCK5),
+ PINMUX_IPSR_GPSR(IP15_31_28, SCK5),
/* IPSR16 */
PINMUX_IPSR_MSEL(IP16_3_0, AUDIO_CLKA_A, SEL_ADG_0),
- PINMUX_IPSR_DATA(IP16_3_0, CC5_OSCOUT),
+ PINMUX_IPSR_GPSR(IP16_3_0, CC5_OSCOUT),
PINMUX_IPSR_MSEL(IP16_7_4, AUDIO_CLKB_B, SEL_ADG_1),
PINMUX_IPSR_MSEL(IP16_7_4, SCIF_CLK_A, SEL_SCIF1_0),
@@ -1335,20 +1334,20 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP16_7_4, REMOCON_A, SEL_REMOCON_0),
PINMUX_IPSR_MSEL(IP16_7_4, TCLK1_A, SEL_TIMER_TMU_0),
- PINMUX_IPSR_DATA(IP16_11_8, USB0_PWEN),
+ PINMUX_IPSR_GPSR(IP16_11_8, USB0_PWEN),
PINMUX_IPSR_MSEL(IP16_11_8, SIM0_RST_C, SEL_SIMCARD_2),
PINMUX_IPSR_MSEL(IP16_11_8, TS_SCK1_D, SEL_TSIF1_3),
PINMUX_IPSR_MSEL(IP16_11_8, STP_ISCLK_1_D, SEL_SSP1_1_3),
PINMUX_IPSR_MSEL(IP16_11_8, BPFCLK_B, SEL_FM_1),
PINMUX_IPSR_MSEL(IP16_11_8, RIF3_CLK_B, SEL_DRIF3_1),
- PINMUX_IPSR_DATA(IP16_15_12, USB0_OVC),
+ PINMUX_IPSR_GPSR(IP16_15_12, USB0_OVC),
PINMUX_IPSR_MSEL(IP16_11_8, SIM0_D_C, SEL_SIMCARD_2),
PINMUX_IPSR_MSEL(IP16_11_8, TS_SDAT1_D, SEL_TSIF1_3),
PINMUX_IPSR_MSEL(IP16_11_8, STP_ISD_1_D, SEL_SSP1_1_3),
PINMUX_IPSR_MSEL(IP16_11_8, RIF3_SYNC_B, SEL_DRIF3_1),
- PINMUX_IPSR_DATA(IP16_19_16, USB1_PWEN),
+ PINMUX_IPSR_GPSR(IP16_19_16, USB1_PWEN),
PINMUX_IPSR_MSEL(IP16_19_16, SIM0_CLK_C, SEL_SIMCARD_2),
PINMUX_IPSR_MSEL(IP16_19_16, SSI_SCK1_A, SEL_SSI_0),
PINMUX_IPSR_MSEL(IP16_19_16, TS_SCK0_E, SEL_TSIF0_4),
@@ -1357,7 +1356,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP16_19_16, RIF2_CLK_B, SEL_DRIF2_1),
PINMUX_IPSR_MSEL(IP16_19_16, SPEEDIN_A, SEL_SPEED_PULSE_0),
- PINMUX_IPSR_DATA(IP16_23_20, USB1_OVC),
+ PINMUX_IPSR_GPSR(IP16_23_20, USB1_OVC),
PINMUX_IPSR_MSEL(IP16_23_20, MSIOF1_SS2_C, SEL_MSIOF1_2),
PINMUX_IPSR_MSEL(IP16_23_20, SSI_WS1_A, SEL_SSI_0),
PINMUX_IPSR_MSEL(IP16_23_20, TS_SDAT0_E, SEL_TSIF0_4),
@@ -1366,7 +1365,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP16_23_20, RIF2_SYNC_B, SEL_DRIF2_1),
PINMUX_IPSR_MSEL(IP16_23_20, REMOCON_B, SEL_REMOCON_1),
- PINMUX_IPSR_DATA(IP16_27_24, USB30_PWEN),
+ PINMUX_IPSR_GPSR(IP16_27_24, USB30_PWEN),
PINMUX_IPSR_MSEL(IP16_27_24, AUDIO_CLKOUT_B, SEL_ADG_1),
PINMUX_IPSR_MSEL(IP16_27_24, SSI_SCK2_B, SEL_SSI_1),
PINMUX_IPSR_MSEL(IP16_27_24, TS_SDEN1_D, SEL_TSIF1_3),
@@ -1374,9 +1373,9 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP16_27_24, STP_OPWM_0_E, SEL_SSP1_0_4),
PINMUX_IPSR_MSEL(IP16_27_24, RIF3_D0_B, SEL_DRIF3_1),
PINMUX_IPSR_MSEL(IP16_27_24, TCLK2_B, SEL_TIMER_TMU_1),
- PINMUX_IPSR_DATA(IP16_27_24, TPU0TO0),
+ PINMUX_IPSR_GPSR(IP16_27_24, TPU0TO0),
- PINMUX_IPSR_DATA(IP16_31_28, USB30_OVC),
+ PINMUX_IPSR_GPSR(IP16_31_28, USB30_OVC),
PINMUX_IPSR_MSEL(IP16_31_28, AUDIO_CLKOUT1_B, SEL_ADG_1),
PINMUX_IPSR_MSEL(IP16_31_28, SSI_WS2_B, SEL_SSI_1),
PINMUX_IPSR_MSEL(IP16_31_28, TS_SPSYNC1_D, SEL_TSIF1_3),
@@ -1384,24 +1383,24 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP16_31_28, STP_IVCXO27_0_E, SEL_SSP1_0_4),
PINMUX_IPSR_MSEL(IP16_31_28, RIF3_D1_B, SEL_DRIF3_1),
PINMUX_IPSR_MSEL(IP16_31_28, FSO_TOE_B, SEL_FSO_1),
- PINMUX_IPSR_DATA(IP16_31_28, TPU0TO1),
+ PINMUX_IPSR_GPSR(IP16_31_28, TPU0TO1),
/* IPSR17 */
- PINMUX_IPSR_DATA(IP17_3_0, USB31_PWEN),
+ PINMUX_IPSR_GPSR(IP17_3_0, USB31_PWEN),
PINMUX_IPSR_MSEL(IP17_3_0, AUDIO_CLKOUT2_B, SEL_ADG_1),
PINMUX_IPSR_MSEL(IP17_3_0, SSI_SCK9_B, SEL_SSI_1),
PINMUX_IPSR_MSEL(IP17_3_0, TS_SDEN0_E, SEL_TSIF0_4),
PINMUX_IPSR_MSEL(IP17_3_0, STP_ISEN_0_E, SEL_SSP1_0_4),
PINMUX_IPSR_MSEL(IP17_3_0, RIF2_D0_B, SEL_DRIF2_1),
- PINMUX_IPSR_DATA(IP17_3_0, TPU0TO2),
+ PINMUX_IPSR_GPSR(IP17_3_0, TPU0TO2),
- PINMUX_IPSR_DATA(IP17_7_4, USB31_OVC),
+ PINMUX_IPSR_GPSR(IP17_7_4, USB31_OVC),
PINMUX_IPSR_MSEL(IP17_7_4, AUDIO_CLKOUT3_B, SEL_ADG_1),
PINMUX_IPSR_MSEL(IP17_7_4, SSI_WS9_B, SEL_SSI_1),
PINMUX_IPSR_MSEL(IP17_7_4, TS_SPSYNC0_E, SEL_TSIF0_4),
PINMUX_IPSR_MSEL(IP17_7_4, STP_ISSYNC_0_E, SEL_SSP1_0_4),
PINMUX_IPSR_MSEL(IP17_7_4, RIF2_D1_B, SEL_DRIF2_1),
- PINMUX_IPSR_DATA(IP17_7_4, TPU0TO3),
+ PINMUX_IPSR_GPSR(IP17_7_4, TPU0TO3),
/* I2C */
PINMUX_IPSR_NOGP(0, I2C_SEL_0_1),
@@ -1600,6 +1599,61 @@ static const unsigned int avb_avtp_capture_b_mux[] = {
AVB_AVTP_CAPTURE_B_MARK,
};
+/* - CAN ------------------------------------------------------------------ */
+static const unsigned int can0_data_a_pins[] = {
+ /* TX, RX */
+ RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24),
+};
+static const unsigned int can0_data_a_mux[] = {
+ CAN0_TX_A_MARK, CAN0_RX_A_MARK,
+};
+static const unsigned int can0_data_b_pins[] = {
+ /* TX, RX */
+ RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1),
+};
+static const unsigned int can0_data_b_mux[] = {
+ CAN0_TX_B_MARK, CAN0_RX_B_MARK,
+};
+static const unsigned int can1_data_pins[] = {
+ /* TX, RX */
+ RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 26),
+};
+static const unsigned int can1_data_mux[] = {
+ CAN1_TX_MARK, CAN1_RX_MARK,
+};
+
+/* - CAN Clock -------------------------------------------------------------- */
+static const unsigned int can_clk_pins[] = {
+ /* CLK */
+ RCAR_GP_PIN(1, 25),
+};
+static const unsigned int can_clk_mux[] = {
+ CAN_CLK_MARK,
+};
+
+/* - CAN FD --------------------------------------------------------------- */
+static const unsigned int canfd0_data_a_pins[] = {
+ /* TX, RX */
+ RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24),
+};
+static const unsigned int canfd0_data_a_mux[] = {
+ CANFD0_TX_A_MARK, CANFD0_RX_A_MARK,
+};
+static const unsigned int canfd0_data_b_pins[] = {
+ /* TX, RX */
+ RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1),
+};
+static const unsigned int canfd0_data_b_mux[] = {
+ CANFD0_TX_B_MARK, CANFD0_RX_B_MARK,
+};
+static const unsigned int canfd1_data_pins[] = {
+ /* TX, RX */
+ RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 26),
+};
+static const unsigned int canfd1_data_mux[] = {
+ CANFD1_TX_MARK, CANFD1_RX_MARK,
+};
+
/* - HSCIF0 ----------------------------------------------------------------- */
static const unsigned int hscif0_data_pins[] = {
/* RX, TX */
@@ -1836,6 +1890,50 @@ static const unsigned int i2c6_c_mux[] = {
SDA6_C_MARK, SCL6_C_MARK,
};
+/* - INTC-EX ---------------------------------------------------------------- */
+static const unsigned int intc_ex_irq0_pins[] = {
+ /* IRQ0 */
+ RCAR_GP_PIN(2, 0),
+};
+static const unsigned int intc_ex_irq0_mux[] = {
+ IRQ0_MARK,
+};
+static const unsigned int intc_ex_irq1_pins[] = {
+ /* IRQ1 */
+ RCAR_GP_PIN(2, 1),
+};
+static const unsigned int intc_ex_irq1_mux[] = {
+ IRQ1_MARK,
+};
+static const unsigned int intc_ex_irq2_pins[] = {
+ /* IRQ2 */
+ RCAR_GP_PIN(2, 2),
+};
+static const unsigned int intc_ex_irq2_mux[] = {
+ IRQ2_MARK,
+};
+static const unsigned int intc_ex_irq3_pins[] = {
+ /* IRQ3 */
+ RCAR_GP_PIN(2, 3),
+};
+static const unsigned int intc_ex_irq3_mux[] = {
+ IRQ3_MARK,
+};
+static const unsigned int intc_ex_irq4_pins[] = {
+ /* IRQ4 */
+ RCAR_GP_PIN(2, 4),
+};
+static const unsigned int intc_ex_irq4_mux[] = {
+ IRQ4_MARK,
+};
+static const unsigned int intc_ex_irq5_pins[] = {
+ /* IRQ5 */
+ RCAR_GP_PIN(2, 5),
+};
+static const unsigned int intc_ex_irq5_mux[] = {
+ IRQ5_MARK,
+};
+
/* - MSIOF0 ----------------------------------------------------------------- */
static const unsigned int msiof0_clk_pins[] = {
/* SCK */
@@ -2492,6 +2590,105 @@ static const unsigned int msiof3_rxd_d_mux[] = {
MSIOF3_RXD_D_MARK,
};
+/* - PWM0 --------------------------------------------------------------------*/
+static const unsigned int pwm0_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 6),
+};
+static const unsigned int pwm0_mux[] = {
+ PWM0_MARK,
+};
+/* - PWM1 --------------------------------------------------------------------*/
+static const unsigned int pwm1_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 7),
+};
+static const unsigned int pwm1_a_mux[] = {
+ PWM1_A_MARK,
+};
+static const unsigned int pwm1_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 8),
+};
+static const unsigned int pwm1_b_mux[] = {
+ PWM1_B_MARK,
+};
+/* - PWM2 --------------------------------------------------------------------*/
+static const unsigned int pwm2_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 8),
+};
+static const unsigned int pwm2_a_mux[] = {
+ PWM2_A_MARK,
+};
+static const unsigned int pwm2_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 11),
+};
+static const unsigned int pwm2_b_mux[] = {
+ PWM2_B_MARK,
+};
+/* - PWM3 --------------------------------------------------------------------*/
+static const unsigned int pwm3_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 0),
+};
+static const unsigned int pwm3_a_mux[] = {
+ PWM3_A_MARK,
+};
+static const unsigned int pwm3_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 2),
+};
+static const unsigned int pwm3_b_mux[] = {
+ PWM3_B_MARK,
+};
+/* - PWM4 --------------------------------------------------------------------*/
+static const unsigned int pwm4_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 1),
+};
+static const unsigned int pwm4_a_mux[] = {
+ PWM4_A_MARK,
+};
+static const unsigned int pwm4_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 3),
+};
+static const unsigned int pwm4_b_mux[] = {
+ PWM4_B_MARK,
+};
+/* - PWM5 --------------------------------------------------------------------*/
+static const unsigned int pwm5_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 2),
+};
+static const unsigned int pwm5_a_mux[] = {
+ PWM5_A_MARK,
+};
+static const unsigned int pwm5_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 4),
+};
+static const unsigned int pwm5_b_mux[] = {
+ PWM5_B_MARK,
+};
+/* - PWM6 --------------------------------------------------------------------*/
+static const unsigned int pwm6_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 3),
+};
+static const unsigned int pwm6_a_mux[] = {
+ PWM6_A_MARK,
+};
+static const unsigned int pwm6_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 5),
+};
+static const unsigned int pwm6_b_mux[] = {
+ PWM6_B_MARK,
+};
+
/* - SATA --------------------------------------------------------------------*/
static const unsigned int sata0_devslp_a_pins[] = {
/* DEVSLP */
@@ -2926,7 +3123,7 @@ static const unsigned int ssi01239_ctrl_pins[] = {
RCAR_GP_PIN(6, 0), RCAR_GP_PIN(6, 1),
};
static const unsigned int ssi01239_ctrl_mux[] = {
- SSI_SCK0129_MARK, SSI_WS0129_MARK,
+ SSI_SCK01239_MARK, SSI_WS01239_MARK,
};
static const unsigned int ssi1_data_a_pins[] = {
/* SDATA */
@@ -3090,6 +3287,31 @@ static const unsigned int ssi9_ctrl_b_mux[] = {
SSI_SCK9_B_MARK, SSI_WS9_B_MARK,
};
+/* - USB0 ------------------------------------------------------------------- */
+static const unsigned int usb0_pins[] = {
+ /* PWEN, OVC */
+ RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25),
+};
+static const unsigned int usb0_mux[] = {
+ USB0_PWEN_MARK, USB0_OVC_MARK,
+};
+/* - USB1 ------------------------------------------------------------------- */
+static const unsigned int usb1_pins[] = {
+ /* PWEN, OVC */
+ RCAR_GP_PIN(6, 26), RCAR_GP_PIN(6, 27),
+};
+static const unsigned int usb1_mux[] = {
+ USB1_PWEN_MARK, USB1_OVC_MARK,
+};
+/* - USB2 ------------------------------------------------------------------- */
+static const unsigned int usb2_pins[] = {
+ /* PWEN, OVC */
+ RCAR_GP_PIN(6, 14), RCAR_GP_PIN(6, 15),
+};
+static const unsigned int usb2_mux[] = {
+ USB2_PWEN_MARK, USB2_OVC_MARK,
+};
+
static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(audio_clk_a_a),
SH_PFC_PIN_GROUP(audio_clk_a_b),
@@ -3117,6 +3339,13 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(avb_avtp_capture_a),
SH_PFC_PIN_GROUP(avb_avtp_match_b),
SH_PFC_PIN_GROUP(avb_avtp_capture_b),
+ SH_PFC_PIN_GROUP(can0_data_a),
+ SH_PFC_PIN_GROUP(can0_data_b),
+ SH_PFC_PIN_GROUP(can1_data),
+ SH_PFC_PIN_GROUP(can_clk),
+ SH_PFC_PIN_GROUP(canfd0_data_a),
+ SH_PFC_PIN_GROUP(canfd0_data_b),
+ SH_PFC_PIN_GROUP(canfd1_data),
SH_PFC_PIN_GROUP(hscif0_data),
SH_PFC_PIN_GROUP(hscif0_clk),
SH_PFC_PIN_GROUP(hscif0_ctrl),
@@ -3149,6 +3378,12 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(i2c6_a),
SH_PFC_PIN_GROUP(i2c6_b),
SH_PFC_PIN_GROUP(i2c6_c),
+ SH_PFC_PIN_GROUP(intc_ex_irq0),
+ SH_PFC_PIN_GROUP(intc_ex_irq1),
+ SH_PFC_PIN_GROUP(intc_ex_irq2),
+ SH_PFC_PIN_GROUP(intc_ex_irq3),
+ SH_PFC_PIN_GROUP(intc_ex_irq4),
+ SH_PFC_PIN_GROUP(intc_ex_irq5),
SH_PFC_PIN_GROUP(msiof0_clk),
SH_PFC_PIN_GROUP(msiof0_sync),
SH_PFC_PIN_GROUP(msiof0_ss1),
@@ -3242,6 +3477,19 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(msiof3_ss1_d),
SH_PFC_PIN_GROUP(msiof3_txd_d),
SH_PFC_PIN_GROUP(msiof3_rxd_d),
+ SH_PFC_PIN_GROUP(pwm0),
+ SH_PFC_PIN_GROUP(pwm1_a),
+ SH_PFC_PIN_GROUP(pwm1_b),
+ SH_PFC_PIN_GROUP(pwm2_a),
+ SH_PFC_PIN_GROUP(pwm2_b),
+ SH_PFC_PIN_GROUP(pwm3_a),
+ SH_PFC_PIN_GROUP(pwm3_b),
+ SH_PFC_PIN_GROUP(pwm4_a),
+ SH_PFC_PIN_GROUP(pwm4_b),
+ SH_PFC_PIN_GROUP(pwm5_a),
+ SH_PFC_PIN_GROUP(pwm5_b),
+ SH_PFC_PIN_GROUP(pwm6_a),
+ SH_PFC_PIN_GROUP(pwm6_b),
SH_PFC_PIN_GROUP(sata0_devslp_a),
SH_PFC_PIN_GROUP(sata0_devslp_b),
SH_PFC_PIN_GROUP(scif0_data),
@@ -3322,6 +3570,9 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(ssi9_data_b),
SH_PFC_PIN_GROUP(ssi9_ctrl_a),
SH_PFC_PIN_GROUP(ssi9_ctrl_b),
+ SH_PFC_PIN_GROUP(usb0),
+ SH_PFC_PIN_GROUP(usb1),
+ SH_PFC_PIN_GROUP(usb2),
};
static const char * const audio_clk_groups[] = {
@@ -3356,6 +3607,28 @@ static const char * const avb_groups[] = {
"avb_avtp_capture_b",
};
+static const char * const can0_groups[] = {
+ "can0_data_a",
+ "can0_data_b",
+};
+
+static const char * const can1_groups[] = {
+ "can1_data",
+};
+
+static const char * const can_clk_groups[] = {
+ "can_clk",
+};
+
+static const char * const canfd0_groups[] = {
+ "canfd0_data_a",
+ "canfd0_data_b",
+};
+
+static const char * const canfd1_groups[] = {
+ "canfd1_data",
+};
+
static const char * const hscif0_groups[] = {
"hscif0_data",
"hscif0_clk",
@@ -3412,6 +3685,15 @@ static const char * const i2c6_groups[] = {
"i2c6_c",
};
+static const char * const intc_ex_groups[] = {
+ "intc_ex_irq0",
+ "intc_ex_irq1",
+ "intc_ex_irq2",
+ "intc_ex_irq3",
+ "intc_ex_irq4",
+ "intc_ex_irq5",
+};
+
static const char * const msiof0_groups[] = {
"msiof0_clk",
"msiof0_sync",
@@ -3517,6 +3799,40 @@ static const char * const msiof3_groups[] = {
"msiof3_rxd_d",
};
+static const char * const pwm0_groups[] = {
+ "pwm0",
+};
+
+static const char * const pwm1_groups[] = {
+ "pwm1_a",
+ "pwm1_b",
+};
+
+static const char * const pwm2_groups[] = {
+ "pwm2_a",
+ "pwm2_b",
+};
+
+static const char * const pwm3_groups[] = {
+ "pwm3_a",
+ "pwm3_b",
+};
+
+static const char * const pwm4_groups[] = {
+ "pwm4_a",
+ "pwm4_b",
+};
+
+static const char * const pwm5_groups[] = {
+ "pwm5_a",
+ "pwm5_b",
+};
+
+static const char * const pwm6_groups[] = {
+ "pwm6_a",
+ "pwm6_b",
+};
+
static const char * const sata0_groups[] = {
"sata0_devslp_a",
"sata0_devslp_b",
@@ -3636,9 +3952,26 @@ static const char * const ssi_groups[] = {
"ssi9_ctrl_b",
};
+static const char * const usb0_groups[] = {
+ "usb0",
+};
+
+static const char * const usb1_groups[] = {
+ "usb1",
+};
+
+static const char * const usb2_groups[] = {
+ "usb2",
+};
+
static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(audio_clk),
SH_PFC_FUNCTION(avb),
+ SH_PFC_FUNCTION(can0),
+ SH_PFC_FUNCTION(can1),
+ SH_PFC_FUNCTION(can_clk),
+ SH_PFC_FUNCTION(canfd0),
+ SH_PFC_FUNCTION(canfd1),
SH_PFC_FUNCTION(hscif0),
SH_PFC_FUNCTION(hscif1),
SH_PFC_FUNCTION(hscif2),
@@ -3647,10 +3980,18 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(i2c1),
SH_PFC_FUNCTION(i2c2),
SH_PFC_FUNCTION(i2c6),
+ SH_PFC_FUNCTION(intc_ex),
SH_PFC_FUNCTION(msiof0),
SH_PFC_FUNCTION(msiof1),
SH_PFC_FUNCTION(msiof2),
SH_PFC_FUNCTION(msiof3),
+ SH_PFC_FUNCTION(pwm0),
+ SH_PFC_FUNCTION(pwm1),
+ SH_PFC_FUNCTION(pwm2),
+ SH_PFC_FUNCTION(pwm3),
+ SH_PFC_FUNCTION(pwm4),
+ SH_PFC_FUNCTION(pwm5),
+ SH_PFC_FUNCTION(pwm6),
SH_PFC_FUNCTION(sata0),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
@@ -3664,6 +4005,9 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(sdhi2),
SH_PFC_FUNCTION(sdhi3),
SH_PFC_FUNCTION(ssi),
+ SH_PFC_FUNCTION(usb0),
+ SH_PFC_FUNCTION(usb1),
+ SH_PFC_FUNCTION(usb2),
};
static const struct pinmux_cfg_reg pinmux_config_regs[] = {
@@ -4213,7 +4557,8 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0, 0, 0, 0, 0, 0, 0,
/* RESERVED 3 */
0, 0,
- MOD_SEL2_2_1
+ /* RESERVED 2, 1 */
+ 0, 0, 0, 0,
MOD_SEL2_0 }
},
{ },
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
index b0b328b3130b..6502e676d368 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
@@ -591,547 +591,547 @@ static const u16 pinmux_data[] = {
PINMUX_SINGLE(IRQ3_B),
/* IPSR0 */
- PINMUX_IPSR_DATA(IP0_1_0, A0),
- PINMUX_IPSR_DATA(IP0_1_0, ST0_CLKIN),
+ PINMUX_IPSR_GPSR(IP0_1_0, A0),
+ PINMUX_IPSR_GPSR(IP0_1_0, ST0_CLKIN),
PINMUX_IPSR_MSEL(IP0_1_0, LCD_DATA0_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_1_0, TCLKA_C, SEL_MTU2_CLK_1),
- PINMUX_IPSR_DATA(IP0_3_2, A1),
- PINMUX_IPSR_DATA(IP0_3_2, ST0_REQ),
+ PINMUX_IPSR_GPSR(IP0_3_2, A1),
+ PINMUX_IPSR_GPSR(IP0_3_2, ST0_REQ),
PINMUX_IPSR_MSEL(IP0_3_2, LCD_DATA1_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_3_2, TCLKB_C, SEL_MTU2_CLK_1),
- PINMUX_IPSR_DATA(IP0_5_4, A2),
- PINMUX_IPSR_DATA(IP0_5_4, ST0_SYC),
+ PINMUX_IPSR_GPSR(IP0_5_4, A2),
+ PINMUX_IPSR_GPSR(IP0_5_4, ST0_SYC),
PINMUX_IPSR_MSEL(IP0_5_4, LCD_DATA2_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_5_4, TCLKC_C, SEL_MTU2_CLK_1),
- PINMUX_IPSR_DATA(IP0_7_6, A3),
- PINMUX_IPSR_DATA(IP0_7_6, ST0_VLD),
+ PINMUX_IPSR_GPSR(IP0_7_6, A3),
+ PINMUX_IPSR_GPSR(IP0_7_6, ST0_VLD),
PINMUX_IPSR_MSEL(IP0_7_6, LCD_DATA3_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_7_6, TCLKD_C, SEL_MTU2_CLK_1),
- PINMUX_IPSR_DATA(IP0_9_8, A4),
- PINMUX_IPSR_DATA(IP0_9_8, ST0_D0),
+ PINMUX_IPSR_GPSR(IP0_9_8, A4),
+ PINMUX_IPSR_GPSR(IP0_9_8, ST0_D0),
PINMUX_IPSR_MSEL(IP0_9_8, LCD_DATA4_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_9_8, TIOC0A_C, SEL_MTU2_CH0_1),
- PINMUX_IPSR_DATA(IP0_11_10, A5),
- PINMUX_IPSR_DATA(IP0_11_10, ST0_D1),
+ PINMUX_IPSR_GPSR(IP0_11_10, A5),
+ PINMUX_IPSR_GPSR(IP0_11_10, ST0_D1),
PINMUX_IPSR_MSEL(IP0_11_10, LCD_DATA5_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_11_10, TIOC0B_C, SEL_MTU2_CH0_1),
- PINMUX_IPSR_DATA(IP0_13_12, A6),
- PINMUX_IPSR_DATA(IP0_13_12, ST0_D2),
+ PINMUX_IPSR_GPSR(IP0_13_12, A6),
+ PINMUX_IPSR_GPSR(IP0_13_12, ST0_D2),
PINMUX_IPSR_MSEL(IP0_13_12, LCD_DATA6_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_13_12, TIOC0C_C, SEL_MTU2_CH0_1),
- PINMUX_IPSR_DATA(IP0_15_14, A7),
- PINMUX_IPSR_DATA(IP0_15_14, ST0_D3),
+ PINMUX_IPSR_GPSR(IP0_15_14, A7),
+ PINMUX_IPSR_GPSR(IP0_15_14, ST0_D3),
PINMUX_IPSR_MSEL(IP0_15_14, LCD_DATA7_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_15_14, TIOC0D_C, SEL_MTU2_CH0_1),
- PINMUX_IPSR_DATA(IP0_17_16, A8),
- PINMUX_IPSR_DATA(IP0_17_16, ST0_D4),
+ PINMUX_IPSR_GPSR(IP0_17_16, A8),
+ PINMUX_IPSR_GPSR(IP0_17_16, ST0_D4),
PINMUX_IPSR_MSEL(IP0_17_16, LCD_DATA8_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_17_16, TIOC1A_C, SEL_MTU2_CH1_2),
- PINMUX_IPSR_DATA(IP0_19_18, A9),
- PINMUX_IPSR_DATA(IP0_19_18, ST0_D5),
+ PINMUX_IPSR_GPSR(IP0_19_18, A9),
+ PINMUX_IPSR_GPSR(IP0_19_18, ST0_D5),
PINMUX_IPSR_MSEL(IP0_19_18, LCD_DATA9_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_19_18, TIOC1B_C, SEL_MTU2_CH1_2),
- PINMUX_IPSR_DATA(IP0_21_20, A10),
- PINMUX_IPSR_DATA(IP0_21_20, ST0_D6),
+ PINMUX_IPSR_GPSR(IP0_21_20, A10),
+ PINMUX_IPSR_GPSR(IP0_21_20, ST0_D6),
PINMUX_IPSR_MSEL(IP0_21_20, LCD_DATA10_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_21_20, TIOC2A_C, SEL_MTU2_CH2_2),
- PINMUX_IPSR_DATA(IP0_23_22, A11),
- PINMUX_IPSR_DATA(IP0_23_22, ST0_D7),
+ PINMUX_IPSR_GPSR(IP0_23_22, A11),
+ PINMUX_IPSR_GPSR(IP0_23_22, ST0_D7),
PINMUX_IPSR_MSEL(IP0_23_22, LCD_DATA11_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_23_22, TIOC2B_C, SEL_MTU2_CH2_2),
- PINMUX_IPSR_DATA(IP0_25_24, A12),
+ PINMUX_IPSR_GPSR(IP0_25_24, A12),
PINMUX_IPSR_MSEL(IP0_25_24, LCD_DATA12_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_25_24, TIOC3A_C, SEL_MTU2_CH3_1),
- PINMUX_IPSR_DATA(IP0_27_26, A13),
+ PINMUX_IPSR_GPSR(IP0_27_26, A13),
PINMUX_IPSR_MSEL(IP0_27_26, LCD_DATA13_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_27_26, TIOC3B_C, SEL_MTU2_CH3_1),
- PINMUX_IPSR_DATA(IP0_29_28, A14),
+ PINMUX_IPSR_GPSR(IP0_29_28, A14),
PINMUX_IPSR_MSEL(IP0_29_28, LCD_DATA14_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_29_28, TIOC3C_C, SEL_MTU2_CH3_1),
- PINMUX_IPSR_DATA(IP0_31_30, A15),
- PINMUX_IPSR_DATA(IP0_31_30, ST0_VCO_CLKIN),
+ PINMUX_IPSR_GPSR(IP0_31_30, A15),
+ PINMUX_IPSR_GPSR(IP0_31_30, ST0_VCO_CLKIN),
PINMUX_IPSR_MSEL(IP0_31_30, LCD_DATA15_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP0_31_30, TIOC3D_C, SEL_MTU2_CH3_1),
/* IPSR1 */
- PINMUX_IPSR_DATA(IP1_1_0, A16),
- PINMUX_IPSR_DATA(IP1_1_0, ST0_PWM),
+ PINMUX_IPSR_GPSR(IP1_1_0, A16),
+ PINMUX_IPSR_GPSR(IP1_1_0, ST0_PWM),
PINMUX_IPSR_MSEL(IP1_1_0, LCD_DON_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP1_1_0, TIOC4A_C, SEL_MTU2_CH4_1),
- PINMUX_IPSR_DATA(IP1_3_2, A17),
- PINMUX_IPSR_DATA(IP1_3_2, ST1_VCO_CLKIN),
+ PINMUX_IPSR_GPSR(IP1_3_2, A17),
+ PINMUX_IPSR_GPSR(IP1_3_2, ST1_VCO_CLKIN),
PINMUX_IPSR_MSEL(IP1_3_2, LCD_CL1_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP1_3_2, TIOC4B_C, SEL_MTU2_CH4_1),
- PINMUX_IPSR_DATA(IP1_5_4, A18),
- PINMUX_IPSR_DATA(IP1_5_4, ST1_PWM),
+ PINMUX_IPSR_GPSR(IP1_5_4, A18),
+ PINMUX_IPSR_GPSR(IP1_5_4, ST1_PWM),
PINMUX_IPSR_MSEL(IP1_5_4, LCD_CL2_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP1_5_4, TIOC4C_C, SEL_MTU2_CH4_1),
- PINMUX_IPSR_DATA(IP1_7_6, A19),
- PINMUX_IPSR_DATA(IP1_7_6, ST1_CLKIN),
+ PINMUX_IPSR_GPSR(IP1_7_6, A19),
+ PINMUX_IPSR_GPSR(IP1_7_6, ST1_CLKIN),
PINMUX_IPSR_MSEL(IP1_7_6, LCD_CLK_A, SEL_LCDC_0),
PINMUX_IPSR_MSEL(IP1_7_6, TIOC4D_C, SEL_MTU2_CH4_1),
- PINMUX_IPSR_DATA(IP1_9_8, A20),
- PINMUX_IPSR_DATA(IP1_9_8, ST1_REQ),
+ PINMUX_IPSR_GPSR(IP1_9_8, A20),
+ PINMUX_IPSR_GPSR(IP1_9_8, ST1_REQ),
PINMUX_IPSR_MSEL(IP1_9_8, LCD_FLM_A, SEL_LCDC_0),
- PINMUX_IPSR_DATA(IP1_11_10, A21),
- PINMUX_IPSR_DATA(IP1_11_10, ST1_SYC),
+ PINMUX_IPSR_GPSR(IP1_11_10, A21),
+ PINMUX_IPSR_GPSR(IP1_11_10, ST1_SYC),
PINMUX_IPSR_MSEL(IP1_11_10, LCD_VCPWC_A, SEL_LCDC_0),
- PINMUX_IPSR_DATA(IP1_13_12, A22),
- PINMUX_IPSR_DATA(IP1_13_12, ST1_VLD),
+ PINMUX_IPSR_GPSR(IP1_13_12, A22),
+ PINMUX_IPSR_GPSR(IP1_13_12, ST1_VLD),
PINMUX_IPSR_MSEL(IP1_13_12, LCD_VEPWC_A, SEL_LCDC_0),
- PINMUX_IPSR_DATA(IP1_15_14, A23),
- PINMUX_IPSR_DATA(IP1_15_14, ST1_D0),
+ PINMUX_IPSR_GPSR(IP1_15_14, A23),
+ PINMUX_IPSR_GPSR(IP1_15_14, ST1_D0),
PINMUX_IPSR_MSEL(IP1_15_14, LCD_M_DISP_A, SEL_LCDC_0),
- PINMUX_IPSR_DATA(IP1_17_16, A24),
+ PINMUX_IPSR_GPSR(IP1_17_16, A24),
PINMUX_IPSR_MSEL(IP1_17_16, RX2_D, SEL_SCIF2_3),
- PINMUX_IPSR_DATA(IP1_17_16, ST1_D1),
+ PINMUX_IPSR_GPSR(IP1_17_16, ST1_D1),
- PINMUX_IPSR_DATA(IP1_19_18, A25),
+ PINMUX_IPSR_GPSR(IP1_19_18, A25),
PINMUX_IPSR_MSEL(IP1_17_16, RX2_D, SEL_SCIF2_3),
- PINMUX_IPSR_DATA(IP1_17_16, ST1_D2),
+ PINMUX_IPSR_GPSR(IP1_17_16, ST1_D2),
- PINMUX_IPSR_DATA(IP1_22_20, D0),
+ PINMUX_IPSR_GPSR(IP1_22_20, D0),
PINMUX_IPSR_MSEL(IP1_22_20, SD0_DAT0_A, SEL_SDHI0_0),
PINMUX_IPSR_MSEL(IP1_22_20, MMC_D0_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP1_22_20, ST1_D3),
+ PINMUX_IPSR_GPSR(IP1_22_20, ST1_D3),
PINMUX_IPSR_MSEL(IP1_22_20, FD0_A, SEL_FLCTL_0),
- PINMUX_IPSR_DATA(IP1_25_23, D1),
+ PINMUX_IPSR_GPSR(IP1_25_23, D1),
PINMUX_IPSR_MSEL(IP1_25_23, SD0_DAT0_A, SEL_SDHI0_0),
PINMUX_IPSR_MSEL(IP1_25_23, MMC_D1_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP1_25_23, ST1_D4),
+ PINMUX_IPSR_GPSR(IP1_25_23, ST1_D4),
PINMUX_IPSR_MSEL(IP1_25_23, FD1_A, SEL_FLCTL_0),
- PINMUX_IPSR_DATA(IP1_28_26, D2),
+ PINMUX_IPSR_GPSR(IP1_28_26, D2),
PINMUX_IPSR_MSEL(IP1_28_26, SD0_DAT0_A, SEL_SDHI0_0),
PINMUX_IPSR_MSEL(IP1_28_26, MMC_D2_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP1_28_26, ST1_D5),
+ PINMUX_IPSR_GPSR(IP1_28_26, ST1_D5),
PINMUX_IPSR_MSEL(IP1_28_26, FD2_A, SEL_FLCTL_0),
- PINMUX_IPSR_DATA(IP1_31_29, D3),
+ PINMUX_IPSR_GPSR(IP1_31_29, D3),
PINMUX_IPSR_MSEL(IP1_31_29, SD0_DAT0_A, SEL_SDHI0_0),
PINMUX_IPSR_MSEL(IP1_31_29, MMC_D3_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP1_31_29, ST1_D6),
+ PINMUX_IPSR_GPSR(IP1_31_29, ST1_D6),
PINMUX_IPSR_MSEL(IP1_31_29, FD3_A, SEL_FLCTL_0),
/* IPSR2 */
- PINMUX_IPSR_DATA(IP2_2_0, D4),
+ PINMUX_IPSR_GPSR(IP2_2_0, D4),
PINMUX_IPSR_MSEL(IP2_2_0, SD0_CD_A, SEL_SDHI0_0),
PINMUX_IPSR_MSEL(IP2_2_0, MMC_D4_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP2_2_0, ST1_D7),
+ PINMUX_IPSR_GPSR(IP2_2_0, ST1_D7),
PINMUX_IPSR_MSEL(IP2_2_0, FD4_A, SEL_FLCTL_0),
- PINMUX_IPSR_DATA(IP2_4_3, D5),
+ PINMUX_IPSR_GPSR(IP2_4_3, D5),
PINMUX_IPSR_MSEL(IP2_4_3, SD0_WP_A, SEL_SDHI0_0),
PINMUX_IPSR_MSEL(IP2_4_3, MMC_D5_A, SEL_MMC_0),
PINMUX_IPSR_MSEL(IP2_4_3, FD5_A, SEL_FLCTL_0),
- PINMUX_IPSR_DATA(IP2_7_5, D6),
+ PINMUX_IPSR_GPSR(IP2_7_5, D6),
PINMUX_IPSR_MSEL(IP2_7_5, RSPI_RSPCK_A, SEL_RSPI_0),
PINMUX_IPSR_MSEL(IP2_7_5, MMC_D6_A, SEL_MMC_0),
PINMUX_IPSR_MSEL(IP2_7_5, QSPCLK_A, SEL_RQSPI_0),
PINMUX_IPSR_MSEL(IP2_7_5, FD6_A, SEL_FLCTL_0),
- PINMUX_IPSR_DATA(IP2_10_8, D7),
+ PINMUX_IPSR_GPSR(IP2_10_8, D7),
PINMUX_IPSR_MSEL(IP2_10_8, RSPI_SSL_A, SEL_RSPI_0),
PINMUX_IPSR_MSEL(IP2_10_8, MMC_D7_A, SEL_MMC_0),
PINMUX_IPSR_MSEL(IP2_10_8, QSSL_A, SEL_RQSPI_0),
PINMUX_IPSR_MSEL(IP2_10_8, FD7_A, SEL_FLCTL_0),
- PINMUX_IPSR_DATA(IP2_13_11, D8),
+ PINMUX_IPSR_GPSR(IP2_13_11, D8),
PINMUX_IPSR_MSEL(IP2_13_11, SD0_CLK_A, SEL_SDHI0_0),
PINMUX_IPSR_MSEL(IP2_13_11, MMC_CLK_A, SEL_MMC_0),
PINMUX_IPSR_MSEL(IP2_13_11, QIO2_A, SEL_RQSPI_0),
PINMUX_IPSR_MSEL(IP2_13_11, FCE_A, SEL_FLCTL_0),
PINMUX_IPSR_MSEL(IP2_13_11, ET0_GTX_CLK_B, SEL_ET0_1),
- PINMUX_IPSR_DATA(IP2_16_14, D9),
+ PINMUX_IPSR_GPSR(IP2_16_14, D9),
PINMUX_IPSR_MSEL(IP2_16_14, SD0_CMD_A, SEL_SDHI0_0),
PINMUX_IPSR_MSEL(IP2_16_14, MMC_CMD_A, SEL_MMC_0),
PINMUX_IPSR_MSEL(IP2_16_14, QIO3_A, SEL_RQSPI_0),
PINMUX_IPSR_MSEL(IP2_16_14, FCLE_A, SEL_FLCTL_0),
PINMUX_IPSR_MSEL(IP2_16_14, ET0_ETXD1_B, SEL_ET0_1),
- PINMUX_IPSR_DATA(IP2_19_17, D10),
+ PINMUX_IPSR_GPSR(IP2_19_17, D10),
PINMUX_IPSR_MSEL(IP2_19_17, RSPI_MOSI_A, SEL_RSPI_0),
PINMUX_IPSR_MSEL(IP2_19_17, QMO_QIO0_A, SEL_RQSPI_0),
PINMUX_IPSR_MSEL(IP2_19_17, FALE_A, SEL_FLCTL_0),
PINMUX_IPSR_MSEL(IP2_19_17, ET0_ETXD2_B, SEL_ET0_1),
- PINMUX_IPSR_DATA(IP2_22_20, D11),
+ PINMUX_IPSR_GPSR(IP2_22_20, D11),
PINMUX_IPSR_MSEL(IP2_22_20, RSPI_MISO_A, SEL_RSPI_0),
PINMUX_IPSR_MSEL(IP2_22_20, QMI_QIO1_A, SEL_RQSPI_0),
PINMUX_IPSR_MSEL(IP2_22_20, FRE_A, SEL_FLCTL_0),
- PINMUX_IPSR_DATA(IP2_24_23, D12),
+ PINMUX_IPSR_GPSR(IP2_24_23, D12),
PINMUX_IPSR_MSEL(IP2_24_23, FWE_A, SEL_FLCTL_0),
PINMUX_IPSR_MSEL(IP2_24_23, ET0_ETXD5_B, SEL_ET0_1),
- PINMUX_IPSR_DATA(IP2_27_25, D13),
+ PINMUX_IPSR_GPSR(IP2_27_25, D13),
PINMUX_IPSR_MSEL(IP2_27_25, RX2_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP2_27_25, FRB_A, SEL_FLCTL_0),
PINMUX_IPSR_MSEL(IP2_27_25, ET0_ETXD6_B, SEL_ET0_1),
- PINMUX_IPSR_DATA(IP2_30_28, D14),
+ PINMUX_IPSR_GPSR(IP2_30_28, D14),
PINMUX_IPSR_MSEL(IP2_30_28, TX2_B, SEL_SCIF2_1),
PINMUX_IPSR_MSEL(IP2_30_28, FSE_A, SEL_FLCTL_0),
PINMUX_IPSR_MSEL(IP2_30_28, ET0_TX_CLK_B, SEL_ET0_1),
/* IPSR3 */
- PINMUX_IPSR_DATA(IP3_1_0, D15),
+ PINMUX_IPSR_GPSR(IP3_1_0, D15),
PINMUX_IPSR_MSEL(IP3_1_0, SCK2_B, SEL_SCIF2_1),
- PINMUX_IPSR_DATA(IP3_2, CS1_A26),
+ PINMUX_IPSR_GPSR(IP3_2, CS1_A26),
PINMUX_IPSR_MSEL(IP3_2, QIO3_B, SEL_RQSPI_1),
- PINMUX_IPSR_DATA(IP3_5_3, EX_CS1),
+ PINMUX_IPSR_GPSR(IP3_5_3, EX_CS1),
PINMUX_IPSR_MSEL(IP3_5_3, RX3_B, SEL_SCIF2_1),
- PINMUX_IPSR_DATA(IP3_5_3, ATACS0),
+ PINMUX_IPSR_GPSR(IP3_5_3, ATACS0),
PINMUX_IPSR_MSEL(IP3_5_3, QIO2_B, SEL_RQSPI_1),
- PINMUX_IPSR_DATA(IP3_5_3, ET0_ETXD0),
+ PINMUX_IPSR_GPSR(IP3_5_3, ET0_ETXD0),
- PINMUX_IPSR_DATA(IP3_8_6, EX_CS2),
+ PINMUX_IPSR_GPSR(IP3_8_6, EX_CS2),
PINMUX_IPSR_MSEL(IP3_8_6, TX3_B, SEL_SCIF3_1),
- PINMUX_IPSR_DATA(IP3_8_6, ATACS1),
+ PINMUX_IPSR_GPSR(IP3_8_6, ATACS1),
PINMUX_IPSR_MSEL(IP3_8_6, QSPCLK_B, SEL_RQSPI_1),
PINMUX_IPSR_MSEL(IP3_8_6, ET0_GTX_CLK_A, SEL_ET0_0),
- PINMUX_IPSR_DATA(IP3_11_9, EX_CS3),
+ PINMUX_IPSR_GPSR(IP3_11_9, EX_CS3),
PINMUX_IPSR_MSEL(IP3_11_9, SD1_CD_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_11_9, ATARD),
+ PINMUX_IPSR_GPSR(IP3_11_9, ATARD),
PINMUX_IPSR_MSEL(IP3_11_9, QMO_QIO0_B, SEL_RQSPI_1),
PINMUX_IPSR_MSEL(IP3_11_9, ET0_ETXD1_A, SEL_ET0_0),
- PINMUX_IPSR_DATA(IP3_14_12, EX_CS4),
+ PINMUX_IPSR_GPSR(IP3_14_12, EX_CS4),
PINMUX_IPSR_MSEL(IP3_14_12, SD1_WP_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_14_12, ATAWR),
+ PINMUX_IPSR_GPSR(IP3_14_12, ATAWR),
PINMUX_IPSR_MSEL(IP3_14_12, QMI_QIO1_B, SEL_RQSPI_1),
PINMUX_IPSR_MSEL(IP3_14_12, ET0_ETXD2_A, SEL_ET0_0),
- PINMUX_IPSR_DATA(IP3_17_15, EX_CS5),
+ PINMUX_IPSR_GPSR(IP3_17_15, EX_CS5),
PINMUX_IPSR_MSEL(IP3_17_15, SD1_CMD_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_17_15, ATADIR),
+ PINMUX_IPSR_GPSR(IP3_17_15, ATADIR),
PINMUX_IPSR_MSEL(IP3_17_15, QSSL_B, SEL_RQSPI_1),
PINMUX_IPSR_MSEL(IP3_17_15, ET0_ETXD3_A, SEL_ET0_0),
- PINMUX_IPSR_DATA(IP3_19_18, RD_WR),
- PINMUX_IPSR_DATA(IP3_19_18, TCLK0),
+ PINMUX_IPSR_GPSR(IP3_19_18, RD_WR),
+ PINMUX_IPSR_GPSR(IP3_19_18, TCLK0),
PINMUX_IPSR_MSEL(IP3_19_18, CAN_CLK_B, SEL_RCAN_CLK_1),
- PINMUX_IPSR_DATA(IP3_19_18, ET0_ETXD4),
+ PINMUX_IPSR_GPSR(IP3_19_18, ET0_ETXD4),
- PINMUX_IPSR_DATA(IP3_20, EX_WAIT0),
+ PINMUX_IPSR_GPSR(IP3_20, EX_WAIT0),
PINMUX_IPSR_MSEL(IP3_20, TCLK1_B, SEL_TMU_1),
- PINMUX_IPSR_DATA(IP3_23_21, EX_WAIT1),
+ PINMUX_IPSR_GPSR(IP3_23_21, EX_WAIT1),
PINMUX_IPSR_MSEL(IP3_23_21, SD1_DAT0_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_23_21, DREQ2),
+ PINMUX_IPSR_GPSR(IP3_23_21, DREQ2),
PINMUX_IPSR_MSEL(IP3_23_21, CAN1_TX_C, SEL_RCAN1_2),
PINMUX_IPSR_MSEL(IP3_23_21, ET0_LINK_C, SEL_ET0_CTL_2),
PINMUX_IPSR_MSEL(IP3_23_21, ET0_ETXD5_A, SEL_ET0_0),
- PINMUX_IPSR_DATA(IP3_26_24, EX_WAIT2),
+ PINMUX_IPSR_GPSR(IP3_26_24, EX_WAIT2),
PINMUX_IPSR_MSEL(IP3_26_24, SD1_DAT1_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_26_24, DACK2),
+ PINMUX_IPSR_GPSR(IP3_26_24, DACK2),
PINMUX_IPSR_MSEL(IP3_26_24, CAN1_RX_C, SEL_RCAN1_2),
PINMUX_IPSR_MSEL(IP3_26_24, ET0_MAGIC_C, SEL_ET0_CTL_2),
PINMUX_IPSR_MSEL(IP3_26_24, ET0_ETXD6_A, SEL_ET0_0),
- PINMUX_IPSR_DATA(IP3_29_27, DRACK0),
+ PINMUX_IPSR_GPSR(IP3_29_27, DRACK0),
PINMUX_IPSR_MSEL(IP3_29_27, SD1_DAT2_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_29_27, ATAG),
+ PINMUX_IPSR_GPSR(IP3_29_27, ATAG),
PINMUX_IPSR_MSEL(IP3_29_27, TCLK1_A, SEL_TMU_0),
- PINMUX_IPSR_DATA(IP3_29_27, ET0_ETXD7),
+ PINMUX_IPSR_GPSR(IP3_29_27, ET0_ETXD7),
/* IPSR4 */
PINMUX_IPSR_MSEL(IP4_2_0, HCTS0_A, SEL_HSCIF_0),
PINMUX_IPSR_MSEL(IP4_2_0, CTS1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_2_0, VI0_FIELD),
+ PINMUX_IPSR_GPSR(IP4_2_0, VI0_FIELD),
PINMUX_IPSR_MSEL(IP4_2_0, RMII0_RXD1_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_2_0, ET0_ERXD7),
+ PINMUX_IPSR_GPSR(IP4_2_0, ET0_ERXD7),
PINMUX_IPSR_MSEL(IP4_5_3, HRTS0_A, SEL_HSCIF_0),
PINMUX_IPSR_MSEL(IP4_5_3, RTS1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_5_3, VI0_HSYNC),
+ PINMUX_IPSR_GPSR(IP4_5_3, VI0_HSYNC),
PINMUX_IPSR_MSEL(IP4_5_3, RMII0_TXD_EN_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_5_3, ET0_RX_DV),
+ PINMUX_IPSR_GPSR(IP4_5_3, ET0_RX_DV),
PINMUX_IPSR_MSEL(IP4_8_6, HSCK0_A, SEL_HSCIF_0),
PINMUX_IPSR_MSEL(IP4_8_6, SCK1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_8_6, VI0_VSYNC),
+ PINMUX_IPSR_GPSR(IP4_8_6, VI0_VSYNC),
PINMUX_IPSR_MSEL(IP4_8_6, RMII0_RX_ER_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_8_6, ET0_RX_ER),
+ PINMUX_IPSR_GPSR(IP4_8_6, ET0_RX_ER),
PINMUX_IPSR_MSEL(IP4_11_9, HRX0_A, SEL_HSCIF_0),
PINMUX_IPSR_MSEL(IP4_11_9, RX1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_11_9, VI0_DATA0_VI0_B0),
+ PINMUX_IPSR_GPSR(IP4_11_9, VI0_DATA0_VI0_B0),
PINMUX_IPSR_MSEL(IP4_11_9, RMII0_CRS_DV_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_11_9, ET0_CRS),
+ PINMUX_IPSR_GPSR(IP4_11_9, ET0_CRS),
PINMUX_IPSR_MSEL(IP4_14_12, HTX0_A, SEL_HSCIF_0),
PINMUX_IPSR_MSEL(IP4_14_12, TX1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_14_12, VI0_DATA1_VI0_B1),
+ PINMUX_IPSR_GPSR(IP4_14_12, VI0_DATA1_VI0_B1),
PINMUX_IPSR_MSEL(IP4_14_12, RMII0_MDC_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_14_12, ET0_COL),
+ PINMUX_IPSR_GPSR(IP4_14_12, ET0_COL),
PINMUX_IPSR_MSEL(IP4_17_15, CTS0_B, SEL_SCIF0_1),
- PINMUX_IPSR_DATA(IP4_17_15, VI0_DATA2_VI0_B2),
+ PINMUX_IPSR_GPSR(IP4_17_15, VI0_DATA2_VI0_B2),
PINMUX_IPSR_MSEL(IP4_17_15, RMII0_MDIO_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_17_15, ET0_MDC),
+ PINMUX_IPSR_GPSR(IP4_17_15, ET0_MDC),
PINMUX_IPSR_MSEL(IP4_19_18, RTS0_B, SEL_SCIF0_1),
- PINMUX_IPSR_DATA(IP4_19_18, VI0_DATA3_VI0_B3),
+ PINMUX_IPSR_GPSR(IP4_19_18, VI0_DATA3_VI0_B3),
PINMUX_IPSR_MSEL(IP4_19_18, ET0_MDIO_A, SEL_ET0_0),
PINMUX_IPSR_MSEL(IP4_21_20, SCK1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_21_20, VI0_DATA4_VI0_B4),
+ PINMUX_IPSR_GPSR(IP4_21_20, VI0_DATA4_VI0_B4),
PINMUX_IPSR_MSEL(IP4_21_20, ET0_LINK_A, SEL_ET0_CTL_0),
PINMUX_IPSR_MSEL(IP4_23_22, RX1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_23_22, VI0_DATA5_VI0_B5),
+ PINMUX_IPSR_GPSR(IP4_23_22, VI0_DATA5_VI0_B5),
PINMUX_IPSR_MSEL(IP4_23_22, ET0_MAGIC_A, SEL_ET0_CTL_0),
PINMUX_IPSR_MSEL(IP4_25_24, TX1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_25_24, VI0_DATA6_VI0_G0),
+ PINMUX_IPSR_GPSR(IP4_25_24, VI0_DATA6_VI0_G0),
PINMUX_IPSR_MSEL(IP4_25_24, ET0_PHY_INT_A, SEL_ET0_CTL_0),
PINMUX_IPSR_MSEL(IP4_27_26, CTS1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_27_26, VI0_DATA7_VI0_G1),
+ PINMUX_IPSR_GPSR(IP4_27_26, VI0_DATA7_VI0_G1),
PINMUX_IPSR_MSEL(IP4_29_28, RTS1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_29_28, VI0_G2),
+ PINMUX_IPSR_GPSR(IP4_29_28, VI0_G2),
PINMUX_IPSR_MSEL(IP4_31_30, SCK2_A, SEL_SCIF2_0),
- PINMUX_IPSR_DATA(IP4_31_30, VI0_G3),
+ PINMUX_IPSR_GPSR(IP4_31_30, VI0_G3),
/* IPSR5 */
PINMUX_IPSR_MSEL(IP5_2_0, SD2_CLK_A, SEL_SDHI2_0),
PINMUX_IPSR_MSEL(IP5_2_0, RX2_A, SEL_SCIF2_0),
- PINMUX_IPSR_DATA(IP5_2_0, VI0_G4),
+ PINMUX_IPSR_GPSR(IP5_2_0, VI0_G4),
PINMUX_IPSR_MSEL(IP5_2_0, ET0_RX_CLK_B, SEL_ET0_1),
PINMUX_IPSR_MSEL(IP5_5_3, SD2_CMD_A, SEL_SDHI2_0),
PINMUX_IPSR_MSEL(IP5_5_3, TX2_A, SEL_SCIF2_0),
- PINMUX_IPSR_DATA(IP5_5_3, VI0_G5),
+ PINMUX_IPSR_GPSR(IP5_5_3, VI0_G5),
PINMUX_IPSR_MSEL(IP5_5_3, ET0_ERXD2_B, SEL_ET0_1),
PINMUX_IPSR_MSEL(IP5_8_6, SD2_DAT0_A, SEL_SDHI2_0),
PINMUX_IPSR_MSEL(IP5_8_6, RX3_A, SEL_SCIF3_0),
- PINMUX_IPSR_DATA(IP4_8_6, VI0_R0),
+ PINMUX_IPSR_GPSR(IP4_8_6, VI0_R0),
PINMUX_IPSR_MSEL(IP4_8_6, ET0_ERXD2_B, SEL_ET0_1),
PINMUX_IPSR_MSEL(IP5_11_9, SD2_DAT1_A, SEL_SDHI2_0),
PINMUX_IPSR_MSEL(IP5_11_9, TX3_A, SEL_SCIF3_0),
- PINMUX_IPSR_DATA(IP5_11_9, VI0_R1),
+ PINMUX_IPSR_GPSR(IP5_11_9, VI0_R1),
PINMUX_IPSR_MSEL(IP5_11_9, ET0_MDIO_B, SEL_ET0_1),
PINMUX_IPSR_MSEL(IP5_14_12, SD2_DAT2_A, SEL_SDHI2_0),
PINMUX_IPSR_MSEL(IP5_14_12, RX4_A, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP5_14_12, VI0_R2),
+ PINMUX_IPSR_GPSR(IP5_14_12, VI0_R2),
PINMUX_IPSR_MSEL(IP5_14_12, ET0_LINK_B, SEL_ET0_CTL_1),
PINMUX_IPSR_MSEL(IP5_17_15, SD2_DAT3_A, SEL_SDHI2_0),
PINMUX_IPSR_MSEL(IP5_17_15, TX4_A, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP5_17_15, VI0_R3),
+ PINMUX_IPSR_GPSR(IP5_17_15, VI0_R3),
PINMUX_IPSR_MSEL(IP5_17_15, ET0_MAGIC_B, SEL_ET0_CTL_1),
PINMUX_IPSR_MSEL(IP5_20_18, SD2_CD_A, SEL_SDHI2_0),
PINMUX_IPSR_MSEL(IP5_20_18, RX5_A, SEL_SCIF5_0),
- PINMUX_IPSR_DATA(IP5_20_18, VI0_R4),
+ PINMUX_IPSR_GPSR(IP5_20_18, VI0_R4),
PINMUX_IPSR_MSEL(IP5_20_18, ET0_PHY_INT_B, SEL_ET0_CTL_1),
PINMUX_IPSR_MSEL(IP5_22_21, SD2_WP_A, SEL_SDHI2_0),
PINMUX_IPSR_MSEL(IP5_22_21, TX5_A, SEL_SCIF5_0),
- PINMUX_IPSR_DATA(IP5_22_21, VI0_R5),
+ PINMUX_IPSR_GPSR(IP5_22_21, VI0_R5),
- PINMUX_IPSR_DATA(IP5_24_23, REF125CK),
- PINMUX_IPSR_DATA(IP5_24_23, ADTRG),
+ PINMUX_IPSR_GPSR(IP5_24_23, REF125CK),
+ PINMUX_IPSR_GPSR(IP5_24_23, ADTRG),
PINMUX_IPSR_MSEL(IP5_24_23, RX5_C, SEL_SCIF5_2),
- PINMUX_IPSR_DATA(IP5_26_25, REF50CK),
+ PINMUX_IPSR_GPSR(IP5_26_25, REF50CK),
PINMUX_IPSR_MSEL(IP5_26_25, CTS1_E, SEL_SCIF1_3),
PINMUX_IPSR_MSEL(IP5_26_25, HCTS0_D, SEL_HSCIF_3),
/* IPSR6 */
- PINMUX_IPSR_DATA(IP6_2_0, DU0_DR0),
+ PINMUX_IPSR_GPSR(IP6_2_0, DU0_DR0),
PINMUX_IPSR_MSEL(IP6_2_0, SCIF_CLK_B, SEL_SCIF_CLK_1),
PINMUX_IPSR_MSEL(IP6_2_0, HRX0_D, SEL_HSCIF_3),
PINMUX_IPSR_MSEL(IP6_2_0, IETX_A, SEL_IEBUS_0),
PINMUX_IPSR_MSEL(IP6_2_0, TCLKA_A, SEL_MTU2_CLK_0),
- PINMUX_IPSR_DATA(IP6_2_0, HIFD00),
+ PINMUX_IPSR_GPSR(IP6_2_0, HIFD00),
- PINMUX_IPSR_DATA(IP6_5_3, DU0_DR1),
+ PINMUX_IPSR_GPSR(IP6_5_3, DU0_DR1),
PINMUX_IPSR_MSEL(IP6_5_3, SCK0_B, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP6_5_3, HTX0_D, SEL_HSCIF_3),
PINMUX_IPSR_MSEL(IP6_5_3, IERX_A, SEL_IEBUS_0),
PINMUX_IPSR_MSEL(IP6_5_3, TCLKB_A, SEL_MTU2_CLK_0),
- PINMUX_IPSR_DATA(IP6_5_3, HIFD01),
+ PINMUX_IPSR_GPSR(IP6_5_3, HIFD01),
- PINMUX_IPSR_DATA(IP6_7_6, DU0_DR2),
+ PINMUX_IPSR_GPSR(IP6_7_6, DU0_DR2),
PINMUX_IPSR_MSEL(IP6_7_6, RX0_B, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP6_7_6, TCLKC_A, SEL_MTU2_CLK_0),
- PINMUX_IPSR_DATA(IP6_7_6, HIFD02),
+ PINMUX_IPSR_GPSR(IP6_7_6, HIFD02),
- PINMUX_IPSR_DATA(IP6_9_8, DU0_DR3),
+ PINMUX_IPSR_GPSR(IP6_9_8, DU0_DR3),
PINMUX_IPSR_MSEL(IP6_9_8, TX0_B, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP6_9_8, TCLKD_A, SEL_MTU2_CLK_0),
- PINMUX_IPSR_DATA(IP6_9_8, HIFD03),
+ PINMUX_IPSR_GPSR(IP6_9_8, HIFD03),
- PINMUX_IPSR_DATA(IP6_11_10, DU0_DR4),
+ PINMUX_IPSR_GPSR(IP6_11_10, DU0_DR4),
PINMUX_IPSR_MSEL(IP6_11_10, CTS0_C, SEL_SCIF0_2),
PINMUX_IPSR_MSEL(IP6_11_10, TIOC0A_A, SEL_MTU2_CH0_0),
- PINMUX_IPSR_DATA(IP6_11_10, HIFD04),
+ PINMUX_IPSR_GPSR(IP6_11_10, HIFD04),
- PINMUX_IPSR_DATA(IP6_13_12, DU0_DR5),
+ PINMUX_IPSR_GPSR(IP6_13_12, DU0_DR5),
PINMUX_IPSR_MSEL(IP6_13_12, RTS0_C, SEL_SCIF0_1),
PINMUX_IPSR_MSEL(IP6_13_12, TIOC0B_A, SEL_MTU2_CH0_0),
- PINMUX_IPSR_DATA(IP6_13_12, HIFD05),
+ PINMUX_IPSR_GPSR(IP6_13_12, HIFD05),
- PINMUX_IPSR_DATA(IP6_15_14, DU0_DR6),
+ PINMUX_IPSR_GPSR(IP6_15_14, DU0_DR6),
PINMUX_IPSR_MSEL(IP6_15_14, SCK1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP6_15_14, TIOC0C_A, SEL_MTU2_CH0_0),
- PINMUX_IPSR_DATA(IP6_15_14, HIFD06),
+ PINMUX_IPSR_GPSR(IP6_15_14, HIFD06),
- PINMUX_IPSR_DATA(IP6_17_16, DU0_DR7),
+ PINMUX_IPSR_GPSR(IP6_17_16, DU0_DR7),
PINMUX_IPSR_MSEL(IP6_17_16, RX1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP6_17_16, TIOC0D_A, SEL_MTU2_CH0_0),
- PINMUX_IPSR_DATA(IP6_17_16, HIFD07),
+ PINMUX_IPSR_GPSR(IP6_17_16, HIFD07),
- PINMUX_IPSR_DATA(IP6_20_18, DU0_DG0),
+ PINMUX_IPSR_GPSR(IP6_20_18, DU0_DG0),
PINMUX_IPSR_MSEL(IP6_20_18, TX1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP6_20_18, HSCK0_D, SEL_HSCIF_3),
PINMUX_IPSR_MSEL(IP6_20_18, IECLK_A, SEL_IEBUS_0),
PINMUX_IPSR_MSEL(IP6_20_18, TIOC1A_A, SEL_MTU2_CH1_0),
- PINMUX_IPSR_DATA(IP6_20_18, HIFD08),
+ PINMUX_IPSR_GPSR(IP6_20_18, HIFD08),
- PINMUX_IPSR_DATA(IP6_23_21, DU0_DG1),
+ PINMUX_IPSR_GPSR(IP6_23_21, DU0_DG1),
PINMUX_IPSR_MSEL(IP6_23_21, CTS1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP6_23_21, HRTS0_D, SEL_HSCIF_3),
PINMUX_IPSR_MSEL(IP6_23_21, TIOC1B_A, SEL_MTU2_CH1_0),
- PINMUX_IPSR_DATA(IP6_23_21, HIFD09),
+ PINMUX_IPSR_GPSR(IP6_23_21, HIFD09),
/* IPSR7 */
- PINMUX_IPSR_DATA(IP7_2_0, DU0_DG2),
+ PINMUX_IPSR_GPSR(IP7_2_0, DU0_DG2),
PINMUX_IPSR_MSEL(IP7_2_0, RTS1_C, SEL_SCIF1_2),
PINMUX_IPSR_MSEL(IP7_2_0, RMII0_MDC_B, SEL_RMII_1),
PINMUX_IPSR_MSEL(IP7_2_0, TIOC2A_A, SEL_MTU2_CH2_0),
- PINMUX_IPSR_DATA(IP7_2_0, HIFD10),
+ PINMUX_IPSR_GPSR(IP7_2_0, HIFD10),
- PINMUX_IPSR_DATA(IP7_5_3, DU0_DG3),
+ PINMUX_IPSR_GPSR(IP7_5_3, DU0_DG3),
PINMUX_IPSR_MSEL(IP7_5_3, SCK2_C, SEL_SCIF2_2),
PINMUX_IPSR_MSEL(IP7_5_3, RMII0_MDIO_B, SEL_RMII_1),
PINMUX_IPSR_MSEL(IP7_5_3, TIOC2B_A, SEL_MTU2_CH2_0),
- PINMUX_IPSR_DATA(IP7_5_3, HIFD11),
+ PINMUX_IPSR_GPSR(IP7_5_3, HIFD11),
- PINMUX_IPSR_DATA(IP7_8_6, DU0_DG4),
+ PINMUX_IPSR_GPSR(IP7_8_6, DU0_DG4),
PINMUX_IPSR_MSEL(IP7_8_6, RX2_C, SEL_SCIF2_2),
PINMUX_IPSR_MSEL(IP7_8_6, RMII0_CRS_DV_B, SEL_RMII_1),
PINMUX_IPSR_MSEL(IP7_8_6, TIOC3A_A, SEL_MTU2_CH3_0),
- PINMUX_IPSR_DATA(IP7_8_6, HIFD12),
+ PINMUX_IPSR_GPSR(IP7_8_6, HIFD12),
- PINMUX_IPSR_DATA(IP7_11_9, DU0_DG5),
+ PINMUX_IPSR_GPSR(IP7_11_9, DU0_DG5),
PINMUX_IPSR_MSEL(IP7_11_9, TX2_C, SEL_SCIF2_2),
PINMUX_IPSR_MSEL(IP7_11_9, RMII0_RX_ER_B, SEL_RMII_1),
PINMUX_IPSR_MSEL(IP7_11_9, TIOC3B_A, SEL_MTU2_CH3_0),
- PINMUX_IPSR_DATA(IP7_11_9, HIFD13),
+ PINMUX_IPSR_GPSR(IP7_11_9, HIFD13),
- PINMUX_IPSR_DATA(IP7_14_12, DU0_DG6),
+ PINMUX_IPSR_GPSR(IP7_14_12, DU0_DG6),
PINMUX_IPSR_MSEL(IP7_14_12, RX3_C, SEL_SCIF3_2),
PINMUX_IPSR_MSEL(IP7_14_12, RMII0_RXD0_B, SEL_RMII_1),
PINMUX_IPSR_MSEL(IP7_14_12, TIOC3C_A, SEL_MTU2_CH3_0),
- PINMUX_IPSR_DATA(IP7_14_12, HIFD14),
+ PINMUX_IPSR_GPSR(IP7_14_12, HIFD14),
- PINMUX_IPSR_DATA(IP7_17_15, DU0_DG7),
+ PINMUX_IPSR_GPSR(IP7_17_15, DU0_DG7),
PINMUX_IPSR_MSEL(IP7_17_15, TX3_C, SEL_SCIF3_2),
PINMUX_IPSR_MSEL(IP7_17_15, RMII0_RXD1_B, SEL_RMII_1),
PINMUX_IPSR_MSEL(IP7_17_15, TIOC3D_A, SEL_MTU2_CH3_0),
- PINMUX_IPSR_DATA(IP7_17_15, HIFD15),
+ PINMUX_IPSR_GPSR(IP7_17_15, HIFD15),
- PINMUX_IPSR_DATA(IP7_20_18, DU0_DB0),
+ PINMUX_IPSR_GPSR(IP7_20_18, DU0_DB0),
PINMUX_IPSR_MSEL(IP7_20_18, RX4_C, SEL_SCIF4_2),
PINMUX_IPSR_MSEL(IP7_20_18, RMII0_TXD_EN_B, SEL_RMII_1),
PINMUX_IPSR_MSEL(IP7_20_18, TIOC4A_A, SEL_MTU2_CH4_0),
- PINMUX_IPSR_DATA(IP7_20_18, HIFCS),
+ PINMUX_IPSR_GPSR(IP7_20_18, HIFCS),
- PINMUX_IPSR_DATA(IP7_23_21, DU0_DB1),
+ PINMUX_IPSR_GPSR(IP7_23_21, DU0_DB1),
PINMUX_IPSR_MSEL(IP7_23_21, TX4_C, SEL_SCIF4_2),
PINMUX_IPSR_MSEL(IP7_23_21, RMII0_TXD0_B, SEL_RMII_1),
PINMUX_IPSR_MSEL(IP7_23_21, TIOC4B_A, SEL_MTU2_CH4_0),
- PINMUX_IPSR_DATA(IP7_23_21, HIFWR),
+ PINMUX_IPSR_GPSR(IP7_23_21, HIFWR),
- PINMUX_IPSR_DATA(IP7_26_24, DU0_DB2),
+ PINMUX_IPSR_GPSR(IP7_26_24, DU0_DB2),
PINMUX_IPSR_MSEL(IP7_26_24, RX5_B, SEL_SCIF5_1),
PINMUX_IPSR_MSEL(IP7_26_24, RMII0_TXD1_B, SEL_RMII_1),
PINMUX_IPSR_MSEL(IP7_26_24, TIOC4C_A, SEL_MTU2_CH4_0),
- PINMUX_IPSR_DATA(IP7_28_27, DU0_DB3),
+ PINMUX_IPSR_GPSR(IP7_28_27, DU0_DB3),
PINMUX_IPSR_MSEL(IP7_28_27, TX5_B, SEL_SCIF5_1),
PINMUX_IPSR_MSEL(IP7_28_27, TIOC4D_A, SEL_MTU2_CH4_0),
- PINMUX_IPSR_DATA(IP7_28_27, HIFRD),
+ PINMUX_IPSR_GPSR(IP7_28_27, HIFRD),
- PINMUX_IPSR_DATA(IP7_30_29, DU0_DB4),
- PINMUX_IPSR_DATA(IP7_30_29, HIFINT),
+ PINMUX_IPSR_GPSR(IP7_30_29, DU0_DB4),
+ PINMUX_IPSR_GPSR(IP7_30_29, HIFINT),
/* IPSR8 */
- PINMUX_IPSR_DATA(IP8_1_0, DU0_DB5),
- PINMUX_IPSR_DATA(IP8_1_0, HIFDREQ),
+ PINMUX_IPSR_GPSR(IP8_1_0, DU0_DB5),
+ PINMUX_IPSR_GPSR(IP8_1_0, HIFDREQ),
- PINMUX_IPSR_DATA(IP8_3_2, DU0_DB6),
- PINMUX_IPSR_DATA(IP8_3_2, HIFRDY),
+ PINMUX_IPSR_GPSR(IP8_3_2, DU0_DB6),
+ PINMUX_IPSR_GPSR(IP8_3_2, HIFRDY),
- PINMUX_IPSR_DATA(IP8_5_4, DU0_DB7),
+ PINMUX_IPSR_GPSR(IP8_5_4, DU0_DB7),
PINMUX_IPSR_MSEL(IP8_5_4, SSI_SCK0_B, SEL_SSI0_1),
PINMUX_IPSR_MSEL(IP8_5_4, HIFEBL_B, SEL_HIF_1),
- PINMUX_IPSR_DATA(IP8_7_6, DU0_DOTCLKIN),
+ PINMUX_IPSR_GPSR(IP8_7_6, DU0_DOTCLKIN),
PINMUX_IPSR_MSEL(IP8_7_6, HSPI_CS0_C, SEL_HSPI_2),
PINMUX_IPSR_MSEL(IP8_7_6, SSI_WS0_B, SEL_SSI0_1),
- PINMUX_IPSR_DATA(IP8_9_8, DU0_DOTCLKOUT),
+ PINMUX_IPSR_GPSR(IP8_9_8, DU0_DOTCLKOUT),
PINMUX_IPSR_MSEL(IP8_9_8, HSPI_CLK0_C, SEL_HSPI_2),
PINMUX_IPSR_MSEL(IP8_9_8, SSI_SDATA0_B, SEL_SSI0_1),
- PINMUX_IPSR_DATA(IP8_11_10, DU0_EXHSYNC_DU0_HSYNC),
+ PINMUX_IPSR_GPSR(IP8_11_10, DU0_EXHSYNC_DU0_HSYNC),
PINMUX_IPSR_MSEL(IP8_11_10, HSPI_TX0_C, SEL_HSPI_2),
PINMUX_IPSR_MSEL(IP8_11_10, SSI_SCK1_B, SEL_SSI1_1),
- PINMUX_IPSR_DATA(IP8_13_12, DU0_EXVSYNC_DU0_VSYNC),
+ PINMUX_IPSR_GPSR(IP8_13_12, DU0_EXVSYNC_DU0_VSYNC),
PINMUX_IPSR_MSEL(IP8_13_12, HSPI_RX0_C, SEL_HSPI_2),
PINMUX_IPSR_MSEL(IP8_13_12, SSI_WS1_B, SEL_SSI1_1),
- PINMUX_IPSR_DATA(IP8_15_14, DU0_EXODDF_DU0_ODDF),
+ PINMUX_IPSR_GPSR(IP8_15_14, DU0_EXODDF_DU0_ODDF),
PINMUX_IPSR_MSEL(IP8_15_14, CAN0_RX_B, SEL_RCAN0_1),
PINMUX_IPSR_MSEL(IP8_15_14, HSCK0_B, SEL_HSCIF_1),
PINMUX_IPSR_MSEL(IP8_15_14, SSI_SDATA1_B, SEL_SSI1_1),
- PINMUX_IPSR_DATA(IP8_17_16, DU0_DISP),
+ PINMUX_IPSR_GPSR(IP8_17_16, DU0_DISP),
PINMUX_IPSR_MSEL(IP8_17_16, CAN0_TX_B, SEL_RCAN0_1),
PINMUX_IPSR_MSEL(IP8_17_16, HRX0_B, SEL_HSCIF_1),
PINMUX_IPSR_MSEL(IP8_17_16, AUDIO_CLKA_B, SEL_AUDIO_CLKA_1),
- PINMUX_IPSR_DATA(IP8_19_18, DU0_CDE),
+ PINMUX_IPSR_GPSR(IP8_19_18, DU0_CDE),
PINMUX_IPSR_MSEL(IP8_19_18, HTX0_B, SEL_HSCIF_1),
PINMUX_IPSR_MSEL(IP8_19_18, AUDIO_CLKB_B, SEL_AUDIO_CLKB_1),
PINMUX_IPSR_MSEL(IP8_19_18, LCD_VCPWC_B, SEL_LCDC_1),
@@ -1139,12 +1139,12 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP8_22_20, IRQ0_A, SEL_INTC_0),
PINMUX_IPSR_MSEL(IP8_22_20, HSPI_TX_B, SEL_HSPI_1),
PINMUX_IPSR_MSEL(IP8_22_20, RX3_E, SEL_SCIF3_4),
- PINMUX_IPSR_DATA(IP8_22_20, ET0_ERXD0),
+ PINMUX_IPSR_GPSR(IP8_22_20, ET0_ERXD0),
PINMUX_IPSR_MSEL(IP8_25_23, IRQ1_A, SEL_INTC_0),
PINMUX_IPSR_MSEL(IP8_25_23, HSPI_RX_B, SEL_HSPI_1),
PINMUX_IPSR_MSEL(IP8_25_23, TX3_E, SEL_SCIF3_4),
- PINMUX_IPSR_DATA(IP8_25_23, ET0_ERXD1),
+ PINMUX_IPSR_GPSR(IP8_25_23, ET0_ERXD1),
PINMUX_IPSR_MSEL(IP8_27_26, IRQ2_A, SEL_INTC_0),
PINMUX_IPSR_MSEL(IP8_27_26, CTS0_A, SEL_SCIF0_0),
@@ -1220,26 +1220,26 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP9_29_28, LCD_DATA14_B, SEL_LCDC_1),
/* IPSE10 */
- PINMUX_IPSR_DATA(IP10_2_0, SSI_SCK23),
+ PINMUX_IPSR_GPSR(IP10_2_0, SSI_SCK23),
PINMUX_IPSR_MSEL(IP10_2_0, VI1_4_B, SEL_VIN1_1),
PINMUX_IPSR_MSEL(IP10_2_0, RX1_D, SEL_SCIF1_3),
PINMUX_IPSR_MSEL(IP10_2_0, FCLE_B, SEL_FLCTL_1),
PINMUX_IPSR_MSEL(IP10_2_0, LCD_DATA15_B, SEL_LCDC_1),
- PINMUX_IPSR_DATA(IP10_5_3, SSI_WS23),
+ PINMUX_IPSR_GPSR(IP10_5_3, SSI_WS23),
PINMUX_IPSR_MSEL(IP10_5_3, VI1_5_B, SEL_VIN1_1),
PINMUX_IPSR_MSEL(IP10_5_3, TX1_D, SEL_SCIF1_3),
PINMUX_IPSR_MSEL(IP10_5_3, HSCK0_C, SEL_HSCIF_2),
PINMUX_IPSR_MSEL(IP10_5_3, FALE_B, SEL_FLCTL_1),
PINMUX_IPSR_MSEL(IP10_5_3, LCD_DON_B, SEL_LCDC_1),
- PINMUX_IPSR_DATA(IP10_8_6, SSI_SDATA2),
+ PINMUX_IPSR_GPSR(IP10_8_6, SSI_SDATA2),
PINMUX_IPSR_MSEL(IP10_8_6, VI1_6_B, SEL_VIN1_1),
PINMUX_IPSR_MSEL(IP10_8_6, HRX0_C, SEL_HSCIF_2),
PINMUX_IPSR_MSEL(IP10_8_6, FRE_B, SEL_FLCTL_1),
PINMUX_IPSR_MSEL(IP10_8_6, LCD_CL1_B, SEL_LCDC_1),
- PINMUX_IPSR_DATA(IP10_11_9, SSI_SDATA3),
+ PINMUX_IPSR_GPSR(IP10_11_9, SSI_SDATA3),
PINMUX_IPSR_MSEL(IP10_11_9, VI1_7_B, SEL_VIN1_1),
PINMUX_IPSR_MSEL(IP10_11_9, HTX0_C, SEL_HSCIF_2),
PINMUX_IPSR_MSEL(IP10_11_9, FWE_B, SEL_FLCTL_1),
@@ -1254,13 +1254,13 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP10_15, AUDIO_CLKB_A, SEL_AUDIO_CLKB_0),
PINMUX_IPSR_MSEL(IP10_15, LCD_CLK_B, SEL_LCDC_1),
- PINMUX_IPSR_DATA(IP10_18_16, AUDIO_CLKC),
+ PINMUX_IPSR_GPSR(IP10_18_16, AUDIO_CLKC),
PINMUX_IPSR_MSEL(IP10_18_16, SCK1_E, SEL_SCIF1_4),
PINMUX_IPSR_MSEL(IP10_18_16, HCTS0_C, SEL_HSCIF_2),
PINMUX_IPSR_MSEL(IP10_18_16, FRB_B, SEL_FLCTL_1),
PINMUX_IPSR_MSEL(IP10_18_16, LCD_VEPWC_B, SEL_LCDC_1),
- PINMUX_IPSR_DATA(IP10_21_19, AUDIO_CLKOUT),
+ PINMUX_IPSR_GPSR(IP10_21_19, AUDIO_CLKOUT),
PINMUX_IPSR_MSEL(IP10_21_19, TX1_E, SEL_SCIF1_4),
PINMUX_IPSR_MSEL(IP10_21_19, HRTS0_C, SEL_HSCIF_2),
PINMUX_IPSR_MSEL(IP10_21_19, FSE_B, SEL_FLCTL_1),
@@ -1271,85 +1271,85 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP10_24_23, CAN0_TX_A, SEL_RCAN0_0),
PINMUX_IPSR_MSEL(IP10_24_23, TX4_D, SEL_SCIF4_3),
- PINMUX_IPSR_DATA(IP10_24_23, MLB_CLK),
+ PINMUX_IPSR_GPSR(IP10_24_23, MLB_CLK),
PINMUX_IPSR_MSEL(IP10_25, CAN1_RX_A, SEL_RCAN1_0),
PINMUX_IPSR_MSEL(IP10_25, IRQ1_B, SEL_INTC_1),
PINMUX_IPSR_MSEL(IP10_27_26, CAN0_RX_A, SEL_RCAN0_0),
PINMUX_IPSR_MSEL(IP10_27_26, IRQ0_B, SEL_INTC_1),
- PINMUX_IPSR_DATA(IP10_27_26, MLB_SIG),
+ PINMUX_IPSR_GPSR(IP10_27_26, MLB_SIG),
PINMUX_IPSR_MSEL(IP10_29_28, CAN1_TX_A, SEL_RCAN1_0),
PINMUX_IPSR_MSEL(IP10_29_28, TX5_C, SEL_SCIF1_2),
- PINMUX_IPSR_DATA(IP10_29_28, MLB_DAT),
+ PINMUX_IPSR_GPSR(IP10_29_28, MLB_DAT),
/* IPSR11 */
- PINMUX_IPSR_DATA(IP11_0, SCL1),
+ PINMUX_IPSR_GPSR(IP11_0, SCL1),
PINMUX_IPSR_MSEL(IP11_0, SCIF_CLK_C, SEL_SCIF_CLK_2),
- PINMUX_IPSR_DATA(IP11_1, SDA1),
+ PINMUX_IPSR_GPSR(IP11_1, SDA1),
PINMUX_IPSR_MSEL(IP11_0, RX1_E, SEL_SCIF1_4),
- PINMUX_IPSR_DATA(IP11_2, SDA0),
+ PINMUX_IPSR_GPSR(IP11_2, SDA0),
PINMUX_IPSR_MSEL(IP11_2, HIFEBL_A, SEL_HIF_0),
- PINMUX_IPSR_DATA(IP11_3, SDSELF),
+ PINMUX_IPSR_GPSR(IP11_3, SDSELF),
PINMUX_IPSR_MSEL(IP11_3, RTS1_E, SEL_SCIF1_3),
PINMUX_IPSR_MSEL(IP11_6_4, SCIF_CLK_A, SEL_SCIF_CLK_0),
PINMUX_IPSR_MSEL(IP11_6_4, HSPI_CLK_A, SEL_HSPI_0),
- PINMUX_IPSR_DATA(IP11_6_4, VI0_CLK),
+ PINMUX_IPSR_GPSR(IP11_6_4, VI0_CLK),
PINMUX_IPSR_MSEL(IP11_6_4, RMII0_TXD0_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP11_6_4, ET0_ERXD4),
+ PINMUX_IPSR_GPSR(IP11_6_4, ET0_ERXD4),
PINMUX_IPSR_MSEL(IP11_9_7, SCK0_A, SEL_SCIF0_0),
PINMUX_IPSR_MSEL(IP11_9_7, HSPI_CS_A, SEL_HSPI_0),
- PINMUX_IPSR_DATA(IP11_9_7, VI0_CLKENB),
+ PINMUX_IPSR_GPSR(IP11_9_7, VI0_CLKENB),
PINMUX_IPSR_MSEL(IP11_9_7, RMII0_TXD1_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP11_9_7, ET0_ERXD5),
+ PINMUX_IPSR_GPSR(IP11_9_7, ET0_ERXD5),
PINMUX_IPSR_MSEL(IP11_11_10, RX0_A, SEL_SCIF0_0),
PINMUX_IPSR_MSEL(IP11_11_10, HSPI_RX_A, SEL_HSPI_0),
PINMUX_IPSR_MSEL(IP11_11_10, RMII0_RXD0_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP11_11_10, ET0_ERXD6),
+ PINMUX_IPSR_GPSR(IP11_11_10, ET0_ERXD6),
PINMUX_IPSR_MSEL(IP11_12, TX0_A, SEL_SCIF0_0),
PINMUX_IPSR_MSEL(IP11_12, HSPI_TX_A, SEL_HSPI_0),
- PINMUX_IPSR_DATA(IP11_15_13, PENC1),
+ PINMUX_IPSR_GPSR(IP11_15_13, PENC1),
PINMUX_IPSR_MSEL(IP11_15_13, TX3_D, SEL_SCIF3_3),
PINMUX_IPSR_MSEL(IP11_15_13, CAN1_TX_B, SEL_RCAN1_1),
PINMUX_IPSR_MSEL(IP11_15_13, TX5_D, SEL_SCIF5_3),
PINMUX_IPSR_MSEL(IP11_15_13, IETX_B, SEL_IEBUS_1),
- PINMUX_IPSR_DATA(IP11_18_16, USB_OVC1),
+ PINMUX_IPSR_GPSR(IP11_18_16, USB_OVC1),
PINMUX_IPSR_MSEL(IP11_18_16, RX3_D, SEL_SCIF3_3),
PINMUX_IPSR_MSEL(IP11_18_16, CAN1_RX_B, SEL_RCAN1_1),
PINMUX_IPSR_MSEL(IP11_18_16, RX5_D, SEL_SCIF5_3),
PINMUX_IPSR_MSEL(IP11_18_16, IERX_B, SEL_IEBUS_1),
- PINMUX_IPSR_DATA(IP11_20_19, DREQ0),
+ PINMUX_IPSR_GPSR(IP11_20_19, DREQ0),
PINMUX_IPSR_MSEL(IP11_20_19, SD1_CLK_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP11_20_19, ET0_TX_EN),
+ PINMUX_IPSR_GPSR(IP11_20_19, ET0_TX_EN),
- PINMUX_IPSR_DATA(IP11_22_21, DACK0),
+ PINMUX_IPSR_GPSR(IP11_22_21, DACK0),
PINMUX_IPSR_MSEL(IP11_22_21, SD1_DAT3_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP11_22_21, ET0_TX_ER),
+ PINMUX_IPSR_GPSR(IP11_22_21, ET0_TX_ER),
- PINMUX_IPSR_DATA(IP11_25_23, DREQ1),
+ PINMUX_IPSR_GPSR(IP11_25_23, DREQ1),
PINMUX_IPSR_MSEL(IP11_25_23, HSPI_CLK_B, SEL_HSPI_1),
PINMUX_IPSR_MSEL(IP11_25_23, RX4_B, SEL_SCIF4_1),
PINMUX_IPSR_MSEL(IP11_25_23, ET0_PHY_INT_C, SEL_ET0_CTL_0),
PINMUX_IPSR_MSEL(IP11_25_23, ET0_TX_CLK_A, SEL_ET0_0),
- PINMUX_IPSR_DATA(IP11_27_26, DACK1),
+ PINMUX_IPSR_GPSR(IP11_27_26, DACK1),
PINMUX_IPSR_MSEL(IP11_27_26, HSPI_CS_B, SEL_HSPI_1),
PINMUX_IPSR_MSEL(IP11_27_26, TX4_B, SEL_SCIF3_1),
PINMUX_IPSR_MSEL(IP11_27_26, ET0_RX_CLK_A, SEL_ET0_0),
- PINMUX_IPSR_DATA(IP11_28, PRESETOUT),
- PINMUX_IPSR_DATA(IP11_28, ST_CLKOUT),
+ PINMUX_IPSR_GPSR(IP11_28, PRESETOUT),
+ PINMUX_IPSR_GPSR(IP11_28, ST_CLKOUT),
};
static const struct sh_pfc_pin pinmux_pins[] = {
diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h
index 2123ab49d6a5..a490834e2089 100644
--- a/drivers/pinctrl/sh-pfc/sh_pfc.h
+++ b/drivers/pinctrl/sh-pfc/sh_pfc.h
@@ -100,10 +100,31 @@ struct pinmux_cfg_reg {
const u8 *var_field_width;
};
+/*
+ * Describe a config register consisting of several fields of the same width
+ * - name: Register name (unused, for documentation purposes only)
+ * - r: Physical register address
+ * - r_width: Width of the register (in bits)
+ * - f_width: Width of the fixed-width register fields (in bits)
+ * This macro must be followed by initialization data: For each register field
+ * (from left to right, i.e. MSB to LSB), 2^f_width enum IDs must be specified,
+ * one for each possible combination of the register field bit values.
+ */
#define PINMUX_CFG_REG(name, r, r_width, f_width) \
.reg = r, .reg_width = r_width, .field_width = f_width, \
.enum_ids = (const u16 [(r_width / f_width) * (1 << f_width)])
+/*
+ * Describe a config register consisting of several fields of different widths
+ * - name: Register name (unused, for documentation purposes only)
+ * - r: Physical register address
+ * - r_width: Width of the register (in bits)
+ * - var_fw0, var_fwn...: List of widths of the register fields (in bits),
+ * From left to right (i.e. MSB to LSB)
+ * This macro must be followed by initialization data: For each register field
+ * (from left to right, i.e. MSB to LSB), 2^var_fwi enum IDs must be specified,
+ * one for each possible combination of the register field bit values.
+ */
#define PINMUX_CFG_REG_VAR(name, r, r_width, var_fw0, var_fwn...) \
.reg = r, .reg_width = r_width, \
.var_field_width = (const u8 [r_width]) \
@@ -116,6 +137,14 @@ struct pinmux_data_reg {
const u16 *enum_ids;
};
+/*
+ * Describe a data register
+ * - name: Register name (unused, for documentation purposes only)
+ * - r: Physical register address
+ * - r_width: Width of the register (in bits)
+ * This macro must be followed by initialization data: For each register bit
+ * (from left to right, i.e. MSB to LSB), one enum ID must be specified.
+ */
#define PINMUX_DATA_REG(name, r, r_width) \
.reg = r, .reg_width = r_width, \
.enum_ids = (const u16 [r_width]) \
@@ -124,6 +153,10 @@ struct pinmux_irq {
const short *gpios;
};
+/*
+ * Describe the mapping from GPIOs to a single IRQ
+ * - ids...: List of GPIOs that are mapped to the same IRQ
+ */
#define PINMUX_IRQ(ids...) \
{ .gpios = (const short []) { ids, -1 } }
@@ -185,18 +218,65 @@ struct sh_pfc_soc_info {
* sh_pfc_soc_info pinmux_data array macros
*/
+/*
+ * Describe generic pinmux data
+ * - data_or_mark: *_DATA or *_MARK enum ID
+ * - ids...: List of enum IDs to associate with data_or_mark
+ */
#define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0
-#define PINMUX_IPSR_NOGP(ispr, fn) \
+/*
+ * Describe a pinmux configuration without GPIO function that needs
+ * configuration in a Peripheral Function Select Register (IPSR)
+ * - ipsr: IPSR field (unused, for documentation purposes only)
+ * - fn: Function name, referring to a field in the IPSR
+ */
+#define PINMUX_IPSR_NOGP(ipsr, fn) \
PINMUX_DATA(fn##_MARK, FN_##fn)
-#define PINMUX_IPSR_DATA(ipsr, fn) \
+
+/*
+ * Describe a pinmux configuration with GPIO function that needs configuration
+ * in both a Peripheral Function Select Register (IPSR) and in a
+ * GPIO/Peripheral Function Select Register (GPSR)
+ * - ipsr: IPSR field
+ * - fn: Function name, also referring to the IPSR field
+ */
+#define PINMUX_IPSR_GPSR(ipsr, fn) \
PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr)
-#define PINMUX_IPSR_NOGM(ispr, fn, ms) \
- PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ms)
-#define PINMUX_IPSR_NOFN(ipsr, fn, ms) \
- PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##ms)
-#define PINMUX_IPSR_MSEL(ipsr, fn, ms) \
- PINMUX_DATA(fn##_MARK, FN_##ms, FN_##ipsr, FN_##fn)
+
+/*
+ * Describe a pinmux configuration without GPIO function that needs
+ * configuration in a Peripheral Function Select Register (IPSR), and where the
+ * pinmux function has a representation in a Module Select Register (MOD_SEL).
+ * - ipsr: IPSR field (unused, for documentation purposes only)
+ * - fn: Function name, also referring to the IPSR field
+ * - msel: Module selector
+ */
+#define PINMUX_IPSR_NOGM(ipsr, fn, msel) \
+ PINMUX_DATA(fn##_MARK, FN_##fn, FN_##msel)
+
+/*
+ * Describe a pinmux configuration with GPIO function where the pinmux function
+ * has no representation in a Peripheral Function Select Register (IPSR), but
+ * instead solely depends on a group selection.
+ * - gpsr: GPSR field
+ * - fn: Function name, also referring to the GPSR field
+ * - gsel: Group selector
+ */
+#define PINMUX_IPSR_NOFN(gpsr, fn, gsel) \
+ PINMUX_DATA(fn##_MARK, FN_##gpsr, FN_##gsel)
+
+/*
+ * Describe a pinmux configuration with GPIO function that needs configuration
+ * in both a Peripheral Function Select Register (IPSR) and a GPIO/Peripheral
+ * Function Select Register (GPSR), and where the pinmux function has a
+ * representation in a Module Select Register (MOD_SEL).
+ * - ipsr: IPSR field
+ * - fn: Function name, also referring to the IPSR field
+ * - msel: Module selector
+ */
+#define PINMUX_IPSR_MSEL(ipsr, fn, msel) \
+ PINMUX_DATA(fn##_MARK, FN_##msel, FN_##ipsr, FN_##fn)
/*
* Describe a pinmux configuration for a single-function pin with GPIO
@@ -381,7 +461,7 @@ struct sh_pfc_soc_info {
PINMUX_GPIO_FN(GPIO_FN_##str, PINMUX_FN_BASE, str##_MARK)
/*
- * PORTnCR macro
+ * PORTnCR helper macro for SH-Mobile/R-Mobile
*/
#define PORTCR(nr, reg) \
{ \
diff --git a/drivers/pinctrl/stm32/Kconfig b/drivers/pinctrl/stm32/Kconfig
new file mode 100644
index 000000000000..0f28841b2332
--- /dev/null
+++ b/drivers/pinctrl/stm32/Kconfig
@@ -0,0 +1,16 @@
+if ARCH_STM32 || COMPILE_TEST
+
+config PINCTRL_STM32
+ bool
+ depends on OF
+ select PINMUX
+ select GENERIC_PINCONF
+ select GPIOLIB
+
+config PINCTRL_STM32F429
+ bool "STMicroelectronics STM32F429 pin control" if COMPILE_TEST && !MACH_STM32F429
+ depends on OF
+ default MACH_STM32F429
+ select PINCTRL_STM32
+
+endif
diff --git a/drivers/pinctrl/stm32/Makefile b/drivers/pinctrl/stm32/Makefile
new file mode 100644
index 000000000000..fc17d4238845
--- /dev/null
+++ b/drivers/pinctrl/stm32/Makefile
@@ -0,0 +1,5 @@
+# Core
+obj-$(CONFIG_PINCTRL_STM32) += pinctrl-stm32.o
+
+# SoC Drivers
+obj-$(CONFIG_PINCTRL_STM32F429) += pinctrl-stm32f429.o
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
new file mode 100644
index 000000000000..8deb566ed4cd
--- /dev/null
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -0,0 +1,829 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Heavily based on Mediatek's pinctrl driver
+ */
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "../pinctrl-utils.h"
+#include "pinctrl-stm32.h"
+
+#define STM32_GPIO_MODER 0x00
+#define STM32_GPIO_TYPER 0x04
+#define STM32_GPIO_SPEEDR 0x08
+#define STM32_GPIO_PUPDR 0x0c
+#define STM32_GPIO_IDR 0x10
+#define STM32_GPIO_ODR 0x14
+#define STM32_GPIO_BSRR 0x18
+#define STM32_GPIO_LCKR 0x1c
+#define STM32_GPIO_AFRL 0x20
+#define STM32_GPIO_AFRH 0x24
+
+#define STM32_GPIO_PINS_PER_BANK 16
+
+#define gpio_range_to_bank(chip) \
+ container_of(chip, struct stm32_gpio_bank, range)
+
+static const char * const stm32_gpio_functions[] = {
+ "gpio", "af0", "af1",
+ "af2", "af3", "af4",
+ "af5", "af6", "af7",
+ "af8", "af9", "af10",
+ "af11", "af12", "af13",
+ "af14", "af15", "analog",
+};
+
+struct stm32_pinctrl_group {
+ const char *name;
+ unsigned long config;
+ unsigned pin;
+};
+
+struct stm32_gpio_bank {
+ void __iomem *base;
+ struct clk *clk;
+ spinlock_t lock;
+ struct gpio_chip gpio_chip;
+ struct pinctrl_gpio_range range;
+};
+
+struct stm32_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl_dev;
+ struct pinctrl_desc pctl_desc;
+ struct stm32_pinctrl_group *groups;
+ unsigned ngroups;
+ const char **grp_names;
+ struct stm32_gpio_bank *banks;
+ unsigned nbanks;
+ const struct stm32_pinctrl_match_data *match_data;
+};
+
+static inline int stm32_gpio_pin(int gpio)
+{
+ return gpio % STM32_GPIO_PINS_PER_BANK;
+}
+
+static inline u32 stm32_gpio_get_mode(u32 function)
+{
+ switch (function) {
+ case STM32_PIN_GPIO:
+ return 0;
+ case STM32_PIN_AF(0) ... STM32_PIN_AF(15):
+ return 2;
+ case STM32_PIN_ANALOG:
+ return 3;
+ }
+
+ return 0;
+}
+
+static inline u32 stm32_gpio_get_alt(u32 function)
+{
+ switch (function) {
+ case STM32_PIN_GPIO:
+ return 0;
+ case STM32_PIN_AF(0) ... STM32_PIN_AF(15):
+ return function - 1;
+ case STM32_PIN_ANALOG:
+ return 0;
+ }
+
+ return 0;
+}
+
+/* GPIO functions */
+
+static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank,
+ unsigned offset, int value)
+{
+ if (!value)
+ offset += STM32_GPIO_PINS_PER_BANK;
+
+ clk_enable(bank->clk);
+
+ writel_relaxed(BIT(offset), bank->base + STM32_GPIO_BSRR);
+
+ clk_disable(bank->clk);
+}
+
+static int stm32_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void stm32_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static int stm32_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
+ int ret;
+
+ clk_enable(bank->clk);
+
+ ret = !!(readl_relaxed(bank->base + STM32_GPIO_IDR) & BIT(offset));
+
+ clk_disable(bank->clk);
+
+ return ret;
+}
+
+static void stm32_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
+
+ __stm32_gpio_set(bank, offset, value);
+}
+
+static int stm32_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_gpio_direction_input(chip->base + offset);
+}
+
+static int stm32_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
+
+ __stm32_gpio_set(bank, offset, value);
+ pinctrl_gpio_direction_output(chip->base + offset);
+
+ return 0;
+}
+
+static struct gpio_chip stm32_gpio_template = {
+ .request = stm32_gpio_request,
+ .free = stm32_gpio_free,
+ .get = stm32_gpio_get,
+ .set = stm32_gpio_set,
+ .direction_input = stm32_gpio_direction_input,
+ .direction_output = stm32_gpio_direction_output,
+};
+
+/* Pinctrl functions */
+
+static struct stm32_pinctrl_group *
+stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin)
+{
+ int i;
+
+ for (i = 0; i < pctl->ngroups; i++) {
+ struct stm32_pinctrl_group *grp = pctl->groups + i;
+
+ if (grp->pin == pin)
+ return grp;
+ }
+
+ return NULL;
+}
+
+static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl,
+ u32 pin_num, u32 fnum)
+{
+ int i;
+
+ for (i = 0; i < pctl->match_data->npins; i++) {
+ const struct stm32_desc_pin *pin = pctl->match_data->pins + i;
+ const struct stm32_desc_function *func = pin->functions;
+
+ if (pin->pin.number != pin_num)
+ continue;
+
+ while (func && func->name) {
+ if (func->num == fnum)
+ return true;
+ func++;
+ }
+
+ break;
+ }
+
+ return false;
+}
+
+static int stm32_pctrl_dt_node_to_map_func(struct stm32_pinctrl *pctl,
+ u32 pin, u32 fnum, struct stm32_pinctrl_group *grp,
+ struct pinctrl_map **map, unsigned *reserved_maps,
+ unsigned *num_maps)
+{
+ if (*num_maps == *reserved_maps)
+ return -ENOSPC;
+
+ (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)[*num_maps].data.mux.group = grp->name;
+
+ if (!stm32_pctrl_is_function_valid(pctl, pin, fnum)) {
+ dev_err(pctl->dev, "invalid function %d on pin %d .\n",
+ fnum, pin);
+ return -EINVAL;
+ }
+
+ (*map)[*num_maps].data.mux.function = stm32_gpio_functions[fnum];
+ (*num_maps)++;
+
+ return 0;
+}
+
+static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *node,
+ struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps)
+{
+ struct stm32_pinctrl *pctl;
+ struct stm32_pinctrl_group *grp;
+ struct property *pins;
+ u32 pinfunc, pin, func;
+ unsigned long *configs;
+ unsigned int num_configs;
+ bool has_config = 0;
+ unsigned reserve = 0;
+ int num_pins, num_funcs, maps_per_pin, i, err;
+
+ pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ pins = of_find_property(node, "pinmux", NULL);
+ if (!pins) {
+ dev_err(pctl->dev, "missing pins property in node %s .\n",
+ node->name);
+ return -EINVAL;
+ }
+
+ err = pinconf_generic_parse_dt_config(node, pctldev, &configs,
+ &num_configs);
+ if (err)
+ return err;
+
+ if (num_configs)
+ has_config = 1;
+
+ num_pins = pins->length / sizeof(u32);
+ num_funcs = num_pins;
+ maps_per_pin = 0;
+ if (num_funcs)
+ maps_per_pin++;
+ if (has_config && num_pins >= 1)
+ maps_per_pin++;
+
+ if (!num_pins || !maps_per_pin)
+ return -EINVAL;
+
+ reserve = num_pins * maps_per_pin;
+
+ err = pinctrl_utils_reserve_map(pctldev, map,
+ reserved_maps, num_maps, reserve);
+ if (err)
+ return err;
+
+ for (i = 0; i < num_pins; i++) {
+ err = of_property_read_u32_index(node, "pinmux",
+ i, &pinfunc);
+ if (err)
+ return err;
+
+ pin = STM32_GET_PIN_NO(pinfunc);
+ func = STM32_GET_PIN_FUNC(pinfunc);
+
+ if (pin >= pctl->match_data->npins) {
+ dev_err(pctl->dev, "invalid pin number.\n");
+ return -EINVAL;
+ }
+
+ if (!stm32_pctrl_is_function_valid(pctl, pin, func)) {
+ dev_err(pctl->dev, "invalid function.\n");
+ return -EINVAL;
+ }
+
+ grp = stm32_pctrl_find_group_by_pin(pctl, pin);
+ if (!grp) {
+ dev_err(pctl->dev, "unable to match pin %d to group\n",
+ pin);
+ return -EINVAL;
+ }
+
+ err = stm32_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map,
+ reserved_maps, num_maps);
+ if (err)
+ return err;
+
+ if (has_config) {
+ err = pinctrl_utils_add_map_configs(pctldev, map,
+ reserved_maps, num_maps, grp->name,
+ configs, num_configs,
+ PIN_MAP_TYPE_CONFIGS_GROUP);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct device_node *np;
+ unsigned reserved_maps;
+ int ret;
+
+ *map = NULL;
+ *num_maps = 0;
+ reserved_maps = 0;
+
+ for_each_child_of_node(np_config, np) {
+ ret = stm32_pctrl_dt_subnode_to_map(pctldev, np, map,
+ &reserved_maps, num_maps);
+ if (ret < 0) {
+ pinctrl_utils_dt_free_map(pctldev, *map, *num_maps);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->ngroups;
+}
+
+static const char *stm32_pctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->groups[group].name;
+}
+
+static int stm32_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = (unsigned *)&pctl->groups[group].pin;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const struct pinctrl_ops stm32_pctrl_ops = {
+ .dt_node_to_map = stm32_pctrl_dt_node_to_map,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+ .get_groups_count = stm32_pctrl_get_groups_count,
+ .get_group_name = stm32_pctrl_get_group_name,
+ .get_group_pins = stm32_pctrl_get_group_pins,
+};
+
+
+/* Pinmux functions */
+
+static int stm32_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(stm32_gpio_functions);
+}
+
+static const char *stm32_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return stm32_gpio_functions[selector];
+}
+
+static int stm32_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pctl->grp_names;
+ *num_groups = pctl->ngroups;
+
+ return 0;
+}
+
+static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
+ int pin, u32 mode, u32 alt)
+{
+ u32 val;
+ int alt_shift = (pin % 8) * 4;
+ int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4;
+ unsigned long flags;
+
+ clk_enable(bank->clk);
+ spin_lock_irqsave(&bank->lock, flags);
+
+ val = readl_relaxed(bank->base + alt_offset);
+ val &= ~GENMASK(alt_shift + 3, alt_shift);
+ val |= (alt << alt_shift);
+ writel_relaxed(val, bank->base + alt_offset);
+
+ val = readl_relaxed(bank->base + STM32_GPIO_MODER);
+ val &= ~GENMASK(pin * 2 + 1, pin * 2);
+ val |= mode << (pin * 2);
+ writel_relaxed(val, bank->base + STM32_GPIO_MODER);
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+ clk_disable(bank->clk);
+}
+
+static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev,
+ unsigned function,
+ unsigned group)
+{
+ bool ret;
+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct stm32_pinctrl_group *g = pctl->groups + group;
+ struct pinctrl_gpio_range *range;
+ struct stm32_gpio_bank *bank;
+ u32 mode, alt;
+ int pin;
+
+ ret = stm32_pctrl_is_function_valid(pctl, g->pin, function);
+ if (!ret) {
+ dev_err(pctl->dev, "invalid function %d on group %d .\n",
+ function, group);
+ return -EINVAL;
+ }
+
+ range = pinctrl_find_gpio_range_from_pin(pctldev, g->pin);
+ bank = gpio_range_to_bank(range);
+ pin = stm32_gpio_pin(g->pin);
+
+ mode = stm32_gpio_get_mode(function);
+ alt = stm32_gpio_get_alt(function);
+
+ stm32_pmx_set_mode(bank, pin, mode, alt);
+
+ return 0;
+}
+
+static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned gpio,
+ bool input)
+{
+ struct stm32_gpio_bank *bank = gpio_range_to_bank(range);
+ int pin = stm32_gpio_pin(gpio);
+
+ stm32_pmx_set_mode(bank, pin, !input, 0);
+
+ return 0;
+}
+
+static const struct pinmux_ops stm32_pmx_ops = {
+ .get_functions_count = stm32_pmx_get_funcs_cnt,
+ .get_function_name = stm32_pmx_get_func_name,
+ .get_function_groups = stm32_pmx_get_func_groups,
+ .set_mux = stm32_pmx_set_mux,
+ .gpio_set_direction = stm32_pmx_gpio_set_direction,
+};
+
+/* Pinconf functions */
+
+static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
+ unsigned offset, u32 drive)
+{
+ unsigned long flags;
+ u32 val;
+
+ clk_enable(bank->clk);
+ spin_lock_irqsave(&bank->lock, flags);
+
+ val = readl_relaxed(bank->base + STM32_GPIO_TYPER);
+ val &= ~BIT(offset);
+ val |= drive << offset;
+ writel_relaxed(val, bank->base + STM32_GPIO_TYPER);
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+ clk_disable(bank->clk);
+}
+
+static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
+ unsigned offset, u32 speed)
+{
+ unsigned long flags;
+ u32 val;
+
+ clk_enable(bank->clk);
+ spin_lock_irqsave(&bank->lock, flags);
+
+ val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR);
+ val &= ~GENMASK(offset * 2 + 1, offset * 2);
+ val |= speed << (offset * 2);
+ writel_relaxed(val, bank->base + STM32_GPIO_SPEEDR);
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+ clk_disable(bank->clk);
+}
+
+static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
+ unsigned offset, u32 bias)
+{
+ unsigned long flags;
+ u32 val;
+
+ clk_enable(bank->clk);
+ spin_lock_irqsave(&bank->lock, flags);
+
+ val = readl_relaxed(bank->base + STM32_GPIO_PUPDR);
+ val &= ~GENMASK(offset * 2 + 1, offset * 2);
+ val |= bias << (offset * 2);
+ writel_relaxed(val, bank->base + STM32_GPIO_PUPDR);
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+ clk_disable(bank->clk);
+}
+
+static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev,
+ unsigned int pin, enum pin_config_param param,
+ enum pin_config_param arg)
+{
+ struct pinctrl_gpio_range *range;
+ struct stm32_gpio_bank *bank;
+ int offset, ret = 0;
+
+ range = pinctrl_find_gpio_range_from_pin(pctldev, pin);
+ bank = gpio_range_to_bank(range);
+ offset = stm32_gpio_pin(pin);
+
+ switch (param) {
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ stm32_pconf_set_driving(bank, offset, 0);
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ stm32_pconf_set_driving(bank, offset, 1);
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ stm32_pconf_set_speed(bank, offset, arg);
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ stm32_pconf_set_bias(bank, offset, 0);
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ stm32_pconf_set_bias(bank, offset, 1);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ stm32_pconf_set_bias(bank, offset, 2);
+ break;
+ case PIN_CONFIG_OUTPUT:
+ __stm32_gpio_set(bank, offset, arg);
+ ret = stm32_pmx_gpio_set_direction(pctldev, NULL, pin, false);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int stm32_pconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned group,
+ unsigned long *config)
+{
+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *config = pctl->groups[group].config;
+
+ return 0;
+}
+
+static int stm32_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct stm32_pinctrl_group *g = &pctl->groups[group];
+ int i, ret;
+
+ for (i = 0; i < num_configs; i++) {
+ ret = stm32_pconf_parse_conf(pctldev, g->pin,
+ pinconf_to_config_param(configs[i]),
+ pinconf_to_config_argument(configs[i]));
+ if (ret < 0)
+ return ret;
+
+ g->config = configs[i];
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops stm32_pconf_ops = {
+ .pin_config_group_get = stm32_pconf_group_get,
+ .pin_config_group_set = stm32_pconf_group_set,
+};
+
+static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl,
+ struct device_node *np)
+{
+ int bank_nr = pctl->nbanks;
+ struct stm32_gpio_bank *bank = &pctl->banks[bank_nr];
+ struct pinctrl_gpio_range *range = &bank->range;
+ struct device *dev = pctl->dev;
+ struct resource res;
+ struct reset_control *rstc;
+ int err, npins;
+
+ rstc = of_reset_control_get(np, NULL);
+ if (!IS_ERR(rstc))
+ reset_control_deassert(rstc);
+
+ if (of_address_to_resource(np, 0, &res))
+ return -ENODEV;
+
+ bank->base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(bank->base))
+ return PTR_ERR(bank->base);
+
+ bank->clk = of_clk_get_by_name(np, NULL);
+ if (IS_ERR(bank->clk)) {
+ dev_err(dev, "failed to get clk (%ld)\n", PTR_ERR(bank->clk));
+ return PTR_ERR(bank->clk);
+ }
+
+ err = clk_prepare(bank->clk);
+ if (err) {
+ dev_err(dev, "failed to prepare clk (%d)\n", err);
+ return err;
+ }
+
+ npins = pctl->match_data->npins;
+ npins -= bank_nr * STM32_GPIO_PINS_PER_BANK;
+ if (npins < 0)
+ return -EINVAL;
+ else if (npins > STM32_GPIO_PINS_PER_BANK)
+ npins = STM32_GPIO_PINS_PER_BANK;
+
+ bank->gpio_chip = stm32_gpio_template;
+ bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK;
+ bank->gpio_chip.ngpio = npins;
+ bank->gpio_chip.of_node = np;
+ bank->gpio_chip.parent = dev;
+ spin_lock_init(&bank->lock);
+
+ of_property_read_string(np, "st,bank-name", &range->name);
+ bank->gpio_chip.label = range->name;
+
+ range->id = bank_nr;
+ range->pin_base = range->base = range->id * STM32_GPIO_PINS_PER_BANK;
+ range->npins = bank->gpio_chip.ngpio;
+ range->gc = &bank->gpio_chip;
+ err = gpiochip_add_data(&bank->gpio_chip, bank);
+ if (err) {
+ dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_nr);
+ return err;
+ }
+
+ dev_info(dev, "%s bank added\n", range->name);
+ return 0;
+}
+
+static int stm32_pctrl_build_state(struct platform_device *pdev)
+{
+ struct stm32_pinctrl *pctl = platform_get_drvdata(pdev);
+ int i;
+
+ pctl->ngroups = pctl->match_data->npins;
+
+ /* Allocate groups */
+ pctl->groups = devm_kcalloc(&pdev->dev, pctl->ngroups,
+ sizeof(*pctl->groups), GFP_KERNEL);
+ if (!pctl->groups)
+ return -ENOMEM;
+
+ /* We assume that one pin is one group, use pin name as group name. */
+ pctl->grp_names = devm_kcalloc(&pdev->dev, pctl->ngroups,
+ sizeof(*pctl->grp_names), GFP_KERNEL);
+ if (!pctl->grp_names)
+ return -ENOMEM;
+
+ for (i = 0; i < pctl->match_data->npins; i++) {
+ const struct stm32_desc_pin *pin = pctl->match_data->pins + i;
+ struct stm32_pinctrl_group *group = pctl->groups + i;
+
+ group->name = pin->pin.name;
+ group->pin = pin->pin.number;
+
+ pctl->grp_names[i] = pin->pin.name;
+ }
+
+ return 0;
+}
+
+int stm32_pctl_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct stm32_pinctrl *pctl;
+ struct pinctrl_pin_desc *pins;
+ int i, ret, banks = 0;
+
+ if (!np)
+ return -EINVAL;
+
+ match = of_match_device(dev->driver->of_match_table, dev);
+ if (!match || !match->data)
+ return -EINVAL;
+
+ if (!of_find_property(np, "pins-are-numbered", NULL)) {
+ dev_err(dev, "only support pins-are-numbered format\n");
+ return -EINVAL;
+ }
+
+ pctl = devm_kzalloc(dev, sizeof(*pctl), GFP_KERNEL);
+ if (!pctl)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, pctl);
+
+ pctl->dev = dev;
+ pctl->match_data = match->data;
+ ret = stm32_pctrl_build_state(pdev);
+ if (ret) {
+ dev_err(dev, "build state failed: %d\n", ret);
+ return -EINVAL;
+ }
+
+ for_each_child_of_node(np, child)
+ if (of_property_read_bool(child, "gpio-controller"))
+ banks++;
+
+ if (!banks) {
+ dev_err(dev, "at least one GPIO bank is required\n");
+ return -EINVAL;
+ }
+
+ pctl->banks = devm_kcalloc(dev, banks, sizeof(*pctl->banks),
+ GFP_KERNEL);
+ if (!pctl->banks)
+ return -ENOMEM;
+
+ for_each_child_of_node(np, child) {
+ if (of_property_read_bool(child, "gpio-controller")) {
+ ret = stm32_gpiolib_register_bank(pctl, child);
+ if (ret)
+ return ret;
+
+ pctl->nbanks++;
+ }
+ }
+
+ pins = devm_kcalloc(&pdev->dev, pctl->match_data->npins, sizeof(*pins),
+ GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ for (i = 0; i < pctl->match_data->npins; i++)
+ pins[i] = pctl->match_data->pins[i].pin;
+
+ pctl->pctl_desc.name = dev_name(&pdev->dev);
+ pctl->pctl_desc.owner = THIS_MODULE;
+ pctl->pctl_desc.pins = pins;
+ pctl->pctl_desc.npins = pctl->match_data->npins;
+ pctl->pctl_desc.confops = &stm32_pconf_ops;
+ pctl->pctl_desc.pctlops = &stm32_pctrl_ops;
+ pctl->pctl_desc.pmxops = &stm32_pmx_ops;
+ pctl->dev = &pdev->dev;
+
+ pctl->pctl_dev = pinctrl_register(&pctl->pctl_desc, &pdev->dev, pctl);
+ if (!pctl->pctl_dev) {
+ dev_err(&pdev->dev, "Failed pinctrl registration\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < pctl->nbanks; i++)
+ pinctrl_add_gpio_range(pctl->pctl_dev, &pctl->banks[i].range);
+
+ dev_info(dev, "Pinctrl STM32 initialized\n");
+
+ return 0;
+}
+
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h
new file mode 100644
index 000000000000..35ebc94c01e4
--- /dev/null
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ */
+#ifndef __PINCTRL_STM32_H
+#define __PINCTRL_STM32_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#define STM32_PIN_NO(x) ((x) << 8)
+#define STM32_GET_PIN_NO(x) ((x) >> 8)
+#define STM32_GET_PIN_FUNC(x) ((x) & 0xff)
+
+#define STM32_PIN_GPIO 0
+#define STM32_PIN_AF(x) ((x) + 1)
+#define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1)
+
+struct stm32_desc_function {
+ const char *name;
+ const unsigned char num;
+};
+
+struct stm32_desc_pin {
+ struct pinctrl_pin_desc pin;
+ const struct stm32_desc_function *functions;
+};
+
+#define STM32_PIN(_pin, ...) \
+ { \
+ .pin = _pin, \
+ .functions = (struct stm32_desc_function[]){ \
+ __VA_ARGS__, { } }, \
+ }
+
+#define STM32_FUNCTION(_num, _name) \
+ { \
+ .num = _num, \
+ .name = _name, \
+ }
+
+struct stm32_pinctrl_match_data {
+ const struct stm32_desc_pin *pins;
+ const unsigned int npins;
+};
+
+int stm32_pctl_probe(struct platform_device *pdev);
+
+#endif /* __PINCTRL_STM32_H */
+
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32f429.c b/drivers/pinctrl/stm32/pinctrl-stm32f429.c
new file mode 100644
index 000000000000..e9b15dc0654b
--- /dev/null
+++ b/drivers/pinctrl/stm32/pinctrl-stm32f429.c
@@ -0,0 +1,1591 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ */
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-stm32.h"
+
+static const struct stm32_desc_pin stm32f429_pins[] = {
+ STM32_PIN(
+ PINCTRL_PIN(0, "PA0"),
+ STM32_FUNCTION(0, "GPIOA0"),
+ STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+ STM32_FUNCTION(3, "TIM5_CH1"),
+ STM32_FUNCTION(4, "TIM8_ETR"),
+ STM32_FUNCTION(8, "USART2_CTS"),
+ STM32_FUNCTION(9, "UART4_TX"),
+ STM32_FUNCTION(12, "ETH_MII_CRS"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(1, "PA1"),
+ STM32_FUNCTION(0, "GPIOA1"),
+ STM32_FUNCTION(2, "TIM2_CH2"),
+ STM32_FUNCTION(3, "TIM5_CH2"),
+ STM32_FUNCTION(8, "USART2_RTS"),
+ STM32_FUNCTION(9, "UART4_RX"),
+ STM32_FUNCTION(12, "ETH_MII_RX_CLK ETH_RMII_REF_CLK"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(2, "PA2"),
+ STM32_FUNCTION(0, "GPIOA2"),
+ STM32_FUNCTION(2, "TIM2_CH3"),
+ STM32_FUNCTION(3, "TIM5_CH3"),
+ STM32_FUNCTION(4, "TIM9_CH1"),
+ STM32_FUNCTION(8, "USART2_TX"),
+ STM32_FUNCTION(12, "ETH_MDIO"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(3, "PA3"),
+ STM32_FUNCTION(0, "GPIOA3"),
+ STM32_FUNCTION(2, "TIM2_CH4"),
+ STM32_FUNCTION(3, "TIM5_CH4"),
+ STM32_FUNCTION(4, "TIM9_CH2"),
+ STM32_FUNCTION(8, "USART2_RX"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_D0"),
+ STM32_FUNCTION(12, "ETH_MII_COL"),
+ STM32_FUNCTION(15, "LCD_B5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(4, "PA4"),
+ STM32_FUNCTION(0, "GPIOA4"),
+ STM32_FUNCTION(6, "SPI1_NSS"),
+ STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"),
+ STM32_FUNCTION(8, "USART2_CK"),
+ STM32_FUNCTION(13, "OTG_HS_SOF"),
+ STM32_FUNCTION(14, "DCMI_HSYNC"),
+ STM32_FUNCTION(15, "LCD_VSYNC"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(5, "PA5"),
+ STM32_FUNCTION(0, "GPIOA5"),
+ STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+ STM32_FUNCTION(4, "TIM8_CH1N"),
+ STM32_FUNCTION(6, "SPI1_SCK"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_CK"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(6, "PA6"),
+ STM32_FUNCTION(0, "GPIOA6"),
+ STM32_FUNCTION(2, "TIM1_BKIN"),
+ STM32_FUNCTION(3, "TIM3_CH1"),
+ STM32_FUNCTION(4, "TIM8_BKIN"),
+ STM32_FUNCTION(6, "SPI1_MISO"),
+ STM32_FUNCTION(10, "TIM13_CH1"),
+ STM32_FUNCTION(14, "DCMI_PIXCLK"),
+ STM32_FUNCTION(15, "LCD_G2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(7, "PA7"),
+ STM32_FUNCTION(0, "GPIOA7"),
+ STM32_FUNCTION(2, "TIM1_CH1N"),
+ STM32_FUNCTION(3, "TIM3_CH2"),
+ STM32_FUNCTION(4, "TIM8_CH1N"),
+ STM32_FUNCTION(6, "SPI1_MOSI"),
+ STM32_FUNCTION(10, "TIM14_CH1"),
+ STM32_FUNCTION(12, "ETH_MII_RX_DV ETH_RMII_CRS_DV"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(8, "PA8"),
+ STM32_FUNCTION(0, "GPIOA8"),
+ STM32_FUNCTION(1, "MCO1"),
+ STM32_FUNCTION(2, "TIM1_CH1"),
+ STM32_FUNCTION(5, "I2C3_SCL"),
+ STM32_FUNCTION(8, "USART1_CK"),
+ STM32_FUNCTION(11, "OTG_FS_SOF"),
+ STM32_FUNCTION(15, "LCD_R6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(9, "PA9"),
+ STM32_FUNCTION(0, "GPIOA9"),
+ STM32_FUNCTION(2, "TIM1_CH2"),
+ STM32_FUNCTION(5, "I2C3_SMBA"),
+ STM32_FUNCTION(8, "USART1_TX"),
+ STM32_FUNCTION(14, "DCMI_D0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(10, "PA10"),
+ STM32_FUNCTION(0, "GPIOA10"),
+ STM32_FUNCTION(2, "TIM1_CH3"),
+ STM32_FUNCTION(8, "USART1_RX"),
+ STM32_FUNCTION(11, "OTG_FS_ID"),
+ STM32_FUNCTION(14, "DCMI_D1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(11, "PA11"),
+ STM32_FUNCTION(0, "GPIOA11"),
+ STM32_FUNCTION(2, "TIM1_CH4"),
+ STM32_FUNCTION(8, "USART1_CTS"),
+ STM32_FUNCTION(10, "CAN1_RX"),
+ STM32_FUNCTION(11, "OTG_FS_DM"),
+ STM32_FUNCTION(15, "LCD_R4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(12, "PA12"),
+ STM32_FUNCTION(0, "GPIOA12"),
+ STM32_FUNCTION(2, "TIM1_ETR"),
+ STM32_FUNCTION(8, "USART1_RTS"),
+ STM32_FUNCTION(10, "CAN1_TX"),
+ STM32_FUNCTION(11, "OTG_FS_DP"),
+ STM32_FUNCTION(15, "LCD_R5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(13, "PA13"),
+ STM32_FUNCTION(0, "GPIOA13"),
+ STM32_FUNCTION(1, "JTMS SWDIO"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(14, "PA14"),
+ STM32_FUNCTION(0, "GPIOA14"),
+ STM32_FUNCTION(1, "JTCK SWCLK"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(15, "PA15"),
+ STM32_FUNCTION(0, "GPIOA15"),
+ STM32_FUNCTION(1, "JTDI"),
+ STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+ STM32_FUNCTION(6, "SPI1_NSS"),
+ STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(16, "PB0"),
+ STM32_FUNCTION(0, "GPIOB0"),
+ STM32_FUNCTION(2, "TIM1_CH2N"),
+ STM32_FUNCTION(3, "TIM3_CH3"),
+ STM32_FUNCTION(4, "TIM8_CH2N"),
+ STM32_FUNCTION(10, "LCD_R3"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_D1"),
+ STM32_FUNCTION(12, "ETH_MII_RXD2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(17, "PB1"),
+ STM32_FUNCTION(0, "GPIOB1"),
+ STM32_FUNCTION(2, "TIM1_CH3N"),
+ STM32_FUNCTION(3, "TIM3_CH4"),
+ STM32_FUNCTION(4, "TIM8_CH3N"),
+ STM32_FUNCTION(10, "LCD_R6"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_D2"),
+ STM32_FUNCTION(12, "ETH_MII_RXD3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(18, "PB2"),
+ STM32_FUNCTION(0, "GPIOB2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(19, "PB3"),
+ STM32_FUNCTION(0, "GPIOB3"),
+ STM32_FUNCTION(1, "JTDO TRACESWO"),
+ STM32_FUNCTION(2, "TIM2_CH2"),
+ STM32_FUNCTION(6, "SPI1_SCK"),
+ STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(20, "PB4"),
+ STM32_FUNCTION(0, "GPIOB4"),
+ STM32_FUNCTION(1, "NJTRST"),
+ STM32_FUNCTION(3, "TIM3_CH1"),
+ STM32_FUNCTION(6, "SPI1_MISO"),
+ STM32_FUNCTION(7, "SPI3_MISO"),
+ STM32_FUNCTION(8, "I2S3EXT_SD"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(21, "PB5"),
+ STM32_FUNCTION(0, "GPIOB5"),
+ STM32_FUNCTION(3, "TIM3_CH2"),
+ STM32_FUNCTION(5, "I2C1_SMBA"),
+ STM32_FUNCTION(6, "SPI1_MOSI"),
+ STM32_FUNCTION(7, "SPI3_MOSI I2S3_SD"),
+ STM32_FUNCTION(10, "CAN2_RX"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_D7"),
+ STM32_FUNCTION(12, "ETH_PPS_OUT"),
+ STM32_FUNCTION(13, "FMC_SDCKE1"),
+ STM32_FUNCTION(14, "DCMI_D10"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(22, "PB6"),
+ STM32_FUNCTION(0, "GPIOB6"),
+ STM32_FUNCTION(3, "TIM4_CH1"),
+ STM32_FUNCTION(5, "I2C1_SCL"),
+ STM32_FUNCTION(8, "USART1_TX"),
+ STM32_FUNCTION(10, "CAN2_TX"),
+ STM32_FUNCTION(13, "FMC_SDNE1"),
+ STM32_FUNCTION(14, "DCMI_D5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(23, "PB7"),
+ STM32_FUNCTION(0, "GPIOB7"),
+ STM32_FUNCTION(3, "TIM4_CH2"),
+ STM32_FUNCTION(5, "I2C1_SDA"),
+ STM32_FUNCTION(8, "USART1_RX"),
+ STM32_FUNCTION(13, "FMC_NL"),
+ STM32_FUNCTION(14, "DCMI_VSYNC"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(24, "PB8"),
+ STM32_FUNCTION(0, "GPIOB8"),
+ STM32_FUNCTION(3, "TIM4_CH3"),
+ STM32_FUNCTION(4, "TIM10_CH1"),
+ STM32_FUNCTION(5, "I2C1_SCL"),
+ STM32_FUNCTION(10, "CAN1_RX"),
+ STM32_FUNCTION(12, "ETH_MII_TXD3"),
+ STM32_FUNCTION(13, "SDIO_D4"),
+ STM32_FUNCTION(14, "DCMI_D6"),
+ STM32_FUNCTION(15, "LCD_B6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(25, "PB9"),
+ STM32_FUNCTION(0, "GPIOB9"),
+ STM32_FUNCTION(3, "TIM4_CH4"),
+ STM32_FUNCTION(4, "TIM11_CH1"),
+ STM32_FUNCTION(5, "I2C1_SDA"),
+ STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+ STM32_FUNCTION(10, "CAN1_TX"),
+ STM32_FUNCTION(13, "SDIO_D5"),
+ STM32_FUNCTION(14, "DCMI_D7"),
+ STM32_FUNCTION(15, "LCD_B7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(26, "PB10"),
+ STM32_FUNCTION(0, "GPIOB10"),
+ STM32_FUNCTION(2, "TIM2_CH3"),
+ STM32_FUNCTION(5, "I2C2_SCL"),
+ STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+ STM32_FUNCTION(8, "USART3_TX"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_D3"),
+ STM32_FUNCTION(12, "ETH_MII_RX_ER"),
+ STM32_FUNCTION(15, "LCD_G4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(27, "PB11"),
+ STM32_FUNCTION(0, "GPIOB11"),
+ STM32_FUNCTION(2, "TIM2_CH4"),
+ STM32_FUNCTION(5, "I2C2_SDA"),
+ STM32_FUNCTION(8, "USART3_RX"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_D4"),
+ STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"),
+ STM32_FUNCTION(15, "LCD_G5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(28, "PB12"),
+ STM32_FUNCTION(0, "GPIOB12"),
+ STM32_FUNCTION(2, "TIM1_BKIN"),
+ STM32_FUNCTION(5, "I2C2_SMBA"),
+ STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+ STM32_FUNCTION(8, "USART3_CK"),
+ STM32_FUNCTION(10, "CAN2_RX"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_D5"),
+ STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"),
+ STM32_FUNCTION(13, "OTG_HS_ID"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(29, "PB13"),
+ STM32_FUNCTION(0, "GPIOB13"),
+ STM32_FUNCTION(2, "TIM1_CH1N"),
+ STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+ STM32_FUNCTION(8, "USART3_CTS"),
+ STM32_FUNCTION(10, "CAN2_TX"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_D6"),
+ STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(30, "PB14"),
+ STM32_FUNCTION(0, "GPIOB14"),
+ STM32_FUNCTION(2, "TIM1_CH2N"),
+ STM32_FUNCTION(4, "TIM8_CH2N"),
+ STM32_FUNCTION(6, "SPI2_MISO"),
+ STM32_FUNCTION(7, "I2S2EXT_SD"),
+ STM32_FUNCTION(8, "USART3_RTS"),
+ STM32_FUNCTION(10, "TIM12_CH1"),
+ STM32_FUNCTION(13, "OTG_HS_DM"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(31, "PB15"),
+ STM32_FUNCTION(0, "GPIOB15"),
+ STM32_FUNCTION(1, "RTC_REFIN"),
+ STM32_FUNCTION(2, "TIM1_CH3N"),
+ STM32_FUNCTION(4, "TIM8_CH3N"),
+ STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+ STM32_FUNCTION(10, "TIM12_CH2"),
+ STM32_FUNCTION(13, "OTG_HS_DP"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(32, "PC0"),
+ STM32_FUNCTION(0, "GPIOC0"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_STP"),
+ STM32_FUNCTION(13, "FMC_SDNWE"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(33, "PC1"),
+ STM32_FUNCTION(0, "GPIOC1"),
+ STM32_FUNCTION(12, "ETH_MDC"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(34, "PC2"),
+ STM32_FUNCTION(0, "GPIOC2"),
+ STM32_FUNCTION(6, "SPI2_MISO"),
+ STM32_FUNCTION(7, "I2S2EXT_SD"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"),
+ STM32_FUNCTION(12, "ETH_MII_TXD2"),
+ STM32_FUNCTION(13, "FMC_SDNE0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(35, "PC3"),
+ STM32_FUNCTION(0, "GPIOC3"),
+ STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"),
+ STM32_FUNCTION(12, "ETH_MII_TX_CLK"),
+ STM32_FUNCTION(13, "FMC_SDCKE0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(36, "PC4"),
+ STM32_FUNCTION(0, "GPIOC4"),
+ STM32_FUNCTION(12, "ETH_MII_RXD0 ETH_RMII_RXD0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(37, "PC5"),
+ STM32_FUNCTION(0, "GPIOC5"),
+ STM32_FUNCTION(12, "ETH_MII_RXD1 ETH_RMII_RXD1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(38, "PC6"),
+ STM32_FUNCTION(0, "GPIOC6"),
+ STM32_FUNCTION(3, "TIM3_CH1"),
+ STM32_FUNCTION(4, "TIM8_CH1"),
+ STM32_FUNCTION(6, "I2S2_MCK"),
+ STM32_FUNCTION(9, "USART6_TX"),
+ STM32_FUNCTION(13, "SDIO_D6"),
+ STM32_FUNCTION(14, "DCMI_D0"),
+ STM32_FUNCTION(15, "LCD_HSYNC"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(39, "PC7"),
+ STM32_FUNCTION(0, "GPIOC7"),
+ STM32_FUNCTION(3, "TIM3_CH2"),
+ STM32_FUNCTION(4, "TIM8_CH2"),
+ STM32_FUNCTION(7, "I2S3_MCK"),
+ STM32_FUNCTION(9, "USART6_RX"),
+ STM32_FUNCTION(13, "SDIO_D7"),
+ STM32_FUNCTION(14, "DCMI_D1"),
+ STM32_FUNCTION(15, "LCD_G6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(40, "PC8"),
+ STM32_FUNCTION(0, "GPIOC8"),
+ STM32_FUNCTION(3, "TIM3_CH3"),
+ STM32_FUNCTION(4, "TIM8_CH3"),
+ STM32_FUNCTION(9, "USART6_CK"),
+ STM32_FUNCTION(13, "SDIO_D0"),
+ STM32_FUNCTION(14, "DCMI_D2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(41, "PC9"),
+ STM32_FUNCTION(0, "GPIOC9"),
+ STM32_FUNCTION(1, "MCO2"),
+ STM32_FUNCTION(3, "TIM3_CH4"),
+ STM32_FUNCTION(4, "TIM8_CH4"),
+ STM32_FUNCTION(5, "I2C3_SDA"),
+ STM32_FUNCTION(6, "I2S_CKIN"),
+ STM32_FUNCTION(13, "SDIO_D1"),
+ STM32_FUNCTION(14, "DCMI_D3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(42, "PC10"),
+ STM32_FUNCTION(0, "GPIOC10"),
+ STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"),
+ STM32_FUNCTION(8, "USART3_TX"),
+ STM32_FUNCTION(9, "UART4_TX"),
+ STM32_FUNCTION(13, "SDIO_D2"),
+ STM32_FUNCTION(14, "DCMI_D8"),
+ STM32_FUNCTION(15, "LCD_R2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(43, "PC11"),
+ STM32_FUNCTION(0, "GPIOC11"),
+ STM32_FUNCTION(6, "I2S3EXT_SD"),
+ STM32_FUNCTION(7, "SPI3_MISO"),
+ STM32_FUNCTION(8, "USART3_RX"),
+ STM32_FUNCTION(9, "UART4_RX"),
+ STM32_FUNCTION(13, "SDIO_D3"),
+ STM32_FUNCTION(14, "DCMI_D4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(44, "PC12"),
+ STM32_FUNCTION(0, "GPIOC12"),
+ STM32_FUNCTION(7, "SPI3_MOSI I2S3_SD"),
+ STM32_FUNCTION(8, "USART3_CK"),
+ STM32_FUNCTION(9, "UART5_TX"),
+ STM32_FUNCTION(13, "SDIO_CK"),
+ STM32_FUNCTION(14, "DCMI_D9"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(45, "PC13"),
+ STM32_FUNCTION(0, "GPIOC13"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(46, "PC14"),
+ STM32_FUNCTION(0, "GPIOC14"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(47, "PC15"),
+ STM32_FUNCTION(0, "GPIOC15"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(48, "PD0"),
+ STM32_FUNCTION(0, "GPIOD0"),
+ STM32_FUNCTION(10, "CAN1_RX"),
+ STM32_FUNCTION(13, "FMC_D2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(49, "PD1"),
+ STM32_FUNCTION(0, "GPIOD1"),
+ STM32_FUNCTION(10, "CAN1_TX"),
+ STM32_FUNCTION(13, "FMC_D3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(50, "PD2"),
+ STM32_FUNCTION(0, "GPIOD2"),
+ STM32_FUNCTION(3, "TIM3_ETR"),
+ STM32_FUNCTION(9, "UART5_RX"),
+ STM32_FUNCTION(13, "SDIO_CMD"),
+ STM32_FUNCTION(14, "DCMI_D11"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(51, "PD3"),
+ STM32_FUNCTION(0, "GPIOD3"),
+ STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+ STM32_FUNCTION(8, "USART2_CTS"),
+ STM32_FUNCTION(13, "FMC_CLK"),
+ STM32_FUNCTION(14, "DCMI_D5"),
+ STM32_FUNCTION(15, "LCD_G7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(52, "PD4"),
+ STM32_FUNCTION(0, "GPIOD4"),
+ STM32_FUNCTION(8, "USART2_RTS"),
+ STM32_FUNCTION(13, "FMC_NOE"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(53, "PD5"),
+ STM32_FUNCTION(0, "GPIOD5"),
+ STM32_FUNCTION(8, "USART2_TX"),
+ STM32_FUNCTION(13, "FMC_NWE"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(54, "PD6"),
+ STM32_FUNCTION(0, "GPIOD6"),
+ STM32_FUNCTION(6, "SPI3_MOSI I2S3_SD"),
+ STM32_FUNCTION(7, "SAI1_SD_A"),
+ STM32_FUNCTION(8, "USART2_RX"),
+ STM32_FUNCTION(13, "FMC_NWAIT"),
+ STM32_FUNCTION(14, "DCMI_D10"),
+ STM32_FUNCTION(15, "LCD_B2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(55, "PD7"),
+ STM32_FUNCTION(0, "GPIOD7"),
+ STM32_FUNCTION(8, "USART2_CK"),
+ STM32_FUNCTION(13, "FMC_NE1 FMC_NCE2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(56, "PD8"),
+ STM32_FUNCTION(0, "GPIOD8"),
+ STM32_FUNCTION(8, "USART3_TX"),
+ STM32_FUNCTION(13, "FMC_D13"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(57, "PD9"),
+ STM32_FUNCTION(0, "GPIOD9"),
+ STM32_FUNCTION(8, "USART3_RX"),
+ STM32_FUNCTION(13, "FMC_D14"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(58, "PD10"),
+ STM32_FUNCTION(0, "GPIOD10"),
+ STM32_FUNCTION(8, "USART3_CK"),
+ STM32_FUNCTION(13, "FMC_D15"),
+ STM32_FUNCTION(15, "LCD_B3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(59, "PD11"),
+ STM32_FUNCTION(0, "GPIOD11"),
+ STM32_FUNCTION(8, "USART3_CTS"),
+ STM32_FUNCTION(13, "FMC_A16"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(60, "PD12"),
+ STM32_FUNCTION(0, "GPIOD12"),
+ STM32_FUNCTION(3, "TIM4_CH1"),
+ STM32_FUNCTION(8, "USART3_RTS"),
+ STM32_FUNCTION(13, "FMC_A17"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(61, "PD13"),
+ STM32_FUNCTION(0, "GPIOD13"),
+ STM32_FUNCTION(3, "TIM4_CH2"),
+ STM32_FUNCTION(13, "FMC_A18"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(62, "PD14"),
+ STM32_FUNCTION(0, "GPIOD14"),
+ STM32_FUNCTION(3, "TIM4_CH3"),
+ STM32_FUNCTION(13, "FMC_D0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(63, "PD15"),
+ STM32_FUNCTION(0, "GPIOD15"),
+ STM32_FUNCTION(3, "TIM4_CH4"),
+ STM32_FUNCTION(13, "FMC_D1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(64, "PE0"),
+ STM32_FUNCTION(0, "GPIOE0"),
+ STM32_FUNCTION(3, "TIM4_ETR"),
+ STM32_FUNCTION(9, "UART8_RX"),
+ STM32_FUNCTION(13, "FMC_NBL0"),
+ STM32_FUNCTION(14, "DCMI_D2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(65, "PE1"),
+ STM32_FUNCTION(0, "GPIOE1"),
+ STM32_FUNCTION(9, "UART8_TX"),
+ STM32_FUNCTION(13, "FMC_NBL1"),
+ STM32_FUNCTION(14, "DCMI_D3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(66, "PE2"),
+ STM32_FUNCTION(0, "GPIOE2"),
+ STM32_FUNCTION(1, "TRACECLK"),
+ STM32_FUNCTION(6, "SPI4_SCK"),
+ STM32_FUNCTION(7, "SAI1_MCLK_A"),
+ STM32_FUNCTION(12, "ETH_MII_TXD3"),
+ STM32_FUNCTION(13, "FMC_A23"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(67, "PE3"),
+ STM32_FUNCTION(0, "GPIOE3"),
+ STM32_FUNCTION(1, "TRACED0"),
+ STM32_FUNCTION(7, "SAI1_SD_B"),
+ STM32_FUNCTION(13, "FMC_A19"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(68, "PE4"),
+ STM32_FUNCTION(0, "GPIOE4"),
+ STM32_FUNCTION(1, "TRACED1"),
+ STM32_FUNCTION(6, "SPI4_NSS"),
+ STM32_FUNCTION(7, "SAI1_FS_A"),
+ STM32_FUNCTION(13, "FMC_A20"),
+ STM32_FUNCTION(14, "DCMI_D4"),
+ STM32_FUNCTION(15, "LCD_B0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(69, "PE5"),
+ STM32_FUNCTION(0, "GPIOE5"),
+ STM32_FUNCTION(1, "TRACED2"),
+ STM32_FUNCTION(4, "TIM9_CH1"),
+ STM32_FUNCTION(6, "SPI4_MISO"),
+ STM32_FUNCTION(7, "SAI1_SCK_A"),
+ STM32_FUNCTION(13, "FMC_A21"),
+ STM32_FUNCTION(14, "DCMI_D6"),
+ STM32_FUNCTION(15, "LCD_G0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(70, "PE6"),
+ STM32_FUNCTION(0, "GPIOE6"),
+ STM32_FUNCTION(1, "TRACED3"),
+ STM32_FUNCTION(4, "TIM9_CH2"),
+ STM32_FUNCTION(6, "SPI4_MOSI"),
+ STM32_FUNCTION(7, "SAI1_SD_A"),
+ STM32_FUNCTION(13, "FMC_A22"),
+ STM32_FUNCTION(14, "DCMI_D7"),
+ STM32_FUNCTION(15, "LCD_G1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(71, "PE7"),
+ STM32_FUNCTION(0, "GPIOE7"),
+ STM32_FUNCTION(2, "TIM1_ETR"),
+ STM32_FUNCTION(9, "UART7_RX"),
+ STM32_FUNCTION(13, "FMC_D4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(72, "PE8"),
+ STM32_FUNCTION(0, "GPIOE8"),
+ STM32_FUNCTION(2, "TIM1_CH1N"),
+ STM32_FUNCTION(9, "UART7_TX"),
+ STM32_FUNCTION(13, "FMC_D5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(73, "PE9"),
+ STM32_FUNCTION(0, "GPIOE9"),
+ STM32_FUNCTION(2, "TIM1_CH1"),
+ STM32_FUNCTION(13, "FMC_D6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(74, "PE10"),
+ STM32_FUNCTION(0, "GPIOE10"),
+ STM32_FUNCTION(2, "TIM1_CH2N"),
+ STM32_FUNCTION(13, "FMC_D7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(75, "PE11"),
+ STM32_FUNCTION(0, "GPIOE11"),
+ STM32_FUNCTION(2, "TIM1_CH2"),
+ STM32_FUNCTION(6, "SPI4_NSS"),
+ STM32_FUNCTION(13, "FMC_D8"),
+ STM32_FUNCTION(15, "LCD_G3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(76, "PE12"),
+ STM32_FUNCTION(0, "GPIOE12"),
+ STM32_FUNCTION(2, "TIM1_CH3N"),
+ STM32_FUNCTION(6, "SPI4_SCK"),
+ STM32_FUNCTION(13, "FMC_D9"),
+ STM32_FUNCTION(15, "LCD_B4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(77, "PE13"),
+ STM32_FUNCTION(0, "GPIOE13"),
+ STM32_FUNCTION(2, "TIM1_CH3"),
+ STM32_FUNCTION(6, "SPI4_MISO"),
+ STM32_FUNCTION(13, "FMC_D10"),
+ STM32_FUNCTION(15, "LCD_DE"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(78, "PE14"),
+ STM32_FUNCTION(0, "GPIOE14"),
+ STM32_FUNCTION(2, "TIM1_CH4"),
+ STM32_FUNCTION(6, "SPI4_MOSI"),
+ STM32_FUNCTION(13, "FMC_D11"),
+ STM32_FUNCTION(15, "LCD_CLK"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(79, "PE15"),
+ STM32_FUNCTION(0, "GPIOE15"),
+ STM32_FUNCTION(2, "TIM1_BKIN"),
+ STM32_FUNCTION(13, "FMC_D12"),
+ STM32_FUNCTION(15, "LCD_R7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(80, "PF0"),
+ STM32_FUNCTION(0, "GPIOF0"),
+ STM32_FUNCTION(5, "I2C2_SDA"),
+ STM32_FUNCTION(13, "FMC_A0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(81, "PF1"),
+ STM32_FUNCTION(0, "GPIOF1"),
+ STM32_FUNCTION(5, "I2C2_SCL"),
+ STM32_FUNCTION(13, "FMC_A1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(82, "PF2"),
+ STM32_FUNCTION(0, "GPIOF2"),
+ STM32_FUNCTION(5, "I2C2_SMBA"),
+ STM32_FUNCTION(13, "FMC_A2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(83, "PF3"),
+ STM32_FUNCTION(0, "GPIOF3"),
+ STM32_FUNCTION(13, "FMC_A3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(84, "PF4"),
+ STM32_FUNCTION(0, "GPIOF4"),
+ STM32_FUNCTION(13, "FMC_A4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(85, "PF5"),
+ STM32_FUNCTION(0, "GPIOF5"),
+ STM32_FUNCTION(13, "FMC_A5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(86, "PF6"),
+ STM32_FUNCTION(0, "GPIOF6"),
+ STM32_FUNCTION(4, "TIM10_CH1"),
+ STM32_FUNCTION(6, "SPI5_NSS"),
+ STM32_FUNCTION(7, "SAI1_SD_B"),
+ STM32_FUNCTION(9, "UART7_RX"),
+ STM32_FUNCTION(13, "FMC_NIORD"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(87, "PF7"),
+ STM32_FUNCTION(0, "GPIOF7"),
+ STM32_FUNCTION(4, "TIM11_CH1"),
+ STM32_FUNCTION(6, "SPI5_SCK"),
+ STM32_FUNCTION(7, "SAI1_MCLK_B"),
+ STM32_FUNCTION(9, "UART7_TX"),
+ STM32_FUNCTION(13, "FMC_NREG"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(88, "PF8"),
+ STM32_FUNCTION(0, "GPIOF8"),
+ STM32_FUNCTION(6, "SPI5_MISO"),
+ STM32_FUNCTION(7, "SAI1_SCK_B"),
+ STM32_FUNCTION(10, "TIM13_CH1"),
+ STM32_FUNCTION(13, "FMC_NIOWR"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(89, "PF9"),
+ STM32_FUNCTION(0, "GPIOF9"),
+ STM32_FUNCTION(6, "SPI5_MOSI"),
+ STM32_FUNCTION(7, "SAI1_FS_B"),
+ STM32_FUNCTION(10, "TIM14_CH1"),
+ STM32_FUNCTION(13, "FMC_CD"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(90, "PF10"),
+ STM32_FUNCTION(0, "GPIOF10"),
+ STM32_FUNCTION(13, "FMC_INTR"),
+ STM32_FUNCTION(14, "DCMI_D11"),
+ STM32_FUNCTION(15, "LCD_DE"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(91, "PF11"),
+ STM32_FUNCTION(0, "GPIOF11"),
+ STM32_FUNCTION(6, "SPI5_MOSI"),
+ STM32_FUNCTION(13, "FMC_SDNRAS"),
+ STM32_FUNCTION(14, "DCMI_D12"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(92, "PF12"),
+ STM32_FUNCTION(0, "GPIOF12"),
+ STM32_FUNCTION(13, "FMC_A6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(93, "PF13"),
+ STM32_FUNCTION(0, "GPIOF13"),
+ STM32_FUNCTION(13, "FMC_A7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(94, "PF14"),
+ STM32_FUNCTION(0, "GPIOF14"),
+ STM32_FUNCTION(13, "FMC_A8"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(95, "PF15"),
+ STM32_FUNCTION(0, "GPIOF15"),
+ STM32_FUNCTION(13, "FMC_A9"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(96, "PG0"),
+ STM32_FUNCTION(0, "GPIOG0"),
+ STM32_FUNCTION(13, "FMC_A10"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(97, "PG1"),
+ STM32_FUNCTION(0, "GPIOG1"),
+ STM32_FUNCTION(13, "FMC_A11"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(98, "PG2"),
+ STM32_FUNCTION(0, "GPIOG2"),
+ STM32_FUNCTION(13, "FMC_A12"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(99, "PG3"),
+ STM32_FUNCTION(0, "GPIOG3"),
+ STM32_FUNCTION(13, "FMC_A13"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(100, "PG4"),
+ STM32_FUNCTION(0, "GPIOG4"),
+ STM32_FUNCTION(13, "FMC_A14 FMC_BA0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(101, "PG5"),
+ STM32_FUNCTION(0, "GPIOG5"),
+ STM32_FUNCTION(13, "FMC_A15 FMC_BA1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(102, "PG6"),
+ STM32_FUNCTION(0, "GPIOG6"),
+ STM32_FUNCTION(13, "FMC_INT2"),
+ STM32_FUNCTION(14, "DCMI_D12"),
+ STM32_FUNCTION(15, "LCD_R7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(103, "PG7"),
+ STM32_FUNCTION(0, "GPIOG7"),
+ STM32_FUNCTION(9, "USART6_CK"),
+ STM32_FUNCTION(13, "FMC_INT3"),
+ STM32_FUNCTION(14, "DCMI_D13"),
+ STM32_FUNCTION(15, "LCD_CLK"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(104, "PG8"),
+ STM32_FUNCTION(0, "GPIOG8"),
+ STM32_FUNCTION(6, "SPI6_NSS"),
+ STM32_FUNCTION(9, "USART6_RTS"),
+ STM32_FUNCTION(12, "ETH_PPS_OUT"),
+ STM32_FUNCTION(13, "FMC_SDCLK"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(105, "PG9"),
+ STM32_FUNCTION(0, "GPIOG9"),
+ STM32_FUNCTION(9, "USART6_RX"),
+ STM32_FUNCTION(13, "FMC_NE2 FMC_NCE3"),
+ STM32_FUNCTION(14, "DCMI_VSYNC"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(106, "PG10"),
+ STM32_FUNCTION(0, "GPIOG10"),
+ STM32_FUNCTION(10, "LCD_G3"),
+ STM32_FUNCTION(13, "FMC_NCE4_1 FMC_NE3"),
+ STM32_FUNCTION(14, "DCMI_D2"),
+ STM32_FUNCTION(15, "LCD_B2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(107, "PG11"),
+ STM32_FUNCTION(0, "GPIOG11"),
+ STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"),
+ STM32_FUNCTION(13, "FMC_NCE4_2"),
+ STM32_FUNCTION(14, "DCMI_D3"),
+ STM32_FUNCTION(15, "LCD_B3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(108, "PG12"),
+ STM32_FUNCTION(0, "GPIOG12"),
+ STM32_FUNCTION(6, "SPI6_MISO"),
+ STM32_FUNCTION(9, "USART6_RTS"),
+ STM32_FUNCTION(10, "LCD_B4"),
+ STM32_FUNCTION(13, "FMC_NE4"),
+ STM32_FUNCTION(15, "LCD_B1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(109, "PG13"),
+ STM32_FUNCTION(0, "GPIOG13"),
+ STM32_FUNCTION(6, "SPI6_SCK"),
+ STM32_FUNCTION(9, "USART6_CTS"),
+ STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"),
+ STM32_FUNCTION(13, "FMC_A24"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(110, "PG14"),
+ STM32_FUNCTION(0, "GPIOG14"),
+ STM32_FUNCTION(6, "SPI6_MOSI"),
+ STM32_FUNCTION(9, "USART6_TX"),
+ STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"),
+ STM32_FUNCTION(13, "FMC_A25"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(111, "PG15"),
+ STM32_FUNCTION(0, "GPIOG15"),
+ STM32_FUNCTION(9, "USART6_CTS"),
+ STM32_FUNCTION(13, "FMC_SDNCAS"),
+ STM32_FUNCTION(14, "DCMI_D13"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(112, "PH0"),
+ STM32_FUNCTION(0, "GPIOH0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(113, "PH1"),
+ STM32_FUNCTION(0, "GPIOH1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(114, "PH2"),
+ STM32_FUNCTION(0, "GPIOH2"),
+ STM32_FUNCTION(12, "ETH_MII_CRS"),
+ STM32_FUNCTION(13, "FMC_SDCKE0"),
+ STM32_FUNCTION(15, "LCD_R0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(115, "PH3"),
+ STM32_FUNCTION(0, "GPIOH3"),
+ STM32_FUNCTION(12, "ETH_MII_COL"),
+ STM32_FUNCTION(13, "FMC_SDNE0"),
+ STM32_FUNCTION(15, "LCD_R1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(116, "PH4"),
+ STM32_FUNCTION(0, "GPIOH4"),
+ STM32_FUNCTION(5, "I2C2_SCL"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(117, "PH5"),
+ STM32_FUNCTION(0, "GPIOH5"),
+ STM32_FUNCTION(5, "I2C2_SDA"),
+ STM32_FUNCTION(6, "SPI5_NSS"),
+ STM32_FUNCTION(13, "FMC_SDNWE"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(118, "PH6"),
+ STM32_FUNCTION(0, "GPIOH6"),
+ STM32_FUNCTION(5, "I2C2_SMBA"),
+ STM32_FUNCTION(6, "SPI5_SCK"),
+ STM32_FUNCTION(10, "TIM12_CH1"),
+ STM32_FUNCTION(12, "ETH_MII_RXD2"),
+ STM32_FUNCTION(13, "FMC_SDNE1"),
+ STM32_FUNCTION(14, "DCMI_D8"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(119, "PH7"),
+ STM32_FUNCTION(0, "GPIOH7"),
+ STM32_FUNCTION(5, "I2C3_SCL"),
+ STM32_FUNCTION(6, "SPI5_MISO"),
+ STM32_FUNCTION(12, "ETH_MII_RXD3"),
+ STM32_FUNCTION(13, "FMC_SDCKE1"),
+ STM32_FUNCTION(14, "DCMI_D9"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(120, "PH8"),
+ STM32_FUNCTION(0, "GPIOH8"),
+ STM32_FUNCTION(5, "I2C3_SDA"),
+ STM32_FUNCTION(13, "FMC_D16"),
+ STM32_FUNCTION(14, "DCMI_HSYNC"),
+ STM32_FUNCTION(15, "LCD_R2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(121, "PH9"),
+ STM32_FUNCTION(0, "GPIOH9"),
+ STM32_FUNCTION(5, "I2C3_SMBA"),
+ STM32_FUNCTION(10, "TIM12_CH2"),
+ STM32_FUNCTION(13, "FMC_D17"),
+ STM32_FUNCTION(14, "DCMI_D0"),
+ STM32_FUNCTION(15, "LCD_R3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(122, "PH10"),
+ STM32_FUNCTION(0, "GPIOH10"),
+ STM32_FUNCTION(3, "TIM5_CH1"),
+ STM32_FUNCTION(13, "FMC_D18"),
+ STM32_FUNCTION(14, "DCMI_D1"),
+ STM32_FUNCTION(15, "LCD_R4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(123, "PH11"),
+ STM32_FUNCTION(0, "GPIOH11"),
+ STM32_FUNCTION(3, "TIM5_CH2"),
+ STM32_FUNCTION(13, "FMC_D19"),
+ STM32_FUNCTION(14, "DCMI_D2"),
+ STM32_FUNCTION(15, "LCD_R5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(124, "PH12"),
+ STM32_FUNCTION(0, "GPIOH12"),
+ STM32_FUNCTION(3, "TIM5_CH3"),
+ STM32_FUNCTION(13, "FMC_D20"),
+ STM32_FUNCTION(14, "DCMI_D3"),
+ STM32_FUNCTION(15, "LCD_R6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(125, "PH13"),
+ STM32_FUNCTION(0, "GPIOH13"),
+ STM32_FUNCTION(4, "TIM8_CH1N"),
+ STM32_FUNCTION(10, "CAN1_TX"),
+ STM32_FUNCTION(13, "FMC_D21"),
+ STM32_FUNCTION(15, "LCD_G2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(126, "PH14"),
+ STM32_FUNCTION(0, "GPIOH14"),
+ STM32_FUNCTION(4, "TIM8_CH2N"),
+ STM32_FUNCTION(13, "FMC_D22"),
+ STM32_FUNCTION(14, "DCMI_D4"),
+ STM32_FUNCTION(15, "LCD_G3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(127, "PH15"),
+ STM32_FUNCTION(0, "GPIOH15"),
+ STM32_FUNCTION(4, "TIM8_CH3N"),
+ STM32_FUNCTION(13, "FMC_D23"),
+ STM32_FUNCTION(14, "DCMI_D11"),
+ STM32_FUNCTION(15, "LCD_G4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(128, "PI0"),
+ STM32_FUNCTION(0, "GPIOI0"),
+ STM32_FUNCTION(3, "TIM5_CH4"),
+ STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+ STM32_FUNCTION(13, "FMC_D24"),
+ STM32_FUNCTION(14, "DCMI_D13"),
+ STM32_FUNCTION(15, "LCD_G5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(129, "PI1"),
+ STM32_FUNCTION(0, "GPIOI1"),
+ STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+ STM32_FUNCTION(13, "FMC_D25"),
+ STM32_FUNCTION(14, "DCMI_D8"),
+ STM32_FUNCTION(15, "LCD_G6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(130, "PI2"),
+ STM32_FUNCTION(0, "GPIOI2"),
+ STM32_FUNCTION(4, "TIM8_CH4"),
+ STM32_FUNCTION(6, "SPI2_MISO"),
+ STM32_FUNCTION(7, "I2S2EXT_SD"),
+ STM32_FUNCTION(13, "FMC_D26"),
+ STM32_FUNCTION(14, "DCMI_D9"),
+ STM32_FUNCTION(15, "LCD_G7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(131, "PI3"),
+ STM32_FUNCTION(0, "GPIOI3"),
+ STM32_FUNCTION(4, "TIM8_ETR"),
+ STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+ STM32_FUNCTION(13, "FMC_D27"),
+ STM32_FUNCTION(14, "DCMI_D10"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(132, "PI4"),
+ STM32_FUNCTION(0, "GPIOI4"),
+ STM32_FUNCTION(4, "TIM8_BKIN"),
+ STM32_FUNCTION(13, "FMC_NBL2"),
+ STM32_FUNCTION(14, "DCMI_D5"),
+ STM32_FUNCTION(15, "LCD_B4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(133, "PI5"),
+ STM32_FUNCTION(0, "GPIOI5"),
+ STM32_FUNCTION(4, "TIM8_CH1"),
+ STM32_FUNCTION(13, "FMC_NBL3"),
+ STM32_FUNCTION(14, "DCMI_VSYNC"),
+ STM32_FUNCTION(15, "LCD_B5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(134, "PI6"),
+ STM32_FUNCTION(0, "GPIOI6"),
+ STM32_FUNCTION(4, "TIM8_CH2"),
+ STM32_FUNCTION(13, "FMC_D28"),
+ STM32_FUNCTION(14, "DCMI_D6"),
+ STM32_FUNCTION(15, "LCD_B6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(135, "PI7"),
+ STM32_FUNCTION(0, "GPIOI7"),
+ STM32_FUNCTION(4, "TIM8_CH3"),
+ STM32_FUNCTION(13, "FMC_D29"),
+ STM32_FUNCTION(14, "DCMI_D7"),
+ STM32_FUNCTION(15, "LCD_B7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(136, "PI8"),
+ STM32_FUNCTION(0, "GPIOI8"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(137, "PI9"),
+ STM32_FUNCTION(0, "GPIOI9"),
+ STM32_FUNCTION(10, "CAN1_RX"),
+ STM32_FUNCTION(13, "FMC_D30"),
+ STM32_FUNCTION(15, "LCD_VSYNC"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(138, "PI10"),
+ STM32_FUNCTION(0, "GPIOI10"),
+ STM32_FUNCTION(12, "ETH_MII_RX_ER"),
+ STM32_FUNCTION(13, "FMC_D31"),
+ STM32_FUNCTION(15, "LCD_HSYNC"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(139, "PI11"),
+ STM32_FUNCTION(0, "GPIOI11"),
+ STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(140, "PI12"),
+ STM32_FUNCTION(0, "GPIOI12"),
+ STM32_FUNCTION(15, "LCD_HSYNC"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(141, "PI13"),
+ STM32_FUNCTION(0, "GPIOI13"),
+ STM32_FUNCTION(15, "LCD_VSYNC"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(142, "PI14"),
+ STM32_FUNCTION(0, "GPIOI14"),
+ STM32_FUNCTION(15, "LCD_CLK"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(143, "PI15"),
+ STM32_FUNCTION(0, "GPIOI15"),
+ STM32_FUNCTION(15, "LCD_R0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(144, "PJ0"),
+ STM32_FUNCTION(0, "GPIOJ0"),
+ STM32_FUNCTION(15, "LCD_R1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(145, "PJ1"),
+ STM32_FUNCTION(0, "GPIOJ1"),
+ STM32_FUNCTION(15, "LCD_R2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(146, "PJ2"),
+ STM32_FUNCTION(0, "GPIOJ2"),
+ STM32_FUNCTION(15, "LCD_R3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(147, "PJ3"),
+ STM32_FUNCTION(0, "GPIOJ3"),
+ STM32_FUNCTION(15, "LCD_R4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(148, "PJ4"),
+ STM32_FUNCTION(0, "GPIOJ4"),
+ STM32_FUNCTION(15, "LCD_R5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(149, "PJ5"),
+ STM32_FUNCTION(0, "GPIOJ5"),
+ STM32_FUNCTION(15, "LCD_R6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(150, "PJ6"),
+ STM32_FUNCTION(0, "GPIOJ6"),
+ STM32_FUNCTION(15, "LCD_R7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(151, "PJ7"),
+ STM32_FUNCTION(0, "GPIOJ7"),
+ STM32_FUNCTION(15, "LCD_G0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(152, "PJ8"),
+ STM32_FUNCTION(0, "GPIOJ8"),
+ STM32_FUNCTION(15, "LCD_G1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(153, "PJ9"),
+ STM32_FUNCTION(0, "GPIOJ9"),
+ STM32_FUNCTION(15, "LCD_G2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(154, "PJ10"),
+ STM32_FUNCTION(0, "GPIOJ10"),
+ STM32_FUNCTION(15, "LCD_G3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(155, "PJ11"),
+ STM32_FUNCTION(0, "GPIOJ11"),
+ STM32_FUNCTION(15, "LCD_G4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(156, "PJ12"),
+ STM32_FUNCTION(0, "GPIOJ12"),
+ STM32_FUNCTION(15, "LCD_B0"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(157, "PJ13"),
+ STM32_FUNCTION(0, "GPIOJ13"),
+ STM32_FUNCTION(15, "LCD_B1"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(158, "PJ14"),
+ STM32_FUNCTION(0, "GPIOJ14"),
+ STM32_FUNCTION(15, "LCD_B2"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(159, "PJ15"),
+ STM32_FUNCTION(0, "GPIOJ15"),
+ STM32_FUNCTION(15, "LCD_B3"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(160, "PK0"),
+ STM32_FUNCTION(0, "GPIOK0"),
+ STM32_FUNCTION(15, "LCD_G5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(161, "PK1"),
+ STM32_FUNCTION(0, "GPIOK1"),
+ STM32_FUNCTION(15, "LCD_G6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(162, "PK2"),
+ STM32_FUNCTION(0, "GPIOK2"),
+ STM32_FUNCTION(15, "LCD_G7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(163, "PK3"),
+ STM32_FUNCTION(0, "GPIOK3"),
+ STM32_FUNCTION(15, "LCD_B4"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(164, "PK4"),
+ STM32_FUNCTION(0, "GPIOK4"),
+ STM32_FUNCTION(15, "LCD_B5"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(165, "PK5"),
+ STM32_FUNCTION(0, "GPIOK5"),
+ STM32_FUNCTION(15, "LCD_B6"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(166, "PK6"),
+ STM32_FUNCTION(0, "GPIOK6"),
+ STM32_FUNCTION(15, "LCD_B7"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+ STM32_PIN(
+ PINCTRL_PIN(167, "PK7"),
+ STM32_FUNCTION(0, "GPIOK7"),
+ STM32_FUNCTION(15, "LCD_DE"),
+ STM32_FUNCTION(16, "EVENTOUT"),
+ STM32_FUNCTION(17, "ANALOG")
+ ),
+};
+
+static struct stm32_pinctrl_match_data stm32f429_match_data = {
+ .pins = stm32f429_pins,
+ .npins = ARRAY_SIZE(stm32f429_pins),
+};
+
+static const struct of_device_id stm32f429_pctrl_match[] = {
+ {
+ .compatible = "st,stm32f429-pinctrl",
+ .data = &stm32f429_match_data,
+ },
+ { }
+};
+
+static struct platform_driver stm32f429_pinctrl_driver = {
+ .probe = stm32_pctl_probe,
+ .driver = {
+ .name = "stm32f429-pinctrl",
+ .of_match_table = stm32f429_pctrl_match,
+ },
+};
+
+static int __init stm32f429_pinctrl_init(void)
+{
+ return platform_driver_register(&stm32f429_pinctrl_driver);
+}
+device_initcall(stm32f429_pinctrl_init);
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index f8dbc8bec0e1..aaf075b972f5 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -1,67 +1,75 @@
if ARCH_SUNXI
-config PINCTRL_SUNXI_COMMON
+config PINCTRL_SUNXI
bool
select PINMUX
select GENERIC_PINCONF
config PINCTRL_SUN4I_A10
def_bool MACH_SUN4I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN5I_A10S
def_bool MACH_SUN5I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN5I_A13
def_bool MACH_SUN5I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN6I_A31
def_bool MACH_SUN6I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN6I_A31S
def_bool MACH_SUN6I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN6I_A31_R
def_bool MACH_SUN6I
depends on RESET_CONTROLLER
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN7I_A20
def_bool MACH_SUN7I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN8I_A23
def_bool MACH_SUN8I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN8I_A33
def_bool MACH_SUN8I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN8I_A83T
def_bool MACH_SUN8I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN8I_A23_R
def_bool MACH_SUN8I
depends on RESET_CONTROLLER
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN8I_H3
def_bool MACH_SUN8I
+ select PINCTRL_SUNXI
+
+config PINCTRL_SUN8I_H3_R
+ def_bool MACH_SUN8I
select PINCTRL_SUNXI_COMMON
config PINCTRL_SUN9I_A80
def_bool MACH_SUN9I
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
config PINCTRL_SUN9I_A80_R
def_bool MACH_SUN9I
depends on RESET_CONTROLLER
- select PINCTRL_SUNXI_COMMON
+ select PINCTRL_SUNXI
+
+config PINCTRL_SUN50I_A64
+ bool
+ select PINCTRL_SUNXI
endif
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
index ef82f22bb9ef..2d8b64e222e0 100644
--- a/drivers/pinctrl/sunxi/Makefile
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -1,5 +1,5 @@
# Core
-obj-$(CONFIG_PINCTRL_SUNXI_COMMON) += pinctrl-sunxi.o
+obj-y += pinctrl-sunxi.o
# SoC Drivers
obj-$(CONFIG_PINCTRL_SUN4I_A10) += pinctrl-sun4i-a10.o
@@ -12,7 +12,9 @@ obj-$(CONFIG_PINCTRL_SUN7I_A20) += pinctrl-sun7i-a20.o
obj-$(CONFIG_PINCTRL_SUN8I_A23) += pinctrl-sun8i-a23.o
obj-$(CONFIG_PINCTRL_SUN8I_A23_R) += pinctrl-sun8i-a23-r.o
obj-$(CONFIG_PINCTRL_SUN8I_A33) += pinctrl-sun8i-a33.o
+obj-$(CONFIG_PINCTRL_SUN50I_A64) += pinctrl-sun50i-a64.o
obj-$(CONFIG_PINCTRL_SUN8I_A83T) += pinctrl-sun8i-a83t.o
obj-$(CONFIG_PINCTRL_SUN8I_H3) += pinctrl-sun8i-h3.o
+obj-$(CONFIG_PINCTRL_SUN8I_H3_R) += pinctrl-sun8i-h3-r.o
obj-$(CONFIG_PINCTRL_SUN9I_A80) += pinctrl-sun9i-a80.o
obj-$(CONFIG_PINCTRL_SUN9I_A80_R) += pinctrl-sun9i-a80-r.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
new file mode 100644
index 000000000000..4f2a726bbaeb
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
@@ -0,0 +1,601 @@
+/*
+ * Allwinner A64 SoCs pinctrl driver.
+ *
+ * Copyright (C) 2016 - ARM Ltd.
+ * Author: Andre Przywara <andre.przywara@arm.com>
+ *
+ * Based on pinctrl-sun7i-a20.c, which is:
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin a64_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* TX */
+ SUNXI_FUNCTION(0x4, "jtag"), /* MS0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RX */
+ SUNXI_FUNCTION(0x4, "jtag"), /* CK0 */
+ SUNXI_FUNCTION(0x5, "sim"), /* VCCEN */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RTS */
+ SUNXI_FUNCTION(0x4, "jtag"), /* DO0 */
+ SUNXI_FUNCTION(0x5, "sim"), /* VPPEN */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
+ SUNXI_FUNCTION(0x3, "i2s0"), /* MCLK */
+ SUNXI_FUNCTION(0x4, "jtag"), /* DI0 */
+ SUNXI_FUNCTION(0x5, "sim"), /* VPPPP */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "aif2"), /* SYNC */
+ SUNXI_FUNCTION(0x3, "i2s0"), /* SYNC */
+ SUNXI_FUNCTION(0x5, "sim"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "aif2"), /* BCLK */
+ SUNXI_FUNCTION(0x3, "i2s0"), /* BCLK */
+ SUNXI_FUNCTION(0x5, "sim"), /* DATA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "aif2"), /* DOUT */
+ SUNXI_FUNCTION(0x3, "i2s0"), /* DOUT */
+ SUNXI_FUNCTION(0x5, "sim"), /* RST */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "aif2"), /* DIN */
+ SUNXI_FUNCTION(0x3, "i2s0"), /* DIN */
+ SUNXI_FUNCTION(0x5, "sim"), /* DET */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart0"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart0"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* EINT9 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NWE */
+ SUNXI_FUNCTION(0x4, "spi0")), /* MOSI */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NALE */
+ SUNXI_FUNCTION(0x3, "mmc2"), /* DS */
+ SUNXI_FUNCTION(0x4, "spi0")), /* MISO */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */
+ SUNXI_FUNCTION(0x4, "spi0")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */
+ SUNXI_FUNCTION(0x4, "spi0")), /* CS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NRE# */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NRB1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQS */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* RST */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "uart3"), /* TX */
+ SUNXI_FUNCTION(0x4, "spi1"), /* CS */
+ SUNXI_FUNCTION(0x5, "ccir")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "uart3"), /* RX */
+ SUNXI_FUNCTION(0x4, "spi1"), /* CLK */
+ SUNXI_FUNCTION(0x5, "ccir")), /* DE */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */
+ SUNXI_FUNCTION(0x3, "uart4"), /* TX */
+ SUNXI_FUNCTION(0x4, "spi1"), /* MOSI */
+ SUNXI_FUNCTION(0x5, "ccir")), /* HSYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */
+ SUNXI_FUNCTION(0x3, "uart4"), /* RX */
+ SUNXI_FUNCTION(0x4, "spi1"), /* MISO */
+ SUNXI_FUNCTION(0x5, "ccir")), /* VSYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */
+ SUNXI_FUNCTION(0x3, "uart4"), /* RTS */
+ SUNXI_FUNCTION(0x5, "ccir")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */
+ SUNXI_FUNCTION(0x3, "uart4"), /* CTS */
+ SUNXI_FUNCTION(0x5, "ccir")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */
+ SUNXI_FUNCTION(0x5, "ccir")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */
+ SUNXI_FUNCTION(0x5, "ccir")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */
+ SUNXI_FUNCTION(0x4, "emac"), /* ERXD3 */
+ SUNXI_FUNCTION(0x5, "ccir")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */
+ SUNXI_FUNCTION(0x4, "emac"), /* ERXD2 */
+ SUNXI_FUNCTION(0x5, "ccir")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */
+ SUNXI_FUNCTION(0x4, "emac")), /* ERXD1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */
+ SUNXI_FUNCTION(0x4, "emac")), /* ERXD0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VP0 */
+ SUNXI_FUNCTION(0x4, "emac")), /* ERXCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VN0 */
+ SUNXI_FUNCTION(0x4, "emac")), /* ERXCTL */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VP1 */
+ SUNXI_FUNCTION(0x4, "emac")), /* ENULL */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VN1 */
+ SUNXI_FUNCTION(0x4, "emac"), /* ETXD3 */
+ SUNXI_FUNCTION(0x5, "ccir")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VP2 */
+ SUNXI_FUNCTION(0x4, "emac"), /* ETXD2 */
+ SUNXI_FUNCTION(0x5, "ccir")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VN2 */
+ SUNXI_FUNCTION(0x4, "emac")), /* ETXD1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VPC */
+ SUNXI_FUNCTION(0x4, "emac")), /* ETXD0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* DE */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VNC */
+ SUNXI_FUNCTION(0x4, "emac")), /* ETXCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VP3 */
+ SUNXI_FUNCTION(0x4, "emac")), /* ETXCTL */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* VN3 */
+ SUNXI_FUNCTION(0x4, "emac")), /* ECLKIN */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm"), /* PWM0 */
+ SUNXI_FUNCTION(0x4, "emac")), /* EMDC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "emac")), /* EMDIO */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* PCK */
+ SUNXI_FUNCTION(0x4, "ts0")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* CK */
+ SUNXI_FUNCTION(0x4, "ts0")), /* ERR */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* HSYNC */
+ SUNXI_FUNCTION(0x4, "ts0")), /* SYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* VSYNC */
+ SUNXI_FUNCTION(0x4, "ts0")), /* DVLD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* D0 */
+ SUNXI_FUNCTION(0x4, "ts0")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* D1 */
+ SUNXI_FUNCTION(0x4, "ts0")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* D2 */
+ SUNXI_FUNCTION(0x4, "ts0")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* D3 */
+ SUNXI_FUNCTION(0x4, "ts0")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* D4 */
+ SUNXI_FUNCTION(0x4, "ts0")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* D5 */
+ SUNXI_FUNCTION(0x4, "ts0")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* D6 */
+ SUNXI_FUNCTION(0x4, "ts0")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0"), /* D7 */
+ SUNXI_FUNCTION(0x4, "ts0")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi0")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pll"), /* LOCK_DBG */
+ SUNXI_FUNCTION(0x3, "i2c2")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "i2c2")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* MSI */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DI1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart0")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DO1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */
+ SUNXI_FUNCTION(0x4, "uart0")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* CK1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)), /* EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)), /* EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)), /* EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)), /* EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)), /* EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)), /* EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)), /* EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)), /* EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 8)), /* EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 9)), /* EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "aif3"), /* SYNC */
+ SUNXI_FUNCTION(0x3, "i2s1"), /* SYNC */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 10)), /* EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "aif3"), /* BCLK */
+ SUNXI_FUNCTION(0x3, "i2s1"), /* BCLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 11)), /* EINT11 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "aif3"), /* DOUT */
+ SUNXI_FUNCTION(0x3, "i2s1"), /* DOUT */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 12)), /* EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "aif3"), /* DIN */
+ SUNXI_FUNCTION(0x3, "i2s1"), /* DIN */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 13)), /* EINT13 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)), /* EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)), /* EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)), /* EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)), /* EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart3"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)), /* EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart3"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)), /* EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart3"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)), /* EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart3"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)), /* EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spdif"), /* OUT */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)), /* EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)), /* EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mic"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)), /* EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mic"), /* DATA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)), /* EINT11 */
+};
+
+static const struct sunxi_pinctrl_desc a64_pinctrl_data = {
+ .pins = a64_pins,
+ .npins = ARRAY_SIZE(a64_pins),
+ .irq_banks = 3,
+};
+
+static int a64_pinctrl_probe(struct platform_device *pdev)
+{
+ return sunxi_pinctrl_init(pdev,
+ &a64_pinctrl_data);
+}
+
+static const struct of_device_id a64_pinctrl_match[] = {
+ { .compatible = "allwinner,sun50i-a64-pinctrl", },
+ {}
+};
+
+static struct platform_driver a64_pinctrl_driver = {
+ .probe = a64_pinctrl_probe,
+ .driver = {
+ .name = "sun50i-a64-pinctrl",
+ .of_match_table = a64_pinctrl_match,
+ },
+};
+builtin_platform_driver(a64_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c b/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c
index cf1ce0c02600..435ad30f45db 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun7i-a20.c
@@ -343,26 +343,22 @@ static const struct sunxi_desc_pin sun7i_a20_pins[] = {
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NCE4 */
- SUNXI_FUNCTION(0x3, "spi2"), /* CS0 */
- SUNXI_FUNCTION_IRQ(0x6, 12)), /* EINT12 */
+ SUNXI_FUNCTION(0x3, "spi2")), /* CS0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 20),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NCE5 */
- SUNXI_FUNCTION(0x3, "spi2"), /* CLK */
- SUNXI_FUNCTION_IRQ(0x6, 13)), /* EINT13 */
+ SUNXI_FUNCTION(0x3, "spi2")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 21),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NCE6 */
- SUNXI_FUNCTION(0x3, "spi2"), /* MOSI */
- SUNXI_FUNCTION_IRQ(0x6, 14)), /* EINT14 */
+ SUNXI_FUNCTION(0x3, "spi2")), /* MOSI */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 22),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NCE7 */
- SUNXI_FUNCTION(0x3, "spi2"), /* MISO */
- SUNXI_FUNCTION_IRQ(0x6, 15)), /* EINT15 */
+ SUNXI_FUNCTION(0x3, "spi2")), /* MISO */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 23),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
@@ -960,65 +956,65 @@ static const struct sunxi_desc_pin sun7i_a20_pins[] = {
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi0"), /* CS0 */
SUNXI_FUNCTION(0x3, "uart5"), /* TX */
- SUNXI_FUNCTION_IRQ(0x5, 22)), /* EINT22 */
+ SUNXI_FUNCTION_IRQ(0x6, 22)), /* EINT22 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 11),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi0"), /* CLK */
SUNXI_FUNCTION(0x3, "uart5"), /* RX */
- SUNXI_FUNCTION_IRQ(0x5, 23)), /* EINT23 */
+ SUNXI_FUNCTION_IRQ(0x6, 23)), /* EINT23 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 12),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi0"), /* MOSI */
SUNXI_FUNCTION(0x3, "uart6"), /* TX */
SUNXI_FUNCTION(0x4, "clk_out_a"), /* CLK_OUT_A */
- SUNXI_FUNCTION_IRQ(0x5, 24)), /* EINT24 */
+ SUNXI_FUNCTION_IRQ(0x6, 24)), /* EINT24 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 13),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi0"), /* MISO */
SUNXI_FUNCTION(0x3, "uart6"), /* RX */
SUNXI_FUNCTION(0x4, "clk_out_b"), /* CLK_OUT_B */
- SUNXI_FUNCTION_IRQ(0x5, 25)), /* EINT25 */
+ SUNXI_FUNCTION_IRQ(0x6, 25)), /* EINT25 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 14),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi0"), /* CS1 */
SUNXI_FUNCTION(0x3, "ps2"), /* SCK1 */
SUNXI_FUNCTION(0x4, "timer4"), /* TCLKIN0 */
- SUNXI_FUNCTION_IRQ(0x5, 26)), /* EINT26 */
+ SUNXI_FUNCTION_IRQ(0x6, 26)), /* EINT26 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 15),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi1"), /* CS1 */
SUNXI_FUNCTION(0x3, "ps2"), /* SDA1 */
SUNXI_FUNCTION(0x4, "timer5"), /* TCLKIN1 */
- SUNXI_FUNCTION_IRQ(0x5, 27)), /* EINT27 */
+ SUNXI_FUNCTION_IRQ(0x6, 27)), /* EINT27 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 16),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */
SUNXI_FUNCTION(0x3, "uart2"), /* RTS */
- SUNXI_FUNCTION_IRQ(0x5, 28)), /* EINT28 */
+ SUNXI_FUNCTION_IRQ(0x6, 28)), /* EINT28 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 17),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi1"), /* CLK */
SUNXI_FUNCTION(0x3, "uart2"), /* CTS */
- SUNXI_FUNCTION_IRQ(0x5, 29)), /* EINT29 */
+ SUNXI_FUNCTION_IRQ(0x6, 29)), /* EINT29 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 18),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */
SUNXI_FUNCTION(0x3, "uart2"), /* TX */
- SUNXI_FUNCTION_IRQ(0x5, 30)), /* EINT30 */
+ SUNXI_FUNCTION_IRQ(0x6, 30)), /* EINT30 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 19),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spi1"), /* MISO */
SUNXI_FUNCTION(0x3, "uart2"), /* RX */
- SUNXI_FUNCTION_IRQ(0x5, 31)), /* EINT31 */
+ SUNXI_FUNCTION_IRQ(0x6, 31)), /* EINT31 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 20),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-h3-r.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-h3-r.c
new file mode 100644
index 000000000000..686ec212120b
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-h3-r.c
@@ -0,0 +1,106 @@
+/*
+ * Allwinner H3 SoCs pinctrl driver.
+ *
+ * Copyright (C) 2016 Krzysztof Adamski <k@japko.eu>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun8i_h3_r_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_twi"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* PL_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_twi"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* PL_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_uart"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* PL_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_uart"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* PL_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_jtag"), /* MS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* PL_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_jtag"), /* CK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* PL_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_jtag"), /* DO */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* PL_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_jtag"), /* DI */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* PL_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* PL_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* PL_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_pwm"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* PL_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_cir_rx"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* PL_EINT11 */
+};
+
+static const struct sunxi_pinctrl_desc sun8i_h3_r_pinctrl_data = {
+ .pins = sun8i_h3_r_pins,
+ .npins = ARRAY_SIZE(sun8i_h3_r_pins),
+ .irq_banks = 1,
+ .pin_base = PL_BASE,
+ .irq_read_needs_mux = true
+};
+
+static int sun8i_h3_r_pinctrl_probe(struct platform_device *pdev)
+{
+ return sunxi_pinctrl_init(pdev,
+ &sun8i_h3_r_pinctrl_data);
+}
+
+static const struct of_device_id sun8i_h3_r_pinctrl_match[] = {
+ { .compatible = "allwinner,sun8i-h3-r-pinctrl", },
+ {}
+};
+
+static struct platform_driver sun8i_h3_r_pinctrl_driver = {
+ .probe = sun8i_h3_r_pinctrl_probe,
+ .driver = {
+ .name = "sun8i-h3-r-pinctrl",
+ .of_match_table = sun8i_h3_r_pinctrl_match,
+ },
+};
+builtin_platform_driver(sun8i_h3_r_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
index 77d4cf047cee..11760bbe9d51 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
@@ -492,6 +492,7 @@ static const struct sunxi_pinctrl_desc sun8i_h3_pinctrl_data = {
.pins = sun8i_h3_pins,
.npins = ARRAY_SIZE(sun8i_h3_pins),
.irq_banks = 2,
+ .irq_read_needs_mux = true
};
static int sun8i_h3_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c
index 42547ffa20a8..92a873f73697 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c
@@ -9,7 +9,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -164,7 +164,6 @@ static const struct of_device_id sun9i_a80_r_pinctrl_match[] = {
{ .compatible = "allwinner,sun9i-a80-r-pinctrl", },
{}
};
-MODULE_DEVICE_TABLE(of, sun9i_a80_r_pinctrl_match);
static struct platform_driver sun9i_a80_r_pinctrl_driver = {
.probe = sun9i_a80_r_pinctrl_probe,
@@ -174,8 +173,4 @@ static struct platform_driver sun9i_a80_r_pinctrl_driver = {
.of_match_table = sun9i_a80_r_pinctrl_match,
},
};
-module_platform_driver(sun9i_a80_r_pinctrl_driver);
-
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
-MODULE_DESCRIPTION("Allwinner A80 R_PIO pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun9i_a80_r_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 7a2465f5e71e..3a2f5619f87c 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -15,7 +15,7 @@
#include <linux/gpio/driver.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
-#include <linux/module.h>
+#include <linux/export.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
@@ -459,15 +459,16 @@ static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
u8 index = sunxi_data_offset(offset);
u32 set_mux = pctl->desc->irq_read_needs_mux &&
test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
+ u32 pin = offset + chip->base;
u32 val;
if (set_mux)
- sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_INPUT);
+ sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT);
val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
if (set_mux)
- sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_IRQ);
+ sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ);
return !!val;
}
diff --git a/drivers/pinctrl/tegra/Kconfig b/drivers/pinctrl/tegra/Kconfig
new file mode 100644
index 000000000000..24e20cc08d5b
--- /dev/null
+++ b/drivers/pinctrl/tegra/Kconfig
@@ -0,0 +1,30 @@
+config PINCTRL_TEGRA
+ bool
+ select PINMUX
+ select PINCONF
+
+config PINCTRL_TEGRA20
+ bool
+ select PINCTRL_TEGRA
+
+config PINCTRL_TEGRA30
+ bool
+ select PINCTRL_TEGRA
+
+config PINCTRL_TEGRA114
+ bool
+ select PINCTRL_TEGRA
+
+config PINCTRL_TEGRA124
+ bool
+ select PINCTRL_TEGRA
+
+config PINCTRL_TEGRA210
+ bool
+ select PINCTRL_TEGRA
+
+config PINCTRL_TEGRA_XUSB
+ def_bool y if ARCH_TEGRA
+ select GENERIC_PHY
+ select PINCONF
+ select PINMUX
diff --git a/drivers/pinctrl/tegra/Makefile b/drivers/pinctrl/tegra/Makefile
new file mode 100644
index 000000000000..a927379b6794
--- /dev/null
+++ b/drivers/pinctrl/tegra/Makefile
@@ -0,0 +1,7 @@
+obj-y += pinctrl-tegra.o
+obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
+obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
+obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o
+obj-$(CONFIG_PINCTRL_TEGRA124) += pinctrl-tegra124.o
+obj-$(CONFIG_PINCTRL_TEGRA210) += pinctrl-tegra210.o
+obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o
diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c
index bd3aa5a4fd6d..2f06029c9405 100644
--- a/drivers/pinctrl/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c
@@ -24,8 +24,8 @@
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
-#include "core.h"
-#include "pinctrl-utils.h"
+#include "../core.h"
+#include "../pinctrl-utils.h"
#define XUSB_PADCTL_ELPG_PROGRAM 0x01c
#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index 9da4da219a07..49388822c0e9 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -30,9 +30,9 @@
#include <linux/pinctrl/pinconf.h>
#include <linux/slab.h>
-#include "core.h"
+#include "../core.h"
+#include "../pinctrl-utils.h"
#include "pinctrl-tegra.h"
-#include "pinctrl-utils.h"
struct tegra_pmx {
struct device *dev;
diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
index 1615db7e3a4b..1615db7e3a4b 100644
--- a/drivers/pinctrl/pinctrl-tegra.h
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
diff --git a/drivers/pinctrl/pinctrl-tegra114.c b/drivers/pinctrl/tegra/pinctrl-tegra114.c
index 05e49d5137ab..05e49d5137ab 100644
--- a/drivers/pinctrl/pinctrl-tegra114.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra114.c
diff --git a/drivers/pinctrl/pinctrl-tegra124.c b/drivers/pinctrl/tegra/pinctrl-tegra124.c
index 7cd44c7c296d..7cd44c7c296d 100644
--- a/drivers/pinctrl/pinctrl-tegra124.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra124.c
diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/tegra/pinctrl-tegra20.c
index 4833db4433d9..4833db4433d9 100644
--- a/drivers/pinctrl/pinctrl-tegra20.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra20.c
diff --git a/drivers/pinctrl/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
index 252b464901c0..252b464901c0 100644
--- a/drivers/pinctrl/pinctrl-tegra210.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/tegra/pinctrl-tegra30.c
index 47b2fd8bb2e9..47b2fd8bb2e9 100644
--- a/drivers/pinctrl/pinctrl-tegra30.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra30.c
diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig
index 7abd614dc383..0b40ded5738f 100644
--- a/drivers/pinctrl/uniphier/Kconfig
+++ b/drivers/pinctrl/uniphier/Kconfig
@@ -1,6 +1,6 @@
menuconfig PINCTRL_UNIPHIER
bool "UniPhier SoC pinctrl drivers"
- depends on ARCH_UNIPHIER
+ depends on ARCH_UNIPHIER || COMPILE_TEST
depends on OF && MFD_SYSCON
default y
select PINMUX
@@ -8,27 +8,27 @@ menuconfig PINCTRL_UNIPHIER
if PINCTRL_UNIPHIER
-config PINCTRL_UNIPHIER_PH1_LD4
+config PINCTRL_UNIPHIER_LD4
tristate "UniPhier PH1-LD4 SoC pinctrl driver"
default y
-config PINCTRL_UNIPHIER_PH1_PRO4
+config PINCTRL_UNIPHIER_PRO4
tristate "UniPhier PH1-Pro4 SoC pinctrl driver"
default y
-config PINCTRL_UNIPHIER_PH1_SLD8
+config PINCTRL_UNIPHIER_SLD8
tristate "UniPhier PH1-sLD8 SoC pinctrl driver"
default y
-config PINCTRL_UNIPHIER_PH1_PRO5
+config PINCTRL_UNIPHIER_PRO5
tristate "UniPhier PH1-Pro5 SoC pinctrl driver"
default y
-config PINCTRL_UNIPHIER_PROXSTREAM2
+config PINCTRL_UNIPHIER_PXS2
tristate "UniPhier ProXstream2 SoC pinctrl driver"
default y
-config PINCTRL_UNIPHIER_PH1_LD6B
+config PINCTRL_UNIPHIER_LD6B
tristate "UniPhier PH1-LD6b SoC pinctrl driver"
default y
diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile
index e7ce9670306c..3b8f9ee0bb6f 100644
--- a/drivers/pinctrl/uniphier/Makefile
+++ b/drivers/pinctrl/uniphier/Makefile
@@ -1,8 +1,8 @@
-obj-y += pinctrl-uniphier-core.o
+obj-y += pinctrl-uniphier-core.o
-obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o
-obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o
-obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o
-obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO5) += pinctrl-ph1-pro5.o
-obj-$(CONFIG_PINCTRL_UNIPHIER_PROXSTREAM2) += pinctrl-proxstream2.o
-obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD6B) += pinctrl-ph1-ld6b.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_LD4) += pinctrl-uniphier-ld4.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_PRO4) += pinctrl-uniphier-pro4.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_SLD8) += pinctrl-uniphier-sld8.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_PRO5) += pinctrl-uniphier-pro5.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_PXS2) += pinctrl-uniphier-pxs2.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_LD6B) += pinctrl-uniphier-ld6b.o
diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld4.c
index a7056dccfa53..a7056dccfa53 100644
--- a/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld4.c
diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c
index 1824831bb4da..1824831bb4da 100644
--- a/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c
diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
index ec8e92dfaf8c..ec8e92dfaf8c 100644
--- a/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c
index e3d648eae85a..e3d648eae85a 100644
--- a/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c
diff --git a/drivers/pinctrl/uniphier/pinctrl-proxstream2.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs2.c
index bc00d7591c59..bc00d7591c59 100644
--- a/drivers/pinctrl/uniphier/pinctrl-proxstream2.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs2.c
diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-sld8.c
index c3700a33a5da..c3700a33a5da 100644
--- a/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-sld8.c
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 0adccbf5c83f..c11db8bceea1 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -4,8 +4,7 @@ endif
if MIPS
source "drivers/platform/mips/Kconfig"
endif
-if GOLDFISH
+
source "drivers/platform/goldfish/Kconfig"
-endif
source "drivers/platform/chrome/Kconfig"
diff --git a/drivers/platform/goldfish/Kconfig b/drivers/platform/goldfish/Kconfig
index 635ef25cc722..fefbb8370da0 100644
--- a/drivers/platform/goldfish/Kconfig
+++ b/drivers/platform/goldfish/Kconfig
@@ -1,5 +1,24 @@
+menuconfig GOLDFISH
+ bool "Platform support for Goldfish virtual devices"
+ depends on X86_32 || X86_64 || ARM || ARM64 || MIPS
+ depends on HAS_IOMEM
+ ---help---
+ Say Y here to get to see options for the Goldfish virtual platform.
+ This option alone does not add any kernel code.
+
+ Unless you are building for the Android Goldfish emulator say N here.
+
+if GOLDFISH
+
+config GOLDFISH_BUS
+ bool "Goldfish platform bus"
+ ---help---
+ This is a virtual bus to host Goldfish Android Virtual Devices.
+
config GOLDFISH_PIPE
tristate "Goldfish virtual device for QEMU pipes"
---help---
This is a virtual device to drive the QEMU pipe interface used by
the Goldfish Android Virtual Device.
+
+endif # GOLDFISH
diff --git a/drivers/platform/goldfish/Makefile b/drivers/platform/goldfish/Makefile
index a0022395eee9..d3487125838c 100644
--- a/drivers/platform/goldfish/Makefile
+++ b/drivers/platform/goldfish/Makefile
@@ -1,5 +1,5 @@
#
# Makefile for Goldfish platform specific drivers
#
-obj-$(CONFIG_GOLDFISH) += pdev_bus.o
+obj-$(CONFIG_GOLDFISH_BUS) += pdev_bus.o
obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe.o
diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index e7a29e2750c6..839df4aace76 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -2,6 +2,7 @@
* Copyright (C) 2011 Google, Inc.
* Copyright (C) 2012 Intel, Inc.
* Copyright (C) 2013 Intel, Inc.
+ * Copyright (C) 2014 Linaro Limited
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -57,6 +58,8 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/goldfish.h>
+#include <linux/mm.h>
+#include <linux/acpi.h>
/*
* IMPORTANT: The following constants must match the ones used and defined
@@ -75,6 +78,7 @@
#define PIPE_REG_PARAMS_ADDR_LOW 0x18 /* read/write: batch data address */
#define PIPE_REG_PARAMS_ADDR_HIGH 0x1c /* read/write: batch data address */
#define PIPE_REG_ACCESS_PARAMS 0x20 /* write: batch access */
+#define PIPE_REG_VERSION 0x24 /* read: device version */
/* list of commands for PIPE_REG_COMMAND */
#define CMD_OPEN 1 /* open new channel */
@@ -90,12 +94,6 @@
#define CMD_WRITE_BUFFER 4 /* send a user buffer to the emulator */
#define CMD_WAKE_ON_WRITE 5 /* tell the emulator to wake us when writing
is possible */
-
-/* The following commands are related to read operations, they must be
- * listed in the same order than the corresponding write ones, since we
- * will use (CMD_READ_BUFFER - CMD_WRITE_BUFFER) as a special offset
- * in goldfish_pipe_read_write() below.
- */
#define CMD_READ_BUFFER 6 /* receive a user buffer from the emulator */
#define CMD_WAKE_ON_READ 7 /* tell the emulator to wake us when reading
* is possible */
@@ -130,6 +128,7 @@ struct goldfish_pipe_dev {
unsigned char __iomem *base;
struct access_params *aps;
int irq;
+ u32 version;
};
static struct goldfish_pipe_dev pipe_dev[1];
@@ -263,19 +262,14 @@ static int access_with_param(struct goldfish_pipe_dev *dev, const int cmd,
return 0;
}
-/* This function is used for both reading from and writing to a given
- * pipe.
- */
static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
- size_t bufflen, int is_write)
+ size_t bufflen, int is_write)
{
unsigned long irq_flags;
struct goldfish_pipe *pipe = filp->private_data;
struct goldfish_pipe_dev *dev = pipe->dev;
- const int cmd_offset = is_write ? 0
- : (CMD_READ_BUFFER - CMD_WRITE_BUFFER);
unsigned long address, address_end;
- int ret = 0;
+ int count = 0, ret = -EINVAL;
/* If the emulator already closed the pipe, no need to go further */
if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))
@@ -298,79 +292,107 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
address_end = address + bufflen;
while (address < address_end) {
- unsigned long page_end = (address & PAGE_MASK) + PAGE_SIZE;
- unsigned long next = page_end < address_end ? page_end
- : address_end;
- unsigned long avail = next - address;
+ unsigned long page_end = (address & PAGE_MASK) + PAGE_SIZE;
+ unsigned long next = page_end < address_end ? page_end
+ : address_end;
+ unsigned long avail = next - address;
int status, wakeBit;
+ struct page *page;
+
+ /* Either vaddr or paddr depending on the device version */
+ unsigned long xaddr;
+
+ /*
+ * We grab the pages on a page-by-page basis in case user
+ * space gives us a potentially huge buffer but the read only
+ * returns a small amount, then there's no need to pin that
+ * much memory to the process.
+ */
+ down_read(&current->mm->mmap_sem);
+ ret = get_user_pages(current, current->mm, address, 1,
+ !is_write, 0, &page, NULL);
+ up_read(&current->mm->mmap_sem);
+ if (ret < 0)
+ break;
- /* Ensure that the corresponding page is properly mapped */
- /* FIXME: this isn't safe or sufficient - use get_user_pages */
- if (is_write) {
- char c;
- /* Ensure that the page is mapped and readable */
- if (__get_user(c, (char __user *)address)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
+ if (dev->version) {
+ /* Device version 1 or newer (qemu-android) expects the
+ * physical address.
+ */
+ xaddr = page_to_phys(page) | (address & ~PAGE_MASK);
} else {
- /* Ensure that the page is mapped and writable */
- if (__put_user(0, (char __user *)address)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
+ /* Device version 0 (classic emulator) expects the
+ * virtual address.
+ */
+ xaddr = address;
}
/* Now, try to transfer the bytes in the current page */
spin_lock_irqsave(&dev->lock, irq_flags);
- if (access_with_param(dev, CMD_WRITE_BUFFER + cmd_offset,
- address, avail, pipe, &status)) {
+ if (access_with_param(dev,
+ is_write ? CMD_WRITE_BUFFER : CMD_READ_BUFFER,
+ xaddr, avail, pipe, &status)) {
gf_write_ptr(pipe, dev->base + PIPE_REG_CHANNEL,
dev->base + PIPE_REG_CHANNEL_HIGH);
writel(avail, dev->base + PIPE_REG_SIZE);
- gf_write_ptr((void *)address,
+ gf_write_ptr((void *)xaddr,
dev->base + PIPE_REG_ADDRESS,
dev->base + PIPE_REG_ADDRESS_HIGH);
- writel(CMD_WRITE_BUFFER + cmd_offset,
+ writel(is_write ? CMD_WRITE_BUFFER : CMD_READ_BUFFER,
dev->base + PIPE_REG_COMMAND);
status = readl(dev->base + PIPE_REG_STATUS);
}
spin_unlock_irqrestore(&dev->lock, irq_flags);
+ if (status > 0 && !is_write)
+ set_page_dirty(page);
+ put_page(page);
+
if (status > 0) { /* Correct transfer */
- ret += status;
+ count += status;
address += status;
continue;
- }
-
- if (status == 0) /* EOF */
+ } else if (status == 0) { /* EOF */
+ ret = 0;
break;
-
- /* An error occured. If we already transfered stuff, just
- * return with its count. We expect the next call to return
- * an error code */
- if (ret > 0)
+ } else if (status < 0 && count > 0) {
+ /*
+ * An error occurred and we already transferred
+ * something on one of the previous pages.
+ * Just return what we already copied and log this
+ * err.
+ *
+ * Note: This seems like an incorrect approach but
+ * cannot change it until we check if any user space
+ * ABI relies on this behavior.
+ */
+ if (status != PIPE_ERROR_AGAIN)
+ pr_info_ratelimited("goldfish_pipe: backend returned error %d on %s\n",
+ status, is_write ? "write" : "read");
+ ret = 0;
break;
+ }
- /* If the error is not PIPE_ERROR_AGAIN, or if we are not in
- * non-blocking mode, just return the error code.
- */
+ /*
+ * If the error is not PIPE_ERROR_AGAIN, or if we are not in
+ * non-blocking mode, just return the error code.
+ */
if (status != PIPE_ERROR_AGAIN ||
(filp->f_flags & O_NONBLOCK) != 0) {
ret = goldfish_pipe_error_convert(status);
break;
}
- /* We will have to wait until more data/space is available.
- * First, mark the pipe as waiting for a specific wake signal.
- */
+ /*
+ * The backend blocked the read/write, wait until the backend
+ * tells us it's ready to process more data.
+ */
wakeBit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ;
set_bit(wakeBit, &pipe->flags);
/* Tell the emulator we're going to wait for a wake event */
- goldfish_cmd(pipe, CMD_WAKE_ON_WRITE + cmd_offset);
+ goldfish_cmd(pipe,
+ is_write ? CMD_WAKE_ON_WRITE : CMD_WAKE_ON_READ);
/* Unlock the pipe, then wait for the wake signal */
mutex_unlock(&pipe->lock);
@@ -388,12 +410,13 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
/* Try to re-acquire the lock */
if (mutex_lock_interruptible(&pipe->lock))
return -ERESTARTSYS;
-
- /* Try the transfer again */
- continue;
}
mutex_unlock(&pipe->lock);
- return ret;
+
+ if (ret < 0)
+ return ret;
+ else
+ return count;
}
static ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer,
@@ -446,10 +469,11 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
unsigned long irq_flags;
int count = 0;
- /* We're going to read from the emulator a list of (channel,flags)
- * pairs corresponding to the wake events that occured on each
- * blocked pipe (i.e. channel).
- */
+ /*
+ * We're going to read from the emulator a list of (channel,flags)
+ * pairs corresponding to the wake events that occurred on each
+ * blocked pipe (i.e. channel).
+ */
spin_lock_irqsave(&dev->lock, irq_flags);
for (;;) {
/* First read the channel, 0 means the end of the list */
@@ -600,6 +624,12 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
goto error;
}
setup_access_params_addr(pdev, dev);
+
+ /* Although the pipe device in the classic Android emulator does not
+ * recognize the 'version' register, it won't treat this as an error
+ * either and will simply return 0, which is fine.
+ */
+ dev->version = readl(dev->base + PIPE_REG_VERSION);
return 0;
error:
@@ -615,11 +645,26 @@ static int goldfish_pipe_remove(struct platform_device *pdev)
return 0;
}
+static const struct acpi_device_id goldfish_pipe_acpi_match[] = {
+ { "GFSH0003", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, goldfish_pipe_acpi_match);
+
+static const struct of_device_id goldfish_pipe_of_match[] = {
+ { .compatible = "google,android-pipe", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, goldfish_pipe_of_match);
+
static struct platform_driver goldfish_pipe = {
.probe = goldfish_pipe_probe,
.remove = goldfish_pipe_remove,
.driver = {
- .name = "goldfish_pipe"
+ .name = "goldfish_pipe",
+ .owner = THIS_MODULE,
+ .of_match_table = goldfish_pipe_of_match,
+ .acpi_match_table = ACPI_PTR(goldfish_pipe_acpi_match),
}
};
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 05796495be0e..4b717c699313 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -252,6 +252,10 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
break;
+ case ACPI_RESOURCE_TYPE_SERIAL_BUS:
+ /* serial bus connections (I2C/SPI/UART) are not pnp */
+ break;
+
default:
dev_warn(&dev->dev, "unknown resource type %d in _CRS\n",
res->type);
diff --git a/drivers/power/88pm860x_charger.c b/drivers/power/88pm860x_charger.c
index 297e72dc70e6..2b82e44d9027 100644
--- a/drivers/power/88pm860x_charger.c
+++ b/drivers/power/88pm860x_charger.c
@@ -435,7 +435,7 @@ static irqreturn_t pm860x_temp_handler(int irq, void *data)
psy = power_supply_get_by_name(pm860x_supplied_to[0]);
if (!psy)
- goto out;
+ return IRQ_HANDLED;
ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_TEMP, &temp);
if (ret)
goto out;
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 1ddd13cc0c07..421770ddafa3 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -75,6 +75,13 @@ config BATTERY_88PM860X
help
Say Y here to enable battery monitor for Marvell 88PM860x chip.
+config BATTERY_ACT8945A
+ tristate "Active-semi ACT8945A charger driver"
+ depends on MFD_ACT8945A || COMPILE_TEST
+ help
+ Say Y here to enable support for power supply provided by
+ Active-semi ActivePath ACT8945A charger.
+
config BATTERY_DS2760
tristate "DS2760 battery driver (HP iPAQ & others)"
depends on W1 && W1_SLAVE_DS2760
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 0e4eab55f8d7..e46b75d448a5 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
obj-$(CONFIG_TEST_POWER) += test_power.o
obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
+obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o
diff --git a/drivers/power/act8945a_charger.c b/drivers/power/act8945a_charger.c
new file mode 100644
index 000000000000..b5c00e45741e
--- /dev/null
+++ b/drivers/power/act8945a_charger.c
@@ -0,0 +1,359 @@
+/*
+ * Power supply driver for the Active-semi ACT8945A PMIC
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ *
+ * Author: Wenyou Yang <wenyou.yang@atmel.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+
+static const char *act8945a_charger_model = "ACT8945A";
+static const char *act8945a_charger_manufacturer = "Active-semi";
+
+/**
+ * ACT8945A Charger Register Map
+ */
+
+/* 0x70: Reserved */
+#define ACT8945A_APCH_CFG 0x71
+#define ACT8945A_APCH_STATUS 0x78
+#define ACT8945A_APCH_CTRL 0x79
+#define ACT8945A_APCH_STATE 0x7A
+
+/* ACT8945A_APCH_CFG */
+#define APCH_CFG_OVPSET (0x3 << 0)
+#define APCH_CFG_OVPSET_6V6 (0x0 << 0)
+#define APCH_CFG_OVPSET_7V (0x1 << 0)
+#define APCH_CFG_OVPSET_7V5 (0x2 << 0)
+#define APCH_CFG_OVPSET_8V (0x3 << 0)
+#define APCH_CFG_PRETIMO (0x3 << 2)
+#define APCH_CFG_PRETIMO_40_MIN (0x0 << 2)
+#define APCH_CFG_PRETIMO_60_MIN (0x1 << 2)
+#define APCH_CFG_PRETIMO_80_MIN (0x2 << 2)
+#define APCH_CFG_PRETIMO_DISABLED (0x3 << 2)
+#define APCH_CFG_TOTTIMO (0x3 << 4)
+#define APCH_CFG_TOTTIMO_3_HOUR (0x0 << 4)
+#define APCH_CFG_TOTTIMO_4_HOUR (0x1 << 4)
+#define APCH_CFG_TOTTIMO_5_HOUR (0x2 << 4)
+#define APCH_CFG_TOTTIMO_DISABLED (0x3 << 4)
+#define APCH_CFG_SUSCHG (0x1 << 7)
+
+#define APCH_STATUS_CHGDAT BIT(0)
+#define APCH_STATUS_INDAT BIT(1)
+#define APCH_STATUS_TEMPDAT BIT(2)
+#define APCH_STATUS_TIMRDAT BIT(3)
+#define APCH_STATUS_CHGSTAT BIT(4)
+#define APCH_STATUS_INSTAT BIT(5)
+#define APCH_STATUS_TEMPSTAT BIT(6)
+#define APCH_STATUS_TIMRSTAT BIT(7)
+
+#define APCH_CTRL_CHGEOCOUT BIT(0)
+#define APCH_CTRL_INDIS BIT(1)
+#define APCH_CTRL_TEMPOUT BIT(2)
+#define APCH_CTRL_TIMRPRE BIT(3)
+#define APCH_CTRL_CHGEOCIN BIT(4)
+#define APCH_CTRL_INCON BIT(5)
+#define APCH_CTRL_TEMPIN BIT(6)
+#define APCH_CTRL_TIMRTOT BIT(7)
+
+#define APCH_STATE_ACINSTAT (0x1 << 1)
+#define APCH_STATE_CSTATE (0x3 << 4)
+#define APCH_STATE_CSTATE_SHIFT 4
+#define APCH_STATE_CSTATE_DISABLED 0x00
+#define APCH_STATE_CSTATE_EOC 0x01
+#define APCH_STATE_CSTATE_FAST 0x02
+#define APCH_STATE_CSTATE_PRE 0x03
+
+struct act8945a_charger {
+ struct regmap *regmap;
+ bool battery_temperature;
+};
+
+static int act8945a_get_charger_state(struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int status, state;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
+ if (ret < 0)
+ return ret;
+
+ state &= APCH_STATE_CSTATE;
+ state >>= APCH_STATE_CSTATE_SHIFT;
+
+ if (state == APCH_STATE_CSTATE_EOC) {
+ if (status & APCH_STATUS_CHGDAT)
+ *val = POWER_SUPPLY_STATUS_FULL;
+ else
+ *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else if ((state == APCH_STATE_CSTATE_FAST) ||
+ (state == APCH_STATE_CSTATE_PRE)) {
+ *val = POWER_SUPPLY_STATUS_CHARGING;
+ } else {
+ *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ }
+
+ return 0;
+}
+
+static int act8945a_get_charge_type(struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int state;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
+ if (ret < 0)
+ return ret;
+
+ state &= APCH_STATE_CSTATE;
+ state >>= APCH_STATE_CSTATE_SHIFT;
+
+ switch (state) {
+ case APCH_STATE_CSTATE_PRE:
+ *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case APCH_STATE_CSTATE_FAST:
+ *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case APCH_STATE_CSTATE_EOC:
+ case APCH_STATE_CSTATE_DISABLED:
+ default:
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ }
+
+ return 0;
+}
+
+static int act8945a_get_battery_health(struct act8945a_charger *charger,
+ struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int status;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ if (charger->battery_temperature && !(status & APCH_STATUS_TEMPDAT))
+ *val = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else if (!(status & APCH_STATUS_INDAT))
+ *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ else if (status & APCH_STATUS_TIMRDAT)
+ *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+ else
+ *val = POWER_SUPPLY_HEALTH_GOOD;
+
+ return 0;
+}
+
+static enum power_supply_property act8945a_charger_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER
+};
+
+static int act8945a_charger_get_property(struct power_supply *psy,
+ enum power_supply_property prop,
+ union power_supply_propval *val)
+{
+ struct act8945a_charger *charger = power_supply_get_drvdata(psy);
+ struct regmap *regmap = charger->regmap;
+ int ret = 0;
+
+ switch (prop) {
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = act8945a_get_charger_state(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ ret = act8945a_get_charge_type(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = act8945a_get_battery_health(charger,
+ regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = act8945a_charger_model;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = act8945a_charger_manufacturer;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct power_supply_desc act8945a_charger_desc = {
+ .name = "act8945a-charger",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .get_property = act8945a_charger_get_property,
+ .properties = act8945a_charger_props,
+ .num_properties = ARRAY_SIZE(act8945a_charger_props),
+};
+
+#define DEFAULT_TOTAL_TIME_OUT 3
+#define DEFAULT_PRE_TIME_OUT 40
+#define DEFAULT_INPUT_OVP_THRESHOLD 6600
+
+static int act8945a_charger_config(struct device *dev,
+ struct act8945a_charger *charger)
+{
+ struct device_node *np = dev->of_node;
+ enum of_gpio_flags flags;
+ struct regmap *regmap = charger->regmap;
+
+ u32 total_time_out;
+ u32 pre_time_out;
+ u32 input_voltage_threshold;
+ int chglev_pin;
+
+ unsigned int value = 0;
+
+ if (!np) {
+ dev_err(dev, "no charger of node\n");
+ return -EINVAL;
+ }
+
+ charger->battery_temperature = of_property_read_bool(np,
+ "active-semi,check-battery-temperature");
+
+ chglev_pin = of_get_named_gpio_flags(np,
+ "active-semi,chglev-gpios", 0, &flags);
+
+ if (gpio_is_valid(chglev_pin)) {
+ gpio_set_value(chglev_pin,
+ ((flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1));
+ }
+
+ if (of_property_read_u32(np,
+ "active-semi,input-voltage-threshold-microvolt",
+ &input_voltage_threshold))
+ input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD;
+
+ if (of_property_read_u32(np,
+ "active-semi,precondition-timeout",
+ &pre_time_out))
+ pre_time_out = DEFAULT_PRE_TIME_OUT;
+
+ if (of_property_read_u32(np, "active-semi,total-timeout",
+ &total_time_out))
+ total_time_out = DEFAULT_TOTAL_TIME_OUT;
+
+ switch (input_voltage_threshold) {
+ case 8000:
+ value |= APCH_CFG_OVPSET_8V;
+ break;
+ case 7500:
+ value |= APCH_CFG_OVPSET_7V5;
+ break;
+ case 7000:
+ value |= APCH_CFG_OVPSET_7V;
+ break;
+ case 6600:
+ default:
+ value |= APCH_CFG_OVPSET_6V6;
+ break;
+ }
+
+ switch (pre_time_out) {
+ case 60:
+ value |= APCH_CFG_PRETIMO_60_MIN;
+ break;
+ case 80:
+ value |= APCH_CFG_PRETIMO_80_MIN;
+ break;
+ case 0:
+ value |= APCH_CFG_PRETIMO_DISABLED;
+ break;
+ case 40:
+ default:
+ value |= APCH_CFG_PRETIMO_40_MIN;
+ break;
+ }
+
+ switch (total_time_out) {
+ case 4:
+ value |= APCH_CFG_TOTTIMO_4_HOUR;
+ break;
+ case 5:
+ value |= APCH_CFG_TOTTIMO_5_HOUR;
+ break;
+ case 0:
+ value |= APCH_CFG_TOTTIMO_DISABLED;
+ break;
+ case 3:
+ default:
+ value |= APCH_CFG_TOTTIMO_3_HOUR;
+ break;
+ }
+
+ return regmap_write(regmap, ACT8945A_APCH_CFG, value);
+}
+
+static int act8945a_charger_probe(struct platform_device *pdev)
+{
+ struct act8945a_charger *charger;
+ struct power_supply *psy;
+ struct power_supply_config psy_cfg = {};
+ int ret;
+
+ charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
+ if (!charger)
+ return -ENOMEM;
+
+ charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!charger->regmap) {
+ dev_err(&pdev->dev, "Parent did not provide regmap\n");
+ return -EINVAL;
+ }
+
+ ret = act8945a_charger_config(pdev->dev.parent, charger);
+ if (ret)
+ return ret;
+
+ psy_cfg.of_node = pdev->dev.parent->of_node;
+ psy_cfg.drv_data = charger;
+
+ psy = devm_power_supply_register(&pdev->dev,
+ &act8945a_charger_desc,
+ &psy_cfg);
+ if (IS_ERR(psy)) {
+ dev_err(&pdev->dev, "failed to register power supply\n");
+ return PTR_ERR(psy);
+ }
+
+ return 0;
+}
+
+static struct platform_driver act8945a_charger_driver = {
+ .driver = {
+ .name = "act8945a-charger",
+ },
+ .probe = act8945a_charger_probe,
+};
+module_platform_driver(act8945a_charger_driver);
+
+MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver");
+MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/bq2415x_charger.c b/drivers/power/bq2415x_charger.c
index 27e89536689a..73e2f0b79dd4 100644
--- a/drivers/power/bq2415x_charger.c
+++ b/drivers/power/bq2415x_charger.c
@@ -1759,6 +1759,7 @@ static const struct i2c_device_id bq2415x_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, bq2415x_i2c_id_table);
+#ifdef CONFIG_ACPI
static const struct acpi_device_id bq2415x_i2c_acpi_match[] = {
{ "BQ2415X", BQUNKNOWN },
{ "BQ241500", BQ24150 },
@@ -1776,10 +1777,31 @@ static const struct acpi_device_id bq2415x_i2c_acpi_match[] = {
{},
};
MODULE_DEVICE_TABLE(acpi, bq2415x_i2c_acpi_match);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id bq2415x_of_match_table[] = {
+ { .compatible = "ti,bq24150" },
+ { .compatible = "ti,bq24150a" },
+ { .compatible = "ti,bq24151" },
+ { .compatible = "ti,bq24151a" },
+ { .compatible = "ti,bq24152" },
+ { .compatible = "ti,bq24153" },
+ { .compatible = "ti,bq24153a" },
+ { .compatible = "ti,bq24155" },
+ { .compatible = "ti,bq24156" },
+ { .compatible = "ti,bq24156a" },
+ { .compatible = "ti,bq24157s" },
+ { .compatible = "ti,bq24158" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bq2415x_of_match_table);
+#endif
static struct i2c_driver bq2415x_driver = {
.driver = {
.name = "bq2415x-charger",
+ .of_match_table = of_match_ptr(bq2415x_of_match_table),
.acpi_match_table = ACPI_PTR(bq2415x_i2c_acpi_match),
},
.probe = bq2415x_probe,
diff --git a/drivers/power/bq24735-charger.c b/drivers/power/bq24735-charger.c
index eb2b3689de97..fa454c19ce17 100644
--- a/drivers/power/bq24735-charger.c
+++ b/drivers/power/bq24735-charger.c
@@ -48,6 +48,8 @@ struct bq24735 {
struct power_supply_desc charger_desc;
struct i2c_client *client;
struct bq24735_platform *pdata;
+ struct mutex lock;
+ bool charging;
};
static inline struct bq24735 *to_bq24735(struct power_supply *psy)
@@ -56,9 +58,23 @@ static inline struct bq24735 *to_bq24735(struct power_supply *psy)
}
static enum power_supply_property bq24735_charger_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
};
+static int bq24735_charger_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static inline int bq24735_write_word(struct i2c_client *client, u8 reg,
u16 value)
{
@@ -90,6 +106,9 @@ static int bq24735_update_word(struct i2c_client *client, u8 reg,
static inline int bq24735_enable_charging(struct bq24735 *charger)
{
+ if (charger->pdata->ext_control)
+ return 0;
+
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
~BQ24735_CHG_OPT_CHARGE_DISABLE);
@@ -97,6 +116,9 @@ static inline int bq24735_enable_charging(struct bq24735 *charger)
static inline int bq24735_disable_charging(struct bq24735 *charger)
{
+ if (charger->pdata->ext_control)
+ return 0;
+
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
BQ24735_CHG_OPT_CHARGE_DISABLE);
@@ -108,6 +130,9 @@ static int bq24735_config_charger(struct bq24735 *charger)
int ret;
u16 value;
+ if (pdata->ext_control)
+ return 0;
+
if (pdata->charge_current) {
value = pdata->charge_current & BQ24735_CHARGE_CURRENT_MASK;
@@ -174,16 +199,30 @@ static bool bq24735_charger_is_present(struct bq24735 *charger)
return false;
}
+static int bq24735_charger_is_charging(struct bq24735 *charger)
+{
+ int ret = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
+
+ if (ret < 0)
+ return ret;
+
+ return !(ret & BQ24735_CHG_OPT_CHARGE_DISABLE);
+}
+
static irqreturn_t bq24735_charger_isr(int irq, void *devid)
{
struct power_supply *psy = devid;
struct bq24735 *charger = to_bq24735(psy);
- if (bq24735_charger_is_present(charger))
+ mutex_lock(&charger->lock);
+
+ if (charger->charging && bq24735_charger_is_present(charger))
bq24735_enable_charging(charger);
else
bq24735_disable_charging(charger);
+ mutex_unlock(&charger->lock);
+
power_supply_changed(psy);
return IRQ_HANDLED;
@@ -199,6 +238,19 @@ static int bq24735_charger_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_ONLINE:
val->intval = bq24735_charger_is_present(charger) ? 1 : 0;
break;
+ case POWER_SUPPLY_PROP_STATUS:
+ switch (bq24735_charger_is_charging(charger)) {
+ case 1:
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case 0:
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+ }
+ break;
default:
return -EINVAL;
}
@@ -206,6 +258,46 @@ static int bq24735_charger_get_property(struct power_supply *psy,
return 0;
}
+static int bq24735_charger_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct bq24735 *charger = to_bq24735(psy);
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ switch (val->intval) {
+ case POWER_SUPPLY_STATUS_CHARGING:
+ mutex_lock(&charger->lock);
+ charger->charging = true;
+ ret = bq24735_enable_charging(charger);
+ mutex_unlock(&charger->lock);
+ if (ret)
+ return ret;
+ bq24735_config_charger(charger);
+ break;
+ case POWER_SUPPLY_STATUS_DISCHARGING:
+ case POWER_SUPPLY_STATUS_NOT_CHARGING:
+ mutex_lock(&charger->lock);
+ charger->charging = false;
+ ret = bq24735_disable_charging(charger);
+ mutex_unlock(&charger->lock);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+ power_supply_changed(psy);
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return 0;
+}
+
static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
{
struct bq24735_platform *pdata;
@@ -239,6 +331,8 @@ static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
if (!ret)
pdata->input_current = val;
+ pdata->ext_control = of_property_read_bool(np, "ti,external-control");
+
return pdata;
}
@@ -255,6 +349,8 @@ static int bq24735_charger_probe(struct i2c_client *client,
if (!charger)
return -ENOMEM;
+ mutex_init(&charger->lock);
+ charger->charging = true;
charger->pdata = client->dev.platform_data;
if (IS_ENABLED(CONFIG_OF) && !charger->pdata && client->dev.of_node)
@@ -285,6 +381,9 @@ static int bq24735_charger_probe(struct i2c_client *client,
supply_desc->properties = bq24735_charger_properties;
supply_desc->num_properties = ARRAY_SIZE(bq24735_charger_properties);
supply_desc->get_property = bq24735_charger_get_property;
+ supply_desc->set_property = bq24735_charger_set_property;
+ supply_desc->property_is_writeable =
+ bq24735_charger_property_is_writeable;
psy_cfg.supplied_to = charger->pdata->supplied_to;
psy_cfg.num_supplicants = charger->pdata->num_supplicants;
@@ -293,27 +392,6 @@ static int bq24735_charger_probe(struct i2c_client *client,
i2c_set_clientdata(client, charger);
- ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
- if (ret < 0) {
- dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
- ret);
- return ret;
- } else if (ret != 0x0040) {
- dev_err(&client->dev,
- "manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
- return -ENODEV;
- }
-
- ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
- if (ret < 0) {
- dev_err(&client->dev, "Failed to read device id : %d\n", ret);
- return ret;
- } else if (ret != 0x000B) {
- dev_err(&client->dev,
- "device id mismatch. 0x000b != 0x%04x\n", ret);
- return -ENODEV;
- }
-
if (gpio_is_valid(charger->pdata->status_gpio)) {
ret = devm_gpio_request(&client->dev,
charger->pdata->status_gpio,
@@ -327,6 +405,30 @@ static int bq24735_charger_probe(struct i2c_client *client,
charger->pdata->status_gpio_valid = !ret;
}
+ if (!charger->pdata->status_gpio_valid
+ || bq24735_charger_is_present(charger)) {
+ ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
+ ret);
+ return ret;
+ } else if (ret != 0x0040) {
+ dev_err(&client->dev,
+ "manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
+ return -ENODEV;
+ }
+
+ ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read device id : %d\n", ret);
+ return ret;
+ } else if (ret != 0x000B) {
+ dev_err(&client->dev,
+ "device id mismatch. 0x000b != 0x%04x\n", ret);
+ return -ENODEV;
+ }
+ }
+
ret = bq24735_config_charger(charger);
if (ret < 0) {
dev_err(&client->dev, "failed in configuring charger");
diff --git a/drivers/power/bq27xxx_battery.c b/drivers/power/bq27xxx_battery.c
index 6b027a418943..45f6ebf88df6 100644
--- a/drivers/power/bq27xxx_battery.c
+++ b/drivers/power/bq27xxx_battery.c
@@ -46,6 +46,7 @@
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <linux/power/bq27xxx_battery.h>
@@ -1090,16 +1091,27 @@ static const struct platform_device_id bq27xxx_battery_platform_id_table[] = {
};
MODULE_DEVICE_TABLE(platform, bq27xxx_battery_platform_id_table);
+#ifdef CONFIG_OF
+static const struct of_device_id bq27xxx_battery_platform_of_match_table[] = {
+ { .compatible = "ti,bq27000" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bq27xxx_battery_platform_of_match_table);
+#endif
+
static struct platform_driver bq27xxx_battery_platform_driver = {
.probe = bq27xxx_battery_platform_probe,
.remove = bq27xxx_battery_platform_remove,
.driver = {
.name = "bq27000-battery",
+ .of_match_table = of_match_ptr(bq27xxx_battery_platform_of_match_table),
},
.id_table = bq27xxx_battery_platform_id_table,
};
module_platform_driver(bq27xxx_battery_platform_driver);
+MODULE_ALIAS("platform:bq27000-battery");
+
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
MODULE_DESCRIPTION("BQ27xxx battery monitor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/power/bq27xxx_battery_i2c.c b/drivers/power/bq27xxx_battery_i2c.c
index 9429e66be096..b8f8d3ade31b 100644
--- a/drivers/power/bq27xxx_battery_i2c.c
+++ b/drivers/power/bq27xxx_battery_i2c.c
@@ -21,6 +21,9 @@
#include <linux/power/bq27xxx_battery.h>
+static DEFINE_IDR(battery_id);
+static DEFINE_MUTEX(battery_mutex);
+
static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data)
{
struct bq27xxx_device_info *di = data;
@@ -70,19 +73,33 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
{
struct bq27xxx_device_info *di;
int ret;
+ char *name;
+ int num;
+
+ /* Get new ID for the new battery device */
+ mutex_lock(&battery_mutex);
+ num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
+ mutex_unlock(&battery_mutex);
+ if (num < 0)
+ return num;
+
+ name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num);
+ if (!name)
+ goto err_mem;
di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL);
if (!di)
- return -ENOMEM;
+ goto err_mem;
+ di->id = num;
di->dev = &client->dev;
di->chip = id->driver_data;
- di->name = id->name;
+ di->name = name;
di->bus.read = bq27xxx_battery_i2c_read;
ret = bq27xxx_battery_setup(di);
if (ret)
- return ret;
+ goto err_failed;
/* Schedule a polling after about 1 min */
schedule_delayed_work(&di->work, 60 * HZ);
@@ -103,6 +120,16 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
}
return 0;
+
+err_mem:
+ ret = -ENOMEM;
+
+err_failed:
+ mutex_lock(&battery_mutex);
+ idr_remove(&battery_id, num);
+ mutex_unlock(&battery_mutex);
+
+ return ret;
}
static int bq27xxx_battery_i2c_remove(struct i2c_client *client)
@@ -111,6 +138,10 @@ static int bq27xxx_battery_i2c_remove(struct i2c_client *client)
bq27xxx_battery_teardown(di);
+ mutex_lock(&battery_mutex);
+ idr_remove(&battery_id, di->id);
+ mutex_unlock(&battery_mutex);
+
return 0;
}
@@ -135,9 +166,33 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
+#ifdef CONFIG_OF
+static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = {
+ { .compatible = "ti,bq27200" },
+ { .compatible = "ti,bq27210" },
+ { .compatible = "ti,bq27500" },
+ { .compatible = "ti,bq27510" },
+ { .compatible = "ti,bq27520" },
+ { .compatible = "ti,bq27530" },
+ { .compatible = "ti,bq27531" },
+ { .compatible = "ti,bq27541" },
+ { .compatible = "ti,bq27542" },
+ { .compatible = "ti,bq27546" },
+ { .compatible = "ti,bq27742" },
+ { .compatible = "ti,bq27545" },
+ { .compatible = "ti,bq27421" },
+ { .compatible = "ti,bq27425" },
+ { .compatible = "ti,bq27441" },
+ { .compatible = "ti,bq27621" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table);
+#endif
+
static struct i2c_driver bq27xxx_battery_i2c_driver = {
.driver = {
.name = "bq27xxx-battery",
+ .of_match_table = of_match_ptr(bq27xxx_battery_i2c_of_match_table),
},
.probe = bq27xxx_battery_i2c_probe,
.remove = bq27xxx_battery_i2c_remove,
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
index 8a971b3dbe58..3a0bc608d4b5 100644
--- a/drivers/power/collie_battery.c
+++ b/drivers/power/collie_battery.c
@@ -26,7 +26,6 @@
static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
static struct work_struct bat_work;
static struct ucb1x00 *ucb;
-static int wakeup_enabled;
struct collie_bat {
int status;
@@ -291,6 +290,8 @@ static struct gpio collie_batt_gpios[] = {
};
#ifdef CONFIG_PM
+static int wakeup_enabled;
+
static int collie_bat_suspend(struct ucb1x00_dev *dev)
{
/* flush all pending status updates */
diff --git a/drivers/power/goldfish_battery.c b/drivers/power/goldfish_battery.c
index a50bb988c69a..f5c525e4482a 100644
--- a/drivers/power/goldfish_battery.c
+++ b/drivers/power/goldfish_battery.c
@@ -24,6 +24,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/acpi.h>
struct goldfish_battery_data {
void __iomem *reg_base;
@@ -227,11 +228,25 @@ static int goldfish_battery_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id goldfish_battery_of_match[] = {
+ { .compatible = "google,goldfish-battery", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, goldfish_battery_of_match);
+
+static const struct acpi_device_id goldfish_battery_acpi_match[] = {
+ { "GFSH0001", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match);
+
static struct platform_driver goldfish_battery_device = {
.probe = goldfish_battery_probe,
.remove = goldfish_battery_remove,
.driver = {
- .name = "goldfish-battery"
+ .name = "goldfish-battery",
+ .of_match_table = goldfish_battery_of_match,
+ .acpi_match_table = ACPI_PTR(goldfish_battery_acpi_match),
}
};
module_platform_driver(goldfish_battery_device);
diff --git a/drivers/power/ipaq_micro_battery.c b/drivers/power/ipaq_micro_battery.c
index f03014ea1dc4..3f314b1a30d7 100644
--- a/drivers/power/ipaq_micro_battery.c
+++ b/drivers/power/ipaq_micro_battery.c
@@ -281,7 +281,7 @@ static int micro_batt_remove(struct platform_device *pdev)
return 0;
}
-static int micro_batt_suspend(struct device *dev)
+static int __maybe_unused micro_batt_suspend(struct device *dev)
{
struct micro_battery *mb = dev_get_drvdata(dev);
@@ -289,7 +289,7 @@ static int micro_batt_suspend(struct device *dev)
return 0;
}
-static int micro_batt_resume(struct device *dev)
+static int __maybe_unused micro_batt_resume(struct device *dev)
{
struct micro_battery *mb = dev_get_drvdata(dev);
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 46a292aa182d..4cd6899b961e 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -411,8 +411,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
if (np) {
int gpio = of_get_named_gpio(np, "nxp,enable-gpio", 0);
- if (gpio < 0)
+ if (gpio < 0) {
+ dev_err(&pdev->dev, "missing DT GPIO nxp,enable-gpio\n");
return gpio;
+ }
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct isp1704_charger_data), GFP_KERNEL);
@@ -422,8 +424,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
ret = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio,
GPIOF_OUT_INIT_HIGH, "isp1704_reset");
- if (ret)
+ if (ret) {
+ dev_err(&pdev->dev, "gpio request failed\n");
goto fail0;
+ }
}
if (!pdata) {
@@ -443,6 +447,7 @@ static int isp1704_charger_probe(struct platform_device *pdev)
if (IS_ERR(isp->phy)) {
ret = PTR_ERR(isp->phy);
+ dev_err(&pdev->dev, "usb_get_phy failed\n");
goto fail0;
}
@@ -452,8 +457,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
isp1704_charger_set_power(isp, 1);
ret = isp1704_test_ulpi(isp);
- if (ret < 0)
+ if (ret < 0) {
+ dev_err(&pdev->dev, "isp1704_test_ulpi failed\n");
goto fail1;
+ }
isp->psy_desc.name = "isp1704";
isp->psy_desc.type = POWER_SUPPLY_TYPE_USB;
@@ -466,6 +473,7 @@ static int isp1704_charger_probe(struct platform_device *pdev)
isp->psy = power_supply_register(isp->dev, &isp->psy_desc, &psy_cfg);
if (IS_ERR(isp->psy)) {
ret = PTR_ERR(isp->psy);
+ dev_err(&pdev->dev, "power_supply_register failed\n");
goto fail1;
}
@@ -478,8 +486,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
isp->nb.notifier_call = isp1704_notifier_call;
ret = usb_register_notifier(isp->phy, &isp->nb);
- if (ret)
+ if (ret) {
+ dev_err(&pdev->dev, "usb_register_notifier failed\n");
goto fail2;
+ }
dev_info(isp->dev, "registered with product id %s\n", isp->model);
@@ -526,6 +536,7 @@ static int isp1704_charger_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id omap_isp1704_of_match[] = {
{ .compatible = "nxp,isp1704", },
+ { .compatible = "nxp,isp1707", },
{},
};
MODULE_DEVICE_TABLE(of, omap_isp1704_of_match);
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c
index abdfc21ec13f..88f04f4d1a70 100644
--- a/drivers/power/jz4740-battery.c
+++ b/drivers/power/jz4740-battery.c
@@ -208,7 +208,7 @@ static void jz_battery_update(struct jz_battery *jz_battery)
}
voltage = jz_battery_read_voltage(jz_battery);
- if (abs(voltage - jz_battery->voltage) < 50000) {
+ if (voltage >= 0 && abs(voltage - jz_battery->voltage) > 50000) {
jz_battery->voltage = voltage;
has_changed = true;
}
diff --git a/drivers/power/lp8788-charger.c b/drivers/power/lp8788-charger.c
index f5a48fd68b01..7321b727d484 100644
--- a/drivers/power/lp8788-charger.c
+++ b/drivers/power/lp8788-charger.c
@@ -455,7 +455,7 @@ static void lp8788_charger_event(struct work_struct *work)
static bool lp8788_find_irq_id(struct lp8788_charger *pchg, int virq, int *id)
{
- bool found;
+ bool found = false;
int i;
for (i = 0; i < pchg->num_irqs; i++) {
diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c
index 8f9bd1d0eeb6..fb62ed3fc38c 100644
--- a/drivers/power/pm2301_charger.c
+++ b/drivers/power/pm2301_charger.c
@@ -911,11 +911,7 @@ static struct pm2xxx_irq pm2xxx_charger_irq[] = {
{"PM2XXX_IRQ_INT", pm2xxx_irq_int},
};
-#ifdef CONFIG_PM
-
-#ifdef CONFIG_PM_SLEEP
-
-static int pm2xxx_wall_charger_resume(struct device *dev)
+static int __maybe_unused pm2xxx_wall_charger_resume(struct device *dev)
{
struct i2c_client *i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
@@ -931,7 +927,7 @@ static int pm2xxx_wall_charger_resume(struct device *dev)
return 0;
}
-static int pm2xxx_wall_charger_suspend(struct device *dev)
+static int __maybe_unused pm2xxx_wall_charger_suspend(struct device *dev)
{
struct i2c_client *i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
@@ -949,9 +945,7 @@ static int pm2xxx_wall_charger_suspend(struct device *dev)
return 0;
}
-#endif
-
-static int pm2xxx_runtime_suspend(struct device *dev)
+static int __maybe_unused pm2xxx_runtime_suspend(struct device *dev)
{
struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
@@ -962,7 +956,7 @@ static int pm2xxx_runtime_suspend(struct device *dev)
return 0;
}
-static int pm2xxx_runtime_resume(struct device *dev)
+static int __maybe_unused pm2xxx_runtime_resume(struct device *dev)
{
struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
@@ -975,15 +969,11 @@ static int pm2xxx_runtime_resume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops pm2xxx_pm_ops = {
+static const struct dev_pm_ops pm2xxx_pm_ops __maybe_unused = {
SET_SYSTEM_SLEEP_PM_OPS(pm2xxx_wall_charger_suspend,
pm2xxx_wall_charger_resume)
SET_RUNTIME_PM_OPS(pm2xxx_runtime_suspend, pm2xxx_runtime_resume, NULL)
};
-#define PM2XXX_PM_OPS (&pm2xxx_pm_ops)
-#else
-#define PM2XXX_PM_OPS NULL
-#endif
static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
@@ -1244,7 +1234,7 @@ static struct i2c_driver pm2xxx_charger_driver = {
.remove = pm2xxx_wall_charger_remove,
.driver = {
.name = "pm2xxx-wall_charger",
- .pm = PM2XXX_PM_OPS,
+ .pm = IS_ENABLED(CONFIG_PM) ? &pm2xxx_pm_ops : NULL,
},
.id_table = pm2xxx_id,
};
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index ed2d7fd0c734..80fed98832f9 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -45,7 +45,8 @@ static ssize_t power_supply_show_property(struct device *dev,
char *buf) {
static char *type_text[] = {
"Unknown", "Battery", "UPS", "Mains", "USB",
- "USB_DCP", "USB_CDP", "USB_ACA"
+ "USB_DCP", "USB_CDP", "USB_ACA", "USB_C",
+ "USB_PD", "USB_PD_DRP"
};
static char *status_text[] = {
"Unknown", "Charging", "Discharging", "Not charging", "Full"
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 1131cf75acc6..0a6408a39c66 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -148,6 +148,7 @@ config POWER_RESET_KEYSTONE
config POWER_RESET_SYSCON
bool "Generic SYSCON regmap reset driver"
depends on OF
+ depends on HAS_IOMEM
select MFD_SYSCON
help
Reboot support for generic SYSCON mapped register reset.
@@ -155,6 +156,7 @@ config POWER_RESET_SYSCON
config POWER_RESET_SYSCON_POWEROFF
bool "Generic SYSCON regmap poweroff driver"
depends on OF
+ depends on HAS_IOMEM
select MFD_SYSCON
help
Poweroff support for generic SYSCON mapped register poweroff.
diff --git a/drivers/power/reset/arm-versatile-reboot.c b/drivers/power/reset/arm-versatile-reboot.c
index b208073c887d..06d34ab47df5 100644
--- a/drivers/power/reset/arm-versatile-reboot.c
+++ b/drivers/power/reset/arm-versatile-reboot.c
@@ -18,8 +18,8 @@
#define INTEGRATOR_HDR_LOCK_OFFSET 0x14
#define INTEGRATOR_CM_CTRL_RESET (1 << 3)
-#define REALVIEW_SYS_LOCK_OFFSET 0x20
-#define REALVIEW_SYS_RESETCTL_OFFSET 0x40
+#define VERSATILE_SYS_LOCK_OFFSET 0x20
+#define VERSATILE_SYS_RESETCTL_OFFSET 0x40
/* Magic unlocking token used on all Versatile boards */
#define VERSATILE_LOCK_VAL 0xA05F
@@ -29,6 +29,7 @@
*/
enum versatile_reboot {
INTEGRATOR_REBOOT_CM,
+ VERSATILE_REBOOT_CM,
REALVIEW_REBOOT_EB,
REALVIEW_REBOOT_PB1176,
REALVIEW_REBOOT_PB11MP,
@@ -46,6 +47,10 @@ static const struct of_device_id versatile_reboot_of_match[] = {
.data = (void *)INTEGRATOR_REBOOT_CM
},
{
+ .compatible = "arm,core-module-versatile",
+ .data = (void *)VERSATILE_REBOOT_CM,
+ },
+ {
.compatible = "arm,realview-eb-syscon",
.data = (void *)REALVIEW_REBOOT_EB,
},
@@ -82,33 +87,43 @@ static int versatile_reboot(struct notifier_block *this, unsigned long mode,
INTEGRATOR_CM_CTRL_RESET,
INTEGRATOR_CM_CTRL_RESET);
break;
+ case VERSATILE_REBOOT_CM:
+ regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
+ VERSATILE_LOCK_VAL);
+ regmap_update_bits(syscon_regmap,
+ VERSATILE_SYS_RESETCTL_OFFSET,
+ 0x0107,
+ 0x0105);
+ regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
+ 0);
+ break;
case REALVIEW_REBOOT_EB:
- regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
+ regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap,
- REALVIEW_SYS_RESETCTL_OFFSET, 0x0008);
+ VERSATILE_SYS_RESETCTL_OFFSET, 0x0008);
break;
case REALVIEW_REBOOT_PB1176:
- regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
+ regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap,
- REALVIEW_SYS_RESETCTL_OFFSET, 0x0100);
+ VERSATILE_SYS_RESETCTL_OFFSET, 0x0100);
break;
case REALVIEW_REBOOT_PB11MP:
case REALVIEW_REBOOT_PBA8:
- regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
+ regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
- regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
+ regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
0x0000);
- regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
+ regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
0x0004);
break;
case REALVIEW_REBOOT_PBX:
- regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
+ regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
- regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
+ regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
0x00f0);
- regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
+ regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
0x00f4);
break;
}
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 6c592dc71aee..cdfd01f0adb8 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -133,6 +133,12 @@ struct rapl_domain_data {
unsigned long timestamp;
};
+struct msrl_action {
+ u32 msr_no;
+ u64 clear_mask;
+ u64 set_mask;
+ int err;
+};
#define DOMAIN_STATE_INACTIVE BIT(0)
#define DOMAIN_STATE_POWER_LIMIT_SET BIT(1)
@@ -149,6 +155,7 @@ struct rapl_power_limit {
static const char pl1_name[] = "long_term";
static const char pl2_name[] = "short_term";
+struct rapl_package;
struct rapl_domain {
const char *name;
enum rapl_domain_type id;
@@ -159,7 +166,7 @@ struct rapl_domain {
u64 attr_map; /* track capabilities */
unsigned int state;
unsigned int domain_energy_unit;
- int package_id;
+ struct rapl_package *rp;
};
#define power_zone_to_rapl_domain(_zone) \
container_of(_zone, struct rapl_domain, power_zone)
@@ -184,6 +191,7 @@ struct rapl_package {
* notify interrupt enable status.
*/
struct list_head plist;
+ int lead_cpu; /* one active cpu per package for access */
};
struct rapl_defaults {
@@ -231,10 +239,10 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
static int rapl_write_data_raw(struct rapl_domain *rd,
enum rapl_primitives prim,
unsigned long long value);
-static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
+static u64 rapl_unit_xlate(struct rapl_domain *rd,
enum unit_type type, u64 value,
int to_raw);
-static void package_power_limit_irq_save(int package_id);
+static void package_power_limit_irq_save(struct rapl_package *rp);
static LIST_HEAD(rapl_packages); /* guarded by CPU hotplug lock */
@@ -260,20 +268,6 @@ static struct rapl_package *find_package_by_id(int id)
return NULL;
}
-/* caller to ensure CPU hotplug lock is held */
-static int find_active_cpu_on_package(int package_id)
-{
- int i;
-
- for_each_online_cpu(i) {
- if (topology_physical_package_id(i) == package_id)
- return i;
- }
- /* all CPUs on this package are offline */
-
- return -ENODEV;
-}
-
/* caller must hold cpu hotplug lock */
static void rapl_cleanup_data(void)
{
@@ -312,25 +306,19 @@ static int get_max_energy_counter(struct powercap_zone *pcd_dev, u64 *energy)
{
struct rapl_domain *rd = power_zone_to_rapl_domain(pcd_dev);
- *energy = rapl_unit_xlate(rd, 0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
+ *energy = rapl_unit_xlate(rd, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
return 0;
}
static int release_zone(struct powercap_zone *power_zone)
{
struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone);
- struct rapl_package *rp;
+ struct rapl_package *rp = rd->rp;
/* package zone is the last zone of a package, we can free
* memory here since all children has been unregistered.
*/
if (rd->id == RAPL_DOMAIN_PACKAGE) {
- rp = find_package_by_id(rd->package_id);
- if (!rp) {
- dev_warn(&power_zone->dev, "no package id %s\n",
- rd->name);
- return -ENODEV;
- }
kfree(rd);
rp->domains = NULL;
}
@@ -432,11 +420,7 @@ static int set_power_limit(struct powercap_zone *power_zone, int id,
get_online_cpus();
rd = power_zone_to_rapl_domain(power_zone);
- rp = find_package_by_id(rd->package_id);
- if (!rp) {
- ret = -ENODEV;
- goto set_exit;
- }
+ rp = rd->rp;
if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
dev_warn(&power_zone->dev, "%s locked by BIOS, monitoring only\n",
@@ -456,7 +440,7 @@ static int set_power_limit(struct powercap_zone *power_zone, int id,
ret = -EINVAL;
}
if (!ret)
- package_power_limit_irq_save(rd->package_id);
+ package_power_limit_irq_save(rp);
set_exit:
put_online_cpus();
return ret;
@@ -655,24 +639,19 @@ static void rapl_init_domains(struct rapl_package *rp)
break;
}
if (mask) {
- rd->package_id = rp->id;
+ rd->rp = rp;
rd++;
}
}
}
-static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
- enum unit_type type, u64 value,
- int to_raw)
+static u64 rapl_unit_xlate(struct rapl_domain *rd, enum unit_type type,
+ u64 value, int to_raw)
{
u64 units = 1;
- struct rapl_package *rp;
+ struct rapl_package *rp = rd->rp;
u64 scale = 1;
- rp = find_package_by_id(package);
- if (!rp)
- return value;
-
switch (type) {
case POWER_UNIT:
units = rp->power_unit;
@@ -769,10 +748,8 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
msr = rd->msrs[rp->id];
if (!msr)
return -EINVAL;
- /* use physical package id to look up active cpus */
- cpu = find_active_cpu_on_package(rd->package_id);
- if (cpu < 0)
- return cpu;
+
+ cpu = rd->rp->lead_cpu;
/* special-case package domain, which uses a different bit*/
if (prim == FW_LOCK && rd->id == RAPL_DOMAIN_PACKAGE) {
@@ -793,42 +770,66 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
final = value & rp->mask;
final = final >> rp->shift;
if (xlate)
- *data = rapl_unit_xlate(rd, rd->package_id, rp->unit, final, 0);
+ *data = rapl_unit_xlate(rd, rp->unit, final, 0);
else
*data = final;
return 0;
}
+
+static int msrl_update_safe(u32 msr_no, u64 clear_mask, u64 set_mask)
+{
+ int err;
+ u64 val;
+
+ err = rdmsrl_safe(msr_no, &val);
+ if (err)
+ goto out;
+
+ val &= ~clear_mask;
+ val |= set_mask;
+
+ err = wrmsrl_safe(msr_no, val);
+
+out:
+ return err;
+}
+
+static void msrl_update_func(void *info)
+{
+ struct msrl_action *ma = info;
+
+ ma->err = msrl_update_safe(ma->msr_no, ma->clear_mask, ma->set_mask);
+}
+
/* Similar use of primitive info in the read counterpart */
static int rapl_write_data_raw(struct rapl_domain *rd,
enum rapl_primitives prim,
unsigned long long value)
{
- u64 msr_val;
- u32 msr;
struct rapl_primitive_info *rp = &rpi[prim];
int cpu;
+ u64 bits;
+ struct msrl_action ma;
+ int ret;
- cpu = find_active_cpu_on_package(rd->package_id);
- if (cpu < 0)
- return cpu;
- msr = rd->msrs[rp->id];
- if (rdmsrl_safe_on_cpu(cpu, msr, &msr_val)) {
- dev_dbg(&rd->power_zone.dev,
- "failed to read msr 0x%x on cpu %d\n", msr, cpu);
- return -EIO;
- }
- value = rapl_unit_xlate(rd, rd->package_id, rp->unit, value, 1);
- msr_val &= ~rp->mask;
- msr_val |= value << rp->shift;
- if (wrmsrl_safe_on_cpu(cpu, msr, msr_val)) {
- dev_dbg(&rd->power_zone.dev,
- "failed to write msr 0x%x on cpu %d\n", msr, cpu);
- return -EIO;
- }
+ cpu = rd->rp->lead_cpu;
+ bits = rapl_unit_xlate(rd, rp->unit, value, 1);
+ bits |= bits << rp->shift;
+ memset(&ma, 0, sizeof(ma));
- return 0;
+ ma.msr_no = rd->msrs[rp->id];
+ ma.clear_mask = rp->mask;
+ ma.set_mask = bits;
+
+ ret = smp_call_function_single(cpu, msrl_update_func, &ma, 1);
+ if (ret)
+ WARN_ON_ONCE(ret);
+ else
+ ret = ma.err;
+
+ return ret;
}
/*
@@ -893,6 +894,21 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
return 0;
}
+static void power_limit_irq_save_cpu(void *info)
+{
+ u32 l, h = 0;
+ struct rapl_package *rp = (struct rapl_package *)info;
+
+ /* save the state of PLN irq mask bit before disabling it */
+ rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h);
+ if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) {
+ rp->power_limit_irq = l & PACKAGE_THERM_INT_PLN_ENABLE;
+ rp->power_limit_irq |= PACKAGE_PLN_INT_SAVED;
+ }
+ l &= ~PACKAGE_THERM_INT_PLN_ENABLE;
+ wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+}
+
/* REVISIT:
* When package power limit is set artificially low by RAPL, LVT
@@ -904,61 +920,40 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
* to do by adding an atomic notifier.
*/
-static void package_power_limit_irq_save(int package_id)
+static void package_power_limit_irq_save(struct rapl_package *rp)
{
- u32 l, h = 0;
- int cpu;
- struct rapl_package *rp;
-
- rp = find_package_by_id(package_id);
- if (!rp)
- return;
-
if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN))
return;
- cpu = find_active_cpu_on_package(package_id);
- if (cpu < 0)
- return;
- /* save the state of PLN irq mask bit before disabling it */
- rdmsr_safe_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h);
- if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) {
- rp->power_limit_irq = l & PACKAGE_THERM_INT_PLN_ENABLE;
- rp->power_limit_irq |= PACKAGE_PLN_INT_SAVED;
- }
- l &= ~PACKAGE_THERM_INT_PLN_ENABLE;
- wrmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+ smp_call_function_single(rp->lead_cpu, power_limit_irq_save_cpu, rp, 1);
}
-/* restore per package power limit interrupt enable state */
-static void package_power_limit_irq_restore(int package_id)
+static void power_limit_irq_restore_cpu(void *info)
{
- u32 l, h;
- int cpu;
- struct rapl_package *rp;
+ u32 l, h = 0;
+ struct rapl_package *rp = (struct rapl_package *)info;
- rp = find_package_by_id(package_id);
- if (!rp)
- return;
+ rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h);
- if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN))
- return;
+ if (rp->power_limit_irq & PACKAGE_THERM_INT_PLN_ENABLE)
+ l |= PACKAGE_THERM_INT_PLN_ENABLE;
+ else
+ l &= ~PACKAGE_THERM_INT_PLN_ENABLE;
+
+ wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+}
- cpu = find_active_cpu_on_package(package_id);
- if (cpu < 0)
+/* restore per package power limit interrupt enable state */
+static void package_power_limit_irq_restore(struct rapl_package *rp)
+{
+ if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN))
return;
/* irq enable state not saved, nothing to restore */
if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED))
return;
- rdmsr_safe_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h);
-
- if (rp->power_limit_irq & PACKAGE_THERM_INT_PLN_ENABLE)
- l |= PACKAGE_THERM_INT_PLN_ENABLE;
- else
- l &= ~PACKAGE_THERM_INT_PLN_ENABLE;
- wrmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+ smp_call_function_single(rp->lead_cpu, power_limit_irq_restore_cpu, rp, 1);
}
static void set_floor_freq_default(struct rapl_domain *rd, bool mode)
@@ -1141,7 +1136,7 @@ static int rapl_unregister_powercap(void)
* hotplug lock held
*/
list_for_each_entry(rp, &rapl_packages, plist) {
- package_power_limit_irq_restore(rp->id);
+ package_power_limit_irq_restore(rp);
for (rd = rp->domains; rd < rp->domains + rp->nr_domains;
rd++) {
@@ -1392,7 +1387,8 @@ static int rapl_detect_topology(void)
/* add the new package to the list */
new_package->id = phy_package_id;
new_package->nr_cpus = 1;
-
+ /* use the first active cpu of the package to access */
+ new_package->lead_cpu = i;
/* check if the package contains valid domains */
if (rapl_detect_domains(new_package, i) ||
rapl_defaults->check_unit(new_package, i)) {
@@ -1448,6 +1444,8 @@ static int rapl_add_package(int cpu)
/* add the new package to the list */
rp->id = phy_package_id;
rp->nr_cpus = 1;
+ rp->lead_cpu = cpu;
+
/* check if the package contains valid domains */
if (rapl_detect_domains(rp, cpu) ||
rapl_defaults->check_unit(rp, cpu)) {
@@ -1480,6 +1478,7 @@ static int rapl_cpu_callback(struct notifier_block *nfb,
unsigned long cpu = (unsigned long)hcpu;
int phy_package_id;
struct rapl_package *rp;
+ int lead_cpu;
phy_package_id = topology_physical_package_id(cpu);
switch (action) {
@@ -1500,6 +1499,15 @@ static int rapl_cpu_callback(struct notifier_block *nfb,
break;
if (--rp->nr_cpus == 0)
rapl_remove_package(rp);
+ else if (cpu == rp->lead_cpu) {
+ /* choose another active cpu in the package */
+ lead_cpu = cpumask_any_but(topology_core_cpumask(cpu), cpu);
+ if (lead_cpu < nr_cpu_ids)
+ rp->lead_cpu = lead_cpu;
+ else /* should never go here */
+ pr_err("no active cpu available for package %d\n",
+ phy_package_id);
+ }
}
return NOTIFY_OK;
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index da7bae991552..579fd65299a0 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -22,6 +22,7 @@
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/timekeeping.h>
#include "ptp_private.h"
@@ -120,11 +121,13 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
struct ptp_clock_caps caps;
struct ptp_clock_request req;
struct ptp_sys_offset *sysoff = NULL;
+ struct ptp_sys_offset_precise precise_offset;
struct ptp_pin_desc pd;
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
struct ptp_clock_info *ops = ptp->info;
struct ptp_clock_time *pct;
struct timespec64 ts;
+ struct system_device_crosststamp xtstamp;
int enable, err = 0;
unsigned int i, pin_index;
@@ -138,6 +141,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
caps.n_per_out = ptp->info->n_per_out;
caps.pps = ptp->info->pps;
caps.n_pins = ptp->info->n_pins;
+ caps.cross_timestamping = ptp->info->getcrosststamp != NULL;
if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
err = -EFAULT;
break;
@@ -180,6 +184,29 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
err = ops->enable(ops, &req, enable);
break;
+ case PTP_SYS_OFFSET_PRECISE:
+ if (!ptp->info->getcrosststamp) {
+ err = -EOPNOTSUPP;
+ break;
+ }
+ err = ptp->info->getcrosststamp(ptp->info, &xtstamp);
+ if (err)
+ break;
+
+ ts = ktime_to_timespec64(xtstamp.device);
+ precise_offset.device.sec = ts.tv_sec;
+ precise_offset.device.nsec = ts.tv_nsec;
+ ts = ktime_to_timespec64(xtstamp.sys_realtime);
+ precise_offset.sys_realtime.sec = ts.tv_sec;
+ precise_offset.sys_realtime.nsec = ts.tv_nsec;
+ ts = ktime_to_timespec64(xtstamp.sys_monoraw);
+ precise_offset.sys_monoraw.sec = ts.tv_sec;
+ precise_offset.sys_monoraw.nsec = ts.tv_nsec;
+ if (copy_to_user((void __user *)arg, &precise_offset,
+ sizeof(precise_offset)))
+ err = -EFAULT;
+ break;
+
case PTP_SYS_OFFSET:
sysoff = kmalloc(sizeof(*sysoff), GFP_KERNEL);
if (!sysoff) {
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index d7b87c64b7cd..e220edc85c68 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -117,7 +117,7 @@ int rio_request_inb_mbox(struct rio_mport *mport,
if (mport->ops->open_inb_mbox == NULL)
goto out;
- res = kmalloc(sizeof(struct resource), GFP_KERNEL);
+ res = kzalloc(sizeof(struct resource), GFP_KERNEL);
if (res) {
rio_init_mbox_res(res, mbox, mbox);
@@ -185,7 +185,7 @@ int rio_request_outb_mbox(struct rio_mport *mport,
if (mport->ops->open_outb_mbox == NULL)
goto out;
- res = kmalloc(sizeof(struct resource), GFP_KERNEL);
+ res = kzalloc(sizeof(struct resource), GFP_KERNEL);
if (res) {
rio_init_mbox_res(res, mbox, mbox);
@@ -285,7 +285,7 @@ int rio_request_inb_dbell(struct rio_mport *mport,
{
int rc = 0;
- struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL);
+ struct resource *res = kzalloc(sizeof(struct resource), GFP_KERNEL);
if (res) {
rio_init_dbell_res(res, start, end);
@@ -360,7 +360,7 @@ int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end)
struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start,
u16 end)
{
- struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL);
+ struct resource *res = kzalloc(sizeof(struct resource), GFP_KERNEL);
if (res) {
rio_init_dbell_res(res, start, end);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8155e80dd3f8..91040ec8e242 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -78,6 +78,15 @@ config REGULATOR_ACT8865
This driver controls a active-semi act8865 voltage output
regulator via I2C bus.
+config REGULATOR_ACT8945A
+ tristate "Active-semi ACT8945A voltage regulator"
+ depends on MFD_ACT8945A
+ help
+ This driver controls a active-semi ACT8945A voltage regulator
+ via I2C bus. The ACT8945A features three step-down DC/DC converters
+ and four low-dropout linear regulators, along with a ActivePath
+ battery charger.
+
config REGULATOR_AD5398
tristate "Analog Devices AD5398/AD5821 regulators"
depends on I2C
@@ -261,6 +270,14 @@ config REGULATOR_HI6421
21 general purpose LDOs, 3 dedicated LDOs, and 5 BUCKs. All
of them come with support to either ECO (idle) or sleep mode.
+config REGULATOR_HI655X
+ tristate "Hisilicon HI655X PMIC regulators support"
+ depends on ARCH_HISI || COMPILE_TEST
+ depends on MFD_HI655X_PMIC && OF
+ help
+ This driver provides support for the voltage regulators of the
+ Hisilicon Hi655x PMIC device.
+
config REGULATOR_ISL9305
tristate "Intersil ISL9305 regulator"
depends on I2C
@@ -343,6 +360,15 @@ config REGULATOR_MAX1586
regulator via I2C bus. The provided regulator is suitable
for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
+config REGULATOR_MAX77620
+ tristate "Maxim 77620/MAX20024 voltage regulator"
+ depends on MFD_MAX77620
+ help
+ This driver controls Maxim MAX77620 voltage output regulator
+ via I2C bus. The provided regulator is suitable for Tegra
+ chip to control Step-Down DC-DC and LDOs. Say Y here to
+ enable the regulator driver.
+
config REGULATOR_MAX8649
tristate "Maxim 8649 voltage regulator"
depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 980b1943fa81..61bfbb9d4a0c 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
obj-$(CONFIG_REGULATOR_AB8500) += ab8500-ext.o ab8500.o
obj-$(CONFIG_REGULATOR_ACT8865) += act8865-regulator.o
+obj-$(CONFIG_REGULATOR_ACT8945A) += act8945a-regulator.o
obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
@@ -34,6 +35,7 @@ obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
+obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
@@ -46,6 +48,7 @@ obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
obj-$(CONFIG_REGULATOR_MAX14577) += max14577.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
+obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o
@@ -54,9 +57,9 @@ obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
-obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
+obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
-obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
+obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
@@ -98,7 +101,7 @@ obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
-obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o
+obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c
index f8d4cd3d1397..000d566e32a4 100644
--- a/drivers/regulator/act8865-regulator.c
+++ b/drivers/regulator/act8865-regulator.c
@@ -218,7 +218,7 @@ static const struct regulator_desc act8600_regulators[] = {
.ops = &act8865_ldo_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = 1,
- .fixed_uV = 1800000,
+ .fixed_uV = 3300000,
.enable_reg = ACT8600_LDO910_CTRL,
.enable_mask = ACT8865_ENA,
.owner = THIS_MODULE,
@@ -369,7 +369,7 @@ static int act8865_pdata_from_dt(struct device *dev,
for (i = 0; i < num_matches; i++) {
regulator->id = i;
regulator->name = matches[i].name;
- regulator->platform_data = matches[i].init_data;
+ regulator->init_data = matches[i].init_data;
of_node[i] = matches[i].of_node;
regulator++;
}
@@ -396,7 +396,7 @@ static struct regulator_init_data
for (i = 0; i < pdata->num_regulators; i++) {
if (pdata->regulators[i].id == id)
- return pdata->regulators[i].platform_data;
+ return pdata->regulators[i].init_data;
}
return NULL;
@@ -415,7 +415,7 @@ static void act8865_power_off(void)
static int act8865_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
- static const struct regulator_desc *regulators;
+ const struct regulator_desc *regulators;
struct act8865_platform_data pdata_of, *pdata;
struct device *dev = &client->dev;
struct device_node **of_node;
diff --git a/drivers/regulator/act8945a-regulator.c b/drivers/regulator/act8945a-regulator.c
new file mode 100644
index 000000000000..441864b9fece
--- /dev/null
+++ b/drivers/regulator/act8945a-regulator.c
@@ -0,0 +1,165 @@
+/*
+ * Voltage regulation driver for active-semi ACT8945A PMIC
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ *
+ * Author: Wenyou Yang <wenyou.yang@atmel.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/**
+ * ACT8945A Global Register Map.
+ */
+#define ACT8945A_SYS_MODE 0x00
+#define ACT8945A_SYS_CTRL 0x01
+#define ACT8945A_DCDC1_VSET1 0x20
+#define ACT8945A_DCDC1_VSET2 0x21
+#define ACT8945A_DCDC1_CTRL 0x22
+#define ACT8945A_DCDC2_VSET1 0x30
+#define ACT8945A_DCDC2_VSET2 0x31
+#define ACT8945A_DCDC2_CTRL 0x32
+#define ACT8945A_DCDC3_VSET1 0x40
+#define ACT8945A_DCDC3_VSET2 0x41
+#define ACT8945A_DCDC3_CTRL 0x42
+#define ACT8945A_LDO1_VSET 0x50
+#define ACT8945A_LDO1_CTRL 0x51
+#define ACT8945A_LDO2_VSET 0x54
+#define ACT8945A_LDO2_CTRL 0x55
+#define ACT8945A_LDO3_VSET 0x60
+#define ACT8945A_LDO3_CTRL 0x61
+#define ACT8945A_LDO4_VSET 0x64
+#define ACT8945A_LDO4_CTRL 0x65
+
+/**
+ * Field Definitions.
+ */
+#define ACT8945A_ENA 0x80 /* ON - [7] */
+#define ACT8945A_VSEL_MASK 0x3F /* VSET - [5:0] */
+
+/**
+ * ACT8945A Voltage Number
+ */
+#define ACT8945A_VOLTAGE_NUM 64
+
+enum {
+ ACT8945A_ID_DCDC1,
+ ACT8945A_ID_DCDC2,
+ ACT8945A_ID_DCDC3,
+ ACT8945A_ID_LDO1,
+ ACT8945A_ID_LDO2,
+ ACT8945A_ID_LDO3,
+ ACT8945A_ID_LDO4,
+ ACT8945A_REG_NUM,
+};
+
+static const struct regulator_linear_range act8945a_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000),
+ REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000),
+ REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
+};
+
+static struct regulator_ops act8945a_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+#define ACT89xx_REG(_name, _family, _id, _vsel_reg, _supply) \
+ [_family##_ID_##_id] = { \
+ .name = _name, \
+ .supply_name = _supply, \
+ .of_match = of_match_ptr("REG_"#_id), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .id = _family##_ID_##_id, \
+ .type = REGULATOR_VOLTAGE, \
+ .ops = &act8945a_ops, \
+ .n_voltages = ACT8945A_VOLTAGE_NUM, \
+ .linear_ranges = act8945a_voltage_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(act8945a_voltage_ranges), \
+ .vsel_reg = _family##_##_id##_##_vsel_reg, \
+ .vsel_mask = ACT8945A_VSEL_MASK, \
+ .enable_reg = _family##_##_id##_CTRL, \
+ .enable_mask = ACT8945A_ENA, \
+ .owner = THIS_MODULE, \
+ }
+
+static const struct regulator_desc act8945a_regulators[] = {
+ ACT89xx_REG("DCDC_REG1", ACT8945A, DCDC1, VSET1, "vp1"),
+ ACT89xx_REG("DCDC_REG2", ACT8945A, DCDC2, VSET1, "vp2"),
+ ACT89xx_REG("DCDC_REG3", ACT8945A, DCDC3, VSET1, "vp3"),
+ ACT89xx_REG("LDO_REG1", ACT8945A, LDO1, VSET, "inl45"),
+ ACT89xx_REG("LDO_REG2", ACT8945A, LDO2, VSET, "inl45"),
+ ACT89xx_REG("LDO_REG3", ACT8945A, LDO3, VSET, "inl67"),
+ ACT89xx_REG("LDO_REG4", ACT8945A, LDO4, VSET, "inl67"),
+};
+
+static const struct regulator_desc act8945a_alt_regulators[] = {
+ ACT89xx_REG("DCDC_REG1", ACT8945A, DCDC1, VSET2, "vp1"),
+ ACT89xx_REG("DCDC_REG2", ACT8945A, DCDC2, VSET2, "vp2"),
+ ACT89xx_REG("DCDC_REG3", ACT8945A, DCDC3, VSET2, "vp3"),
+ ACT89xx_REG("LDO_REG1", ACT8945A, LDO1, VSET, "inl45"),
+ ACT89xx_REG("LDO_REG2", ACT8945A, LDO2, VSET, "inl45"),
+ ACT89xx_REG("LDO_REG3", ACT8945A, LDO3, VSET, "inl67"),
+ ACT89xx_REG("LDO_REG4", ACT8945A, LDO4, VSET, "inl67"),
+};
+
+static int act8945a_pmic_probe(struct platform_device *pdev)
+{
+ struct regulator_config config = { };
+ const struct regulator_desc *regulators;
+ struct regulator_dev *rdev;
+ int i, num_regulators;
+ bool voltage_select;
+
+ voltage_select = of_property_read_bool(pdev->dev.parent->of_node,
+ "active-semi,vsel-high");
+
+ if (voltage_select) {
+ regulators = act8945a_alt_regulators;
+ num_regulators = ARRAY_SIZE(act8945a_alt_regulators);
+ } else {
+ regulators = act8945a_regulators;
+ num_regulators = ARRAY_SIZE(act8945a_regulators);
+ }
+
+ config.dev = &pdev->dev;
+ config.dev->of_node = pdev->dev.parent->of_node;
+ for (i = 0; i < num_regulators; i++) {
+ rdev = devm_regulator_register(&pdev->dev, &regulators[i], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
+ "failed to register %s regulator\n",
+ regulators[i].name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver act8945a_pmic_driver = {
+ .driver = {
+ .name = "act8945a-regulator",
+ },
+ .probe = act8945a_pmic_probe,
+};
+module_platform_driver(act8945a_pmic_driver);
+
+MODULE_DESCRIPTION("Active-semi ACT8945A voltage regulator driver");
+MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index ea50a886ba63..8b0f788a9bbb 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -58,10 +58,12 @@ static int ad5398_write_reg(struct i2c_client *client, const unsigned short data
val = cpu_to_be16(data);
ret = i2c_master_send(client, (char *)&val, 2);
- if (ret < 0)
+ if (ret != 2) {
dev_err(&client->dev, "I2C write error\n");
+ return ret < 0 ? ret : -EIO;
+ }
- return ret;
+ return 0;
}
static int ad5398_get_current_limit(struct regulator_dev *rdev)
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index f2e1a39ce0f3..214e815e98eb 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -39,7 +39,7 @@
#define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
_vmask, _ereg, _emask, _enable_val, _disable_val) \
[_family##_##_id] = { \
- .name = #_id, \
+ .name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
@@ -61,7 +61,7 @@
#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
_vmask, _ereg, _emask) \
[_family##_##_id] = { \
- .name = #_id, \
+ .name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
@@ -78,21 +78,15 @@
.ops = &axp20x_ops, \
}
-#define AXP_DESC_SW(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
- _vmask, _ereg, _emask) \
+#define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \
[_family##_##_id] = { \
- .name = #_id, \
+ .name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = _family##_##_id, \
- .n_voltages = (((_max) - (_min)) / (_step) + 1), \
.owner = THIS_MODULE, \
- .min_uV = (_min) * 1000, \
- .uV_step = (_step) * 1000, \
- .vsel_reg = (_vreg), \
- .vsel_mask = (_vmask), \
.enable_reg = (_ereg), \
.enable_mask = (_emask), \
.ops = &axp20x_ops_sw, \
@@ -100,7 +94,7 @@
#define AXP_DESC_FIXED(_family, _id, _match, _supply, _volt) \
[_family##_##_id] = { \
- .name = #_id, \
+ .name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
@@ -112,39 +106,34 @@
.ops = &axp20x_ops_fixed \
}
-#define AXP_DESC_TABLE(_family, _id, _match, _supply, _table, _vreg, _vmask, \
- _ereg, _emask) \
+#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \
+ _vreg, _vmask, _ereg, _emask) \
[_family##_##_id] = { \
- .name = #_id, \
+ .name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = _family##_##_id, \
- .n_voltages = ARRAY_SIZE(_table), \
+ .n_voltages = (_n_voltages), \
.owner = THIS_MODULE, \
.vsel_reg = (_vreg), \
.vsel_mask = (_vmask), \
.enable_reg = (_ereg), \
.enable_mask = (_emask), \
- .volt_table = (_table), \
- .ops = &axp20x_ops_table, \
+ .linear_ranges = (_ranges), \
+ .n_linear_ranges = ARRAY_SIZE(_ranges), \
+ .ops = &axp20x_ops_range, \
}
-static const int axp20x_ldo4_data[] = { 1250000, 1300000, 1400000, 1500000, 1600000,
- 1700000, 1800000, 1900000, 2000000, 2500000,
- 2700000, 2800000, 3000000, 3100000, 3200000,
- 3300000 };
-
static struct regulator_ops axp20x_ops_fixed = {
.list_voltage = regulator_list_voltage_linear,
};
-static struct regulator_ops axp20x_ops_table = {
+static struct regulator_ops axp20x_ops_range = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .list_voltage = regulator_list_voltage_table,
- .map_voltage = regulator_map_voltage_ascend,
+ .list_voltage = regulator_list_voltage_linear_range,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
@@ -160,13 +149,17 @@ static struct regulator_ops axp20x_ops = {
};
static struct regulator_ops axp20x_ops_sw = {
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .list_voltage = regulator_list_voltage_linear,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
+static const struct regulator_linear_range axp20x_ldo4_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1250000, 0x0, 0x0, 0),
+ REGULATOR_LINEAR_RANGE(1300000, 0x1, 0x8, 100000),
+ REGULATOR_LINEAR_RANGE(2500000, 0x9, 0xf, 100000),
+};
+
static const struct regulator_desc axp20x_regulators[] = {
AXP_DESC(AXP20X, DCDC2, "dcdc2", "vin2", 700, 2275, 25,
AXP20X_DCDC2_V_OUT, 0x3f, AXP20X_PWR_OUT_CTRL, 0x10),
@@ -177,8 +170,9 @@ static const struct regulator_desc axp20x_regulators[] = {
AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04),
AXP_DESC(AXP20X, LDO3, "ldo3", "ldo3in", 700, 3500, 25,
AXP20X_LDO3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x40),
- AXP_DESC_TABLE(AXP20X, LDO4, "ldo4", "ldo24in", axp20x_ldo4_data,
- AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08),
+ AXP_DESC_RANGES(AXP20X, LDO4, "ldo4", "ldo24in", axp20x_ldo4_ranges,
+ 16, AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL,
+ 0x08),
AXP_DESC_IO(AXP20X, LDO5, "ldo5", "ldo5in", 1800, 3300, 100,
AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07,
AXP20X_IO_ENABLED, AXP20X_IO_DISABLED),
@@ -196,8 +190,8 @@ static const struct regulator_desc axp22x_regulators[] = {
AXP_DESC(AXP22X, DCDC5, "dcdc5", "vin5", 1000, 2550, 50,
AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)),
/* secondary switchable output of DCDC1 */
- AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, 1600, 3400, 100,
- AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(7)),
+ AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2,
+ BIT(7)),
/* LDO regulator internally chained to DCDC5 */
AXP_DESC(AXP22X, DC5LDO, "dc5ldo", NULL, 700, 1400, 100,
AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)),
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 744c9889f88d..e0b764284773 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1057,18 +1057,18 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = machine_constraints_voltage(rdev, rdev->constraints);
if (ret != 0)
- goto out;
+ return ret;
ret = machine_constraints_current(rdev, rdev->constraints);
if (ret != 0)
- goto out;
+ return ret;
if (rdev->constraints->ilim_uA && ops->set_input_current_limit) {
ret = ops->set_input_current_limit(rdev,
rdev->constraints->ilim_uA);
if (ret < 0) {
rdev_err(rdev, "failed to set input limit\n");
- goto out;
+ return ret;
}
}
@@ -1077,21 +1077,20 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = suspend_prepare(rdev, rdev->constraints->initial_state);
if (ret < 0) {
rdev_err(rdev, "failed to set suspend state\n");
- goto out;
+ return ret;
}
}
if (rdev->constraints->initial_mode) {
if (!ops->set_mode) {
rdev_err(rdev, "no set_mode operation\n");
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
ret = ops->set_mode(rdev, rdev->constraints->initial_mode);
if (ret < 0) {
rdev_err(rdev, "failed to set initial mode: %d\n", ret);
- goto out;
+ return ret;
}
}
@@ -1102,7 +1101,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = _regulator_do_enable(rdev);
if (ret < 0 && ret != -EINVAL) {
rdev_err(rdev, "failed to enable\n");
- goto out;
+ return ret;
}
}
@@ -1111,7 +1110,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
if (ret < 0) {
rdev_err(rdev, "failed to set ramp_delay\n");
- goto out;
+ return ret;
}
}
@@ -1119,7 +1118,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = ops->set_pull_down(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to set pull down\n");
- goto out;
+ return ret;
}
}
@@ -1127,7 +1126,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = ops->set_soft_start(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to set soft start\n");
- goto out;
+ return ret;
}
}
@@ -1136,16 +1135,34 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = ops->set_over_current_protection(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to set over current protection\n");
- goto out;
+ return ret;
+ }
+ }
+
+ if (rdev->constraints->active_discharge && ops->set_active_discharge) {
+ bool ad_state = (rdev->constraints->active_discharge ==
+ REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
+
+ ret = ops->set_active_discharge(rdev, ad_state);
+ if (ret < 0) {
+ rdev_err(rdev, "failed to set active discharge\n");
+ return ret;
+ }
+ }
+
+ if (rdev->constraints->active_discharge && ops->set_active_discharge) {
+ bool ad_state = (rdev->constraints->active_discharge ==
+ REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
+
+ ret = ops->set_active_discharge(rdev, ad_state);
+ if (ret < 0) {
+ rdev_err(rdev, "failed to set active discharge\n");
+ return ret;
}
}
print_constraints(rdev);
return 0;
-out:
- kfree(rdev->constraints);
- rdev->constraints = NULL;
- return ret;
}
/**
@@ -3918,6 +3935,16 @@ regulator_register(const struct regulator_desc *regulator_desc,
goto clean;
}
+ if ((config->ena_gpio || config->ena_gpio_initialized) &&
+ gpio_is_valid(config->ena_gpio)) {
+ ret = regulator_ena_gpio_request(rdev, config);
+ if (ret != 0) {
+ rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
+ config->ena_gpio, ret);
+ goto clean;
+ }
+ }
+
/* register with sysfs */
rdev->dev.class = &regulator_class;
rdev->dev.parent = dev;
@@ -3926,21 +3953,11 @@ regulator_register(const struct regulator_desc *regulator_desc,
ret = device_register(&rdev->dev);
if (ret != 0) {
put_device(&rdev->dev);
- goto clean;
+ goto wash;
}
dev_set_drvdata(&rdev->dev, rdev);
- if ((config->ena_gpio || config->ena_gpio_initialized) &&
- gpio_is_valid(config->ena_gpio)) {
- ret = regulator_ena_gpio_request(rdev, config);
- if (ret != 0) {
- rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
- config->ena_gpio, ret);
- goto wash;
- }
- }
-
/* set regulator constraints */
if (init_data)
constraints = &init_data->constraints;
@@ -3979,13 +3996,13 @@ unset_supplies:
scrub:
regulator_ena_gpio_free(rdev);
- kfree(rdev->constraints);
-wash:
device_unregister(&rdev->dev);
/* device core frees rdev */
rdev = ERR_PTR(ret);
goto out;
+wash:
+ regulator_ena_gpio_free(rdev);
clean:
kfree(rdev);
rdev = ERR_PTR(ret);
diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c
index 8b3cc9f0cd64..01c0e3709b66 100644
--- a/drivers/regulator/da9210-regulator.c
+++ b/drivers/regulator/da9210-regulator.c
@@ -132,6 +132,8 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
if (error < 0)
goto error_i2c;
+ mutex_lock(&chip->rdev->mutex);
+
if (val & DA9210_E_OVCURR) {
regulator_notifier_call_chain(chip->rdev,
REGULATOR_EVENT_OVER_CURRENT,
@@ -155,6 +157,9 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
NULL);
handled |= DA9210_E_VMAX;
}
+
+ mutex_unlock(&chip->rdev->mutex);
+
if (handled) {
/* Clear handled events */
error = regmap_write(chip->regmap, DA9210_REG_EVENT_B, handled);
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index 4940e8287df6..2cb5cc311610 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -114,6 +114,22 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
return 0;
}
+static int fan53555_set_suspend_enable(struct regulator_dev *rdev)
+{
+ struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+
+ return regmap_update_bits(di->regmap, di->sleep_reg,
+ VSEL_BUCK_EN, VSEL_BUCK_EN);
+}
+
+static int fan53555_set_suspend_disable(struct regulator_dev *rdev)
+{
+ struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+
+ return regmap_update_bits(di->regmap, di->sleep_reg,
+ VSEL_BUCK_EN, 0);
+}
+
static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct fan53555_device_info *di = rdev_get_drvdata(rdev);
@@ -192,6 +208,8 @@ static struct regulator_ops fan53555_regulator_ops = {
.set_mode = fan53555_set_mode,
.get_mode = fan53555_get_mode,
.set_ramp_delay = fan53555_set_ramp,
+ .set_suspend_enable = fan53555_set_suspend_enable,
+ .set_suspend_disable = fan53555_set_suspend_disable,
};
static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index 7bba8b747f30..a8718e98674a 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -283,8 +283,10 @@ static int gpio_regulator_probe(struct platform_device *pdev)
drvdata->nr_gpios = config->nr_gpios;
ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
if (ret) {
- dev_err(&pdev->dev,
- "Could not obtain regulator setting GPIOs: %d\n", ret);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "Could not obtain regulator setting GPIOs: %d\n",
+ ret);
goto err_memstate;
}
}
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index 3bbb32680a94..b1e32e7482e9 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -465,3 +465,26 @@ int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
return 0;
}
EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
+
+/**
+ * regulator_set_active_discharge_regmap - Default set_active_discharge()
+ * using regmap
+ *
+ * @rdev: device to operate on.
+ * @enable: state to set, 0 to disable and 1 to enable.
+ */
+int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
+ bool enable)
+{
+ unsigned int val;
+
+ if (enable)
+ val = rdev->desc->active_discharge_on;
+ else
+ val = rdev->desc->active_discharge_off;
+
+ return regmap_update_bits(rdev->regmap,
+ rdev->desc->active_discharge_reg,
+ rdev->desc->active_discharge_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_set_active_discharge_regmap);
diff --git a/drivers/regulator/hi655x-regulator.c b/drivers/regulator/hi655x-regulator.c
new file mode 100644
index 000000000000..aca18466f522
--- /dev/null
+++ b/drivers/regulator/hi655x-regulator.c
@@ -0,0 +1,227 @@
+/*
+ * Device driver for regulators in Hi655x IC
+ *
+ * Copyright (c) 2016 Hisilicon.
+ *
+ * Authors:
+ * Chen Feng <puck.chen@hisilicon.com>
+ * Fei Wang <w.f@huawei.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/hi655x-pmic.h>
+
+struct hi655x_regulator {
+ unsigned int disable_reg;
+ unsigned int status_reg;
+ unsigned int ctrl_regs;
+ unsigned int ctrl_mask;
+ struct regulator_desc rdesc;
+};
+
+/* LDO7 & LDO10 */
+static const unsigned int ldo7_voltages[] = {
+ 1800000, 1850000, 2850000, 2900000,
+ 3000000, 3100000, 3200000, 3300000,
+};
+
+static const unsigned int ldo19_voltages[] = {
+ 1800000, 1850000, 1900000, 1750000,
+ 2800000, 2850000, 2900000, 3000000,
+};
+
+static const unsigned int ldo22_voltages[] = {
+ 900000, 1000000, 1050000, 1100000,
+ 1150000, 1175000, 1185000, 1200000,
+};
+
+enum hi655x_regulator_id {
+ HI655X_LDO0,
+ HI655X_LDO1,
+ HI655X_LDO2,
+ HI655X_LDO3,
+ HI655X_LDO4,
+ HI655X_LDO5,
+ HI655X_LDO6,
+ HI655X_LDO7,
+ HI655X_LDO8,
+ HI655X_LDO9,
+ HI655X_LDO10,
+ HI655X_LDO11,
+ HI655X_LDO12,
+ HI655X_LDO13,
+ HI655X_LDO14,
+ HI655X_LDO15,
+ HI655X_LDO16,
+ HI655X_LDO17,
+ HI655X_LDO18,
+ HI655X_LDO19,
+ HI655X_LDO20,
+ HI655X_LDO21,
+ HI655X_LDO22,
+};
+
+static int hi655x_is_enabled(struct regulator_dev *rdev)
+{
+ unsigned int value = 0;
+
+ struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
+
+ regmap_read(rdev->regmap, regulator->status_reg, &value);
+ return (value & BIT(regulator->ctrl_mask));
+}
+
+static int hi655x_disable(struct regulator_dev *rdev)
+{
+ int ret = 0;
+
+ struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
+
+ ret = regmap_write(rdev->regmap, regulator->disable_reg,
+ BIT(regulator->ctrl_mask));
+ return ret;
+}
+
+static struct regulator_ops hi655x_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = hi655x_disable,
+ .is_enabled = hi655x_is_enabled,
+ .list_voltage = regulator_list_voltage_table,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static struct regulator_ops hi655x_ldo_linear_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = hi655x_disable,
+ .is_enabled = hi655x_is_enabled,
+ .list_voltage = regulator_list_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+#define HI655X_LDO(_ID, vreg, vmask, ereg, dreg, \
+ sreg, cmask, vtable) { \
+ .rdesc = { \
+ .name = #_ID, \
+ .of_match = of_match_ptr(#_ID), \
+ .ops = &hi655x_regulator_ops, \
+ .regulators_node = of_match_ptr("regulators"), \
+ .type = REGULATOR_VOLTAGE, \
+ .id = HI655X_##_ID, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(vtable), \
+ .volt_table = vtable, \
+ .vsel_reg = HI655X_BUS_ADDR(vreg), \
+ .vsel_mask = vmask, \
+ .enable_reg = HI655X_BUS_ADDR(ereg), \
+ .enable_mask = BIT(cmask), \
+ }, \
+ .disable_reg = HI655X_BUS_ADDR(dreg), \
+ .status_reg = HI655X_BUS_ADDR(sreg), \
+ .ctrl_mask = cmask, \
+}
+
+#define HI655X_LDO_LINEAR(_ID, vreg, vmask, ereg, dreg, \
+ sreg, cmask, minv, nvolt, vstep) { \
+ .rdesc = { \
+ .name = #_ID, \
+ .of_match = of_match_ptr(#_ID), \
+ .ops = &hi655x_ldo_linear_ops, \
+ .regulators_node = of_match_ptr("regulators"), \
+ .type = REGULATOR_VOLTAGE, \
+ .id = HI655X_##_ID, \
+ .owner = THIS_MODULE, \
+ .min_uV = minv, \
+ .n_voltages = nvolt, \
+ .uV_step = vstep, \
+ .vsel_reg = HI655X_BUS_ADDR(vreg), \
+ .vsel_mask = vmask, \
+ .enable_reg = HI655X_BUS_ADDR(ereg), \
+ .enable_mask = BIT(cmask), \
+ }, \
+ .disable_reg = HI655X_BUS_ADDR(dreg), \
+ .status_reg = HI655X_BUS_ADDR(sreg), \
+ .ctrl_mask = cmask, \
+}
+
+static struct hi655x_regulator regulators[] = {
+ HI655X_LDO_LINEAR(LDO2, 0x72, 0x07, 0x29, 0x2a, 0x2b, 0x01,
+ 2500000, 8, 100000),
+ HI655X_LDO(LDO7, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x06, ldo7_voltages),
+ HI655X_LDO(LDO10, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x01, ldo7_voltages),
+ HI655X_LDO_LINEAR(LDO13, 0x7e, 0x07, 0x2c, 0x2d, 0x2e, 0x04,
+ 1600000, 8, 50000),
+ HI655X_LDO_LINEAR(LDO14, 0x7f, 0x07, 0x2c, 0x2d, 0x2e, 0x05,
+ 2500000, 8, 100000),
+ HI655X_LDO_LINEAR(LDO15, 0x80, 0x07, 0x2c, 0x2d, 0x2e, 0x06,
+ 1600000, 8, 50000),
+ HI655X_LDO_LINEAR(LDO17, 0x82, 0x07, 0x2f, 0x30, 0x31, 0x00,
+ 2500000, 8, 100000),
+ HI655X_LDO(LDO19, 0x84, 0x07, 0x2f, 0x30, 0x31, 0x02, ldo19_voltages),
+ HI655X_LDO_LINEAR(LDO21, 0x86, 0x07, 0x2f, 0x30, 0x31, 0x04,
+ 1650000, 8, 50000),
+ HI655X_LDO(LDO22, 0x87, 0x07, 0x2f, 0x30, 0x31, 0x05, ldo22_voltages),
+};
+
+static int hi655x_regulator_probe(struct platform_device *pdev)
+{
+ unsigned int i;
+ struct hi655x_regulator *regulator;
+ struct hi655x_pmic *pmic;
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+
+ pmic = dev_get_drvdata(pdev->dev.parent);
+ if (!pmic) {
+ dev_err(&pdev->dev, "no pmic in the regulator parent node\n");
+ return -ENODEV;
+ }
+
+ regulator = devm_kzalloc(&pdev->dev, sizeof(*regulator), GFP_KERNEL);
+ if (!regulator)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, regulator);
+
+ config.dev = pdev->dev.parent;
+ config.regmap = pmic->regmap;
+ config.driver_data = regulator;
+ for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+ rdev = devm_regulator_register(&pdev->dev,
+ &regulators[i].rdesc,
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ regulator->rdesc.name);
+ return PTR_ERR(rdev);
+ }
+ }
+ return 0;
+}
+
+static struct platform_driver hi655x_regulator_driver = {
+ .driver = {
+ .name = "hi655x-regulator",
+ },
+ .probe = hi655x_regulator_probe,
+};
+module_platform_driver(hi655x_regulator_driver);
+
+MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>");
+MODULE_DESCRIPTION("Hisilicon Hi655x regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index 19d758486553..38992112fd6e 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -15,6 +15,7 @@
#include <linux/regmap.h>
#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/delay.h>
#include <linux/regulator/lp872x.h>
#include <linux/regulator/driver.h>
#include <linux/platform_device.h>
@@ -738,10 +739,8 @@ static int lp872x_init_dvs(struct lp872x *lp)
goto set_default_dvs_mode;
gpio = dvs->gpio;
- if (!gpio_is_valid(gpio)) {
- dev_warn(lp->dev, "invalid gpio: %d\n", gpio);
+ if (!gpio_is_valid(gpio))
goto set_default_dvs_mode;
- }
pinstate = dvs->init_state;
ret = devm_gpio_request_one(lp->dev, gpio, pinstate, "LP872X DVS");
@@ -759,6 +758,33 @@ set_default_dvs_mode:
default_dvs_mode[lp->chipid]);
}
+static int lp872x_hw_enable(struct lp872x *lp)
+{
+ int ret, gpio;
+
+ if (!lp->pdata)
+ return -EINVAL;
+
+ gpio = lp->pdata->enable_gpio;
+ if (!gpio_is_valid(gpio))
+ return 0;
+
+ /* Always set enable GPIO high. */
+ ret = devm_gpio_request_one(lp->dev, gpio, GPIOF_OUT_INIT_HIGH, "LP872X EN");
+ if (ret) {
+ dev_err(lp->dev, "gpio request err: %d\n", ret);
+ return ret;
+ }
+
+ /* Each chip has a different enable delay. */
+ if (lp->chipid == LP8720)
+ usleep_range(LP8720_ENABLE_DELAY, 1.5 * LP8720_ENABLE_DELAY);
+ else
+ usleep_range(LP8725_ENABLE_DELAY, 1.5 * LP8725_ENABLE_DELAY);
+
+ return 0;
+}
+
static int lp872x_config(struct lp872x *lp)
{
struct lp872x_platform_data *pdata = lp->pdata;
@@ -877,6 +903,8 @@ static struct lp872x_platform_data
of_property_read_u8(np, "ti,dvs-state", &dvs_state);
pdata->dvs->init_state = dvs_state ? DVS_HIGH : DVS_LOW;
+ pdata->enable_gpio = of_get_named_gpio(np, "enable-gpios", 0);
+
if (of_get_child_count(np) == 0)
goto out;
@@ -950,6 +978,10 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
lp->chipid = id->driver_data;
i2c_set_clientdata(cl, lp);
+ ret = lp872x_hw_enable(lp);
+ if (ret)
+ return ret;
+
ret = lp872x_config(lp);
if (ret)
return ret;
diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c
index 972c386b2690..47bef328fb58 100644
--- a/drivers/regulator/ltc3589.c
+++ b/drivers/regulator/ltc3589.c
@@ -520,12 +520,15 @@ static int ltc3589_probe(struct i2c_client *client,
}
}
- ret = devm_request_threaded_irq(dev, client->irq, NULL, ltc3589_isr,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- client->name, ltc3589);
- if (ret) {
- dev_err(dev, "Failed to request IRQ: %d\n", ret);
- return ret;
+ if (client->irq) {
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ ltc3589_isr,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ client->name, ltc3589);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ: %d\n", ret);
+ return ret;
+ }
}
return 0;
diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c
new file mode 100644
index 000000000000..73a3356a5c19
--- /dev/null
+++ b/drivers/regulator/max77620-regulator.c
@@ -0,0 +1,813 @@
+/*
+ * Maxim MAX77620 Regulator driver
+ *
+ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author: Mallikarjun Kasoju <mkasoju@nvidia.com>
+ * Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/mfd/max77620.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define max77620_rails(_name) "max77620-"#_name
+
+/* Power Mode */
+#define MAX77620_POWER_MODE_NORMAL 3
+#define MAX77620_POWER_MODE_LPM 2
+#define MAX77620_POWER_MODE_GLPM 1
+#define MAX77620_POWER_MODE_DISABLE 0
+
+/* SD Slew Rate */
+#define MAX77620_SD_SR_13_75 0
+#define MAX77620_SD_SR_27_5 1
+#define MAX77620_SD_SR_55 2
+#define MAX77620_SD_SR_100 3
+
+enum max77620_regulators {
+ MAX77620_REGULATOR_ID_SD0,
+ MAX77620_REGULATOR_ID_SD1,
+ MAX77620_REGULATOR_ID_SD2,
+ MAX77620_REGULATOR_ID_SD3,
+ MAX77620_REGULATOR_ID_SD4,
+ MAX77620_REGULATOR_ID_LDO0,
+ MAX77620_REGULATOR_ID_LDO1,
+ MAX77620_REGULATOR_ID_LDO2,
+ MAX77620_REGULATOR_ID_LDO3,
+ MAX77620_REGULATOR_ID_LDO4,
+ MAX77620_REGULATOR_ID_LDO5,
+ MAX77620_REGULATOR_ID_LDO6,
+ MAX77620_REGULATOR_ID_LDO7,
+ MAX77620_REGULATOR_ID_LDO8,
+ MAX77620_NUM_REGS,
+};
+
+/* Regulator types */
+enum max77620_regulator_type {
+ MAX77620_REGULATOR_TYPE_SD,
+ MAX77620_REGULATOR_TYPE_LDO_N,
+ MAX77620_REGULATOR_TYPE_LDO_P,
+};
+
+struct max77620_regulator_info {
+ u8 type;
+ u8 fps_addr;
+ u8 volt_addr;
+ u8 cfg_addr;
+ u8 power_mode_mask;
+ u8 power_mode_shift;
+ u8 remote_sense_addr;
+ u8 remote_sense_mask;
+ struct regulator_desc desc;
+};
+
+struct max77620_regulator_pdata {
+ struct regulator_init_data *reg_idata;
+ int active_fps_src;
+ int active_fps_pd_slot;
+ int active_fps_pu_slot;
+ int suspend_fps_src;
+ int suspend_fps_pd_slot;
+ int suspend_fps_pu_slot;
+ int current_mode;
+};
+
+struct max77620_regulator {
+ struct device *dev;
+ struct regmap *rmap;
+ struct max77620_regulator_info *rinfo[MAX77620_NUM_REGS];
+ struct max77620_regulator_pdata reg_pdata[MAX77620_NUM_REGS];
+ int enable_power_mode[MAX77620_NUM_REGS];
+ int current_power_mode[MAX77620_NUM_REGS];
+ int active_fps_src[MAX77620_NUM_REGS];
+};
+
+#define fps_src_name(fps_src) \
+ (fps_src == MAX77620_FPS_SRC_0 ? "FPS_SRC_0" : \
+ fps_src == MAX77620_FPS_SRC_1 ? "FPS_SRC_1" : \
+ fps_src == MAX77620_FPS_SRC_2 ? "FPS_SRC_2" : "FPS_SRC_NONE")
+
+static int max77620_regulator_get_fps_src(struct max77620_regulator *pmic,
+ int id)
+{
+ struct max77620_regulator_info *rinfo = pmic->rinfo[id];
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val);
+ if (ret < 0) {
+ dev_err(pmic->dev, "Reg 0x%02x read failed %d\n",
+ rinfo->fps_addr, ret);
+ return ret;
+ }
+
+ return (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT;
+}
+
+static int max77620_regulator_set_fps_src(struct max77620_regulator *pmic,
+ int fps_src, int id)
+{
+ struct max77620_regulator_info *rinfo = pmic->rinfo[id];
+ unsigned int val;
+ int ret;
+
+ switch (fps_src) {
+ case MAX77620_FPS_SRC_0:
+ case MAX77620_FPS_SRC_1:
+ case MAX77620_FPS_SRC_2:
+ case MAX77620_FPS_SRC_NONE:
+ break;
+
+ case MAX77620_FPS_SRC_DEF:
+ ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val);
+ if (ret < 0) {
+ dev_err(pmic->dev, "Reg 0x%02x read failed %d\n",
+ rinfo->fps_addr, ret);
+ return ret;
+ }
+ ret = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT;
+ pmic->active_fps_src[id] = ret;
+ return 0;
+
+ default:
+ dev_err(pmic->dev, "Invalid FPS %d for regulator %d\n",
+ fps_src, id);
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(pmic->rmap, rinfo->fps_addr,
+ MAX77620_FPS_SRC_MASK,
+ fps_src << MAX77620_FPS_SRC_SHIFT);
+ if (ret < 0) {
+ dev_err(pmic->dev, "Reg 0x%02x update failed %d\n",
+ rinfo->fps_addr, ret);
+ return ret;
+ }
+ pmic->active_fps_src[id] = fps_src;
+
+ return 0;
+}
+
+static int max77620_regulator_set_fps_slots(struct max77620_regulator *pmic,
+ int id, bool is_suspend)
+{
+ struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
+ struct max77620_regulator_info *rinfo = pmic->rinfo[id];
+ unsigned int val = 0;
+ unsigned int mask = 0;
+ int pu = rpdata->active_fps_pu_slot;
+ int pd = rpdata->active_fps_pd_slot;
+ int ret = 0;
+
+ if (is_suspend) {
+ pu = rpdata->suspend_fps_pu_slot;
+ pd = rpdata->suspend_fps_pd_slot;
+ }
+
+ /* FPS power up period setting */
+ if (pu >= 0) {
+ val |= (pu << MAX77620_FPS_PU_PERIOD_SHIFT);
+ mask |= MAX77620_FPS_PU_PERIOD_MASK;
+ }
+
+ /* FPS power down period setting */
+ if (pd >= 0) {
+ val |= (pd << MAX77620_FPS_PD_PERIOD_SHIFT);
+ mask |= MAX77620_FPS_PD_PERIOD_MASK;
+ }
+
+ if (mask) {
+ ret = regmap_update_bits(pmic->rmap, rinfo->fps_addr,
+ mask, val);
+ if (ret < 0) {
+ dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n",
+ rinfo->fps_addr, ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int max77620_regulator_set_power_mode(struct max77620_regulator *pmic,
+ int power_mode, int id)
+{
+ struct max77620_regulator_info *rinfo = pmic->rinfo[id];
+ u8 mask = rinfo->power_mode_mask;
+ u8 shift = rinfo->power_mode_shift;
+ u8 addr;
+ int ret;
+
+ switch (rinfo->type) {
+ case MAX77620_REGULATOR_TYPE_SD:
+ addr = rinfo->cfg_addr;
+ break;
+ default:
+ addr = rinfo->volt_addr;
+ break;
+ }
+
+ ret = regmap_update_bits(pmic->rmap, addr, mask, power_mode << shift);
+ if (ret < 0) {
+ dev_err(pmic->dev, "Regulator %d mode set failed: %d\n",
+ id, ret);
+ return ret;
+ }
+ pmic->current_power_mode[id] = power_mode;
+
+ return ret;
+}
+
+static int max77620_regulator_get_power_mode(struct max77620_regulator *pmic,
+ int id)
+{
+ struct max77620_regulator_info *rinfo = pmic->rinfo[id];
+ unsigned int val, addr;
+ u8 mask = rinfo->power_mode_mask;
+ u8 shift = rinfo->power_mode_shift;
+ int ret;
+
+ switch (rinfo->type) {
+ case MAX77620_REGULATOR_TYPE_SD:
+ addr = rinfo->cfg_addr;
+ break;
+ default:
+ addr = rinfo->volt_addr;
+ break;
+ }
+
+ ret = regmap_read(pmic->rmap, addr, &val);
+ if (ret < 0) {
+ dev_err(pmic->dev, "Regulator %d: Reg 0x%02x read failed: %d\n",
+ id, addr, ret);
+ return ret;
+ }
+
+ return (val & mask) >> shift;
+}
+
+static int max77620_read_slew_rate(struct max77620_regulator *pmic, int id)
+{
+ struct max77620_regulator_info *rinfo = pmic->rinfo[id];
+ unsigned int rval;
+ int slew_rate;
+ int ret;
+
+ ret = regmap_read(pmic->rmap, rinfo->cfg_addr, &rval);
+ if (ret < 0) {
+ dev_err(pmic->dev, "Register 0x%02x read failed: %d\n",
+ rinfo->cfg_addr, ret);
+ return ret;
+ }
+
+ switch (rinfo->type) {
+ case MAX77620_REGULATOR_TYPE_SD:
+ slew_rate = (rval >> MAX77620_SD_SR_SHIFT) & 0x3;
+ switch (slew_rate) {
+ case 0:
+ slew_rate = 13750;
+ break;
+ case 1:
+ slew_rate = 27500;
+ break;
+ case 2:
+ slew_rate = 55000;
+ break;
+ case 3:
+ slew_rate = 100000;
+ break;
+ }
+ rinfo->desc.ramp_delay = slew_rate;
+ break;
+ default:
+ slew_rate = rval & 0x1;
+ switch (slew_rate) {
+ case 0:
+ slew_rate = 100000;
+ break;
+ case 1:
+ slew_rate = 5000;
+ break;
+ }
+ rinfo->desc.ramp_delay = slew_rate;
+ break;
+ }
+
+ return 0;
+}
+
+static int max77620_init_pmic(struct max77620_regulator *pmic, int id)
+{
+ struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
+ int ret;
+
+ /* Update power mode */
+ ret = max77620_regulator_get_power_mode(pmic, id);
+ if (ret < 0)
+ return ret;
+
+ pmic->current_power_mode[id] = ret;
+ pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL;
+
+ if (rpdata->active_fps_src == MAX77620_FPS_SRC_DEF) {
+ ret = max77620_regulator_get_fps_src(pmic, id);
+ if (ret < 0)
+ return ret;
+ rpdata->active_fps_src = ret;
+ }
+
+ /* If rails are externally control of FPS then enable it always. */
+ if (rpdata->active_fps_src == MAX77620_FPS_SRC_NONE) {
+ ret = max77620_regulator_set_power_mode(pmic,
+ pmic->enable_power_mode[id], id);
+ if (ret < 0)
+ return ret;
+ } else {
+ if (pmic->current_power_mode[id] !=
+ pmic->enable_power_mode[id]) {
+ ret = max77620_regulator_set_power_mode(pmic,
+ pmic->enable_power_mode[id], id);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ ret = max77620_regulator_set_fps_src(pmic, rpdata->active_fps_src, id);
+ if (ret < 0)
+ return ret;
+
+ ret = max77620_regulator_set_fps_slots(pmic, id, false);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int max77620_regulator_enable(struct regulator_dev *rdev)
+{
+ struct max77620_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+
+ if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE)
+ return 0;
+
+ return max77620_regulator_set_power_mode(pmic,
+ pmic->enable_power_mode[id], id);
+}
+
+static int max77620_regulator_disable(struct regulator_dev *rdev)
+{
+ struct max77620_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+
+ if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE)
+ return 0;
+
+ return max77620_regulator_set_power_mode(pmic,
+ MAX77620_POWER_MODE_DISABLE, id);
+}
+
+static int max77620_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct max77620_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int ret = 1;
+
+ if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE)
+ return 1;
+
+ ret = max77620_regulator_get_power_mode(pmic, id);
+ if (ret < 0)
+ return ret;
+
+ if (ret != MAX77620_POWER_MODE_DISABLE)
+ return 1;
+
+ return 0;
+}
+
+static int max77620_regulator_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct max77620_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ struct max77620_regulator_info *rinfo = pmic->rinfo[id];
+ struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
+ bool fpwm = false;
+ int power_mode;
+ int ret;
+ u8 val;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ fpwm = true;
+ power_mode = MAX77620_POWER_MODE_NORMAL;
+ break;
+
+ case REGULATOR_MODE_NORMAL:
+ power_mode = MAX77620_POWER_MODE_NORMAL;
+ break;
+
+ case REGULATOR_MODE_IDLE:
+ power_mode = MAX77620_POWER_MODE_LPM;
+ break;
+
+ default:
+ dev_err(pmic->dev, "Regulator %d mode %d is invalid\n",
+ id, mode);
+ return -EINVAL;
+ }
+
+ if (rinfo->type != MAX77620_REGULATOR_TYPE_SD)
+ goto skip_fpwm;
+
+ val = (fpwm) ? MAX77620_SD_FPWM_MASK : 0;
+ ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr,
+ MAX77620_SD_FPWM_MASK, val);
+ if (ret < 0) {
+ dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n",
+ rinfo->cfg_addr, ret);
+ return ret;
+ }
+ rpdata->current_mode = mode;
+
+skip_fpwm:
+ ret = max77620_regulator_set_power_mode(pmic, power_mode, id);
+ if (ret < 0)
+ return ret;
+
+ pmic->enable_power_mode[id] = power_mode;
+
+ return 0;
+}
+
+static unsigned int max77620_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct max77620_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ struct max77620_regulator_info *rinfo = pmic->rinfo[id];
+ int fpwm = 0;
+ int ret;
+ int pm_mode, reg_mode;
+ unsigned int val;
+
+ ret = max77620_regulator_get_power_mode(pmic, id);
+ if (ret < 0)
+ return 0;
+
+ pm_mode = ret;
+
+ if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) {
+ ret = regmap_read(pmic->rmap, rinfo->cfg_addr, &val);
+ if (ret < 0) {
+ dev_err(pmic->dev, "Reg 0x%02x read failed: %d\n",
+ rinfo->cfg_addr, ret);
+ return ret;
+ }
+ fpwm = !!(val & MAX77620_SD_FPWM_MASK);
+ }
+
+ switch (pm_mode) {
+ case MAX77620_POWER_MODE_NORMAL:
+ case MAX77620_POWER_MODE_DISABLE:
+ if (fpwm)
+ reg_mode = REGULATOR_MODE_FAST;
+ else
+ reg_mode = REGULATOR_MODE_NORMAL;
+ break;
+ case MAX77620_POWER_MODE_LPM:
+ case MAX77620_POWER_MODE_GLPM:
+ reg_mode = REGULATOR_MODE_IDLE;
+ break;
+ default:
+ return 0;
+ }
+
+ return reg_mode;
+}
+
+static int max77620_regulator_set_ramp_delay(struct regulator_dev *rdev,
+ int ramp_delay)
+{
+ struct max77620_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ struct max77620_regulator_info *rinfo = pmic->rinfo[id];
+ int ret, val;
+ u8 mask;
+
+ if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) {
+ if (ramp_delay <= 13750)
+ val = 0;
+ else if (ramp_delay <= 27500)
+ val = 1;
+ else if (ramp_delay <= 55000)
+ val = 2;
+ else
+ val = 3;
+ val <<= MAX77620_SD_SR_SHIFT;
+ mask = MAX77620_SD_SR_MASK;
+ } else {
+ if (ramp_delay <= 5000)
+ val = 1;
+ else
+ val = 0;
+ mask = MAX77620_LDO_SLEW_RATE_MASK;
+ }
+
+ ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, mask, val);
+ if (ret < 0)
+ dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n",
+ rinfo->cfg_addr, ret);
+
+ return ret;
+}
+
+static int max77620_of_parse_cb(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ struct max77620_regulator *pmic = config->driver_data;
+ struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[desc->id];
+ u32 pval;
+ int ret;
+
+ ret = of_property_read_u32(np, "maxim,active-fps-source", &pval);
+ rpdata->active_fps_src = (!ret) ? pval : MAX77620_FPS_SRC_DEF;
+
+ ret = of_property_read_u32(np, "maxim,active-fps-power-up-slot", &pval);
+ rpdata->active_fps_pu_slot = (!ret) ? pval : -1;
+
+ ret = of_property_read_u32(
+ np, "maxim,active-fps-power-down-slot", &pval);
+ rpdata->active_fps_pd_slot = (!ret) ? pval : -1;
+
+ ret = of_property_read_u32(np, "maxim,suspend-fps-source", &pval);
+ rpdata->suspend_fps_src = (!ret) ? pval : -1;
+
+ ret = of_property_read_u32(
+ np, "maxim,suspend-fps-power-up-slot", &pval);
+ rpdata->suspend_fps_pu_slot = (!ret) ? pval : -1;
+
+ ret = of_property_read_u32(
+ np, "maxim,suspend-fps-power-down-slot", &pval);
+ rpdata->suspend_fps_pd_slot = (!ret) ? pval : -1;
+
+ return max77620_init_pmic(pmic, desc->id);
+}
+
+static struct regulator_ops max77620_regulator_ops = {
+ .is_enabled = max77620_regulator_is_enabled,
+ .enable = max77620_regulator_enable,
+ .disable = max77620_regulator_disable,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_mode = max77620_regulator_set_mode,
+ .get_mode = max77620_regulator_get_mode,
+ .set_ramp_delay = max77620_regulator_set_ramp_delay,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_active_discharge = regulator_set_active_discharge_regmap,
+};
+
+#define MAX77620_SD_CNF2_ROVS_EN_NONE 0
+#define RAIL_SD(_id, _name, _sname, _volt_mask, _min_uV, _max_uV, \
+ _step_uV, _rs_add, _rs_mask) \
+ [MAX77620_REGULATOR_ID_##_id] = { \
+ .type = MAX77620_REGULATOR_TYPE_SD, \
+ .volt_addr = MAX77620_REG_##_id, \
+ .cfg_addr = MAX77620_REG_##_id##_CFG, \
+ .fps_addr = MAX77620_REG_FPS_##_id, \
+ .remote_sense_addr = _rs_add, \
+ .remote_sense_mask = MAX77620_SD_CNF2_ROVS_EN_##_rs_mask, \
+ .power_mode_mask = MAX77620_SD_POWER_MODE_MASK, \
+ .power_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, \
+ .desc = { \
+ .name = max77620_rails(_name), \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .of_parse_cb = max77620_of_parse_cb, \
+ .supply_name = _sname, \
+ .id = MAX77620_REGULATOR_ID_##_id, \
+ .ops = &max77620_regulator_ops, \
+ .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \
+ .min_uV = _min_uV, \
+ .uV_step = _step_uV, \
+ .enable_time = 500, \
+ .vsel_mask = MAX77620_##_volt_mask##_VOLT_MASK, \
+ .vsel_reg = MAX77620_REG_##_id, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = MAX77620_SD_CFG1_ADE_ENABLE, \
+ .active_discharge_mask = MAX77620_SD_CFG1_ADE_MASK, \
+ .active_discharge_reg = MAX77620_REG_##_id##_CFG, \
+ .type = REGULATOR_VOLTAGE, \
+ }, \
+ }
+
+#define RAIL_LDO(_id, _name, _sname, _type, _min_uV, _max_uV, _step_uV) \
+ [MAX77620_REGULATOR_ID_##_id] = { \
+ .type = MAX77620_REGULATOR_TYPE_LDO_##_type, \
+ .volt_addr = MAX77620_REG_##_id##_CFG, \
+ .cfg_addr = MAX77620_REG_##_id##_CFG2, \
+ .fps_addr = MAX77620_REG_FPS_##_id, \
+ .remote_sense_addr = 0xFF, \
+ .power_mode_mask = MAX77620_LDO_POWER_MODE_MASK, \
+ .power_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, \
+ .desc = { \
+ .name = max77620_rails(_name), \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .of_parse_cb = max77620_of_parse_cb, \
+ .supply_name = _sname, \
+ .id = MAX77620_REGULATOR_ID_##_id, \
+ .ops = &max77620_regulator_ops, \
+ .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \
+ .min_uV = _min_uV, \
+ .uV_step = _step_uV, \
+ .enable_time = 500, \
+ .vsel_mask = MAX77620_LDO_VOLT_MASK, \
+ .vsel_reg = MAX77620_REG_##_id##_CFG, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = MAX77620_LDO_CFG2_ADE_ENABLE, \
+ .active_discharge_mask = MAX77620_LDO_CFG2_ADE_MASK, \
+ .active_discharge_reg = MAX77620_REG_##_id##_CFG2, \
+ .type = REGULATOR_VOLTAGE, \
+ }, \
+ }
+
+static struct max77620_regulator_info max77620_regs_info[MAX77620_NUM_REGS] = {
+ RAIL_SD(SD0, sd0, "in-sd0", SD0, 600000, 1400000, 12500, 0x22, SD0),
+ RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 1550000, 12500, 0x22, SD1),
+ RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE),
+ RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE),
+ RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE),
+
+ RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000),
+ RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000),
+ RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500),
+ RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000),
+ RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000),
+};
+
+static struct max77620_regulator_info max20024_regs_info[MAX77620_NUM_REGS] = {
+ RAIL_SD(SD0, sd0, "in-sd0", SD0, 800000, 1587500, 12500, 0x22, SD0),
+ RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 3387500, 12500, 0x22, SD1),
+ RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE),
+ RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE),
+ RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE),
+
+ RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000),
+ RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000),
+ RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500),
+ RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000),
+ RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000),
+};
+
+static int max77620_regulator_probe(struct platform_device *pdev)
+{
+ struct max77620_chip *max77620_chip = dev_get_drvdata(pdev->dev.parent);
+ struct max77620_regulator_info *rinfo;
+ struct device *dev = &pdev->dev;
+ struct regulator_config config = { };
+ struct max77620_regulator *pmic;
+ int ret = 0;
+ int id;
+
+ pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
+ if (!pmic)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, pmic);
+ pmic->dev = dev;
+ pmic->rmap = max77620_chip->rmap;
+ if (!dev->of_node)
+ dev->of_node = pdev->dev.parent->of_node;
+
+ switch (max77620_chip->chip_id) {
+ case MAX77620:
+ rinfo = max77620_regs_info;
+ break;
+ default:
+ rinfo = max20024_regs_info;
+ break;
+ }
+
+ config.regmap = pmic->rmap;
+ config.dev = dev;
+ config.driver_data = pmic;
+
+ for (id = 0; id < MAX77620_NUM_REGS; id++) {
+ struct regulator_dev *rdev;
+ struct regulator_desc *rdesc;
+
+ if ((max77620_chip->chip_id == MAX77620) &&
+ (id == MAX77620_REGULATOR_ID_SD4))
+ continue;
+
+ rdesc = &rinfo[id].desc;
+ pmic->rinfo[id] = &max77620_regs_info[id];
+ pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL;
+
+ ret = max77620_read_slew_rate(pmic, id);
+ if (ret < 0)
+ return ret;
+
+ rdev = devm_regulator_register(dev, rdesc, &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "Regulator registration %s failed: %d\n",
+ rdesc->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max77620_regulator_suspend(struct device *dev)
+{
+ struct max77620_regulator *pmic = dev_get_drvdata(dev);
+ struct max77620_regulator_pdata *reg_pdata;
+ int id;
+
+ for (id = 0; id < MAX77620_NUM_REGS; id++) {
+ reg_pdata = &pmic->reg_pdata[id];
+
+ max77620_regulator_set_fps_slots(pmic, id, true);
+ if (reg_pdata->suspend_fps_src < 0)
+ continue;
+
+ max77620_regulator_set_fps_src(pmic, reg_pdata->suspend_fps_src,
+ id);
+ }
+
+ return 0;
+}
+
+static int max77620_regulator_resume(struct device *dev)
+{
+ struct max77620_regulator *pmic = dev_get_drvdata(dev);
+ struct max77620_regulator_pdata *reg_pdata;
+ int id;
+
+ for (id = 0; id < MAX77620_NUM_REGS; id++) {
+ reg_pdata = &pmic->reg_pdata[id];
+
+ max77620_regulator_set_fps_slots(pmic, id, false);
+ if (reg_pdata->active_fps_src < 0)
+ continue;
+ max77620_regulator_set_fps_src(pmic, reg_pdata->active_fps_src,
+ id);
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops max77620_regulator_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(max77620_regulator_suspend,
+ max77620_regulator_resume)
+};
+
+static const struct platform_device_id max77620_regulator_devtype[] = {
+ { .name = "max77620-pmic", },
+ { .name = "max20024-pmic", },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, max77620_regulator_devtype);
+
+static struct platform_driver max77620_regulator_driver = {
+ .probe = max77620_regulator_probe,
+ .id_table = max77620_regulator_devtype,
+ .driver = {
+ .name = "max77620-pmic",
+ .pm = &max77620_regulator_pm_ops,
+ },
+};
+
+module_platform_driver(max77620_regulator_driver);
+
+MODULE_DESCRIPTION("MAX77620/MAX20024 regulator driver");
+MODULE_AUTHOR("Mallikarjun Kasoju <mkasoju@nvidia.com>");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686-regulator.c
index 17ccf365a9c0..17ccf365a9c0 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686-regulator.c
diff --git a/drivers/regulator/max77802.c b/drivers/regulator/max77802-regulator.c
index c07ee13bd470..c07ee13bd470 100644
--- a/drivers/regulator/max77802.c
+++ b/drivers/regulator/max77802-regulator.c
diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c
index a5b2f4762677..17a5b6c2d6a9 100644
--- a/drivers/regulator/mt6397-regulator.c
+++ b/drivers/regulator/mt6397-regulator.c
@@ -317,11 +317,25 @@ static int mt6397_regulator_probe(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id mt6397_platform_ids[] = {
+ {"mt6397-regulator", 0},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6397_platform_ids);
+
+static const struct of_device_id mt6397_of_match[] = {
+ { .compatible = "mediatek,mt6397-regulator", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mt6397_of_match);
+
static struct platform_driver mt6397_regulator_driver = {
.driver = {
.name = "mt6397-regulator",
+ .of_match_table = of_match_ptr(mt6397_of_match),
},
.probe = mt6397_regulator_probe,
+ .id_table = mt6397_platform_ids,
};
module_platform_driver(mt6397_regulator_driver);
@@ -329,4 +343,3 @@ module_platform_driver(mt6397_regulator_driver);
MODULE_AUTHOR("Flora Fu <flora.fu@mediatek.com>");
MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mt6397-regulator");
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 499e437c7e91..6b0aa80b22fd 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -28,7 +28,6 @@ static void of_get_regulation_constraints(struct device_node *np,
struct regulator_init_data **init_data,
const struct regulator_desc *desc)
{
- const __be32 *min_uV, *max_uV;
struct regulation_constraints *constraints = &(*init_data)->constraints;
struct regulator_state *suspend_state;
struct device_node *suspend_np;
@@ -37,18 +36,18 @@ static void of_get_regulation_constraints(struct device_node *np,
constraints->name = of_get_property(np, "regulator-name", NULL);
- min_uV = of_get_property(np, "regulator-min-microvolt", NULL);
- if (min_uV)
- constraints->min_uV = be32_to_cpu(*min_uV);
- max_uV = of_get_property(np, "regulator-max-microvolt", NULL);
- if (max_uV)
- constraints->max_uV = be32_to_cpu(*max_uV);
+ if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
+ constraints->min_uV = pval;
+
+ if (!of_property_read_u32(np, "regulator-max-microvolt", &pval))
+ constraints->max_uV = pval;
/* Voltage change possible? */
if (constraints->min_uV != constraints->max_uV)
constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
/* Only one voltage? Then make sure it's set. */
- if (min_uV && max_uV && constraints->min_uV == constraints->max_uV)
+ if (constraints->min_uV && constraints->max_uV &&
+ constraints->min_uV == constraints->max_uV)
constraints->apply_uV = true;
if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
@@ -93,6 +92,12 @@ static void of_get_regulation_constraints(struct device_node *np,
constraints->soft_start = of_property_read_bool(np,
"regulator-soft-start");
+ ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
+ if (!ret) {
+ constraints->active_discharge =
+ (pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE :
+ REGULATOR_ACTIVE_DISCHARGE_DISABLE;
+ }
if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) {
if (desc && desc->of_map_mode) {
diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c
index 094376c8de4b..c448b727f5f8 100644
--- a/drivers/regulator/pv88060-regulator.c
+++ b/drivers/regulator/pv88060-regulator.c
@@ -285,8 +285,8 @@ static irqreturn_t pv88060_irq_handler(int irq, void *data)
}
}
- err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,
- PV88060_E_VDD_FLT, PV88060_E_VDD_FLT);
+ err = regmap_write(chip->regmap, PV88060_REG_EVENT_A,
+ PV88060_E_VDD_FLT);
if (err < 0)
goto error_i2c;
@@ -302,8 +302,8 @@ static irqreturn_t pv88060_irq_handler(int irq, void *data)
}
}
- err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,
- PV88060_E_OVER_TEMP, PV88060_E_OVER_TEMP);
+ err = regmap_write(chip->regmap, PV88060_REG_EVENT_A,
+ PV88060_E_OVER_TEMP);
if (err < 0)
goto error_i2c;
diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c
index ac15f31b5fe0..0057c6740d6f 100644
--- a/drivers/regulator/pv88090-regulator.c
+++ b/drivers/regulator/pv88090-regulator.c
@@ -283,8 +283,8 @@ static irqreturn_t pv88090_irq_handler(int irq, void *data)
}
}
- err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
- PV88090_E_VDD_FLT, PV88090_E_VDD_FLT);
+ err = regmap_write(chip->regmap, PV88090_REG_EVENT_A,
+ PV88090_E_VDD_FLT);
if (err < 0)
goto error_i2c;
@@ -300,8 +300,8 @@ static irqreturn_t pv88090_irq_handler(int irq, void *data)
}
}
- err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
- PV88090_E_OVER_TEMP, PV88090_E_OVER_TEMP);
+ err = regmap_write(chip->regmap, PV88090_REG_EVENT_A,
+ PV88090_E_OVER_TEMP);
if (err < 0)
goto error_i2c;
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index 3aca067b9901..4689d62f4841 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -27,6 +27,13 @@ struct pwm_regulator_data {
/* Voltage table */
struct pwm_voltages *duty_cycle_table;
+
+ /* regulator descriptor */
+ struct regulator_desc desc;
+
+ /* Regulator ops */
+ struct regulator_ops ops;
+
int state;
/* Continuous voltage */
@@ -115,7 +122,7 @@ static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int
int max_uV = rdev->constraints->max_uV;
int diff = max_uV - min_uV;
- return 100 - (((req_uV * 100) - (min_uV * 100)) / diff);
+ return ((req_uV * 100) - (min_uV * 100)) / diff;
}
static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
@@ -212,8 +219,10 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
}
drvdata->duty_cycle_table = duty_cycle_table;
- pwm_regulator_desc.ops = &pwm_regulator_voltage_table_ops;
- pwm_regulator_desc.n_voltages = length / sizeof(*duty_cycle_table);
+ memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops,
+ sizeof(drvdata->ops));
+ drvdata->desc.ops = &drvdata->ops;
+ drvdata->desc.n_voltages = length / sizeof(*duty_cycle_table);
return 0;
}
@@ -221,8 +230,10 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
static int pwm_regulator_init_continuous(struct platform_device *pdev,
struct pwm_regulator_data *drvdata)
{
- pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops;
- pwm_regulator_desc.continuous_voltage_range = true;
+ memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops,
+ sizeof(drvdata->ops));
+ drvdata->desc.ops = &drvdata->ops;
+ drvdata->desc.continuous_voltage_range = true;
return 0;
}
@@ -245,6 +256,8 @@ static int pwm_regulator_probe(struct platform_device *pdev)
if (!drvdata)
return -ENOMEM;
+ memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));
+
if (of_find_property(np, "voltage-table", NULL))
ret = pwm_regulator_init_table(pdev, drvdata);
else
@@ -253,7 +266,7 @@ static int pwm_regulator_probe(struct platform_device *pdev)
return ret;
init_data = of_get_regulator_init_data(&pdev->dev, np,
- &pwm_regulator_desc);
+ &drvdata->desc);
if (!init_data)
return -ENOMEM;
@@ -269,10 +282,10 @@ static int pwm_regulator_probe(struct platform_device *pdev)
}
regulator = devm_regulator_register(&pdev->dev,
- &pwm_regulator_desc, &config);
+ &drvdata->desc, &config);
if (IS_ERR(regulator)) {
dev_err(&pdev->dev, "Failed to register regulator %s\n",
- pwm_regulator_desc.name);
+ drvdata->desc.name);
return PTR_ERR(regulator);
}
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index 3242ffc0cb25..d24e2c783dc5 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -38,7 +38,6 @@
/* The highest number of possible regulators for supported devices. */
#define S2MPS_REGULATOR_MAX S2MPS13_REGULATOR_MAX
struct s2mps11_info {
- unsigned int rdev_num;
int ramp_delay2;
int ramp_delay34;
int ramp_delay5;
@@ -54,7 +53,10 @@ struct s2mps11_info {
*/
DECLARE_BITMAP(suspend_state, S2MPS_REGULATOR_MAX);
- /* Array of size rdev_num with GPIO-s for external sleep control */
+ /*
+ * Array (size: number of regulators) with GPIO-s for external
+ * sleep control.
+ */
int *ext_control_gpio;
};
@@ -819,7 +821,8 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
}
static int s2mps11_pmic_dt_parse(struct platform_device *pdev,
- struct of_regulator_match *rdata, struct s2mps11_info *s2mps11)
+ struct of_regulator_match *rdata, struct s2mps11_info *s2mps11,
+ unsigned int rdev_num)
{
struct device_node *reg_np;
@@ -829,7 +832,7 @@ static int s2mps11_pmic_dt_parse(struct platform_device *pdev,
return -EINVAL;
}
- of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
+ of_regulator_match(&pdev->dev, reg_np, rdata, rdev_num);
if (s2mps11->dev_type == S2MPS14X)
s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11);
@@ -1077,6 +1080,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
struct of_regulator_match *rdata = NULL;
struct regulator_config config = { };
struct s2mps11_info *s2mps11;
+ unsigned int rdev_num = 0;
int i, ret = 0;
const struct regulator_desc *regulators;
@@ -1088,28 +1092,29 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
s2mps11->dev_type = platform_get_device_id(pdev)->driver_data;
switch (s2mps11->dev_type) {
case S2MPS11X:
- s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators);
+ rdev_num = ARRAY_SIZE(s2mps11_regulators);
regulators = s2mps11_regulators;
- BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
+ BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps11_regulators));
break;
case S2MPS13X:
- s2mps11->rdev_num = ARRAY_SIZE(s2mps13_regulators);
+ rdev_num = ARRAY_SIZE(s2mps13_regulators);
regulators = s2mps13_regulators;
- BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
+ BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps13_regulators));
break;
case S2MPS14X:
- s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators);
+ rdev_num = ARRAY_SIZE(s2mps14_regulators);
regulators = s2mps14_regulators;
- BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
+ BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps14_regulators));
break;
case S2MPS15X:
- s2mps11->rdev_num = ARRAY_SIZE(s2mps15_regulators);
+ rdev_num = ARRAY_SIZE(s2mps15_regulators);
regulators = s2mps15_regulators;
+ BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps15_regulators));
break;
case S2MPU02:
- s2mps11->rdev_num = ARRAY_SIZE(s2mpu02_regulators);
+ rdev_num = ARRAY_SIZE(s2mpu02_regulators);
regulators = s2mpu02_regulators;
- BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
+ BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mpu02_regulators));
break;
default:
dev_err(&pdev->dev, "Invalid device type: %u\n",
@@ -1118,7 +1123,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
}
s2mps11->ext_control_gpio = devm_kmalloc(&pdev->dev,
- sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num,
+ sizeof(*s2mps11->ext_control_gpio) * rdev_num,
GFP_KERNEL);
if (!s2mps11->ext_control_gpio)
return -ENOMEM;
@@ -1126,7 +1131,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
* 0 is a valid GPIO so initialize all GPIO-s to negative value
* to indicate that external control won't be used for this regulator.
*/
- for (i = 0; i < s2mps11->rdev_num; i++)
+ for (i = 0; i < rdev_num; i++)
s2mps11->ext_control_gpio[i] = -EINVAL;
if (!iodev->dev->of_node) {
@@ -1140,14 +1145,14 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
}
}
- rdata = kzalloc(sizeof(*rdata) * s2mps11->rdev_num, GFP_KERNEL);
+ rdata = kzalloc(sizeof(*rdata) * rdev_num, GFP_KERNEL);
if (!rdata)
return -ENOMEM;
- for (i = 0; i < s2mps11->rdev_num; i++)
+ for (i = 0; i < rdev_num; i++)
rdata[i].name = regulators[i].name;
- ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11);
+ ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, rdev_num);
if (ret)
goto out;
@@ -1159,7 +1164,7 @@ common_reg:
config.driver_data = s2mps11;
config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
config.ena_gpio_initialized = true;
- for (i = 0; i < s2mps11->rdev_num; i++) {
+ for (i = 0; i < rdev_num; i++) {
struct regulator_dev *regulator;
if (pdata) {
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 58f5d3b8e981..27343e1c43ef 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -202,9 +202,10 @@ static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id,
}
}
- if (i < s5m8767->num_regulators)
- *enable_ctrl =
- s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
+ if (i >= s5m8767->num_regulators)
+ return -EINVAL;
+
+ *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
return 0;
}
@@ -937,8 +938,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
else
regulators[id].vsel_mask = 0xff;
- s5m8767_get_register(s5m8767, id, &enable_reg,
+ ret = s5m8767_get_register(s5m8767, id, &enable_reg,
&enable_val);
+ if (ret) {
+ dev_err(s5m8767->dev, "error reading registers\n");
+ return ret;
+ }
regulators[id].enable_reg = enable_reg;
regulators[id].enable_mask = S5M8767_ENCTRL_MASK;
regulators[id].enable_val = enable_val;
diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress-regulator.c
index c810cbbd463f..c810cbbd463f 100644
--- a/drivers/regulator/vexpress.c
+++ b/drivers/regulator/vexpress-regulator.c
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 28c711f0ac6b..72e97d7a5209 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -77,4 +77,13 @@ config DA8XX_REMOTEPROC
It's safe to say n here if you're not interested in multimedia
offloading.
+config ST_REMOTEPROC
+ tristate "ST remoteproc support"
+ depends on ARCH_STI
+ select REMOTEPROC
+ help
+ Say y here to support ST's adjunct processors via the remote
+ processor framework.
+ This can be either built-in or a loadable module.
+
endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 81b04d1e2e58..279cb2edc880 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o
obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
+obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 9e03d158f411..3d7d58a109d8 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -823,8 +823,10 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
/* look for the resource table */
table = rproc_find_rsc_table(rproc, fw, &tablesz);
- if (!table)
+ if (!table) {
+ dev_err(dev, "Failed to find resource table\n");
goto clean_up;
+ }
/* Verify that resource table in loaded fw is unchanged */
if (rproc->table_csum != crc32(0, table, tablesz)) {
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index 916af5096f57..74a120b6e206 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -88,8 +88,42 @@ static ssize_t rproc_state_read(struct file *filp, char __user *userbuf,
return simple_read_from_buffer(userbuf, count, ppos, buf, i);
}
+static ssize_t rproc_state_write(struct file *filp, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct rproc *rproc = filp->private_data;
+ char buf[10];
+ int ret;
+
+ if (count > sizeof(buf) || count <= 0)
+ return -EINVAL;
+
+ ret = copy_from_user(buf, userbuf, count);
+ if (ret)
+ return -EFAULT;
+
+ if (buf[count - 1] == '\n')
+ buf[count - 1] = '\0';
+
+ if (!strncmp(buf, "start", count)) {
+ ret = rproc_boot(rproc);
+ if (ret) {
+ dev_err(&rproc->dev, "Boot failed: %d\n", ret);
+ return ret;
+ }
+ } else if (!strncmp(buf, "stop", count)) {
+ rproc_shutdown(rproc);
+ } else {
+ dev_err(&rproc->dev, "Unrecognised option: %s\n", buf);
+ return -EINVAL;
+ }
+
+ return count;
+}
+
static const struct file_operations rproc_state_ops = {
.read = rproc_state_read,
+ .write = rproc_state_write,
.open = simple_open,
.llseek = generic_file_llseek,
};
@@ -157,7 +191,7 @@ rproc_recovery_write(struct file *filp, const char __user *user_buf,
int ret;
if (count < 1 || count > sizeof(buf))
- return count;
+ return -EINVAL;
ret = copy_from_user(buf, user_buf, count);
if (ret)
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
new file mode 100644
index 000000000000..6bb04d453247
--- /dev/null
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -0,0 +1,297 @@
+/*
+ * ST's Remote Processor Control Driver
+ *
+ * Copyright (C) 2015 STMicroelectronics - All Rights Reserved
+ *
+ * Author: Ludovic Barre <ludovic.barre@st.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/remoteproc.h>
+#include <linux/reset.h>
+
+struct st_rproc_config {
+ bool sw_reset;
+ bool pwr_reset;
+ unsigned long bootaddr_mask;
+};
+
+struct st_rproc {
+ struct st_rproc_config *config;
+ struct reset_control *sw_reset;
+ struct reset_control *pwr_reset;
+ struct clk *clk;
+ u32 clk_rate;
+ struct regmap *boot_base;
+ u32 boot_offset;
+};
+
+static int st_rproc_start(struct rproc *rproc)
+{
+ struct st_rproc *ddata = rproc->priv;
+ int err;
+
+ regmap_update_bits(ddata->boot_base, ddata->boot_offset,
+ ddata->config->bootaddr_mask, rproc->bootaddr);
+
+ err = clk_enable(ddata->clk);
+ if (err) {
+ dev_err(&rproc->dev, "Failed to enable clock\n");
+ return err;
+ }
+
+ if (ddata->config->sw_reset) {
+ err = reset_control_deassert(ddata->sw_reset);
+ if (err) {
+ dev_err(&rproc->dev, "Failed to deassert S/W Reset\n");
+ goto sw_reset_fail;
+ }
+ }
+
+ if (ddata->config->pwr_reset) {
+ err = reset_control_deassert(ddata->pwr_reset);
+ if (err) {
+ dev_err(&rproc->dev, "Failed to deassert Power Reset\n");
+ goto pwr_reset_fail;
+ }
+ }
+
+ dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
+
+ return 0;
+
+
+pwr_reset_fail:
+ if (ddata->config->pwr_reset)
+ reset_control_assert(ddata->sw_reset);
+sw_reset_fail:
+ clk_disable(ddata->clk);
+
+ return err;
+}
+
+static int st_rproc_stop(struct rproc *rproc)
+{
+ struct st_rproc *ddata = rproc->priv;
+ int sw_err = 0, pwr_err = 0;
+
+ if (ddata->config->sw_reset) {
+ sw_err = reset_control_assert(ddata->sw_reset);
+ if (sw_err)
+ dev_err(&rproc->dev, "Failed to assert S/W Reset\n");
+ }
+
+ if (ddata->config->pwr_reset) {
+ pwr_err = reset_control_assert(ddata->pwr_reset);
+ if (pwr_err)
+ dev_err(&rproc->dev, "Failed to assert Power Reset\n");
+ }
+
+ clk_disable(ddata->clk);
+
+ return sw_err ?: pwr_err;
+}
+
+static struct rproc_ops st_rproc_ops = {
+ .start = st_rproc_start,
+ .stop = st_rproc_stop,
+};
+
+/*
+ * Fetch state of the processor: 0 is off, 1 is on.
+ */
+static int st_rproc_state(struct platform_device *pdev)
+{
+ struct rproc *rproc = platform_get_drvdata(pdev);
+ struct st_rproc *ddata = rproc->priv;
+ int reset_sw = 0, reset_pwr = 0;
+
+ if (ddata->config->sw_reset)
+ reset_sw = reset_control_status(ddata->sw_reset);
+
+ if (ddata->config->pwr_reset)
+ reset_pwr = reset_control_status(ddata->pwr_reset);
+
+ if (reset_sw < 0 || reset_pwr < 0)
+ return -EINVAL;
+
+ return !reset_sw && !reset_pwr;
+}
+
+static const struct st_rproc_config st40_rproc_cfg = {
+ .sw_reset = true,
+ .pwr_reset = true,
+ .bootaddr_mask = GENMASK(28, 1),
+};
+
+static const struct st_rproc_config st231_rproc_cfg = {
+ .sw_reset = true,
+ .pwr_reset = false,
+ .bootaddr_mask = GENMASK(31, 6),
+};
+
+static const struct of_device_id st_rproc_match[] = {
+ { .compatible = "st,st40-rproc", .data = &st40_rproc_cfg },
+ { .compatible = "st,st231-rproc", .data = &st231_rproc_cfg },
+ {},
+};
+MODULE_DEVICE_TABLE(of, st_rproc_match);
+
+static int st_rproc_parse_dt(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rproc *rproc = platform_get_drvdata(pdev);
+ struct st_rproc *ddata = rproc->priv;
+ struct device_node *np = dev->of_node;
+ int err;
+
+ if (ddata->config->sw_reset) {
+ ddata->sw_reset = devm_reset_control_get(dev, "sw_reset");
+ if (IS_ERR(ddata->sw_reset)) {
+ dev_err(dev, "Failed to get S/W Reset\n");
+ return PTR_ERR(ddata->sw_reset);
+ }
+ }
+
+ if (ddata->config->pwr_reset) {
+ ddata->pwr_reset = devm_reset_control_get(dev, "pwr_reset");
+ if (IS_ERR(ddata->pwr_reset)) {
+ dev_err(dev, "Failed to get Power Reset\n");
+ return PTR_ERR(ddata->pwr_reset);
+ }
+ }
+
+ ddata->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(ddata->clk)) {
+ dev_err(dev, "Failed to get clock\n");
+ return PTR_ERR(ddata->clk);
+ }
+
+ err = of_property_read_u32(np, "clock-frequency", &ddata->clk_rate);
+ if (err) {
+ dev_err(dev, "failed to get clock frequency\n");
+ return err;
+ }
+
+ ddata->boot_base = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+ if (!ddata->boot_base) {
+ dev_err(dev, "Boot base not found\n");
+ return -EINVAL;
+ }
+
+ err = of_property_read_u32_index(np, "st,syscfg", 1,
+ &ddata->boot_offset);
+ if (err) {
+ dev_err(dev, "Boot offset not found\n");
+ return -EINVAL;
+ }
+
+ err = of_reserved_mem_device_init(dev);
+ if (err) {
+ dev_err(dev, "Failed to obtain shared memory\n");
+ return err;
+ }
+
+ err = clk_prepare(ddata->clk);
+ if (err)
+ dev_err(dev, "failed to get clock\n");
+
+ return err;
+}
+
+static int st_rproc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *match;
+ struct st_rproc *ddata;
+ struct device_node *np = dev->of_node;
+ struct rproc *rproc;
+ int enabled;
+ int ret;
+
+ match = of_match_device(st_rproc_match, dev);
+ if (!match || !match->data) {
+ dev_err(dev, "No device match found\n");
+ return -ENODEV;
+ }
+
+ rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
+ if (!rproc)
+ return -ENOMEM;
+
+ rproc->has_iommu = false;
+ ddata = rproc->priv;
+ ddata->config = (struct st_rproc_config *)match->data;
+
+ platform_set_drvdata(pdev, rproc);
+
+ ret = st_rproc_parse_dt(pdev);
+ if (ret)
+ goto free_rproc;
+
+ enabled = st_rproc_state(pdev);
+ if (enabled < 0)
+ goto free_rproc;
+
+ if (enabled) {
+ atomic_inc(&rproc->power);
+ rproc->state = RPROC_RUNNING;
+ } else {
+ clk_set_rate(ddata->clk, ddata->clk_rate);
+ }
+
+ ret = rproc_add(rproc);
+ if (ret)
+ goto free_rproc;
+
+ return 0;
+
+free_rproc:
+ rproc_put(rproc);
+ return ret;
+}
+
+static int st_rproc_remove(struct platform_device *pdev)
+{
+ struct rproc *rproc = platform_get_drvdata(pdev);
+ struct st_rproc *ddata = rproc->priv;
+
+ rproc_del(rproc);
+
+ clk_disable_unprepare(ddata->clk);
+
+ of_reserved_mem_device_release(&pdev->dev);
+
+ rproc_put(rproc);
+
+ return 0;
+}
+
+static struct platform_driver st_rproc_driver = {
+ .probe = st_rproc_probe,
+ .remove = st_rproc_remove,
+ .driver = {
+ .name = "st-rproc",
+ .of_match_table = of_match_ptr(st_rproc_match),
+ },
+};
+module_platform_driver(st_rproc_driver);
+
+MODULE_DESCRIPTION("ST Remote Processor Control Driver");
+MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
index edf81819cce1..02d271d101b4 100644
--- a/drivers/remoteproc/wkup_m3_rproc.c
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -122,6 +122,7 @@ static const struct of_device_id wkup_m3_rproc_of_match[] = {
{ .compatible = "ti,am4372-wkup-m3", },
{},
};
+MODULE_DEVICE_TABLE(of, wkup_m3_rproc_of_match);
static int wkup_m3_rproc_probe(struct platform_device *pdev)
{
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 376322f71fd5..544bd3493852 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -140,7 +140,6 @@ config RTC_DRV_TEST
will be called rtc-test.
comment "I2C RTC drivers"
- depends on I2C
if I2C
@@ -212,6 +211,15 @@ config RTC_DRV_DS1307
This driver can also be built as a module. If so, the module
will be called rtc-ds1307.
+config RTC_DRV_DS1307_HWMON
+ bool "HWMON support for rtc-ds1307"
+ depends on RTC_DRV_DS1307 && HWMON
+ depends on !(RTC_DRV_DS1307=y && HWMON=m)
+ default y
+ help
+ Say Y here if you want to expose temperature sensor data on
+ rtc-ds1307 (only DS3231)
+
config RTC_DRV_DS1374
tristate "Dallas/Maxim DS1374"
help
@@ -239,16 +247,6 @@ config RTC_DRV_DS1672
This driver can also be built as a module. If so, the module
will be called rtc-ds1672.
-config RTC_DRV_DS3232
- tristate "Dallas/Maxim DS3232"
- help
- If you say yes here you get support for Dallas Semiconductor
- DS3232 real-time clock chips. If an interrupt is associated
- with the device, the alarm functionality is supported.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-ds3232.
-
config RTC_DRV_HYM8563
tristate "Haoyu Microelectronics HYM8563"
depends on OF
@@ -317,10 +315,10 @@ config RTC_DRV_MAX8997
config RTC_DRV_MAX77686
tristate "Maxim MAX77686"
- depends on MFD_MAX77686
+ depends on MFD_MAX77686 || MFD_MAX77620
help
If you say yes here you will get support for the
- RTC of Maxim MAX77686 PMIC.
+ RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC.
This driver can also be built as a module. If so, the module
will be called rtc-max77686.
@@ -335,16 +333,6 @@ config RTC_DRV_RK808
This driver can also be built as a module. If so, the module
will be called rk808-rtc.
-config RTC_DRV_MAX77802
- tristate "Maxim 77802 RTC"
- depends on MFD_MAX77686
- help
- If you say yes here you will get support for the
- RTC of Maxim MAX77802 PMIC.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-max77802.
-
config RTC_DRV_RS5C372
tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
help
@@ -391,25 +379,6 @@ config RTC_DRV_X1205
This driver can also be built as a module. If so, the module
will be called rtc-x1205.
-config RTC_DRV_PALMAS
- tristate "TI Palmas RTC driver"
- depends on MFD_PALMAS
- help
- If you say yes here you get support for the RTC of TI PALMA series PMIC
- chips.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-palma.
-
-config RTC_DRV_PCF2127
- tristate "NXP PCF2127"
- help
- If you say yes here you get support for the NXP PCF2127/29 RTC
- chips.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-pcf2127.
-
config RTC_DRV_PCF8523
tristate "NXP PCF8523"
help
@@ -419,6 +388,14 @@ config RTC_DRV_PCF8523
This driver can also be built as a module. If so, the module
will be called rtc-pcf8523.
+config RTC_DRV_PCF85063
+ tristate "NXP PCF85063"
+ help
+ If you say yes here you get support for the PCF85063 RTC chip
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf85063.
+
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
help
@@ -429,14 +406,6 @@ config RTC_DRV_PCF8563
This driver can also be built as a module. If so, the module
will be called rtc-pcf8563.
-config RTC_DRV_PCF85063
- tristate "nxp PCF85063"
- help
- If you say yes here you get support for the PCF85063 RTC chip
-
- This driver can also be built as a module. If so, the module
- will be called rtc-pcf85063.
-
config RTC_DRV_PCF8583
tristate "Philips PCF8583"
help
@@ -501,6 +470,16 @@ config RTC_DRV_TWL4030
This driver can also be built as a module. If so, the module
will be called rtc-twl.
+config RTC_DRV_PALMAS
+ tristate "TI Palmas RTC driver"
+ depends on MFD_PALMAS
+ help
+ If you say yes here you get support for the RTC of TI PALMA series PMIC
+ chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-palma.
+
config RTC_DRV_TPS6586X
tristate "TI TPS6586X RTC driver"
depends on MFD_TPS6586X
@@ -595,14 +574,23 @@ config RTC_DRV_EM3027
will be called rtc-em3027.
config RTC_DRV_RV3029C2
- tristate "Micro Crystal RTC"
+ tristate "Micro Crystal RV3029"
help
If you say yes here you get support for the Micro Crystal
- RV3029-C2 RTC chips.
+ RV3029 RTC chips.
This driver can also be built as a module. If so, the module
will be called rtc-rv3029c2.
+config RTC_DRV_RV3029_HWMON
+ bool "HWMON support for RV3029"
+ depends on RTC_DRV_RV3029C2 && HWMON
+ depends on !(RTC_DRV_RV3029C2=y && HWMON=m)
+ default y
+ help
+ Say Y here if you want to expose temperature sensor data on
+ rtc-rv3029c2.
+
config RTC_DRV_RV8803
tristate "Micro Crystal RV8803"
help
@@ -691,15 +679,6 @@ config RTC_DRV_DS1390
This driver can also be built as a module. If so, the module
will be called rtc-ds1390.
-config RTC_DRV_MAX6902
- tristate "Maxim MAX6902"
- help
- If you say yes here you will get support for the
- Maxim MAX6902 SPI RTC chip.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-max6902.
-
config RTC_DRV_R9701
tristate "Epson RTC-9701JE"
help
@@ -709,6 +688,23 @@ config RTC_DRV_R9701
This driver can also be built as a module. If so, the module
will be called rtc-r9701.
+config RTC_DRV_RX4581
+ tristate "Epson RX-4581"
+ help
+ If you say yes here you will get support for the Epson RX-4581.
+
+ This driver can also be built as a module. If so the module
+ will be called rtc-rx4581.
+
+config RTC_DRV_RX6110
+ tristate "Epson RX-6110"
+ select REGMAP_SPI
+ help
+ If you say yes here you will get support for the Epson RX-6610.
+
+ This driver can also be built as a module. If so the module
+ will be called rtc-rx6110.
+
config RTC_DRV_RS5C348
tristate "Ricoh RS5C348A/B"
help
@@ -718,14 +714,14 @@ config RTC_DRV_RS5C348
This driver can also be built as a module. If so, the module
will be called rtc-rs5c348.
-config RTC_DRV_DS3234
- tristate "Maxim/Dallas DS3234"
+config RTC_DRV_MAX6902
+ tristate "Maxim MAX6902"
help
- If you say yes here you get support for the
- Maxim/Dallas DS3234 SPI RTC chip.
+ If you say yes here you will get support for the
+ Maxim MAX6902 SPI RTC chip.
This driver can also be built as a module. If so, the module
- will be called rtc-ds3234.
+ will be called rtc-max6902.
config RTC_DRV_PCF2123
tristate "NXP PCF2123"
@@ -736,14 +732,6 @@ config RTC_DRV_PCF2123
This driver can also be built as a module. If so, the module
will be called rtc-pcf2123.
-config RTC_DRV_RX4581
- tristate "Epson RX-4581"
- help
- If you say yes here you will get support for the Epson RX-4581.
-
- This driver can also be built as a module. If so the module
- will be called rtc-rx4581.
-
config RTC_DRV_MCP795
tristate "Microchip MCP795"
help
@@ -754,6 +742,41 @@ config RTC_DRV_MCP795
endif # SPI_MASTER
+#
+# Helper to resolve issues with configs that have SPI enabled but I2C
+# modular. See SND_SOC_I2C_AND_SPI for more information
+#
+config RTC_I2C_AND_SPI
+ tristate
+ default m if I2C=m
+ default y if I2C=y
+ default y if SPI_MASTER=y
+ select REGMAP_I2C if I2C
+ select REGMAP_SPI if SPI_MASTER
+
+comment "SPI and I2C RTC drivers"
+
+config RTC_DRV_DS3232
+ tristate "Dallas/Maxim DS3232/DS3234"
+ depends on RTC_I2C_AND_SPI
+ help
+ If you say yes here you get support for Dallas Semiconductor
+ DS3232 and DS3234 real-time clock chips. If an interrupt is associated
+ with the device, the alarm functionality is supported.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds3232.
+
+config RTC_DRV_PCF2127
+ tristate "NXP PCF2127"
+ depends on RTC_I2C_AND_SPI
+ help
+ If you say yes here you get support for the NXP PCF2127/29 RTC
+ chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf2127.
+
comment "Platform RTC drivers"
# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
@@ -1087,7 +1110,7 @@ config RTC_DRV_WM8350
config RTC_DRV_SPEAR
tristate "SPEAR ST RTC"
- depends on PLAT_SPEAR
+ depends on PLAT_SPEAR || COMPILE_TEST
default y
help
If you say Y here you will get support for the RTC found on
@@ -1119,7 +1142,7 @@ config RTC_DRV_AB8500
config RTC_DRV_NUC900
tristate "NUC910/NUC920 RTC driver"
- depends on ARCH_W90X900
+ depends on ARCH_W90X900 || COMPILE_TEST
help
If you say yes here you get support for the RTC subsystem of the
NUC910/NUC920 used in embedded systems.
@@ -1144,9 +1167,19 @@ config RTC_DRV_ZYNQMP
comment "on-CPU RTC drivers"
+config RTC_DRV_ASM9260
+ tristate "Alphascale asm9260 RTC"
+ depends on MACH_ASM9260
+ help
+ If you say yes here you get support for the RTC on the
+ Alphascale asm9260 SoC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-asm9260.
+
config RTC_DRV_DAVINCI
tristate "TI DaVinci RTC"
- depends on ARCH_DAVINCI_DM365
+ depends on ARCH_DAVINCI_DM365 || COMPILE_TEST
help
If you say yes here you get support for the RTC on the
DaVinci platforms (DM365).
@@ -1156,7 +1189,7 @@ config RTC_DRV_DAVINCI
config RTC_DRV_DIGICOLOR
tristate "Conexant Digicolor RTC"
- depends on ARCH_DIGICOLOR
+ depends on ARCH_DIGICOLOR || COMPILE_TEST
help
If you say yes here you get support for the RTC on Conexant
Digicolor platforms. This currently includes the CX92755 SoC.
@@ -1175,7 +1208,7 @@ config RTC_DRV_IMXDI
config RTC_DRV_OMAP
tristate "TI OMAP Real Time Clock"
- depends on ARCH_OMAP || ARCH_DAVINCI
+ depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST
help
Say "yes" here to support the on chip real time clock
present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx.
@@ -1192,7 +1225,7 @@ config HAVE_S3C_RTC
config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC"
- depends on ARCH_S3C64XX || HAVE_S3C_RTC
+ depends on ARCH_S3C64XX || HAVE_S3C_RTC || COMPILE_TEST
help
RTC (Realtime Clock) driver for the clock inbuilt into the
Samsung S3C24XX series of SoCs. This can provide periodic
@@ -1208,7 +1241,7 @@ config RTC_DRV_S3C
config RTC_DRV_EP93XX
tristate "Cirrus Logic EP93XX"
- depends on ARCH_EP93XX
+ depends on ARCH_EP93XX || COMPILE_TEST
help
If you say yes here you get support for the
RTC embedded in the Cirrus Logic EP93XX processors.
@@ -1238,7 +1271,7 @@ config RTC_DRV_SH
config RTC_DRV_VR41XX
tristate "NEC VR41XX"
- depends on CPU_VR41XX
+ depends on CPU_VR41XX || COMPILE_TEST
help
If you say Y here you will get access to the real time clock
built into your NEC VR41XX CPU.
@@ -1268,14 +1301,14 @@ config RTC_DRV_PL031
config RTC_DRV_AT32AP700X
tristate "AT32AP700X series RTC"
- depends on PLATFORM_AT32AP
+ depends on PLATFORM_AT32AP || COMPILE_TEST
help
Driver for the internal RTC (Realtime Clock) on Atmel AVR32
AT32AP700x family processors.
config RTC_DRV_AT91RM9200
tristate "AT91RM9200 or some AT91SAM9 RTC"
- depends on ARCH_AT91
+ depends on ARCH_AT91 || COMPILE_TEST
help
Driver for the internal RTC (Realtime Clock) module found on
Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips
@@ -1283,7 +1316,7 @@ config RTC_DRV_AT91RM9200
config RTC_DRV_AT91SAM9
tristate "AT91SAM9 RTT as RTC"
- depends on ARCH_AT91
+ depends on ARCH_AT91 || COMPILE_TEST
select MFD_SYSCON
help
Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which
@@ -1325,17 +1358,17 @@ config RTC_DRV_GENERIC
tristate "Generic RTC support"
# Please consider writing a new RTC driver instead of using the generic
# RTC abstraction
- depends on PARISC || M68K || PPC || SUPERH32
+ depends on PARISC || M68K || PPC || SUPERH32 || COMPILE_TEST
help
Say Y or M here to enable RTC support on systems using the generic
RTC abstraction. If you do not know what you are doing, you should
just say Y.
config RTC_DRV_PXA
- tristate "PXA27x/PXA3xx"
- depends on ARCH_PXA
- select RTC_DRV_SA1100
- help
+ tristate "PXA27x/PXA3xx"
+ depends on ARCH_PXA
+ select RTC_DRV_SA1100
+ help
If you say Y here you will get access to the real time clock
built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs
consisting of an SA1100 compatible RTC and the extended PXA RTC.
@@ -1345,7 +1378,7 @@ config RTC_DRV_PXA
config RTC_DRV_VT8500
tristate "VIA/WonderMedia 85xx SoC RTC"
- depends on ARCH_VT8500
+ depends on ARCH_VT8500 || COMPILE_TEST
help
If you say Y here you will get access to the real time clock
built into your VIA VT8500 SoC or its relatives.
@@ -1360,14 +1393,15 @@ config RTC_DRV_SUN4V
config RTC_DRV_SUN6I
tristate "Allwinner A31 RTC"
- depends on MACH_SUN6I || MACH_SUN8I
+ default MACH_SUN6I || MACH_SUN8I || COMPILE_TEST
+ depends on ARCH_SUNXI
help
- If you say Y here you will get support for the RTC found on
- Allwinner A31.
+ If you say Y here you will get support for the RTC found in
+ some Allwinner SoCs like the A31 or the A64.
config RTC_DRV_SUNXI
tristate "Allwinner sun4i/sun7i RTC"
- depends on MACH_SUN4I || MACH_SUN7I
+ depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
help
If you say Y here you will get support for the RTC found on
Allwinner A10/A20.
@@ -1388,7 +1422,7 @@ config RTC_DRV_TX4939
config RTC_DRV_MV
tristate "Marvell SoC RTC"
- depends on ARCH_DOVE || ARCH_MVEBU
+ depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST
help
If you say yes here you will get support for the in-chip RTC
that can be found in some of Marvell's SoC devices, such as
@@ -1399,7 +1433,7 @@ config RTC_DRV_MV
config RTC_DRV_ARMADA38X
tristate "Armada 38x Marvell SoC RTC"
- depends on ARCH_MVEBU
+ depends on ARCH_MVEBU || COMPILE_TEST
help
If you say yes here you will get support for the in-chip RTC
that can be found in the Armada 38x Marvell's SoC device
@@ -1429,7 +1463,7 @@ config RTC_DRV_PS3
config RTC_DRV_COH901331
tristate "ST-Ericsson COH 901 331 RTC"
- depends on ARCH_U300
+ depends on ARCH_U300 || COMPILE_TEST
help
If you say Y here you will get access to ST-Ericsson
COH 901 331 RTC clock found in some ST-Ericsson Mobile
@@ -1441,7 +1475,7 @@ config RTC_DRV_COH901331
config RTC_DRV_STMP
tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC"
- depends on ARCH_MXS
+ depends on ARCH_MXS || COMPILE_TEST
select STMP_DEVICE
help
If you say yes here you will get support for the onboard
@@ -1476,7 +1510,7 @@ config RTC_DRV_MPC5121
config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC"
- depends on MACH_JZ4740
+ depends on MACH_JZ4740 || COMPILE_TEST
help
If you say yes here you get support for the Ingenic JZ4740 SoC RTC
controller.
@@ -1497,7 +1531,7 @@ config RTC_DRV_LPC24XX
so, the module will be called rtc-lpc24xx.
config RTC_DRV_LPC32XX
- depends on ARCH_LPC32XX
+ depends on ARCH_LPC32XX || COMPILE_TEST
tristate "NXP LPC32XX RTC"
help
This enables support for the NXP RTC in the LPC32XX
@@ -1507,7 +1541,7 @@ config RTC_DRV_LPC32XX
config RTC_DRV_PM8XXX
tristate "Qualcomm PMIC8XXX RTC"
- depends on MFD_PM8XXX || MFD_SPMI_PMIC
+ depends on MFD_PM8XXX || MFD_SPMI_PMIC || COMPILE_TEST
help
If you say yes here you get support for the
Qualcomm PMIC8XXX RTC.
@@ -1517,7 +1551,7 @@ config RTC_DRV_PM8XXX
config RTC_DRV_TEGRA
tristate "NVIDIA Tegra Internal RTC driver"
- depends on ARCH_TEGRA
+ depends on ARCH_TEGRA || COMPILE_TEST
help
If you say yes here you get support for the
Tegra 200 series internal RTC module.
@@ -1603,7 +1637,7 @@ config RTC_DRV_MOXART
config RTC_DRV_MT6397
tristate "Mediatek Real Time Clock driver"
- depends on MFD_MT6397 || COMPILE_TEST
+ depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN)
help
This selects the Mediatek(R) RTC driver. RTC is part of Mediatek
MT6397 PMIC. You should enable MT6397 PMIC MFD before select
@@ -1622,6 +1656,16 @@ config RTC_DRV_XGENE
This driver can also be built as a module, if so, the module
will be called "rtc-xgene".
+config RTC_DRV_PIC32
+ tristate "Microchip PIC32 RTC"
+ depends on MACH_PIC32
+ default y
+ help
+ If you say yes here you get support for the PIC32 RTC module.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pic32
+
comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 62d61b26ca7e..ea2833723fa9 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
+obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
@@ -59,7 +60,6 @@ obj-$(CONFIG_RTC_DRV_DS1685_FAMILY) += rtc-ds1685.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o
obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o
-obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
@@ -86,7 +86,6 @@ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
-obj-$(CONFIG_RTC_DRV_MAX77802) += rtc-max77802.o
obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
@@ -112,6 +111,7 @@ obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
+obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o
obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
@@ -128,6 +128,7 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o
obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
+obj-$(CONFIG_RTC_DRV_RX6110) += rtc-rx6110.o
obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o
obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index de86578bcd6d..74fd9746aeca 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -361,17 +361,4 @@ static int __init rtc_init(void)
rtc_dev_init();
return 0;
}
-
-static void __exit rtc_exit(void)
-{
- rtc_dev_exit();
- class_destroy(rtc_class);
- ida_destroy(&rtc_ida);
-}
-
subsys_initcall(rtc_init);
-module_exit(rtc_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("RTC class support");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 5836751b8203..9ef5f6f89f98 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -939,4 +939,58 @@ void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
mutex_unlock(&rtc->ops_lock);
}
+/**
+ * rtc_read_offset - Read the amount of rtc offset in parts per billion
+ * @ rtc: rtc device to be used
+ * @ offset: the offset in parts per billion
+ *
+ * see below for details.
+ *
+ * Kernel interface to read rtc clock offset
+ * Returns 0 on success, or a negative number on error.
+ * If read_offset() is not implemented for the rtc, return -EINVAL
+ */
+int rtc_read_offset(struct rtc_device *rtc, long *offset)
+{
+ int ret;
+
+ if (!rtc->ops)
+ return -ENODEV;
+
+ if (!rtc->ops->read_offset)
+ return -EINVAL;
+
+ mutex_lock(&rtc->ops_lock);
+ ret = rtc->ops->read_offset(rtc->dev.parent, offset);
+ mutex_unlock(&rtc->ops_lock);
+ return ret;
+}
+/**
+ * rtc_set_offset - Adjusts the duration of the average second
+ * @ rtc: rtc device to be used
+ * @ offset: the offset in parts per billion
+ *
+ * Some rtc's allow an adjustment to the average duration of a second
+ * to compensate for differences in the actual clock rate due to temperature,
+ * the crystal, capacitor, etc.
+ *
+ * Kernel interface to adjust an rtc clock offset.
+ * Return 0 on success, or a negative number on error.
+ * If the rtc offset is not setable (or not implemented), return -EINVAL
+ */
+int rtc_set_offset(struct rtc_device *rtc, long offset)
+{
+ int ret;
+
+ if (!rtc->ops)
+ return -ENODEV;
+
+ if (!rtc->ops->set_offset)
+ return -EINVAL;
+
+ mutex_lock(&rtc->ops_lock);
+ ret = rtc->ops->set_offset(rtc->dev.parent, offset);
+ mutex_unlock(&rtc->ops_lock);
+ return ret;
+}
diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c
index 56cc5821118b..6ef0c887e6ca 100644
--- a/drivers/rtc/rtc-as3722.c
+++ b/drivers/rtc/rtc-as3722.c
@@ -210,7 +210,7 @@ static int as3722_rtc_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq);
ret = devm_request_threaded_irq(&pdev->dev, as3722_rtc->alarm_irq, NULL,
- as3722_alarm_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ as3722_alarm_irq, IRQF_ONESHOT,
"rtc-alarm", as3722_rtc);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c
new file mode 100644
index 000000000000..14e08c4c1a01
--- /dev/null
+++ b/drivers/rtc/rtc-asm9260.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2016 Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+/* Miscellaneous registers */
+/* Interrupt Location Register */
+#define HW_ILR 0x00
+#define BM_RTCALF BIT(1)
+#define BM_RTCCIF BIT(0)
+
+/* Clock Control Register */
+#define HW_CCR 0x08
+/* Calibration counter disable */
+#define BM_CCALOFF BIT(4)
+/* Reset internal oscillator divider */
+#define BM_CTCRST BIT(1)
+/* Clock Enable */
+#define BM_CLKEN BIT(0)
+
+/* Counter Increment Interrupt Register */
+#define HW_CIIR 0x0C
+#define BM_CIIR_IMYEAR BIT(7)
+#define BM_CIIR_IMMON BIT(6)
+#define BM_CIIR_IMDOY BIT(5)
+#define BM_CIIR_IMDOW BIT(4)
+#define BM_CIIR_IMDOM BIT(3)
+#define BM_CIIR_IMHOUR BIT(2)
+#define BM_CIIR_IMMIN BIT(1)
+#define BM_CIIR_IMSEC BIT(0)
+
+/* Alarm Mask Register */
+#define HW_AMR 0x10
+#define BM_AMR_IMYEAR BIT(7)
+#define BM_AMR_IMMON BIT(6)
+#define BM_AMR_IMDOY BIT(5)
+#define BM_AMR_IMDOW BIT(4)
+#define BM_AMR_IMDOM BIT(3)
+#define BM_AMR_IMHOUR BIT(2)
+#define BM_AMR_IMMIN BIT(1)
+#define BM_AMR_IMSEC BIT(0)
+#define BM_AMR_OFF 0xff
+
+/* Consolidated time registers */
+#define HW_CTIME0 0x14
+#define BM_CTIME0_DOW_S 24
+#define BM_CTIME0_DOW_M 0x7
+#define BM_CTIME0_HOUR_S 16
+#define BM_CTIME0_HOUR_M 0x1f
+#define BM_CTIME0_MIN_S 8
+#define BM_CTIME0_MIN_M 0x3f
+#define BM_CTIME0_SEC_S 0
+#define BM_CTIME0_SEC_M 0x3f
+
+#define HW_CTIME1 0x18
+#define BM_CTIME1_YEAR_S 16
+#define BM_CTIME1_YEAR_M 0xfff
+#define BM_CTIME1_MON_S 8
+#define BM_CTIME1_MON_M 0xf
+#define BM_CTIME1_DOM_S 0
+#define BM_CTIME1_DOM_M 0x1f
+
+#define HW_CTIME2 0x1C
+#define BM_CTIME2_DOY_S 0
+#define BM_CTIME2_DOY_M 0xfff
+
+/* Time counter registers */
+#define HW_SEC 0x20
+#define HW_MIN 0x24
+#define HW_HOUR 0x28
+#define HW_DOM 0x2C
+#define HW_DOW 0x30
+#define HW_DOY 0x34
+#define HW_MONTH 0x38
+#define HW_YEAR 0x3C
+
+#define HW_CALIBRATION 0x40
+#define BM_CALDIR_BACK BIT(17)
+#define BM_CALVAL_M 0x1ffff
+
+/* General purpose registers */
+#define HW_GPREG0 0x44
+#define HW_GPREG1 0x48
+#define HW_GPREG2 0x4C
+#define HW_GPREG3 0x50
+#define HW_GPREG4 0x54
+
+/* Alarm register group */
+#define HW_ALSEC 0x60
+#define HW_ALMIN 0x64
+#define HW_ALHOUR 0x68
+#define HW_ALDOM 0x6C
+#define HW_ALDOW 0x70
+#define HW_ALDOY 0x74
+#define HW_ALMON 0x78
+#define HW_ALYEAR 0x7C
+
+struct asm9260_rtc_priv {
+ struct device *dev;
+ void __iomem *iobase;
+ struct rtc_device *rtc;
+ struct clk *clk;
+ /* io lock */
+ spinlock_t lock;
+};
+
+static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id)
+{
+ struct asm9260_rtc_priv *priv = dev_id;
+ u32 isr;
+ unsigned long events = 0;
+
+ isr = ioread32(priv->iobase + HW_CIIR);
+ if (!isr)
+ return IRQ_NONE;
+
+ iowrite32(0, priv->iobase + HW_CIIR);
+
+ events |= RTC_AF | RTC_IRQF;
+
+ rtc_update_irq(priv->rtc, 1, events);
+
+ return IRQ_HANDLED;
+}
+
+static int asm9260_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
+ u32 ctime0, ctime1, ctime2;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&priv->lock, irq_flags);
+ ctime0 = ioread32(priv->iobase + HW_CTIME0);
+ ctime1 = ioread32(priv->iobase + HW_CTIME1);
+ ctime2 = ioread32(priv->iobase + HW_CTIME2);
+
+ if (ctime1 != ioread32(priv->iobase + HW_CTIME1)) {
+ /*
+ * woops, counter flipped right now. Now we are safe
+ * to reread.
+ */
+ ctime0 = ioread32(priv->iobase + HW_CTIME0);
+ ctime1 = ioread32(priv->iobase + HW_CTIME1);
+ ctime2 = ioread32(priv->iobase + HW_CTIME2);
+ }
+ spin_unlock_irqrestore(&priv->lock, irq_flags);
+
+ tm->tm_sec = (ctime0 >> BM_CTIME0_SEC_S) & BM_CTIME0_SEC_M;
+ tm->tm_min = (ctime0 >> BM_CTIME0_MIN_S) & BM_CTIME0_MIN_M;
+ tm->tm_hour = (ctime0 >> BM_CTIME0_HOUR_S) & BM_CTIME0_HOUR_M;
+ tm->tm_wday = (ctime0 >> BM_CTIME0_DOW_S) & BM_CTIME0_DOW_M;
+
+ tm->tm_mday = (ctime1 >> BM_CTIME1_DOM_S) & BM_CTIME1_DOM_M;
+ tm->tm_mon = (ctime1 >> BM_CTIME1_MON_S) & BM_CTIME1_MON_M;
+ tm->tm_year = (ctime1 >> BM_CTIME1_YEAR_S) & BM_CTIME1_YEAR_M;
+
+ tm->tm_yday = (ctime2 >> BM_CTIME2_DOY_S) & BM_CTIME2_DOY_M;
+
+ return 0;
+}
+
+static int asm9260_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&priv->lock, irq_flags);
+ /*
+ * make sure SEC counter will not flip other counter on write time,
+ * real value will be written at the enf of sequence.
+ */
+ iowrite32(0, priv->iobase + HW_SEC);
+
+ iowrite32(tm->tm_year, priv->iobase + HW_YEAR);
+ iowrite32(tm->tm_mon, priv->iobase + HW_MONTH);
+ iowrite32(tm->tm_mday, priv->iobase + HW_DOM);
+ iowrite32(tm->tm_wday, priv->iobase + HW_DOW);
+ iowrite32(tm->tm_yday, priv->iobase + HW_DOY);
+ iowrite32(tm->tm_hour, priv->iobase + HW_HOUR);
+ iowrite32(tm->tm_min, priv->iobase + HW_MIN);
+ iowrite32(tm->tm_sec, priv->iobase + HW_SEC);
+ spin_unlock_irqrestore(&priv->lock, irq_flags);
+
+ return 0;
+}
+
+static int asm9260_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&priv->lock, irq_flags);
+ alrm->time.tm_year = ioread32(priv->iobase + HW_ALYEAR);
+ alrm->time.tm_mon = ioread32(priv->iobase + HW_ALMON);
+ alrm->time.tm_mday = ioread32(priv->iobase + HW_ALDOM);
+ alrm->time.tm_wday = ioread32(priv->iobase + HW_ALDOW);
+ alrm->time.tm_yday = ioread32(priv->iobase + HW_ALDOY);
+ alrm->time.tm_hour = ioread32(priv->iobase + HW_ALHOUR);
+ alrm->time.tm_min = ioread32(priv->iobase + HW_ALMIN);
+ alrm->time.tm_sec = ioread32(priv->iobase + HW_ALSEC);
+
+ alrm->enabled = ioread32(priv->iobase + HW_AMR) ? 1 : 0;
+ alrm->pending = ioread32(priv->iobase + HW_CIIR) ? 1 : 0;
+ spin_unlock_irqrestore(&priv->lock, irq_flags);
+
+ return rtc_valid_tm(&alrm->time);
+}
+
+static int asm9260_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&priv->lock, irq_flags);
+ iowrite32(alrm->time.tm_year, priv->iobase + HW_ALYEAR);
+ iowrite32(alrm->time.tm_mon, priv->iobase + HW_ALMON);
+ iowrite32(alrm->time.tm_mday, priv->iobase + HW_ALDOM);
+ iowrite32(alrm->time.tm_wday, priv->iobase + HW_ALDOW);
+ iowrite32(alrm->time.tm_yday, priv->iobase + HW_ALDOY);
+ iowrite32(alrm->time.tm_hour, priv->iobase + HW_ALHOUR);
+ iowrite32(alrm->time.tm_min, priv->iobase + HW_ALMIN);
+ iowrite32(alrm->time.tm_sec, priv->iobase + HW_ALSEC);
+
+ iowrite32(alrm->enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR);
+ spin_unlock_irqrestore(&priv->lock, irq_flags);
+
+ return 0;
+}
+
+static int asm9260_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
+
+ iowrite32(enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR);
+ return 0;
+}
+
+static const struct rtc_class_ops asm9260_rtc_ops = {
+ .read_time = asm9260_rtc_read_time,
+ .set_time = asm9260_rtc_set_time,
+ .read_alarm = asm9260_rtc_read_alarm,
+ .set_alarm = asm9260_rtc_set_alarm,
+ .alarm_irq_enable = asm9260_alarm_irq_enable,
+};
+
+static int __init asm9260_rtc_probe(struct platform_device *pdev)
+{
+ struct asm9260_rtc_priv *priv;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int irq_alarm, ret;
+ u32 ccr;
+
+ priv = devm_kzalloc(dev, sizeof(struct asm9260_rtc_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+ platform_set_drvdata(pdev, priv);
+
+ irq_alarm = platform_get_irq(pdev, 0);
+ if (irq_alarm < 0) {
+ dev_err(dev, "No alarm IRQ resource defined\n");
+ return irq_alarm;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->iobase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->iobase))
+ return PTR_ERR(priv->iobase);
+
+ priv->clk = devm_clk_get(dev, "ahb");
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable clk!\n");
+ return ret;
+ }
+
+ ccr = ioread32(priv->iobase + HW_CCR);
+ /* if dev is not enabled, reset it */
+ if ((ccr & (BM_CLKEN | BM_CTCRST)) != BM_CLKEN) {
+ iowrite32(BM_CTCRST, priv->iobase + HW_CCR);
+ ccr = 0;
+ }
+
+ iowrite32(BM_CLKEN | ccr, priv->iobase + HW_CCR);
+ iowrite32(0, priv->iobase + HW_CIIR);
+ iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR);
+
+ priv->rtc = devm_rtc_device_register(dev, dev_name(dev),
+ &asm9260_rtc_ops, THIS_MODULE);
+ if (IS_ERR(priv->rtc)) {
+ ret = PTR_ERR(priv->rtc);
+ dev_err(dev, "Failed to register RTC device: %d\n", ret);
+ goto err_return;
+ }
+
+ ret = devm_request_threaded_irq(dev, irq_alarm, NULL,
+ asm9260_rtc_irq, IRQF_ONESHOT,
+ dev_name(dev), priv);
+ if (ret < 0) {
+ dev_err(dev, "can't get irq %i, err %d\n",
+ irq_alarm, ret);
+ goto err_return;
+ }
+
+ return 0;
+
+err_return:
+ clk_disable_unprepare(priv->clk);
+ return ret;
+}
+
+static int __exit asm9260_rtc_remove(struct platform_device *pdev)
+{
+ struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev);
+
+ /* Disable alarm matching */
+ iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR);
+ clk_disable_unprepare(priv->clk);
+ return 0;
+}
+
+static const struct of_device_id asm9260_dt_ids[] = {
+ { .compatible = "alphascale,asm9260-rtc", },
+ {}
+};
+
+static struct platform_driver asm9260_rtc_driver = {
+ .probe = asm9260_rtc_probe,
+ .remove = asm9260_rtc_remove,
+ .driver = {
+ .name = "asm9260-rtc",
+ .owner = THIS_MODULE,
+ .of_match_table = asm9260_dt_ids,
+ },
+};
+
+module_platform_driver(asm9260_rtc_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
+MODULE_DESCRIPTION("Alphascale asm9260 SoC Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index f39691eea736..8e41c4613e51 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -532,7 +532,7 @@ ds1305_nvram_read(struct file *filp, struct kobject *kobj,
struct spi_transfer x[2];
int status;
- spi = container_of(kobj, struct spi_device, dev.kobj);
+ spi = to_spi_device(kobj_to_dev(kobj));
addr = DS1305_NVRAM + off;
msg_init(&m, x, &addr, count, NULL, buf);
@@ -554,7 +554,7 @@ ds1305_nvram_write(struct file *filp, struct kobject *kobj,
struct spi_transfer x[2];
int status;
- spi = container_of(kobj, struct spi_device, dev.kobj);
+ spi = to_spi_device(kobj_to_dev(kobj));
addr = (DS1305_WRITE | DS1305_NVRAM) + off;
msg_init(&m, x, &addr, count, buf, NULL);
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index cf685f67b391..b2156ee5bae1 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -19,6 +19,9 @@
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/clk-provider.h>
/*
* We can't determine type by probing, but if we expect pre-Linux code
@@ -89,6 +92,7 @@ enum ds_type {
# define DS1340_BIT_OSF 0x80
#define DS1337_REG_STATUS 0x0f
# define DS1337_BIT_OSF 0x80
+# define DS3231_BIT_EN32KHZ 0x08
# define DS1337_BIT_A2I 0x02
# define DS1337_BIT_A1I 0x01
#define DS1339_REG_ALARM1_SECS 0x07
@@ -118,6 +122,9 @@ struct ds1307 {
u8 length, u8 *values);
s32 (*write_block_data)(const struct i2c_client *client, u8 command,
u8 length, const u8 *values);
+#ifdef CONFIG_COMMON_CLK
+ struct clk_hw clks[2];
+#endif
};
struct chip_desc {
@@ -842,6 +849,378 @@ out:
return;
}
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_RTC_DRV_DS1307_HWMON
+
+/*
+ * Temperature sensor support for ds3231 devices.
+ */
+
+#define DS3231_REG_TEMPERATURE 0x11
+
+/*
+ * A user-initiated temperature conversion is not started by this function,
+ * so the temperature is updated once every 64 seconds.
+ */
+static int ds3231_hwmon_read_temp(struct device *dev, s16 *mC)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ u8 temp_buf[2];
+ s16 temp;
+ int ret;
+
+ ret = ds1307->read_block_data(ds1307->client, DS3231_REG_TEMPERATURE,
+ sizeof(temp_buf), temp_buf);
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(temp_buf))
+ return -EIO;
+
+ /*
+ * Temperature is represented as a 10-bit code with a resolution of
+ * 0.25 degree celsius and encoded in two's complement format.
+ */
+ temp = (temp_buf[0] << 8) | temp_buf[1];
+ temp >>= 6;
+ *mC = temp * 250;
+
+ return 0;
+}
+
+static ssize_t ds3231_hwmon_show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ s16 temp;
+
+ ret = ds3231_hwmon_read_temp(dev, &temp);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", temp);
+}
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ds3231_hwmon_show_temp,
+ NULL, 0);
+
+static struct attribute *ds3231_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(ds3231_hwmon);
+
+static void ds1307_hwmon_register(struct ds1307 *ds1307)
+{
+ struct device *dev;
+
+ if (ds1307->type != ds_3231)
+ return;
+
+ dev = devm_hwmon_device_register_with_groups(&ds1307->client->dev,
+ ds1307->client->name,
+ ds1307, ds3231_hwmon_groups);
+ if (IS_ERR(dev)) {
+ dev_warn(&ds1307->client->dev,
+ "unable to register hwmon device %ld\n", PTR_ERR(dev));
+ }
+}
+
+#else
+
+static void ds1307_hwmon_register(struct ds1307 *ds1307)
+{
+}
+
+#endif /* CONFIG_RTC_DRV_DS1307_HWMON */
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Square-wave output support for DS3231
+ * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS3231.pdf
+ */
+#ifdef CONFIG_COMMON_CLK
+
+enum {
+ DS3231_CLK_SQW = 0,
+ DS3231_CLK_32KHZ,
+};
+
+#define clk_sqw_to_ds1307(clk) \
+ container_of(clk, struct ds1307, clks[DS3231_CLK_SQW])
+#define clk_32khz_to_ds1307(clk) \
+ container_of(clk, struct ds1307, clks[DS3231_CLK_32KHZ])
+
+static int ds3231_clk_sqw_rates[] = {
+ 1,
+ 1024,
+ 4096,
+ 8192,
+};
+
+static int ds1337_write_control(struct ds1307 *ds1307, u8 mask, u8 value)
+{
+ struct i2c_client *client = ds1307->client;
+ struct mutex *lock = &ds1307->rtc->ops_lock;
+ int control;
+ int ret;
+
+ mutex_lock(lock);
+
+ control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+ if (control < 0) {
+ ret = control;
+ goto out;
+ }
+
+ control &= ~mask;
+ control |= value;
+
+ ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
+out:
+ mutex_unlock(lock);
+
+ return ret;
+}
+
+static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+ int control;
+ int rate_sel = 0;
+
+ control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
+ if (control < 0)
+ return control;
+ if (control & DS1337_BIT_RS1)
+ rate_sel += 1;
+ if (control & DS1337_BIT_RS2)
+ rate_sel += 2;
+
+ return ds3231_clk_sqw_rates[rate_sel];
+}
+
+static long ds3231_clk_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(ds3231_clk_sqw_rates) - 1; i >= 0; i--) {
+ if (ds3231_clk_sqw_rates[i] <= rate)
+ return ds3231_clk_sqw_rates[i];
+ }
+
+ return 0;
+}
+
+static int ds3231_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+ int control = 0;
+ int rate_sel;
+
+ for (rate_sel = 0; rate_sel < ARRAY_SIZE(ds3231_clk_sqw_rates);
+ rate_sel++) {
+ if (ds3231_clk_sqw_rates[rate_sel] == rate)
+ break;
+ }
+
+ if (rate_sel == ARRAY_SIZE(ds3231_clk_sqw_rates))
+ return -EINVAL;
+
+ if (rate_sel & 1)
+ control |= DS1337_BIT_RS1;
+ if (rate_sel & 2)
+ control |= DS1337_BIT_RS2;
+
+ return ds1337_write_control(ds1307, DS1337_BIT_RS1 | DS1337_BIT_RS2,
+ control);
+}
+
+static int ds3231_clk_sqw_prepare(struct clk_hw *hw)
+{
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+ return ds1337_write_control(ds1307, DS1337_BIT_INTCN, 0);
+}
+
+static void ds3231_clk_sqw_unprepare(struct clk_hw *hw)
+{
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+ ds1337_write_control(ds1307, DS1337_BIT_INTCN, DS1337_BIT_INTCN);
+}
+
+static int ds3231_clk_sqw_is_prepared(struct clk_hw *hw)
+{
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+ int control;
+
+ control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
+ if (control < 0)
+ return control;
+
+ return !(control & DS1337_BIT_INTCN);
+}
+
+static const struct clk_ops ds3231_clk_sqw_ops = {
+ .prepare = ds3231_clk_sqw_prepare,
+ .unprepare = ds3231_clk_sqw_unprepare,
+ .is_prepared = ds3231_clk_sqw_is_prepared,
+ .recalc_rate = ds3231_clk_sqw_recalc_rate,
+ .round_rate = ds3231_clk_sqw_round_rate,
+ .set_rate = ds3231_clk_sqw_set_rate,
+};
+
+static unsigned long ds3231_clk_32khz_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return 32768;
+}
+
+static int ds3231_clk_32khz_control(struct ds1307 *ds1307, bool enable)
+{
+ struct i2c_client *client = ds1307->client;
+ struct mutex *lock = &ds1307->rtc->ops_lock;
+ int status;
+ int ret;
+
+ mutex_lock(lock);
+
+ status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
+ if (status < 0) {
+ ret = status;
+ goto out;
+ }
+
+ if (enable)
+ status |= DS3231_BIT_EN32KHZ;
+ else
+ status &= ~DS3231_BIT_EN32KHZ;
+
+ ret = i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, status);
+out:
+ mutex_unlock(lock);
+
+ return ret;
+}
+
+static int ds3231_clk_32khz_prepare(struct clk_hw *hw)
+{
+ struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);
+
+ return ds3231_clk_32khz_control(ds1307, true);
+}
+
+static void ds3231_clk_32khz_unprepare(struct clk_hw *hw)
+{
+ struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);
+
+ ds3231_clk_32khz_control(ds1307, false);
+}
+
+static int ds3231_clk_32khz_is_prepared(struct clk_hw *hw)
+{
+ struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);
+ int status;
+
+ status = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_STATUS);
+ if (status < 0)
+ return status;
+
+ return !!(status & DS3231_BIT_EN32KHZ);
+}
+
+static const struct clk_ops ds3231_clk_32khz_ops = {
+ .prepare = ds3231_clk_32khz_prepare,
+ .unprepare = ds3231_clk_32khz_unprepare,
+ .is_prepared = ds3231_clk_32khz_is_prepared,
+ .recalc_rate = ds3231_clk_32khz_recalc_rate,
+};
+
+static struct clk_init_data ds3231_clks_init[] = {
+ [DS3231_CLK_SQW] = {
+ .name = "ds3231_clk_sqw",
+ .ops = &ds3231_clk_sqw_ops,
+ .flags = CLK_IS_ROOT,
+ },
+ [DS3231_CLK_32KHZ] = {
+ .name = "ds3231_clk_32khz",
+ .ops = &ds3231_clk_32khz_ops,
+ .flags = CLK_IS_ROOT,
+ },
+};
+
+static int ds3231_clks_register(struct ds1307 *ds1307)
+{
+ struct i2c_client *client = ds1307->client;
+ struct device_node *node = client->dev.of_node;
+ struct clk_onecell_data *onecell;
+ int i;
+
+ onecell = devm_kzalloc(&client->dev, sizeof(*onecell), GFP_KERNEL);
+ if (!onecell)
+ return -ENOMEM;
+
+ onecell->clk_num = ARRAY_SIZE(ds3231_clks_init);
+ onecell->clks = devm_kcalloc(&client->dev, onecell->clk_num,
+ sizeof(onecell->clks[0]), GFP_KERNEL);
+ if (!onecell->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(ds3231_clks_init); i++) {
+ struct clk_init_data init = ds3231_clks_init[i];
+
+ /*
+ * Interrupt signal due to alarm conditions and square-wave
+ * output share same pin, so don't initialize both.
+ */
+ if (i == DS3231_CLK_SQW && test_bit(HAS_ALARM, &ds1307->flags))
+ continue;
+
+ /* optional override of the clockname */
+ of_property_read_string_index(node, "clock-output-names", i,
+ &init.name);
+ ds1307->clks[i].init = &init;
+
+ onecell->clks[i] = devm_clk_register(&client->dev,
+ &ds1307->clks[i]);
+ if (IS_ERR(onecell->clks[i]))
+ return PTR_ERR(onecell->clks[i]);
+ }
+
+ if (!node)
+ return 0;
+
+ of_clk_add_provider(node, of_clk_src_onecell_get, onecell);
+
+ return 0;
+}
+
+static void ds1307_clks_register(struct ds1307 *ds1307)
+{
+ int ret;
+
+ if (ds1307->type != ds_3231)
+ return;
+
+ ret = ds3231_clks_register(ds1307);
+ if (ret) {
+ dev_warn(&ds1307->client->dev,
+ "unable to register clock device %d\n", ret);
+ }
+}
+
+#else
+
+static void ds1307_clks_register(struct ds1307 *ds1307)
+{
+}
+
+#endif /* CONFIG_COMMON_CLK */
+
static int ds1307_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -851,6 +1230,7 @@ static int ds1307_probe(struct i2c_client *client,
struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
bool want_irq = false;
+ bool ds1307_can_wakeup_device = false;
unsigned char *buf;
struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
irq_handler_t irq_handler = ds1307_irq;
@@ -898,6 +1278,20 @@ static int ds1307_probe(struct i2c_client *client,
ds1307->write_block_data = ds1307_write_block_data;
}
+#ifdef CONFIG_OF
+/*
+ * For devices with no IRQ directly connected to the SoC, the RTC chip
+ * can be forced as a wakeup source by stating that explicitly in
+ * the device's .dts file using the "wakeup-source" boolean property.
+ * If the "wakeup-source" property is set, don't request an IRQ.
+ * This will guarantee the 'wakealarm' sysfs entry is available on the device,
+ * if supported by the RTC.
+ */
+ if (of_property_read_bool(client->dev.of_node, "wakeup-source")) {
+ ds1307_can_wakeup_device = true;
+ }
+#endif
+
switch (ds1307->type) {
case ds_1337:
case ds_1339:
@@ -916,11 +1310,13 @@ static int ds1307_probe(struct i2c_client *client,
ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
/*
- * Using IRQ? Disable the square wave and both alarms.
+ * Using IRQ or defined as wakeup-source?
+ * Disable the square wave and both alarms.
* For some variants, be sure alarms can trigger when we're
* running on Vbackup (BBSQI/BBSQW)
*/
- if (ds1307->client->irq > 0 && chip->alarm) {
+ if (chip->alarm && (ds1307->client->irq > 0 ||
+ ds1307_can_wakeup_device)) {
ds1307->regs[0] |= DS1337_BIT_INTCN
| bbsqi_bitpos[ds1307->type];
ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
@@ -1135,6 +1531,14 @@ read_rtc:
return PTR_ERR(ds1307->rtc);
}
+ if (ds1307_can_wakeup_device) {
+ /* Disable request for an IRQ */
+ want_irq = false;
+ dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n");
+ /* We cannot support UIE mode if we do not have an IRQ line */
+ ds1307->rtc->uie_unsupported = 1;
+ }
+
if (want_irq) {
err = devm_request_threaded_irq(&client->dev,
client->irq, NULL, irq_handler,
@@ -1182,6 +1586,9 @@ read_rtc:
}
}
+ ds1307_hwmon_register(ds1307);
+ ds1307_clks_register(ds1307);
+
return 0;
exit:
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 535050fc5e9f..1e6cfc84b1f6 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -187,9 +187,9 @@ ds1685_rtc_end_data_access(struct ds1685_priv *rtc)
* Only use this where you are certain another lock will not be held.
*/
static inline void
-ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long flags)
+ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long *flags)
{
- spin_lock_irqsave(&rtc->lock, flags);
+ spin_lock_irqsave(&rtc->lock, *flags);
ds1685_rtc_switch_to_bank1(rtc);
}
@@ -1300,7 +1300,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev,
{
struct ds1685_priv *rtc = dev_get_drvdata(dev);
u8 reg = 0, bit = 0, tmp;
- unsigned long flags = 0;
+ unsigned long flags;
long int val = 0;
const struct ds1685_rtc_ctrl_regs *reg_info =
ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
@@ -1321,7 +1321,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev,
bit = reg_info->bit;
/* Safe to spinlock during a write. */
- ds1685_rtc_begin_ctrl_access(rtc, flags);
+ ds1685_rtc_begin_ctrl_access(rtc, &flags);
tmp = rtc->read(rtc, reg);
rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit))));
ds1685_rtc_end_ctrl_access(rtc, flags);
@@ -2161,6 +2161,7 @@ ds1685_rtc_poweroff(struct platform_device *pdev)
/* Check for valid RTC data, else, spin forever. */
if (unlikely(!pdev)) {
pr_emerg("platform device data not available, spinning forever ...\n");
+ while(1);
unreachable();
} else {
/* Get the rtc data. */
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index 4e99ace66f74..7edc889729c5 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -1,19 +1,15 @@
/*
- * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C
+ * RTC client/driver for the Maxim/Dallas DS3232/DS3234 Real-Time Clock
*
* Copyright (C) 2009-2011 Freescale Semiconductor.
* Author: Jack Lan <jack.lan@freescale.com>
+ * Copyright (C) 2008 MIMOMax Wireless Ltd.
*
* 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.
*/
-/*
- * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
- * recommened in .../Documentation/i2c/writing-clients section
- * "Sending and receiving", using SMBus level communication is preferred.
- */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -21,10 +17,11 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
-#include <linux/workqueue.h>
#include <linux/slab.h>
+#include <linux/regmap.h>
#define DS3232_REG_SECONDS 0x00
#define DS3232_REG_MINUTES 0x01
@@ -50,39 +47,33 @@
# define DS3232_REG_SR_A1F 0x01
struct ds3232 {
- struct i2c_client *client;
+ struct device *dev;
+ struct regmap *regmap;
+ int irq;
struct rtc_device *rtc;
- struct work_struct work;
- /* The mutex protects alarm operations, and prevents a race
- * between the enable_irq() in the workqueue and the free_irq()
- * in the remove function.
- */
- struct mutex mutex;
bool suspended;
- int exiting;
};
-static struct i2c_driver ds3232_driver;
-
-static int ds3232_check_rtc_status(struct i2c_client *client)
+static int ds3232_check_rtc_status(struct device *dev)
{
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
int ret = 0;
int control, stat;
- stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
- if (stat < 0)
- return stat;
+ ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
+ if (ret)
+ return ret;
if (stat & DS3232_REG_SR_OSF)
- dev_warn(&client->dev,
+ dev_warn(dev,
"oscillator discontinuity flagged, "
"time unreliable\n");
stat &= ~(DS3232_REG_SR_OSF | DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
- ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
- if (ret < 0)
+ ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
+ if (ret)
return ret;
/* If the alarm is pending, clear it before requesting
@@ -90,31 +81,28 @@ static int ds3232_check_rtc_status(struct i2c_client *client)
* before everything is initialized.
*/
- control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
- if (control < 0)
- return control;
+ ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
+ if (ret)
+ return ret;
control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
control |= DS3232_REG_CR_INTCN;
- return i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
+ return regmap_write(ds3232->regmap, DS3232_REG_CR, control);
}
static int ds3232_read_time(struct device *dev, struct rtc_time *time)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
int ret;
u8 buf[7];
unsigned int year, month, day, hour, minute, second;
unsigned int week, twelve_hr, am_pm;
unsigned int century, add_century = 0;
- ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_SECONDS, 7, buf);
-
- if (ret < 0)
+ ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_SECONDS, buf, 7);
+ if (ret)
return ret;
- if (ret < 7)
- return -EIO;
second = buf[0];
minute = buf[1];
@@ -159,7 +147,7 @@ static int ds3232_read_time(struct device *dev, struct rtc_time *time)
static int ds3232_set_time(struct device *dev, struct rtc_time *time)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
u8 buf[7];
/* Extract time from rtc_time and load into ds3232*/
@@ -179,8 +167,7 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
buf[6] = bin2bcd(time->tm_year);
}
- return i2c_smbus_write_i2c_block_data(client,
- DS3232_REG_SECONDS, 7, buf);
+ return regmap_bulk_write(ds3232->regmap, DS3232_REG_SECONDS, buf, 7);
}
/*
@@ -190,24 +177,19 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
*/
static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct ds3232 *ds3232 = i2c_get_clientdata(client);
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
int control, stat;
int ret;
u8 buf[4];
- mutex_lock(&ds3232->mutex);
-
- ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
- if (ret < 0)
+ ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
+ if (ret)
goto out;
- stat = ret;
- ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
- if (ret < 0)
+ ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
+ if (ret)
goto out;
- control = ret;
- ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
- if (ret < 0)
+ ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
+ if (ret)
goto out;
alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
@@ -226,7 +208,6 @@ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
ret = 0;
out:
- mutex_unlock(&ds3232->mutex);
return ret;
}
@@ -236,166 +217,129 @@ out:
*/
static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct ds3232 *ds3232 = i2c_get_clientdata(client);
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
int control, stat;
int ret;
u8 buf[4];
- if (client->irq <= 0)
+ if (ds3232->irq <= 0)
return -EINVAL;
- mutex_lock(&ds3232->mutex);
-
buf[0] = bin2bcd(alarm->time.tm_sec);
buf[1] = bin2bcd(alarm->time.tm_min);
buf[2] = bin2bcd(alarm->time.tm_hour);
buf[3] = bin2bcd(alarm->time.tm_mday);
/* clear alarm interrupt enable bit */
- ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
- if (ret < 0)
+ ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
+ if (ret)
goto out;
- control = ret;
control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
- ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
- if (ret < 0)
+ ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
+ if (ret)
goto out;
/* clear any pending alarm flag */
- ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
- if (ret < 0)
+ ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
+ if (ret)
goto out;
- stat = ret;
stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
- ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
- if (ret < 0)
+ ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
+ if (ret)
goto out;
- ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
+ ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
+ if (ret)
+ goto out;
if (alarm->enabled) {
control |= DS3232_REG_CR_A1IE;
- ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
+ ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
}
out:
- mutex_unlock(&ds3232->mutex);
return ret;
}
-static void ds3232_update_alarm(struct i2c_client *client)
+static int ds3232_update_alarm(struct device *dev, unsigned int enabled)
{
- struct ds3232 *ds3232 = i2c_get_clientdata(client);
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
int control;
int ret;
- u8 buf[4];
-
- mutex_lock(&ds3232->mutex);
-
- ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
- if (ret < 0)
- goto unlock;
-
- buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
- 0x80 : buf[0];
- buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
- 0x80 : buf[1];
- buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
- 0x80 : buf[2];
- buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
- 0x80 : buf[3];
-
- ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
- if (ret < 0)
- goto unlock;
- control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
- if (control < 0)
- goto unlock;
+ ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
+ if (ret)
+ return ret;
- if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF))
+ if (enabled)
/* enable alarm1 interrupt */
control |= DS3232_REG_CR_A1IE;
else
/* disable alarm1 interrupt */
control &= ~(DS3232_REG_CR_A1IE);
- i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
+ ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
-unlock:
- mutex_unlock(&ds3232->mutex);
+ return ret;
}
static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct ds3232 *ds3232 = i2c_get_clientdata(client);
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
- if (client->irq <= 0)
+ if (ds3232->irq <= 0)
return -EINVAL;
- if (enabled)
- ds3232->rtc->irq_data |= RTC_AF;
- else
- ds3232->rtc->irq_data &= ~RTC_AF;
-
- ds3232_update_alarm(client);
- return 0;
+ return ds3232_update_alarm(dev, enabled);
}
static irqreturn_t ds3232_irq(int irq, void *dev_id)
{
- struct i2c_client *client = dev_id;
- struct ds3232 *ds3232 = i2c_get_clientdata(client);
-
- disable_irq_nosync(irq);
-
- /*
- * If rtc as a wakeup source, can't schedule the work
- * at system resume flow, because at this time the i2c bus
- * has not been resumed.
- */
- if (!ds3232->suspended)
- schedule_work(&ds3232->work);
-
- return IRQ_HANDLED;
-}
-
-static void ds3232_work(struct work_struct *work)
-{
- struct ds3232 *ds3232 = container_of(work, struct ds3232, work);
- struct i2c_client *client = ds3232->client;
+ struct device *dev = dev_id;
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
+ struct mutex *lock = &ds3232->rtc->ops_lock;
+ int ret;
int stat, control;
- mutex_lock(&ds3232->mutex);
+ mutex_lock(lock);
- stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
- if (stat < 0)
+ ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
+ if (ret)
goto unlock;
if (stat & DS3232_REG_SR_A1F) {
- control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
- if (control < 0) {
- pr_warn("Read Control Register error - Disable IRQ%d\n",
- client->irq);
+ ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
+ if (ret) {
+ dev_warn(ds3232->dev,
+ "Read Control Register error %d\n", ret);
} else {
/* disable alarm1 interrupt */
control &= ~(DS3232_REG_CR_A1IE);
- i2c_smbus_write_byte_data(client, DS3232_REG_CR,
- control);
+ ret = regmap_write(ds3232->regmap, DS3232_REG_CR,
+ control);
+ if (ret) {
+ dev_warn(ds3232->dev,
+ "Write Control Register error %d\n",
+ ret);
+ goto unlock;
+ }
/* clear the alarm pend flag */
stat &= ~DS3232_REG_SR_A1F;
- i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
+ ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
+ if (ret) {
+ dev_warn(ds3232->dev,
+ "Write Status Register error %d\n",
+ ret);
+ goto unlock;
+ }
rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
-
- if (!ds3232->exiting)
- enable_irq(client->irq);
}
}
unlock:
- mutex_unlock(&ds3232->mutex);
+ mutex_unlock(lock);
+
+ return IRQ_HANDLED;
}
static const struct rtc_class_ops ds3232_rtc_ops = {
@@ -406,67 +350,50 @@ static const struct rtc_class_ops ds3232_rtc_ops = {
.alarm_irq_enable = ds3232_alarm_irq_enable,
};
-static int ds3232_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name)
{
struct ds3232 *ds3232;
int ret;
- ds3232 = devm_kzalloc(&client->dev, sizeof(struct ds3232), GFP_KERNEL);
+ ds3232 = devm_kzalloc(dev, sizeof(*ds3232), GFP_KERNEL);
if (!ds3232)
return -ENOMEM;
- ds3232->client = client;
- i2c_set_clientdata(client, ds3232);
-
- INIT_WORK(&ds3232->work, ds3232_work);
- mutex_init(&ds3232->mutex);
+ ds3232->regmap = regmap;
+ ds3232->irq = irq;
+ ds3232->dev = dev;
+ dev_set_drvdata(dev, ds3232);
- ret = ds3232_check_rtc_status(client);
+ ret = ds3232_check_rtc_status(dev);
if (ret)
return ret;
- if (client->irq > 0) {
- ret = devm_request_irq(&client->dev, client->irq, ds3232_irq,
- IRQF_SHARED, "ds3232", client);
+ if (ds3232->irq > 0) {
+ ret = devm_request_threaded_irq(dev, ds3232->irq, NULL,
+ ds3232_irq,
+ IRQF_SHARED | IRQF_ONESHOT,
+ name, dev);
if (ret) {
- dev_err(&client->dev, "unable to request IRQ\n");
- }
- device_init_wakeup(&client->dev, 1);
- }
- ds3232->rtc = devm_rtc_device_register(&client->dev, client->name,
- &ds3232_rtc_ops, THIS_MODULE);
- return PTR_ERR_OR_ZERO(ds3232->rtc);
-}
-
-static int ds3232_remove(struct i2c_client *client)
-{
- struct ds3232 *ds3232 = i2c_get_clientdata(client);
-
- if (client->irq > 0) {
- mutex_lock(&ds3232->mutex);
- ds3232->exiting = 1;
- mutex_unlock(&ds3232->mutex);
-
- devm_free_irq(&client->dev, client->irq, client);
- cancel_work_sync(&ds3232->work);
+ ds3232->irq = 0;
+ dev_err(dev, "unable to request IRQ\n");
+ } else
+ device_init_wakeup(dev, 1);
}
+ ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
+ THIS_MODULE);
- return 0;
+ return PTR_ERR_OR_ZERO(ds3232->rtc);
}
#ifdef CONFIG_PM_SLEEP
static int ds3232_suspend(struct device *dev)
{
struct ds3232 *ds3232 = dev_get_drvdata(dev);
- struct i2c_client *client = to_i2c_client(dev);
- if (device_can_wakeup(dev)) {
- ds3232->suspended = true;
- if (irq_set_irq_wake(client->irq, 1)) {
+ if (device_may_wakeup(dev)) {
+ if (enable_irq_wake(ds3232->irq))
dev_warn_once(dev, "Cannot set wakeup source\n");
- ds3232->suspended = false;
- }
}
return 0;
@@ -475,16 +402,9 @@ static int ds3232_suspend(struct device *dev)
static int ds3232_resume(struct device *dev)
{
struct ds3232 *ds3232 = dev_get_drvdata(dev);
- struct i2c_client *client = to_i2c_client(dev);
- if (ds3232->suspended) {
- ds3232->suspended = false;
-
- /* Clear the hardware alarm pend flag */
- schedule_work(&ds3232->work);
-
- irq_set_irq_wake(client->irq, 0);
- }
+ if (device_may_wakeup(dev))
+ disable_irq_wake(ds3232->irq);
return 0;
}
@@ -494,6 +414,27 @@ static const struct dev_pm_ops ds3232_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume)
};
+#if IS_ENABLED(CONFIG_I2C)
+
+static int ds3232_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ static const struct regmap_config config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ };
+
+ regmap = devm_regmap_init_i2c(client, &config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "%s: regmap allocation failed: %ld\n",
+ __func__, PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ return ds3232_probe(&client->dev, regmap, client->irq, client->name);
+}
+
static const struct i2c_device_id ds3232_id[] = {
{ "ds3232", 0 },
{ }
@@ -505,13 +446,162 @@ static struct i2c_driver ds3232_driver = {
.name = "rtc-ds3232",
.pm = &ds3232_pm_ops,
},
- .probe = ds3232_probe,
- .remove = ds3232_remove,
+ .probe = ds3232_i2c_probe,
.id_table = ds3232_id,
};
-module_i2c_driver(ds3232_driver);
+static int ds3232_register_driver(void)
+{
+ return i2c_add_driver(&ds3232_driver);
+}
+
+static void ds3232_unregister_driver(void)
+{
+ i2c_del_driver(&ds3232_driver);
+}
+
+#else
+
+static int ds3232_register_driver(void)
+{
+ return 0;
+}
+
+static void ds3232_unregister_driver(void)
+{
+}
+
+#endif
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
+static int ds3234_probe(struct spi_device *spi)
+{
+ int res;
+ unsigned int tmp;
+ static const struct regmap_config config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .write_flag_mask = 0x80,
+ };
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n",
+ __func__, PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+
+ res = regmap_read(regmap, DS3232_REG_SECONDS, &tmp);
+ if (res)
+ return res;
+
+ /* Control settings
+ *
+ * CONTROL_REG
+ * BIT 7 6 5 4 3 2 1 0
+ * EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE
+ *
+ * 0 0 0 1 1 1 0 0
+ *
+ * CONTROL_STAT_REG
+ * BIT 7 6 5 4 3 2 1 0
+ * OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F
+ *
+ * 1 0 0 0 1 0 0 0
+ */
+ res = regmap_read(regmap, DS3232_REG_CR, &tmp);
+ if (res)
+ return res;
+ res = regmap_write(regmap, DS3232_REG_CR, tmp & 0x1c);
+ if (res)
+ return res;
+
+ res = regmap_read(regmap, DS3232_REG_SR, &tmp);
+ if (res)
+ return res;
+ res = regmap_write(regmap, DS3232_REG_SR, tmp & 0x88);
+ if (res)
+ return res;
+
+ /* Print our settings */
+ res = regmap_read(regmap, DS3232_REG_CR, &tmp);
+ if (res)
+ return res;
+ dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp);
+
+ res = regmap_read(regmap, DS3232_REG_SR, &tmp);
+ if (res)
+ return res;
+ dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
+
+ return ds3232_probe(&spi->dev, regmap, spi->irq, "ds3234");
+}
+
+static struct spi_driver ds3234_driver = {
+ .driver = {
+ .name = "ds3234",
+ },
+ .probe = ds3234_probe,
+};
+
+static int ds3234_register_driver(void)
+{
+ return spi_register_driver(&ds3234_driver);
+}
+
+static void ds3234_unregister_driver(void)
+{
+ spi_unregister_driver(&ds3234_driver);
+}
+
+#else
+
+static int ds3234_register_driver(void)
+{
+ return 0;
+}
+
+static void ds3234_unregister_driver(void)
+{
+}
+
+#endif
+
+static int __init ds323x_init(void)
+{
+ int ret;
+
+ ret = ds3232_register_driver();
+ if (ret) {
+ pr_err("Failed to register ds3232 driver: %d\n", ret);
+ return ret;
+ }
+
+ ret = ds3234_register_driver();
+ if (ret) {
+ pr_err("Failed to register ds3234 driver: %d\n", ret);
+ ds3232_unregister_driver();
+ }
+
+ return ret;
+}
+module_init(ds323x_init)
+
+static void __exit ds323x_exit(void)
+{
+ ds3234_unregister_driver();
+ ds3232_unregister_driver();
+}
+module_exit(ds323x_exit)
MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>");
-MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver");
+MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
+MODULE_DESCRIPTION("Maxim/Dallas DS3232/DS3234 RTC Driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ds3234");
diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c
deleted file mode 100644
index 570ab28fc354..000000000000
--- a/drivers/rtc/rtc-ds3234.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/* rtc-ds3234.c
- *
- * Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal
- * and SRAM.
- *
- * Copyright (C) 2008 MIMOMax Wireless Ltd.
- *
- * 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
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/rtc.h>
-#include <linux/spi/spi.h>
-#include <linux/bcd.h>
-
-#define DS3234_REG_SECONDS 0x00
-#define DS3234_REG_MINUTES 0x01
-#define DS3234_REG_HOURS 0x02
-#define DS3234_REG_DAY 0x03
-#define DS3234_REG_DATE 0x04
-#define DS3234_REG_MONTH 0x05
-#define DS3234_REG_YEAR 0x06
-#define DS3234_REG_CENTURY (1 << 7) /* Bit 7 of the Month register */
-
-#define DS3234_REG_CONTROL 0x0E
-#define DS3234_REG_CONT_STAT 0x0F
-
-static int ds3234_set_reg(struct device *dev, unsigned char address,
- unsigned char data)
-{
- struct spi_device *spi = to_spi_device(dev);
- unsigned char buf[2];
-
- /* MSB must be '1' to indicate write */
- buf[0] = address | 0x80;
- buf[1] = data;
-
- return spi_write_then_read(spi, buf, 2, NULL, 0);
-}
-
-static int ds3234_get_reg(struct device *dev, unsigned char address,
- unsigned char *data)
-{
- struct spi_device *spi = to_spi_device(dev);
-
- *data = address & 0x7f;
-
- return spi_write_then_read(spi, data, 1, data, 1);
-}
-
-static int ds3234_read_time(struct device *dev, struct rtc_time *dt)
-{
- int err;
- unsigned char buf[8];
- struct spi_device *spi = to_spi_device(dev);
-
- buf[0] = 0x00; /* Start address */
-
- err = spi_write_then_read(spi, buf, 1, buf, 8);
- if (err != 0)
- return err;
-
- /* Seconds, Minutes, Hours, Day, Date, Month, Year */
- dt->tm_sec = bcd2bin(buf[0]);
- dt->tm_min = bcd2bin(buf[1]);
- dt->tm_hour = bcd2bin(buf[2] & 0x3f);
- dt->tm_wday = bcd2bin(buf[3]) - 1; /* 0 = Sun */
- dt->tm_mday = bcd2bin(buf[4]);
- dt->tm_mon = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */
- dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */
-
- return rtc_valid_tm(dt);
-}
-
-static int ds3234_set_time(struct device *dev, struct rtc_time *dt)
-{
- ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec));
- ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min));
- ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f);
-
- /* 0 = Sun */
- ds3234_set_reg(dev, DS3234_REG_DAY, bin2bcd(dt->tm_wday + 1));
- ds3234_set_reg(dev, DS3234_REG_DATE, bin2bcd(dt->tm_mday));
-
- /* 0 = Jan */
- ds3234_set_reg(dev, DS3234_REG_MONTH, bin2bcd(dt->tm_mon + 1));
-
- /* Assume 20YY although we just want to make sure not to go negative. */
- if (dt->tm_year > 100)
- dt->tm_year -= 100;
-
- ds3234_set_reg(dev, DS3234_REG_YEAR, bin2bcd(dt->tm_year));
-
- return 0;
-}
-
-static const struct rtc_class_ops ds3234_rtc_ops = {
- .read_time = ds3234_read_time,
- .set_time = ds3234_set_time,
-};
-
-static int ds3234_probe(struct spi_device *spi)
-{
- struct rtc_device *rtc;
- unsigned char tmp;
- int res;
-
- spi->mode = SPI_MODE_3;
- spi->bits_per_word = 8;
- spi_setup(spi);
-
- res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp);
- if (res != 0)
- return res;
-
- /* Control settings
- *
- * CONTROL_REG
- * BIT 7 6 5 4 3 2 1 0
- * EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE
- *
- * 0 0 0 1 1 1 0 0
- *
- * CONTROL_STAT_REG
- * BIT 7 6 5 4 3 2 1 0
- * OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F
- *
- * 1 0 0 0 1 0 0 0
- */
- ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
- ds3234_set_reg(&spi->dev, DS3234_REG_CONTROL, tmp & 0x1c);
-
- ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
- ds3234_set_reg(&spi->dev, DS3234_REG_CONT_STAT, tmp & 0x88);
-
- /* Print our settings */
- ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
- dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp);
-
- ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
- dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
-
- rtc = devm_rtc_device_register(&spi->dev, "ds3234",
- &ds3234_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc))
- return PTR_ERR(rtc);
-
- spi_set_drvdata(spi, rtc);
-
- return 0;
-}
-
-static struct spi_driver ds3234_driver = {
- .driver = {
- .name = "ds3234",
- },
- .probe = ds3234_probe,
-};
-
-module_spi_driver(ds3234_driver);
-
-MODULE_DESCRIPTION("DS3234 SPI RTC driver");
-MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:ds3234");
diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c
index e782ebd719b2..d726c6aa96a8 100644
--- a/drivers/rtc/rtc-generic.c
+++ b/drivers/rtc/rtc-generic.c
@@ -9,6 +9,8 @@
#include <linux/platform_device.h>
#include <linux/rtc.h>
+#if defined(CONFIG_M68K) || defined(CONFIG_PARISC) || \
+ defined(CONFIG_PPC) || defined(CONFIG_SUPERH32)
#include <asm/rtc.h>
static int generic_get_time(struct device *dev, struct rtc_time *tm)
@@ -33,13 +35,21 @@ static const struct rtc_class_ops generic_rtc_ops = {
.read_time = generic_get_time,
.set_time = generic_set_time,
};
+#else
+#define generic_rtc_ops *(struct rtc_class_ops*)NULL
+#endif
static int __init generic_rtc_probe(struct platform_device *dev)
{
struct rtc_device *rtc;
+ const struct rtc_class_ops *ops;
+
+ ops = dev_get_platdata(&dev->dev);
+ if (!ops)
+ ops = &generic_rtc_ops;
rtc = devm_rtc_device_register(&dev->dev, "rtc-generic",
- &generic_rtc_ops, THIS_MODULE);
+ ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c
index 097325d96db5..b1b4746a0eab 100644
--- a/drivers/rtc/rtc-hym8563.c
+++ b/drivers/rtc/rtc-hym8563.c
@@ -144,7 +144,7 @@ static int hym8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
* it does not seem to carry it over a subsequent write/read.
* So we'll limit ourself to 100 years, starting at 2000 for now.
*/
- buf[6] = tm->tm_year - 100;
+ buf[6] = bin2bcd(tm->tm_year - 100);
/*
* CTL1 only contains TEST-mode bits apart from stop,
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index 7184a0eda793..182fdd00e290 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -1,5 +1,5 @@
/*
- * RTC driver for Maxim MAX77686
+ * RTC driver for Maxim MAX77686 and MAX77802
*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
*
@@ -12,8 +12,7 @@
*
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
+#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/rtc.h>
#include <linux/delay.h>
@@ -24,24 +23,38 @@
#include <linux/irqdomain.h>
#include <linux/regmap.h>
+#define MAX77686_I2C_ADDR_RTC (0x0C >> 1)
+#define MAX77620_I2C_ADDR_RTC 0x68
+#define MAX77686_INVALID_I2C_ADDR (-1)
+
+/* Define non existing register */
+#define MAX77686_INVALID_REG (-1)
+
/* RTC Control Register */
#define BCD_EN_SHIFT 0
-#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
+#define BCD_EN_MASK BIT(BCD_EN_SHIFT)
#define MODEL24_SHIFT 1
-#define MODEL24_MASK (1 << MODEL24_SHIFT)
+#define MODEL24_MASK BIT(MODEL24_SHIFT)
/* RTC Update Register1 */
#define RTC_UDR_SHIFT 0
-#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
+#define RTC_UDR_MASK BIT(RTC_UDR_SHIFT)
#define RTC_RBUDR_SHIFT 4
-#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
+#define RTC_RBUDR_MASK BIT(RTC_RBUDR_SHIFT)
/* RTC Hour register */
#define HOUR_PM_SHIFT 6
-#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
+#define HOUR_PM_MASK BIT(HOUR_PM_SHIFT)
/* RTC Alarm Enable */
#define ALARM_ENABLE_SHIFT 7
-#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
+#define ALARM_ENABLE_MASK BIT(ALARM_ENABLE_SHIFT)
-#define MAX77686_RTC_UPDATE_DELAY 16
+#define REG_RTC_NONE 0xdeadbeef
+
+/*
+ * MAX77802 has separate register (RTCAE1) for alarm enable instead
+ * using 1 bit from registers RTC{SEC,MIN,HOUR,DAY,MONTH,YEAR,DATE}
+ * as in done in MAX77686.
+ */
+#define MAX77802_ALARM_ENABLE_VALUE 0x77
enum {
RTC_SEC = 0,
@@ -54,15 +67,38 @@ enum {
RTC_NR_TIME
};
+struct max77686_rtc_driver_data {
+ /* Minimum usecs needed for a RTC update */
+ unsigned long delay;
+ /* Mask used to read RTC registers value */
+ u8 mask;
+ /* Registers offset to I2C addresses map */
+ const unsigned int *map;
+ /* Has a separate alarm enable register? */
+ bool alarm_enable_reg;
+ /* I2C address for RTC block */
+ int rtc_i2c_addr;
+ /* RTC interrupt via platform resource */
+ bool rtc_irq_from_platform;
+ /* Pending alarm status register */
+ int alarm_pending_status_reg;
+ /* RTC IRQ CHIP for regmap */
+ const struct regmap_irq_chip *rtc_irq_chip;
+};
+
struct max77686_rtc_info {
struct device *dev;
- struct max77686_dev *max77686;
struct i2c_client *rtc;
struct rtc_device *rtc_dev;
struct mutex lock;
struct regmap *regmap;
+ struct regmap *rtc_regmap;
+
+ const struct max77686_rtc_driver_data *drv_data;
+ struct regmap_irq_chip_data *rtc_irq_data;
+ int rtc_irq;
int virq;
int rtc_24hr_mode;
};
@@ -72,29 +108,190 @@ enum MAX77686_RTC_OP {
MAX77686_RTC_READ,
};
+/* These are not registers but just offsets that are mapped to addresses */
+enum max77686_rtc_reg_offset {
+ REG_RTC_CONTROLM = 0,
+ REG_RTC_CONTROL,
+ REG_RTC_UPDATE0,
+ REG_WTSR_SMPL_CNTL,
+ REG_RTC_SEC,
+ REG_RTC_MIN,
+ REG_RTC_HOUR,
+ REG_RTC_WEEKDAY,
+ REG_RTC_MONTH,
+ REG_RTC_YEAR,
+ REG_RTC_DATE,
+ REG_ALARM1_SEC,
+ REG_ALARM1_MIN,
+ REG_ALARM1_HOUR,
+ REG_ALARM1_WEEKDAY,
+ REG_ALARM1_MONTH,
+ REG_ALARM1_YEAR,
+ REG_ALARM1_DATE,
+ REG_ALARM2_SEC,
+ REG_ALARM2_MIN,
+ REG_ALARM2_HOUR,
+ REG_ALARM2_WEEKDAY,
+ REG_ALARM2_MONTH,
+ REG_ALARM2_YEAR,
+ REG_ALARM2_DATE,
+ REG_RTC_AE1,
+ REG_RTC_END,
+};
+
+/* Maps RTC registers offset to the MAX77686 register addresses */
+static const unsigned int max77686_map[REG_RTC_END] = {
+ [REG_RTC_CONTROLM] = MAX77686_RTC_CONTROLM,
+ [REG_RTC_CONTROL] = MAX77686_RTC_CONTROL,
+ [REG_RTC_UPDATE0] = MAX77686_RTC_UPDATE0,
+ [REG_WTSR_SMPL_CNTL] = MAX77686_WTSR_SMPL_CNTL,
+ [REG_RTC_SEC] = MAX77686_RTC_SEC,
+ [REG_RTC_MIN] = MAX77686_RTC_MIN,
+ [REG_RTC_HOUR] = MAX77686_RTC_HOUR,
+ [REG_RTC_WEEKDAY] = MAX77686_RTC_WEEKDAY,
+ [REG_RTC_MONTH] = MAX77686_RTC_MONTH,
+ [REG_RTC_YEAR] = MAX77686_RTC_YEAR,
+ [REG_RTC_DATE] = MAX77686_RTC_DATE,
+ [REG_ALARM1_SEC] = MAX77686_ALARM1_SEC,
+ [REG_ALARM1_MIN] = MAX77686_ALARM1_MIN,
+ [REG_ALARM1_HOUR] = MAX77686_ALARM1_HOUR,
+ [REG_ALARM1_WEEKDAY] = MAX77686_ALARM1_WEEKDAY,
+ [REG_ALARM1_MONTH] = MAX77686_ALARM1_MONTH,
+ [REG_ALARM1_YEAR] = MAX77686_ALARM1_YEAR,
+ [REG_ALARM1_DATE] = MAX77686_ALARM1_DATE,
+ [REG_ALARM2_SEC] = MAX77686_ALARM2_SEC,
+ [REG_ALARM2_MIN] = MAX77686_ALARM2_MIN,
+ [REG_ALARM2_HOUR] = MAX77686_ALARM2_HOUR,
+ [REG_ALARM2_WEEKDAY] = MAX77686_ALARM2_WEEKDAY,
+ [REG_ALARM2_MONTH] = MAX77686_ALARM2_MONTH,
+ [REG_ALARM2_YEAR] = MAX77686_ALARM2_YEAR,
+ [REG_ALARM2_DATE] = MAX77686_ALARM2_DATE,
+ [REG_RTC_AE1] = REG_RTC_NONE,
+};
+
+static const struct regmap_irq max77686_rtc_irqs[] = {
+ /* RTC interrupts */
+ REGMAP_IRQ_REG(0, 0, MAX77686_RTCINT_RTC60S_MSK),
+ REGMAP_IRQ_REG(1, 0, MAX77686_RTCINT_RTCA1_MSK),
+ REGMAP_IRQ_REG(2, 0, MAX77686_RTCINT_RTCA2_MSK),
+ REGMAP_IRQ_REG(3, 0, MAX77686_RTCINT_SMPL_MSK),
+ REGMAP_IRQ_REG(4, 0, MAX77686_RTCINT_RTC1S_MSK),
+ REGMAP_IRQ_REG(5, 0, MAX77686_RTCINT_WTSR_MSK),
+};
+
+static const struct regmap_irq_chip max77686_rtc_irq_chip = {
+ .name = "max77686-rtc",
+ .status_base = MAX77686_RTC_INT,
+ .mask_base = MAX77686_RTC_INTM,
+ .num_regs = 1,
+ .irqs = max77686_rtc_irqs,
+ .num_irqs = ARRAY_SIZE(max77686_rtc_irqs),
+};
+
+static const struct max77686_rtc_driver_data max77686_drv_data = {
+ .delay = 16000,
+ .mask = 0x7f,
+ .map = max77686_map,
+ .alarm_enable_reg = false,
+ .rtc_irq_from_platform = false,
+ .alarm_pending_status_reg = MAX77686_REG_STATUS2,
+ .rtc_i2c_addr = MAX77686_I2C_ADDR_RTC,
+ .rtc_irq_chip = &max77686_rtc_irq_chip,
+};
+
+static const struct max77686_rtc_driver_data max77620_drv_data = {
+ .delay = 16000,
+ .mask = 0x7f,
+ .map = max77686_map,
+ .alarm_enable_reg = false,
+ .rtc_irq_from_platform = true,
+ .alarm_pending_status_reg = MAX77686_INVALID_REG,
+ .rtc_i2c_addr = MAX77620_I2C_ADDR_RTC,
+ .rtc_irq_chip = &max77686_rtc_irq_chip,
+};
+
+static const unsigned int max77802_map[REG_RTC_END] = {
+ [REG_RTC_CONTROLM] = MAX77802_RTC_CONTROLM,
+ [REG_RTC_CONTROL] = MAX77802_RTC_CONTROL,
+ [REG_RTC_UPDATE0] = MAX77802_RTC_UPDATE0,
+ [REG_WTSR_SMPL_CNTL] = MAX77802_WTSR_SMPL_CNTL,
+ [REG_RTC_SEC] = MAX77802_RTC_SEC,
+ [REG_RTC_MIN] = MAX77802_RTC_MIN,
+ [REG_RTC_HOUR] = MAX77802_RTC_HOUR,
+ [REG_RTC_WEEKDAY] = MAX77802_RTC_WEEKDAY,
+ [REG_RTC_MONTH] = MAX77802_RTC_MONTH,
+ [REG_RTC_YEAR] = MAX77802_RTC_YEAR,
+ [REG_RTC_DATE] = MAX77802_RTC_DATE,
+ [REG_ALARM1_SEC] = MAX77802_ALARM1_SEC,
+ [REG_ALARM1_MIN] = MAX77802_ALARM1_MIN,
+ [REG_ALARM1_HOUR] = MAX77802_ALARM1_HOUR,
+ [REG_ALARM1_WEEKDAY] = MAX77802_ALARM1_WEEKDAY,
+ [REG_ALARM1_MONTH] = MAX77802_ALARM1_MONTH,
+ [REG_ALARM1_YEAR] = MAX77802_ALARM1_YEAR,
+ [REG_ALARM1_DATE] = MAX77802_ALARM1_DATE,
+ [REG_ALARM2_SEC] = MAX77802_ALARM2_SEC,
+ [REG_ALARM2_MIN] = MAX77802_ALARM2_MIN,
+ [REG_ALARM2_HOUR] = MAX77802_ALARM2_HOUR,
+ [REG_ALARM2_WEEKDAY] = MAX77802_ALARM2_WEEKDAY,
+ [REG_ALARM2_MONTH] = MAX77802_ALARM2_MONTH,
+ [REG_ALARM2_YEAR] = MAX77802_ALARM2_YEAR,
+ [REG_ALARM2_DATE] = MAX77802_ALARM2_DATE,
+ [REG_RTC_AE1] = MAX77802_RTC_AE1,
+};
+
+static const struct regmap_irq_chip max77802_rtc_irq_chip = {
+ .name = "max77802-rtc",
+ .status_base = MAX77802_RTC_INT,
+ .mask_base = MAX77802_RTC_INTM,
+ .num_regs = 1,
+ .irqs = max77686_rtc_irqs, /* same masks as 77686 */
+ .num_irqs = ARRAY_SIZE(max77686_rtc_irqs),
+};
+
+static const struct max77686_rtc_driver_data max77802_drv_data = {
+ .delay = 200,
+ .mask = 0xff,
+ .map = max77802_map,
+ .alarm_enable_reg = true,
+ .rtc_irq_from_platform = false,
+ .alarm_pending_status_reg = MAX77686_REG_STATUS2,
+ .rtc_i2c_addr = MAX77686_INVALID_I2C_ADDR,
+ .rtc_irq_chip = &max77802_rtc_irq_chip,
+};
+
static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
- int rtc_24hr_mode)
+ struct max77686_rtc_info *info)
{
- tm->tm_sec = data[RTC_SEC] & 0x7f;
- tm->tm_min = data[RTC_MIN] & 0x7f;
- if (rtc_24hr_mode)
+ u8 mask = info->drv_data->mask;
+
+ tm->tm_sec = data[RTC_SEC] & mask;
+ tm->tm_min = data[RTC_MIN] & mask;
+ if (info->rtc_24hr_mode) {
tm->tm_hour = data[RTC_HOUR] & 0x1f;
- else {
+ } else {
tm->tm_hour = data[RTC_HOUR] & 0x0f;
if (data[RTC_HOUR] & HOUR_PM_MASK)
tm->tm_hour += 12;
}
/* Only a single bit is set in data[], so fls() would be equivalent */
- tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f) - 1;
+ tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1;
tm->tm_mday = data[RTC_DATE] & 0x1f;
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
- tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
+ tm->tm_year = data[RTC_YEAR] & mask;
tm->tm_yday = 0;
tm->tm_isdst = 0;
+
+ /*
+ * MAX77686 uses 1 bit from sec/min/hour/etc RTC registers and the
+ * year values are just 0..99 so add 100 to support up to 2099.
+ */
+ if (!info->drv_data->alarm_enable_reg)
+ tm->tm_year += 100;
}
-static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
+static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data,
+ struct max77686_rtc_info *info)
{
data[RTC_SEC] = tm->tm_sec;
data[RTC_MIN] = tm->tm_min;
@@ -102,35 +299,44 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
data[RTC_WEEKDAY] = 1 << tm->tm_wday;
data[RTC_DATE] = tm->tm_mday;
data[RTC_MONTH] = tm->tm_mon + 1;
+
+ if (info->drv_data->alarm_enable_reg) {
+ data[RTC_YEAR] = tm->tm_year;
+ return 0;
+ }
+
data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
if (tm->tm_year < 100) {
- pr_warn("RTC cannot handle the year %d. Assume it's 2000.\n",
+ dev_err(info->dev, "RTC cannot handle the year %d.\n",
1900 + tm->tm_year);
return -EINVAL;
}
+
return 0;
}
static int max77686_rtc_update(struct max77686_rtc_info *info,
- enum MAX77686_RTC_OP op)
+ enum MAX77686_RTC_OP op)
{
int ret;
unsigned int data;
+ unsigned long delay = info->drv_data->delay;
if (op == MAX77686_RTC_WRITE)
data = 1 << RTC_UDR_SHIFT;
else
data = 1 << RTC_RBUDR_SHIFT;
- ret = regmap_update_bits(info->max77686->rtc_regmap,
- MAX77686_RTC_UPDATE0, data, data);
+ ret = regmap_update_bits(info->rtc_regmap,
+ info->drv_data->map[REG_RTC_UPDATE0],
+ data, data);
if (ret < 0)
- dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
- __func__, ret, data);
+ dev_err(info->dev, "Fail to write update reg(ret=%d, data=0x%x)\n",
+ ret, data);
else {
- /* Minimum 16ms delay required before RTC update. */
- msleep(MAX77686_RTC_UPDATE_DELAY);
+ /* Minimum delay required before RTC update. */
+ usleep_range(delay, delay * 2);
}
return ret;
@@ -148,14 +354,15 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (ret < 0)
goto out;
- ret = regmap_bulk_read(info->max77686->rtc_regmap,
- MAX77686_RTC_SEC, data, RTC_NR_TIME);
+ ret = regmap_bulk_read(info->rtc_regmap,
+ info->drv_data->map[REG_RTC_SEC],
+ data, ARRAY_SIZE(data));
if (ret < 0) {
- dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret);
+ dev_err(info->dev, "Fail to read time reg(%d)\n", ret);
goto out;
}
- max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
+ max77686_rtc_data_to_tm(data, tm, info);
ret = rtc_valid_tm(tm);
@@ -170,17 +377,17 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm)
u8 data[RTC_NR_TIME];
int ret;
- ret = max77686_rtc_tm_to_data(tm, data);
+ ret = max77686_rtc_tm_to_data(tm, data, info);
if (ret < 0)
return ret;
mutex_lock(&info->lock);
- ret = regmap_bulk_write(info->max77686->rtc_regmap,
- MAX77686_RTC_SEC, data, RTC_NR_TIME);
+ ret = regmap_bulk_write(info->rtc_regmap,
+ info->drv_data->map[REG_RTC_SEC],
+ data, ARRAY_SIZE(data));
if (ret < 0) {
- dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
- ret);
+ dev_err(info->dev, "Fail to write time reg(%d)\n", ret);
goto out;
}
@@ -196,6 +403,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
struct max77686_rtc_info *info = dev_get_drvdata(dev);
u8 data[RTC_NR_TIME];
unsigned int val;
+ const unsigned int *map = info->drv_data->map;
int i, ret;
mutex_lock(&info->lock);
@@ -204,29 +412,53 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret < 0)
goto out;
- ret = regmap_bulk_read(info->max77686->rtc_regmap,
- MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
+ ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC],
+ data, ARRAY_SIZE(data));
if (ret < 0) {
- dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
- __func__, __LINE__, ret);
+ dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret);
goto out;
}
- max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
+ max77686_rtc_data_to_tm(data, &alrm->time, info);
alrm->enabled = 0;
- for (i = 0; i < RTC_NR_TIME; i++) {
- if (data[i] & ALARM_ENABLE_MASK) {
+
+ if (info->drv_data->alarm_enable_reg) {
+ if (map[REG_RTC_AE1] == REG_RTC_NONE) {
+ ret = -EINVAL;
+ dev_err(info->dev,
+ "alarm enable register not set(%d)\n", ret);
+ goto out;
+ }
+
+ ret = regmap_read(info->rtc_regmap, map[REG_RTC_AE1], &val);
+ if (ret < 0) {
+ dev_err(info->dev,
+ "fail to read alarm enable(%d)\n", ret);
+ goto out;
+ }
+
+ if (val)
alrm->enabled = 1;
- break;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(data); i++) {
+ if (data[i] & ALARM_ENABLE_MASK) {
+ alrm->enabled = 1;
+ break;
+ }
}
}
alrm->pending = 0;
- ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val);
+
+ if (info->drv_data->alarm_pending_status_reg == MAX77686_INVALID_REG)
+ goto out;
+
+ ret = regmap_read(info->regmap,
+ info->drv_data->alarm_pending_status_reg, &val);
if (ret < 0) {
- dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
- __func__, __LINE__, ret);
+ dev_err(info->dev,
+ "Fail to read alarm pending status reg(%d)\n", ret);
goto out;
}
@@ -235,7 +467,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
out:
mutex_unlock(&info->lock);
- return 0;
+ return ret;
}
static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
@@ -243,6 +475,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
u8 data[RTC_NR_TIME];
int ret, i;
struct rtc_time tm;
+ const unsigned int *map = info->drv_data->map;
if (!mutex_is_locked(&info->lock))
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
@@ -251,24 +484,34 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
if (ret < 0)
goto out;
- ret = regmap_bulk_read(info->max77686->rtc_regmap,
- MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
- __func__, ret);
- goto out;
- }
+ if (info->drv_data->alarm_enable_reg) {
+ if (map[REG_RTC_AE1] == REG_RTC_NONE) {
+ ret = -EINVAL;
+ dev_err(info->dev,
+ "alarm enable register not set(%d)\n", ret);
+ goto out;
+ }
+
+ ret = regmap_write(info->rtc_regmap, map[REG_RTC_AE1], 0);
+ } else {
+ ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC],
+ data, ARRAY_SIZE(data));
+ if (ret < 0) {
+ dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret);
+ goto out;
+ }
- max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
+ max77686_rtc_data_to_tm(data, &tm, info);
- for (i = 0; i < RTC_NR_TIME; i++)
- data[i] &= ~ALARM_ENABLE_MASK;
+ for (i = 0; i < ARRAY_SIZE(data); i++)
+ data[i] &= ~ALARM_ENABLE_MASK;
+
+ ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC],
+ data, ARRAY_SIZE(data));
+ }
- ret = regmap_bulk_write(info->max77686->rtc_regmap,
- MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
if (ret < 0) {
- dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
- __func__, ret);
+ dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret);
goto out;
}
@@ -282,6 +525,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
u8 data[RTC_NR_TIME];
int ret;
struct rtc_time tm;
+ const unsigned int *map = info->drv_data->map;
if (!mutex_is_locked(&info->lock))
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
@@ -290,32 +534,36 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
if (ret < 0)
goto out;
- ret = regmap_bulk_read(info->max77686->rtc_regmap,
- MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
- __func__, ret);
- goto out;
+ if (info->drv_data->alarm_enable_reg) {
+ ret = regmap_write(info->rtc_regmap, map[REG_RTC_AE1],
+ MAX77802_ALARM_ENABLE_VALUE);
+ } else {
+ ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC],
+ data, ARRAY_SIZE(data));
+ if (ret < 0) {
+ dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret);
+ goto out;
+ }
+
+ max77686_rtc_data_to_tm(data, &tm, info);
+
+ data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
+ data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
+ data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
+ data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
+ if (data[RTC_MONTH] & 0xf)
+ data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
+ if (data[RTC_YEAR] & info->drv_data->mask)
+ data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
+ if (data[RTC_DATE] & 0x1f)
+ data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
+
+ ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC],
+ data, ARRAY_SIZE(data));
}
- max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
-
- data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
- data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
- data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
- data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
- if (data[RTC_MONTH] & 0xf)
- data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
- if (data[RTC_YEAR] & 0x7f)
- data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
- if (data[RTC_DATE] & 0x1f)
- data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
-
- ret = regmap_bulk_write(info->max77686->rtc_regmap,
- MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
if (ret < 0) {
- dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
- __func__, ret);
+ dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret);
goto out;
}
@@ -330,7 +578,7 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
u8 data[RTC_NR_TIME];
int ret;
- ret = max77686_rtc_tm_to_data(&alrm->time, data);
+ ret = max77686_rtc_tm_to_data(&alrm->time, data, info);
if (ret < 0)
return ret;
@@ -340,12 +588,12 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret < 0)
goto out;
- ret = regmap_bulk_write(info->max77686->rtc_regmap,
- MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
+ ret = regmap_bulk_write(info->rtc_regmap,
+ info->drv_data->map[REG_ALARM1_SEC],
+ data, ARRAY_SIZE(data));
if (ret < 0) {
- dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
- __func__, ret);
+ dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret);
goto out;
}
@@ -361,7 +609,7 @@ out:
}
static int max77686_rtc_alarm_irq_enable(struct device *dev,
- unsigned int enabled)
+ unsigned int enabled)
{
struct max77686_rtc_info *info = dev_get_drvdata(dev);
int ret;
@@ -380,7 +628,7 @@ static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data)
{
struct max77686_rtc_info *info = data;
- dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
+ dev_dbg(info->dev, "RTC alarm IRQ: %d\n", irq);
rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
@@ -406,10 +654,11 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
info->rtc_24hr_mode = 1;
- ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2);
+ ret = regmap_bulk_write(info->rtc_regmap,
+ info->drv_data->map[REG_RTC_CONTROLM],
+ data, ARRAY_SIZE(data));
if (ret < 0) {
- dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
- __func__, ret);
+ dev_err(info->dev, "Fail to write controlm reg(%d)\n", ret);
return ret;
}
@@ -417,28 +666,97 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
return ret;
}
+static const struct regmap_config max77686_rtc_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
+{
+ struct device *parent = info->dev->parent;
+ struct i2c_client *parent_i2c = to_i2c_client(parent);
+ int ret;
+
+ if (info->drv_data->rtc_irq_from_platform) {
+ struct platform_device *pdev = to_platform_device(info->dev);
+
+ info->rtc_irq = platform_get_irq(pdev, 0);
+ if (info->rtc_irq < 0) {
+ dev_err(info->dev, "Failed to get rtc interrupts: %d\n",
+ info->rtc_irq);
+ return info->rtc_irq;
+ }
+ } else {
+ info->rtc_irq = parent_i2c->irq;
+ }
+
+ info->regmap = dev_get_regmap(parent, NULL);
+ if (!info->regmap) {
+ dev_err(info->dev, "Failed to get rtc regmap\n");
+ return -ENODEV;
+ }
+
+ if (info->drv_data->rtc_i2c_addr == MAX77686_INVALID_I2C_ADDR) {
+ info->rtc_regmap = info->regmap;
+ goto add_rtc_irq;
+ }
+
+ info->rtc = i2c_new_dummy(parent_i2c->adapter,
+ info->drv_data->rtc_i2c_addr);
+ if (!info->rtc) {
+ dev_err(info->dev, "Failed to allocate I2C device for RTC\n");
+ return -ENODEV;
+ }
+
+ info->rtc_regmap = devm_regmap_init_i2c(info->rtc,
+ &max77686_rtc_regmap_config);
+ if (IS_ERR(info->rtc_regmap)) {
+ ret = PTR_ERR(info->rtc_regmap);
+ dev_err(info->dev, "Failed to allocate RTC regmap: %d\n", ret);
+ goto err_unregister_i2c;
+ }
+
+add_rtc_irq:
+ ret = regmap_add_irq_chip(info->rtc_regmap, info->rtc_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+ IRQF_SHARED, 0, info->drv_data->rtc_irq_chip,
+ &info->rtc_irq_data);
+ if (ret < 0) {
+ dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret);
+ goto err_unregister_i2c;
+ }
+
+ return 0;
+
+err_unregister_i2c:
+ if (info->rtc)
+ i2c_unregister_device(info->rtc);
+ return ret;
+}
+
static int max77686_rtc_probe(struct platform_device *pdev)
{
- struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent);
struct max77686_rtc_info *info;
+ const struct platform_device_id *id = platform_get_device_id(pdev);
int ret;
- dev_info(&pdev->dev, "%s\n", __func__);
-
info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!info)
return -ENOMEM;
mutex_init(&info->lock);
info->dev = &pdev->dev;
- info->max77686 = max77686;
- info->rtc = max77686->rtc;
+ info->drv_data = (const struct max77686_rtc_driver_data *)
+ id->driver_data;
+
+ ret = max77686_init_rtc_regmap(info);
+ if (ret < 0)
+ return ret;
platform_set_drvdata(pdev, info);
ret = max77686_rtc_init_reg(info);
-
if (ret < 0) {
dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
goto err_rtc;
@@ -446,7 +764,7 @@ static int max77686_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc",
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev, id->name,
&max77686_rtc_ops, THIS_MODULE);
if (IS_ERR(info->rtc_dev)) {
@@ -457,29 +775,43 @@ static int max77686_rtc_probe(struct platform_device *pdev)
goto err_rtc;
}
- if (!max77686->rtc_irq_data) {
- ret = -EINVAL;
- dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__);
- goto err_rtc;
- }
-
- info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
+ info->virq = regmap_irq_get_virq(info->rtc_irq_data,
MAX77686_RTCIRQ_RTCA1);
- if (!info->virq) {
+ if (info->virq <= 0) {
ret = -ENXIO;
goto err_rtc;
}
- ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
- max77686_rtc_alarm_irq, 0, "rtc-alarm1", info);
- if (ret < 0)
+ ret = request_threaded_irq(info->virq, NULL, max77686_rtc_alarm_irq, 0,
+ "rtc-alarm1", info);
+ if (ret < 0) {
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
info->virq, ret);
+ goto err_rtc;
+ }
+
+ return 0;
err_rtc:
+ regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data);
+ if (info->rtc)
+ i2c_unregister_device(info->rtc);
+
return ret;
}
+static int max77686_rtc_remove(struct platform_device *pdev)
+{
+ struct max77686_rtc_info *info = platform_get_drvdata(pdev);
+
+ free_irq(info->virq, info);
+ regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data);
+ if (info->rtc)
+ i2c_unregister_device(info->rtc);
+
+ return 0;
+}
+
#ifdef CONFIG_PM_SLEEP
static int max77686_rtc_suspend(struct device *dev)
{
@@ -508,7 +840,9 @@ static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
max77686_rtc_suspend, max77686_rtc_resume);
static const struct platform_device_id rtc_id[] = {
- { "max77686-rtc", 0 },
+ { "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, },
+ { "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data, },
+ { "max77620-rtc", .driver_data = (kernel_ulong_t)&max77620_drv_data, },
{},
};
MODULE_DEVICE_TABLE(platform, rtc_id);
@@ -519,6 +853,7 @@ static struct platform_driver max77686_rtc_driver = {
.pm = &max77686_rtc_pm_ops,
},
.probe = max77686_rtc_probe,
+ .remove = max77686_rtc_remove,
.id_table = rtc_id,
};
diff --git a/drivers/rtc/rtc-max77802.c b/drivers/rtc/rtc-max77802.c
deleted file mode 100644
index 82ffcc5a5345..000000000000
--- a/drivers/rtc/rtc-max77802.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * RTC driver for Maxim MAX77802
- *
- * Copyright (C) 2013 Google, Inc
- *
- * Copyright (C) 2012 Samsung Electronics Co.Ltd
- *
- * based on rtc-max8997.c
- *
- * 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.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/rtc.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/max77686-private.h>
-#include <linux/irqdomain.h>
-#include <linux/regmap.h>
-
-/* RTC Control Register */
-#define BCD_EN_SHIFT 0
-#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
-#define MODEL24_SHIFT 1
-#define MODEL24_MASK (1 << MODEL24_SHIFT)
-/* RTC Update Register1 */
-#define RTC_UDR_SHIFT 0
-#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
-#define RTC_RBUDR_SHIFT 4
-#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
-/* RTC Hour register */
-#define HOUR_PM_SHIFT 6
-#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
-/* RTC Alarm Enable */
-#define ALARM_ENABLE_SHIFT 7
-#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
-
-/* For the RTCAE1 register, we write this value to enable the alarm */
-#define ALARM_ENABLE_VALUE 0x77
-
-#define MAX77802_RTC_UPDATE_DELAY_US 200
-
-enum {
- RTC_SEC = 0,
- RTC_MIN,
- RTC_HOUR,
- RTC_WEEKDAY,
- RTC_MONTH,
- RTC_YEAR,
- RTC_DATE,
- RTC_NR_TIME
-};
-
-struct max77802_rtc_info {
- struct device *dev;
- struct max77686_dev *max77802;
- struct i2c_client *rtc;
- struct rtc_device *rtc_dev;
- struct mutex lock;
-
- struct regmap *regmap;
-
- int virq;
- int rtc_24hr_mode;
-};
-
-enum MAX77802_RTC_OP {
- MAX77802_RTC_WRITE,
- MAX77802_RTC_READ,
-};
-
-static void max77802_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
- int rtc_24hr_mode)
-{
- tm->tm_sec = data[RTC_SEC] & 0xff;
- tm->tm_min = data[RTC_MIN] & 0xff;
- if (rtc_24hr_mode)
- tm->tm_hour = data[RTC_HOUR] & 0x1f;
- else {
- tm->tm_hour = data[RTC_HOUR] & 0x0f;
- if (data[RTC_HOUR] & HOUR_PM_MASK)
- tm->tm_hour += 12;
- }
-
- /* Only a single bit is set in data[], so fls() would be equivalent */
- tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0xff) - 1;
- tm->tm_mday = data[RTC_DATE] & 0x1f;
- tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
-
- tm->tm_year = data[RTC_YEAR] & 0xff;
- tm->tm_yday = 0;
- tm->tm_isdst = 0;
-}
-
-static int max77802_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
-{
- data[RTC_SEC] = tm->tm_sec;
- data[RTC_MIN] = tm->tm_min;
- data[RTC_HOUR] = tm->tm_hour;
- data[RTC_WEEKDAY] = 1 << tm->tm_wday;
- data[RTC_DATE] = tm->tm_mday;
- data[RTC_MONTH] = tm->tm_mon + 1;
- data[RTC_YEAR] = tm->tm_year;
-
- return 0;
-}
-
-static int max77802_rtc_update(struct max77802_rtc_info *info,
- enum MAX77802_RTC_OP op)
-{
- int ret;
- unsigned int data;
-
- if (op == MAX77802_RTC_WRITE)
- data = 1 << RTC_UDR_SHIFT;
- else
- data = 1 << RTC_RBUDR_SHIFT;
-
- ret = regmap_update_bits(info->max77802->regmap,
- MAX77802_RTC_UPDATE0, data, data);
- if (ret < 0)
- dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
- __func__, ret, data);
- else {
- /* Minimum delay required before RTC update. */
- usleep_range(MAX77802_RTC_UPDATE_DELAY_US,
- MAX77802_RTC_UPDATE_DELAY_US * 2);
- }
-
- return ret;
-}
-
-static int max77802_rtc_read_time(struct device *dev, struct rtc_time *tm)
-{
- struct max77802_rtc_info *info = dev_get_drvdata(dev);
- u8 data[RTC_NR_TIME];
- int ret;
-
- mutex_lock(&info->lock);
-
- ret = max77802_rtc_update(info, MAX77802_RTC_READ);
- if (ret < 0)
- goto out;
-
- ret = regmap_bulk_read(info->max77802->regmap,
- MAX77802_RTC_SEC, data, RTC_NR_TIME);
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
- ret);
- goto out;
- }
-
- max77802_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
-
- ret = rtc_valid_tm(tm);
-
-out:
- mutex_unlock(&info->lock);
- return ret;
-}
-
-static int max77802_rtc_set_time(struct device *dev, struct rtc_time *tm)
-{
- struct max77802_rtc_info *info = dev_get_drvdata(dev);
- u8 data[RTC_NR_TIME];
- int ret;
-
- ret = max77802_rtc_tm_to_data(tm, data);
- if (ret < 0)
- return ret;
-
- mutex_lock(&info->lock);
-
- ret = regmap_bulk_write(info->max77802->regmap,
- MAX77802_RTC_SEC, data, RTC_NR_TIME);
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
- ret);
- goto out;
- }
-
- ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
-
-out:
- mutex_unlock(&info->lock);
- return ret;
-}
-
-static int max77802_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
-{
- struct max77802_rtc_info *info = dev_get_drvdata(dev);
- u8 data[RTC_NR_TIME];
- unsigned int val;
- int ret;
-
- mutex_lock(&info->lock);
-
- ret = max77802_rtc_update(info, MAX77802_RTC_READ);
- if (ret < 0)
- goto out;
-
- ret = regmap_bulk_read(info->max77802->regmap,
- MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
- if (ret < 0) {
- dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
- __func__, __LINE__, ret);
- goto out;
- }
-
- max77802_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
-
- alrm->enabled = 0;
- ret = regmap_read(info->max77802->regmap,
- MAX77802_RTC_AE1, &val);
- if (ret < 0) {
- dev_err(info->dev, "%s:%d fail to read alarm enable(%d)\n",
- __func__, __LINE__, ret);
- goto out;
- }
- if (val)
- alrm->enabled = 1;
-
- alrm->pending = 0;
- ret = regmap_read(info->max77802->regmap, MAX77802_REG_STATUS2, &val);
- if (ret < 0) {
- dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
- __func__, __LINE__, ret);
- goto out;
- }
-
- if (val & (1 << 2)) /* RTCA1 */
- alrm->pending = 1;
-
-out:
- mutex_unlock(&info->lock);
- return 0;
-}
-
-static int max77802_rtc_stop_alarm(struct max77802_rtc_info *info)
-{
- int ret;
-
- if (!mutex_is_locked(&info->lock))
- dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
-
- ret = max77802_rtc_update(info, MAX77802_RTC_READ);
- if (ret < 0)
- goto out;
-
- ret = regmap_write(info->max77802->regmap,
- MAX77802_RTC_AE1, 0);
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
- __func__, ret);
- goto out;
- }
-
- ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
-out:
- return ret;
-}
-
-static int max77802_rtc_start_alarm(struct max77802_rtc_info *info)
-{
- int ret;
-
- if (!mutex_is_locked(&info->lock))
- dev_warn(info->dev, "%s: should have mutex locked\n",
- __func__);
-
- ret = max77802_rtc_update(info, MAX77802_RTC_READ);
- if (ret < 0)
- goto out;
-
- ret = regmap_write(info->max77802->regmap,
- MAX77802_RTC_AE1,
- ALARM_ENABLE_VALUE);
-
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
- __func__, ret);
- goto out;
- }
-
- ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
-out:
- return ret;
-}
-
-static int max77802_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
-{
- struct max77802_rtc_info *info = dev_get_drvdata(dev);
- u8 data[RTC_NR_TIME];
- int ret;
-
- ret = max77802_rtc_tm_to_data(&alrm->time, data);
- if (ret < 0)
- return ret;
-
- mutex_lock(&info->lock);
-
- ret = max77802_rtc_stop_alarm(info);
- if (ret < 0)
- goto out;
-
- ret = regmap_bulk_write(info->max77802->regmap,
- MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
-
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
- __func__, ret);
- goto out;
- }
-
- ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
- if (ret < 0)
- goto out;
-
- if (alrm->enabled)
- ret = max77802_rtc_start_alarm(info);
-out:
- mutex_unlock(&info->lock);
- return ret;
-}
-
-static int max77802_rtc_alarm_irq_enable(struct device *dev,
- unsigned int enabled)
-{
- struct max77802_rtc_info *info = dev_get_drvdata(dev);
- int ret;
-
- mutex_lock(&info->lock);
- if (enabled)
- ret = max77802_rtc_start_alarm(info);
- else
- ret = max77802_rtc_stop_alarm(info);
- mutex_unlock(&info->lock);
-
- return ret;
-}
-
-static irqreturn_t max77802_rtc_alarm_irq(int irq, void *data)
-{
- struct max77802_rtc_info *info = data;
-
- dev_dbg(info->dev, "%s:irq(%d)\n", __func__, irq);
-
- rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
-
- return IRQ_HANDLED;
-}
-
-static const struct rtc_class_ops max77802_rtc_ops = {
- .read_time = max77802_rtc_read_time,
- .set_time = max77802_rtc_set_time,
- .read_alarm = max77802_rtc_read_alarm,
- .set_alarm = max77802_rtc_set_alarm,
- .alarm_irq_enable = max77802_rtc_alarm_irq_enable,
-};
-
-static int max77802_rtc_init_reg(struct max77802_rtc_info *info)
-{
- u8 data[2];
- int ret;
-
- max77802_rtc_update(info, MAX77802_RTC_READ);
-
- /* Set RTC control register : Binary mode, 24hour mdoe */
- data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
- data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
-
- info->rtc_24hr_mode = 1;
-
- ret = regmap_bulk_write(info->max77802->regmap,
- MAX77802_RTC_CONTROLM, data, ARRAY_SIZE(data));
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
- __func__, ret);
- return ret;
- }
-
- ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
- return ret;
-}
-
-static int max77802_rtc_probe(struct platform_device *pdev)
-{
- struct max77686_dev *max77802 = dev_get_drvdata(pdev->dev.parent);
- struct max77802_rtc_info *info;
- int ret;
-
- dev_dbg(&pdev->dev, "%s\n", __func__);
-
- info = devm_kzalloc(&pdev->dev, sizeof(struct max77802_rtc_info),
- GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- mutex_init(&info->lock);
- info->dev = &pdev->dev;
- info->max77802 = max77802;
- info->rtc = max77802->i2c;
-
- platform_set_drvdata(pdev, info);
-
- ret = max77802_rtc_init_reg(info);
-
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
- return ret;
- }
-
- device_init_wakeup(&pdev->dev, 1);
-
- info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77802-rtc",
- &max77802_rtc_ops, THIS_MODULE);
-
- if (IS_ERR(info->rtc_dev)) {
- ret = PTR_ERR(info->rtc_dev);
- dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
- if (ret == 0)
- ret = -EINVAL;
- return ret;
- }
-
- if (!max77802->rtc_irq_data) {
- dev_err(&pdev->dev, "No RTC regmap IRQ chip\n");
- return -EINVAL;
- }
-
- info->virq = regmap_irq_get_virq(max77802->rtc_irq_data,
- MAX77686_RTCIRQ_RTCA1);
-
- if (info->virq <= 0) {
- dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
- MAX77686_RTCIRQ_RTCA1);
- return -EINVAL;
- }
-
- ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
- max77802_rtc_alarm_irq, 0, "rtc-alarm1",
- info);
- if (ret < 0)
- dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
- info->virq, ret);
-
- return ret;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int max77802_rtc_suspend(struct device *dev)
-{
- if (device_may_wakeup(dev)) {
- struct max77802_rtc_info *info = dev_get_drvdata(dev);
-
- return enable_irq_wake(info->virq);
- }
-
- return 0;
-}
-
-static int max77802_rtc_resume(struct device *dev)
-{
- if (device_may_wakeup(dev)) {
- struct max77802_rtc_info *info = dev_get_drvdata(dev);
-
- return disable_irq_wake(info->virq);
- }
-
- return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(max77802_rtc_pm_ops,
- max77802_rtc_suspend, max77802_rtc_resume);
-
-static const struct platform_device_id rtc_id[] = {
- { "max77802-rtc", 0 },
- {},
-};
-MODULE_DEVICE_TABLE(platform, rtc_id);
-
-static struct platform_driver max77802_rtc_driver = {
- .driver = {
- .name = "max77802-rtc",
- .pm = &max77802_rtc_pm_ops,
- },
- .probe = max77802_rtc_probe,
- .id_table = rtc_id,
-};
-
-module_platform_driver(max77802_rtc_driver);
-
-MODULE_DESCRIPTION("Maxim MAX77802 RTC driver");
-MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
index 06a5c52b292f..44f622c3e048 100644
--- a/drivers/rtc/rtc-mt6397.c
+++ b/drivers/rtc/rtc-mt6397.c
@@ -419,4 +419,3 @@ module_platform_driver(mtk_rtc_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Tianping Fang <tianping.fang@mediatek.com>");
MODULE_DESCRIPTION("RTC Driver for MediaTek MT6397 PMIC");
-MODULE_ALIAS("platform:mt6397-rtc");
diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c
index 7ea2c471feca..6080e0edef63 100644
--- a/drivers/rtc/rtc-palmas.c
+++ b/drivers/rtc/rtc-palmas.c
@@ -311,8 +311,7 @@ static int palmas_rtc_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, palmas_rtc->irq, NULL,
palmas_rtc_interrupt,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT |
- IRQF_EARLY_RESUME,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
dev_name(&pdev->dev), palmas_rtc);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret);
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index ea8a31c91641..da27738b1242 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -48,6 +48,7 @@
#define DRV_VERSION "0.6"
+/* REGISTERS */
#define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */
#define PCF2123_REG_CTRL2 (0x01) /* Control Register 2 */
#define PCF2123_REG_SC (0x02) /* datetime */
@@ -57,10 +58,54 @@
#define PCF2123_REG_DW (0x06)
#define PCF2123_REG_MO (0x07)
#define PCF2123_REG_YR (0x08)
+#define PCF2123_REG_ALRM_MN (0x09) /* Alarm Registers */
+#define PCF2123_REG_ALRM_HR (0x0a)
+#define PCF2123_REG_ALRM_DM (0x0b)
+#define PCF2123_REG_ALRM_DW (0x0c)
+#define PCF2123_REG_OFFSET (0x0d) /* Clock Rate Offset Register */
+#define PCF2123_REG_TMR_CLKOUT (0x0e) /* Timer Registers */
+#define PCF2123_REG_CTDWN_TMR (0x0f)
+
+/* PCF2123_REG_CTRL1 BITS */
+#define CTRL1_CLEAR (0) /* Clear */
+#define CTRL1_CORR_INT BIT(1) /* Correction irq enable */
+#define CTRL1_12_HOUR BIT(2) /* 12 hour time */
+#define CTRL1_SW_RESET (BIT(3) | BIT(4) | BIT(6)) /* Software reset */
+#define CTRL1_STOP BIT(5) /* Stop the clock */
+#define CTRL1_EXT_TEST BIT(7) /* External clock test mode */
+
+/* PCF2123_REG_CTRL2 BITS */
+#define CTRL2_TIE BIT(0) /* Countdown timer irq enable */
+#define CTRL2_AIE BIT(1) /* Alarm irq enable */
+#define CTRL2_TF BIT(2) /* Countdown timer flag */
+#define CTRL2_AF BIT(3) /* Alarm flag */
+#define CTRL2_TI_TP BIT(4) /* Irq pin generates pulse */
+#define CTRL2_MSF BIT(5) /* Minute or second irq flag */
+#define CTRL2_SI BIT(6) /* Second irq enable */
+#define CTRL2_MI BIT(7) /* Minute irq enable */
+
+/* PCF2123_REG_SC BITS */
+#define OSC_HAS_STOPPED BIT(7) /* Clock has been stopped */
+
+/* PCF2123_REG_ALRM_XX BITS */
+#define ALRM_ENABLE BIT(7) /* MN, HR, DM, or DW alarm enable */
+
+/* PCF2123_REG_TMR_CLKOUT BITS */
+#define CD_TMR_4096KHZ (0) /* 4096 KHz countdown timer */
+#define CD_TMR_64HZ (1) /* 64 Hz countdown timer */
+#define CD_TMR_1HZ (2) /* 1 Hz countdown timer */
+#define CD_TMR_60th_HZ (3) /* 60th Hz countdown timer */
+#define CD_TMR_TE BIT(3) /* Countdown timer enable */
+
+/* PCF2123_REG_OFFSET BITS */
+#define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */
+#define OFFSET_COARSE BIT(7) /* Coarse mode offset */
+#define OFFSET_STEP (2170) /* Offset step in parts per billion */
+
+/* READ/WRITE ADDRESS BITS */
+#define PCF2123_WRITE BIT(4)
+#define PCF2123_READ (BIT(4) | BIT(7))
-#define PCF2123_SUBADDR (1 << 4)
-#define PCF2123_WRITE ((0 << 7) | PCF2123_SUBADDR)
-#define PCF2123_READ ((1 << 7) | PCF2123_SUBADDR)
static struct spi_driver pcf2123_driver;
@@ -84,12 +129,44 @@ static inline void pcf2123_delay_trec(void)
ndelay(30);
}
+static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ int ret;
+
+ reg |= PCF2123_READ;
+ ret = spi_write_then_read(spi, &reg, 1, rxbuf, size);
+ pcf2123_delay_trec();
+
+ return ret;
+}
+
+static int pcf2123_write(struct device *dev, u8 *txbuf, size_t size)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ int ret;
+
+ txbuf[0] |= PCF2123_WRITE;
+ ret = spi_write(spi, txbuf, size);
+ pcf2123_delay_trec();
+
+ return ret;
+}
+
+static int pcf2123_write_reg(struct device *dev, u8 reg, u8 val)
+{
+ u8 txbuf[2];
+
+ txbuf[0] = reg;
+ txbuf[1] = val;
+ return pcf2123_write(dev, txbuf, sizeof(txbuf));
+}
+
static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
char *buffer)
{
- struct spi_device *spi = to_spi_device(dev);
struct pcf2123_sysfs_reg *r;
- u8 txbuf[1], rxbuf[1];
+ u8 rxbuf[1];
unsigned long reg;
int ret;
@@ -99,19 +176,16 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
- txbuf[0] = PCF2123_READ | reg;
- ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
+ ret = pcf2123_read(dev, reg, rxbuf, 1);
if (ret < 0)
return -EIO;
- pcf2123_delay_trec();
+
return sprintf(buffer, "0x%x\n", rxbuf[0]);
}
static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
const char *buffer, size_t count) {
- struct spi_device *spi = to_spi_device(dev);
struct pcf2123_sysfs_reg *r;
- u8 txbuf[2];
unsigned long reg;
unsigned long val;
@@ -127,27 +201,78 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
- txbuf[0] = PCF2123_WRITE | reg;
- txbuf[1] = val;
- ret = spi_write(spi, txbuf, sizeof(txbuf));
+ pcf2123_write_reg(dev, reg, val);
if (ret < 0)
return -EIO;
- pcf2123_delay_trec();
return count;
}
+static int pcf2123_read_offset(struct device *dev, long *offset)
+{
+ int ret;
+ s8 reg;
+
+ ret = pcf2123_read(dev, PCF2123_REG_OFFSET, &reg, 1);
+ if (ret < 0)
+ return ret;
+
+ if (reg & OFFSET_COARSE)
+ reg <<= 1; /* multiply by 2 and sign extend */
+ else
+ reg |= (reg & OFFSET_SIGN_BIT) << 1; /* sign extend only */
+
+ *offset = ((long)reg) * OFFSET_STEP;
+
+ return 0;
+}
+
+/*
+ * The offset register is a 7 bit signed value with a coarse bit in bit 7.
+ * The main difference between the two is normal offset adjusts the first
+ * second of n minutes every other hour, with 61, 62 and 63 being shoved
+ * into the 60th minute.
+ * The coarse adjustment does the same, but every hour.
+ * the two overlap, with every even normal offset value corresponding
+ * to a coarse offset. Based on this algorithm, it seems that despite the
+ * name, coarse offset is a better fit for overlapping values.
+ */
+static int pcf2123_set_offset(struct device *dev, long offset)
+{
+ s8 reg;
+
+ if (offset > OFFSET_STEP * 127)
+ reg = 127;
+ else if (offset < OFFSET_STEP * -128)
+ reg = -128;
+ else
+ reg = (s8)((offset + (OFFSET_STEP >> 1)) / OFFSET_STEP);
+
+ /* choose fine offset only for odd values in the normal range */
+ if (reg & 1 && reg <= 63 && reg >= -64) {
+ /* Normal offset. Clear the coarse bit */
+ reg &= ~OFFSET_COARSE;
+ } else {
+ /* Coarse offset. Divide by 2 and set the coarse bit */
+ reg >>= 1;
+ reg |= OFFSET_COARSE;
+ }
+
+ return pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg);
+}
+
static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct spi_device *spi = to_spi_device(dev);
- u8 txbuf[1], rxbuf[7];
+ u8 rxbuf[7];
int ret;
- txbuf[0] = PCF2123_READ | PCF2123_REG_SC;
- ret = spi_write_then_read(spi, txbuf, sizeof(txbuf),
- rxbuf, sizeof(rxbuf));
+ ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf));
if (ret < 0)
return ret;
- pcf2123_delay_trec();
+
+ if (rxbuf[0] & OSC_HAS_STOPPED) {
+ dev_info(dev, "clock was stopped. Time is not valid\n");
+ return -EINVAL;
+ }
tm->tm_sec = bcd2bin(rxbuf[0] & 0x7F);
tm->tm_min = bcd2bin(rxbuf[1] & 0x7F);
@@ -170,7 +295,6 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- struct spi_device *spi = to_spi_device(dev);
u8 txbuf[8];
int ret;
@@ -181,15 +305,12 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
/* Stop the counter first */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x20;
- ret = spi_write(spi, txbuf, 2);
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
if (ret < 0)
return ret;
- pcf2123_delay_trec();
/* Set the new time */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_SC;
+ txbuf[0] = PCF2123_REG_SC;
txbuf[1] = bin2bcd(tm->tm_sec & 0x7F);
txbuf[2] = bin2bcd(tm->tm_min & 0x7F);
txbuf[3] = bin2bcd(tm->tm_hour & 0x3F);
@@ -198,18 +319,48 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
- ret = spi_write(spi, txbuf, sizeof(txbuf));
+ ret = pcf2123_write(dev, txbuf, sizeof(txbuf));
if (ret < 0)
return ret;
- pcf2123_delay_trec();
/* Start the counter */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x00;
- ret = spi_write(spi, txbuf, 2);
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int pcf2123_reset(struct device *dev)
+{
+ int ret;
+ u8 rxbuf[2];
+
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
+ if (ret < 0)
+ return ret;
+
+ /* Stop the counter */
+ dev_dbg(dev, "stopping RTC\n");
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
+ if (ret < 0)
+ return ret;
+
+ /* See if the counter was actually stopped */
+ dev_dbg(dev, "checking for presence of RTC\n");
+ ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf));
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n",
+ rxbuf[0], rxbuf[1]);
+ if (!(rxbuf[0] & CTRL1_STOP))
+ return -ENODEV;
+
+ /* Start the counter */
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
if (ret < 0)
return ret;
- pcf2123_delay_trec();
return 0;
}
@@ -217,13 +368,16 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
static const struct rtc_class_ops pcf2123_rtc_ops = {
.read_time = pcf2123_rtc_read_time,
.set_time = pcf2123_rtc_set_time,
+ .read_offset = pcf2123_read_offset,
+ .set_offset = pcf2123_set_offset,
+
};
static int pcf2123_probe(struct spi_device *spi)
{
struct rtc_device *rtc;
+ struct rtc_time tm;
struct pcf2123_plat_data *pdata;
- u8 txbuf[2], rxbuf[2];
int ret, i;
pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data),
@@ -232,56 +386,19 @@ static int pcf2123_probe(struct spi_device *spi)
return -ENOMEM;
spi->dev.platform_data = pdata;
- /* Send a software reset command */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x58;
- dev_dbg(&spi->dev, "resetting RTC (0x%02X 0x%02X)\n",
- txbuf[0], txbuf[1]);
- ret = spi_write(spi, txbuf, 2 * sizeof(u8));
- if (ret < 0)
- goto kfree_exit;
- pcf2123_delay_trec();
-
- /* Stop the counter */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x20;
- dev_dbg(&spi->dev, "stopping RTC (0x%02X 0x%02X)\n",
- txbuf[0], txbuf[1]);
- ret = spi_write(spi, txbuf, 2 * sizeof(u8));
- if (ret < 0)
- goto kfree_exit;
- pcf2123_delay_trec();
-
- /* See if the counter was actually stopped */
- txbuf[0] = PCF2123_READ | PCF2123_REG_CTRL1;
- dev_dbg(&spi->dev, "checking for presence of RTC (0x%02X)\n",
- txbuf[0]);
- ret = spi_write_then_read(spi, txbuf, 1 * sizeof(u8),
- rxbuf, 2 * sizeof(u8));
- dev_dbg(&spi->dev, "received data from RTC (0x%02X 0x%02X)\n",
- rxbuf[0], rxbuf[1]);
- if (ret < 0)
- goto kfree_exit;
- pcf2123_delay_trec();
-
- if (!(rxbuf[0] & 0x20)) {
- dev_err(&spi->dev, "chip not found\n");
- ret = -ENODEV;
- goto kfree_exit;
+ ret = pcf2123_rtc_read_time(&spi->dev, &tm);
+ if (ret < 0) {
+ ret = pcf2123_reset(&spi->dev);
+ if (ret < 0) {
+ dev_err(&spi->dev, "chip not found\n");
+ goto kfree_exit;
+ }
}
dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n");
dev_info(&spi->dev, "spiclk %u KHz.\n",
(spi->max_speed_hz + 500) / 1000);
- /* Start the counter */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x00;
- ret = spi_write(spi, txbuf, sizeof(txbuf));
- if (ret < 0)
- goto kfree_exit;
- pcf2123_delay_trec();
-
/* Finalize the initialization */
rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name,
&pcf2123_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 629bfdf8c745..2bfdf638b673 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -1,12 +1,12 @@
/*
- * An I2C driver for the NXP PCF2127 RTC
+ * An I2C and SPI driver for the NXP PCF2127/29 RTC
* Copyright 2013 Til-Technologies
*
* Author: Renaud Cerrato <r.cerrato@til-technologies.fr>
*
* based on the other drivers in this same directory.
*
- * http://www.nxp.com/documents/data_sheet/PCF2127AT.pdf
+ * Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf
*
* 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
@@ -14,11 +14,13 @@
*/
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/regmap.h>
#define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */
#define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */
@@ -36,29 +38,30 @@
#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */
-static struct i2c_driver pcf2127_driver;
-
struct pcf2127 {
struct rtc_device *rtc;
+ struct regmap *regmap;
};
/*
* In the routines that deal directly with the pcf2127 hardware, we use
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
*/
-static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- unsigned char buf[10] = { PCF2127_REG_CTRL1 };
+ struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
+ unsigned char buf[10];
+ int ret;
- /* read registers */
- if (i2c_master_send(client, buf, 1) != 1 ||
- i2c_master_recv(client, buf, sizeof(buf)) != sizeof(buf)) {
- dev_err(&client->dev, "%s: read error\n", __func__);
- return -EIO;
+ ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, buf,
+ sizeof(buf));
+ if (ret) {
+ dev_err(dev, "%s: read error\n", __func__);
+ return ret;
}
if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF)
- dev_info(&client->dev,
+ dev_info(dev,
"low voltage detected, check/replace RTC battery.\n");
if (buf[PCF2127_REG_SC] & PCF2127_OSF) {
@@ -66,12 +69,12 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
* no need clear the flag here,
* it will be cleared once the new date is saved
*/
- dev_warn(&client->dev,
+ dev_warn(dev,
"oscillator stop detected, date/time is not reliable\n");
return -EINVAL;
}
- dev_dbg(&client->dev,
+ dev_dbg(dev,
"%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, "
"sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
@@ -91,7 +94,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
if (tm->tm_year < 70)
tm->tm_year += 100; /* assume we are in 1970...2069 */
- dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
@@ -100,20 +103,18 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
return rtc_valid_tm(tm);
}
-static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- unsigned char buf[8];
+ struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
+ unsigned char buf[7];
int i = 0, err;
- dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
+ dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
- /* start register address */
- buf[i++] = PCF2127_REG_SC;
-
/* hours, minutes and seconds */
buf[i++] = bin2bcd(tm->tm_sec); /* this will also clear OSF flag */
buf[i++] = bin2bcd(tm->tm_min);
@@ -128,11 +129,11 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
buf[i++] = bin2bcd(tm->tm_year % 100);
/* write register's data */
- err = i2c_master_send(client, buf, i);
- if (err != i) {
- dev_err(&client->dev,
+ err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i);
+ if (err) {
+ dev_err(dev,
"%s: err=%d", __func__, err);
- return -EIO;
+ return err;
}
return 0;
@@ -142,26 +143,17 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf2127_rtc_ioctl(struct device *dev,
unsigned int cmd, unsigned long arg)
{
- struct i2c_client *client = to_i2c_client(dev);
- unsigned char buf = PCF2127_REG_CTRL3;
+ struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
int touser;
int ret;
switch (cmd) {
case RTC_VL_READ:
- ret = i2c_master_send(client, &buf, 1);
- if (!ret)
- ret = -EIO;
- if (ret < 0)
- return ret;
-
- ret = i2c_master_recv(client, &buf, 1);
- if (!ret)
- ret = -EIO;
- if (ret < 0)
+ ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &touser);
+ if (ret)
return ret;
- touser = buf & PCF2127_REG_CTRL3_BLF ? 1 : 0;
+ touser = touser & PCF2127_REG_CTRL3_BLF ? 1 : 0;
if (copy_to_user((void __user *)arg, &touser, sizeof(int)))
return -EFAULT;
@@ -174,71 +166,270 @@ static int pcf2127_rtc_ioctl(struct device *dev,
#define pcf2127_rtc_ioctl NULL
#endif
-static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
-{
- return pcf2127_get_datetime(to_i2c_client(dev), tm);
-}
-
-static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm)
-{
- return pcf2127_set_datetime(to_i2c_client(dev), tm);
-}
-
static const struct rtc_class_ops pcf2127_rtc_ops = {
.ioctl = pcf2127_rtc_ioctl,
.read_time = pcf2127_rtc_read_time,
.set_time = pcf2127_rtc_set_time,
};
-static int pcf2127_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int pcf2127_probe(struct device *dev, struct regmap *regmap,
+ const char *name)
{
struct pcf2127 *pcf2127;
- dev_dbg(&client->dev, "%s\n", __func__);
+ dev_dbg(dev, "%s\n", __func__);
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
- return -ENODEV;
-
- pcf2127 = devm_kzalloc(&client->dev, sizeof(struct pcf2127),
- GFP_KERNEL);
+ pcf2127 = devm_kzalloc(dev, sizeof(*pcf2127), GFP_KERNEL);
if (!pcf2127)
return -ENOMEM;
- i2c_set_clientdata(client, pcf2127);
+ pcf2127->regmap = regmap;
+
+ dev_set_drvdata(dev, pcf2127);
- pcf2127->rtc = devm_rtc_device_register(&client->dev,
- pcf2127_driver.driver.name,
- &pcf2127_rtc_ops, THIS_MODULE);
+ pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops,
+ THIS_MODULE);
return PTR_ERR_OR_ZERO(pcf2127->rtc);
}
-static const struct i2c_device_id pcf2127_id[] = {
- { "pcf2127", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, pcf2127_id);
-
#ifdef CONFIG_OF
static const struct of_device_id pcf2127_of_match[] = {
{ .compatible = "nxp,pcf2127" },
+ { .compatible = "nxp,pcf2129" },
{}
};
MODULE_DEVICE_TABLE(of, pcf2127_of_match);
#endif
-static struct i2c_driver pcf2127_driver = {
+#if IS_ENABLED(CONFIG_I2C)
+
+static int pcf2127_i2c_write(void *context, const void *data, size_t count)
+{
+ struct device *dev = context;
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret;
+
+ ret = i2c_master_send(client, data, count);
+ if (ret != count)
+ return ret < 0 ? ret : -EIO;
+
+ return 0;
+}
+
+static int pcf2127_i2c_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
+{
+ struct device *dev = context;
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret;
+ void *buf;
+
+ if (WARN_ON(reg_size != 1))
+ return -EINVAL;
+
+ buf = kmalloc(val_size + 1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, reg, 1);
+ memcpy(buf + 1, val, val_size);
+
+ ret = i2c_master_send(client, buf, val_size + 1);
+ if (ret != val_size + 1)
+ return ret < 0 ? ret : -EIO;
+
+ return 0;
+}
+
+static int pcf2127_i2c_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct device *dev = context;
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret;
+
+ if (WARN_ON(reg_size != 1))
+ return -EINVAL;
+
+ ret = i2c_master_send(client, reg, 1);
+ if (ret != 1)
+ return ret < 0 ? ret : -EIO;
+
+ ret = i2c_master_recv(client, val, val_size);
+ if (ret != val_size)
+ return ret < 0 ? ret : -EIO;
+
+ return 0;
+}
+
+/*
+ * The reason we need this custom regmap_bus instead of using regmap_init_i2c()
+ * is that the STOP condition is required between set register address and
+ * read register data when reading from registers.
+ */
+static const struct regmap_bus pcf2127_i2c_regmap = {
+ .write = pcf2127_i2c_write,
+ .gather_write = pcf2127_i2c_gather_write,
+ .read = pcf2127_i2c_read,
+};
+
+static struct i2c_driver pcf2127_i2c_driver;
+
+static int pcf2127_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ static const struct regmap_config config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ };
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap,
+ &client->dev, &config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "%s: regmap allocation failed: %ld\n",
+ __func__, PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ return pcf2127_probe(&client->dev, regmap,
+ pcf2127_i2c_driver.driver.name);
+}
+
+static const struct i2c_device_id pcf2127_i2c_id[] = {
+ { "pcf2127", 0 },
+ { "pcf2129", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id);
+
+static struct i2c_driver pcf2127_i2c_driver = {
+ .driver = {
+ .name = "rtc-pcf2127-i2c",
+ .of_match_table = of_match_ptr(pcf2127_of_match),
+ },
+ .probe = pcf2127_i2c_probe,
+ .id_table = pcf2127_i2c_id,
+};
+
+static int pcf2127_i2c_register_driver(void)
+{
+ return i2c_add_driver(&pcf2127_i2c_driver);
+}
+
+static void pcf2127_i2c_unregister_driver(void)
+{
+ i2c_del_driver(&pcf2127_i2c_driver);
+}
+
+#else
+
+static int pcf2127_i2c_register_driver(void)
+{
+ return 0;
+}
+
+static void pcf2127_i2c_unregister_driver(void)
+{
+}
+
+#endif
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
+static struct spi_driver pcf2127_spi_driver;
+
+static int pcf2127_spi_probe(struct spi_device *spi)
+{
+ static const struct regmap_config config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read_flag_mask = 0xa0,
+ .write_flag_mask = 0x20,
+ };
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n",
+ __func__, PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name);
+}
+
+static const struct spi_device_id pcf2127_spi_id[] = {
+ { "pcf2127", 0 },
+ { "pcf2129", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, pcf2127_spi_id);
+
+static struct spi_driver pcf2127_spi_driver = {
.driver = {
- .name = "rtc-pcf2127",
+ .name = "rtc-pcf2127-spi",
.of_match_table = of_match_ptr(pcf2127_of_match),
},
- .probe = pcf2127_probe,
- .id_table = pcf2127_id,
+ .probe = pcf2127_spi_probe,
+ .id_table = pcf2127_spi_id,
};
-module_i2c_driver(pcf2127_driver);
+static int pcf2127_spi_register_driver(void)
+{
+ return spi_register_driver(&pcf2127_spi_driver);
+}
+
+static void pcf2127_spi_unregister_driver(void)
+{
+ spi_unregister_driver(&pcf2127_spi_driver);
+}
+
+#else
+
+static int pcf2127_spi_register_driver(void)
+{
+ return 0;
+}
+
+static void pcf2127_spi_unregister_driver(void)
+{
+}
+
+#endif
+
+static int __init pcf2127_init(void)
+{
+ int ret;
+
+ ret = pcf2127_i2c_register_driver();
+ if (ret) {
+ pr_err("Failed to register pcf2127 i2c driver: %d\n", ret);
+ return ret;
+ }
+
+ ret = pcf2127_spi_register_driver();
+ if (ret) {
+ pr_err("Failed to register pcf2127 spi driver: %d\n", ret);
+ pcf2127_i2c_unregister_driver();
+ }
+
+ return ret;
+}
+module_init(pcf2127_init)
+
+static void __exit pcf2127_exit(void)
+{
+ pcf2127_spi_unregister_driver();
+ pcf2127_i2c_unregister_driver();
+}
+module_exit(pcf2127_exit)
MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>");
-MODULE_DESCRIPTION("NXP PCF2127 RTC driver");
+MODULE_DESCRIPTION("NXP PCF2127/29 RTC driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 63334cbeca41..e8ddbb359d11 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -16,12 +16,12 @@
#include <linux/rtc.h>
#include <linux/module.h>
-#define DRV_VERSION "0.0.1"
-
#define PCF85063_REG_CTRL1 0x00 /* status */
+#define PCF85063_REG_CTRL1_STOP BIT(5)
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_REG_SC 0x04 /* datetime */
+#define PCF85063_REG_SC_OS 0x80
#define PCF85063_REG_MN 0x05
#define PCF85063_REG_HR 0x06
#define PCF85063_REG_DM 0x07
@@ -29,15 +29,31 @@
#define PCF85063_REG_MO 0x09
#define PCF85063_REG_YR 0x0A
-#define PCF85063_MO_C 0x80 /* century */
-
static struct i2c_driver pcf85063_driver;
-struct pcf85063 {
- struct rtc_device *rtc;
- int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
- int voltage_low; /* indicates if a low_voltage was detected */
-};
+static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
+{
+ s32 ret;
+
+ ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ /* stop the clock */
+ ret |= PCF85063_REG_CTRL1_STOP;
+
+ ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ *ctrl1 = ret;
+
+ return 0;
+}
/*
* In the routines that deal directly with the pcf85063 hardware, we use
@@ -45,81 +61,85 @@ struct pcf85063 {
*/
static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
- struct pcf85063 *pcf85063 = i2c_get_clientdata(client);
- unsigned char buf[13] = { PCF85063_REG_CTRL1 };
- struct i2c_msg msgs[] = {
- {/* setup read ptr */
- .addr = client->addr,
- .len = 1,
- .buf = buf
- },
- {/* read status + date */
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = 13,
- .buf = buf
- },
- };
-
- /* read registers */
- if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __func__);
+ int rc;
+ u8 regs[7];
+
+ /*
+ * while reading, the time/date registers are blocked and not updated
+ * anymore until the access is finished. To not lose a second
+ * event, the access must be finished within one second. So, read all
+ * time/date registers in one turn.
+ */
+ rc = i2c_smbus_read_i2c_block_data(client, PCF85063_REG_SC,
+ sizeof(regs), regs);
+ if (rc != sizeof(regs)) {
+ dev_err(&client->dev, "date/time register read error\n");
return -EIO;
}
- tm->tm_sec = bcd2bin(buf[PCF85063_REG_SC] & 0x7F);
- tm->tm_min = bcd2bin(buf[PCF85063_REG_MN] & 0x7F);
- tm->tm_hour = bcd2bin(buf[PCF85063_REG_HR] & 0x3F); /* rtc hr 0-23 */
- tm->tm_mday = bcd2bin(buf[PCF85063_REG_DM] & 0x3F);
- tm->tm_wday = buf[PCF85063_REG_DW] & 0x07;
- tm->tm_mon = bcd2bin(buf[PCF85063_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
- tm->tm_year = bcd2bin(buf[PCF85063_REG_YR]);
+ /* if the clock has lost its power it makes no sense to use its time */
+ if (regs[0] & PCF85063_REG_SC_OS) {
+ dev_warn(&client->dev, "Power loss detected, invalid time\n");
+ return -EINVAL;
+ }
+
+ tm->tm_sec = bcd2bin(regs[0] & 0x7F);
+ tm->tm_min = bcd2bin(regs[1] & 0x7F);
+ tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */
+ tm->tm_mday = bcd2bin(regs[3] & 0x3F);
+ tm->tm_wday = regs[4] & 0x07;
+ tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */
+ tm->tm_year = bcd2bin(regs[6]);
if (tm->tm_year < 70)
tm->tm_year += 100; /* assume we are in 1970...2069 */
- /* detect the polarity heuristically. see note above. */
- pcf85063->c_polarity = (buf[PCF85063_REG_MO] & PCF85063_MO_C) ?
- (tm->tm_year >= 100) : (tm->tm_year < 100);
return rtc_valid_tm(tm);
}
static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
- int i = 0, err = 0;
- unsigned char buf[11];
+ int rc;
+ u8 regs[8];
- /* Control & status */
- buf[PCF85063_REG_CTRL1] = 0;
- buf[PCF85063_REG_CTRL2] = 5;
+ /*
+ * to accurately set the time, reset the divider chain and keep it in
+ * reset state until all time/date registers are written
+ */
+ rc = pcf85063_stop_clock(client, &regs[7]);
+ if (rc != 0)
+ return rc;
/* hours, minutes and seconds */
- buf[PCF85063_REG_SC] = bin2bcd(tm->tm_sec) & 0x7F;
+ regs[0] = bin2bcd(tm->tm_sec) & 0x7F; /* clear OS flag */
- buf[PCF85063_REG_MN] = bin2bcd(tm->tm_min);
- buf[PCF85063_REG_HR] = bin2bcd(tm->tm_hour);
+ regs[1] = bin2bcd(tm->tm_min);
+ regs[2] = bin2bcd(tm->tm_hour);
/* Day of month, 1 - 31 */
- buf[PCF85063_REG_DM] = bin2bcd(tm->tm_mday);
+ regs[3] = bin2bcd(tm->tm_mday);
/* Day, 0 - 6 */
- buf[PCF85063_REG_DW] = tm->tm_wday & 0x07;
+ regs[4] = tm->tm_wday & 0x07;
/* month, 1 - 12 */
- buf[PCF85063_REG_MO] = bin2bcd(tm->tm_mon + 1);
+ regs[5] = bin2bcd(tm->tm_mon + 1);
/* year and century */
- buf[PCF85063_REG_YR] = bin2bcd(tm->tm_year % 100);
-
- /* write register's data */
- for (i = 0; i < sizeof(buf); i++) {
- unsigned char data[2] = { i, buf[i] };
-
- err = i2c_master_send(client, data, sizeof(data));
- if (err != sizeof(data)) {
- dev_err(&client->dev, "%s: err=%d addr=%02x, data=%02x\n",
- __func__, err, data[0], data[1]);
- return -EIO;
- }
+ regs[6] = bin2bcd(tm->tm_year % 100);
+
+ /*
+ * after all time/date registers are written, let the 'address auto
+ * increment' feature wrap around and write register CTRL1 to re-enable
+ * the clock divider chain again
+ */
+ regs[7] &= ~PCF85063_REG_CTRL1_STOP;
+
+ /* write all registers at once */
+ rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC,
+ sizeof(regs), regs);
+ if (rc < 0) {
+ dev_err(&client->dev, "date/time register write error\n");
+ return rc;
}
return 0;
@@ -143,27 +163,18 @@ static const struct rtc_class_ops pcf85063_rtc_ops = {
static int pcf85063_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct pcf85063 *pcf85063;
+ struct rtc_device *rtc;
dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063),
- GFP_KERNEL);
- if (!pcf85063)
- return -ENOMEM;
-
- dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
-
- i2c_set_clientdata(client, pcf85063);
-
- pcf85063->rtc = devm_rtc_device_register(&client->dev,
- pcf85063_driver.driver.name,
- &pcf85063_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&client->dev,
+ pcf85063_driver.driver.name,
+ &pcf85063_rtc_ops, THIS_MODULE);
- return PTR_ERR_OR_ZERO(pcf85063->rtc);
+ return PTR_ERR_OR_ZERO(rtc);
}
static const struct i2c_device_id pcf85063_id[] = {
@@ -194,4 +205,3 @@ module_i2c_driver(pcf85063_driver);
MODULE_AUTHOR("Søren Andersen <san@rosetechnology.dk>");
MODULE_DESCRIPTION("PCF85063 RTC driver");
MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index 988566caaaa6..28c48b3c1946 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -178,28 +178,8 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (err < 0)
return err;
- if (regs[0] & REG_SECONDS_OS) {
- /*
- * If the oscillator was stopped, try to clear the flag. Upon
- * power-up the flag is always set, but if we cannot clear it
- * the oscillator isn't running properly for some reason. The
- * sensible thing therefore is to return an error, signalling
- * that the clock cannot be assumed to be correct.
- */
-
- regs[0] &= ~REG_SECONDS_OS;
-
- err = pcf8523_write(client, REG_SECONDS, regs[0]);
- if (err < 0)
- return err;
-
- err = pcf8523_read(client, REG_SECONDS, &regs[0]);
- if (err < 0)
- return err;
-
- if (regs[0] & REG_SECONDS_OS)
- return -EAGAIN;
- }
+ if (regs[0] & REG_SECONDS_OS)
+ return -EINVAL;
tm->tm_sec = bcd2bin(regs[0] & 0x7f);
tm->tm_min = bcd2bin(regs[1] & 0x7f);
@@ -235,6 +215,7 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
return err;
regs[0] = REG_SECONDS;
+ /* This will purposely overwrite REG_SECONDS_OS */
regs[1] = bin2bcd(tm->tm_sec);
regs[2] = bin2bcd(tm->tm_min);
regs[3] = bin2bcd(tm->tm_hour);
diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c
new file mode 100644
index 000000000000..64e1e4578492
--- /dev/null
+++ b/drivers/rtc/rtc-pic32.c
@@ -0,0 +1,411 @@
+/*
+ * PIC32 RTC driver
+ *
+ * Joshua Henderson <joshua.henderson@microchip.com>
+ * Copyright (C) 2016 Microchip Technology Inc. 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.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#include <asm/mach-pic32/pic32.h>
+
+#define PIC32_RTCCON 0x00
+#define PIC32_RTCCON_ON BIT(15)
+#define PIC32_RTCCON_SIDL BIT(13)
+#define PIC32_RTCCON_RTCCLKSEL (3 << 9)
+#define PIC32_RTCCON_RTCCLKON BIT(6)
+#define PIC32_RTCCON_RTCWREN BIT(3)
+#define PIC32_RTCCON_RTCSYNC BIT(2)
+#define PIC32_RTCCON_HALFSEC BIT(1)
+#define PIC32_RTCCON_RTCOE BIT(0)
+
+#define PIC32_RTCALRM 0x10
+#define PIC32_RTCALRM_ALRMEN BIT(15)
+#define PIC32_RTCALRM_CHIME BIT(14)
+#define PIC32_RTCALRM_PIV BIT(13)
+#define PIC32_RTCALRM_ALARMSYNC BIT(12)
+#define PIC32_RTCALRM_AMASK 0x0F00
+#define PIC32_RTCALRM_ARPT 0xFF
+
+#define PIC32_RTCHOUR 0x23
+#define PIC32_RTCMIN 0x22
+#define PIC32_RTCSEC 0x21
+#define PIC32_RTCYEAR 0x33
+#define PIC32_RTCMON 0x32
+#define PIC32_RTCDAY 0x31
+
+#define PIC32_ALRMTIME 0x40
+#define PIC32_ALRMDATE 0x50
+
+#define PIC32_ALRMHOUR 0x43
+#define PIC32_ALRMMIN 0x42
+#define PIC32_ALRMSEC 0x41
+#define PIC32_ALRMYEAR 0x53
+#define PIC32_ALRMMON 0x52
+#define PIC32_ALRMDAY 0x51
+
+struct pic32_rtc_dev {
+ struct rtc_device *rtc;
+ void __iomem *reg_base;
+ struct clk *clk;
+ spinlock_t alarm_lock;
+ int alarm_irq;
+ bool alarm_clk_enabled;
+};
+
+static void pic32_rtc_alarm_clk_enable(struct pic32_rtc_dev *pdata,
+ bool enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdata->alarm_lock, flags);
+ if (enable) {
+ if (!pdata->alarm_clk_enabled) {
+ clk_enable(pdata->clk);
+ pdata->alarm_clk_enabled = true;
+ }
+ } else {
+ if (pdata->alarm_clk_enabled) {
+ clk_disable(pdata->clk);
+ pdata->alarm_clk_enabled = false;
+ }
+ }
+ spin_unlock_irqrestore(&pdata->alarm_lock, flags);
+}
+
+static irqreturn_t pic32_rtc_alarmirq(int irq, void *id)
+{
+ struct pic32_rtc_dev *pdata = (struct pic32_rtc_dev *)id;
+
+ clk_enable(pdata->clk);
+ rtc_update_irq(pdata->rtc, 1, RTC_AF | RTC_IRQF);
+ clk_disable(pdata->clk);
+
+ pic32_rtc_alarm_clk_enable(pdata, false);
+
+ return IRQ_HANDLED;
+}
+
+static int pic32_rtc_setaie(struct device *dev, unsigned int enabled)
+{
+ struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
+ void __iomem *base = pdata->reg_base;
+
+ clk_enable(pdata->clk);
+
+ writel(PIC32_RTCALRM_ALRMEN,
+ base + (enabled ? PIC32_SET(PIC32_RTCALRM) :
+ PIC32_CLR(PIC32_RTCALRM)));
+
+ clk_disable(pdata->clk);
+
+ pic32_rtc_alarm_clk_enable(pdata, enabled);
+
+ return 0;
+}
+
+static int pic32_rtc_setfreq(struct device *dev, int freq)
+{
+ struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
+ void __iomem *base = pdata->reg_base;
+
+ clk_enable(pdata->clk);
+
+ writel(PIC32_RTCALRM_AMASK, base + PIC32_CLR(PIC32_RTCALRM));
+ writel(freq << 8, base + PIC32_SET(PIC32_RTCALRM));
+ writel(PIC32_RTCALRM_CHIME, base + PIC32_SET(PIC32_RTCALRM));
+
+ clk_disable(pdata->clk);
+
+ return 0;
+}
+
+static int pic32_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+{
+ struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
+ void __iomem *base = pdata->reg_base;
+ unsigned int tries = 0;
+
+ clk_enable(pdata->clk);
+
+ do {
+ rtc_tm->tm_hour = readb(base + PIC32_RTCHOUR);
+ rtc_tm->tm_min = readb(base + PIC32_RTCMIN);
+ rtc_tm->tm_mon = readb(base + PIC32_RTCMON);
+ rtc_tm->tm_mday = readb(base + PIC32_RTCDAY);
+ rtc_tm->tm_year = readb(base + PIC32_RTCYEAR);
+ rtc_tm->tm_sec = readb(base + PIC32_RTCSEC);
+
+ /*
+ * The only way to work out whether the system was mid-update
+ * when we read it is to check the second counter, and if it
+ * is zero, then we re-try the entire read.
+ */
+ tries += 1;
+ } while (rtc_tm->tm_sec == 0 && tries < 2);
+
+ rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
+ rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
+ rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
+ rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
+ rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon) - 1;
+ rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
+
+ rtc_tm->tm_year += 100;
+
+ dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n",
+ 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+ rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+
+ clk_disable(pdata->clk);
+ return rtc_valid_tm(rtc_tm);
+}
+
+static int pic32_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+ struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
+ void __iomem *base = pdata->reg_base;
+ int year = tm->tm_year - 100;
+
+ dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (year < 0 || year >= 100) {
+ dev_err(dev, "rtc only supports 100 years\n");
+ return -EINVAL;
+ }
+
+ clk_enable(pdata->clk);
+ writeb(bin2bcd(tm->tm_sec), base + PIC32_RTCSEC);
+ writeb(bin2bcd(tm->tm_min), base + PIC32_RTCMIN);
+ writeb(bin2bcd(tm->tm_hour), base + PIC32_RTCHOUR);
+ writeb(bin2bcd(tm->tm_mday), base + PIC32_RTCDAY);
+ writeb(bin2bcd(tm->tm_mon + 1), base + PIC32_RTCMON);
+ writeb(bin2bcd(year), base + PIC32_RTCYEAR);
+ clk_disable(pdata->clk);
+
+ return 0;
+}
+
+static int pic32_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
+ struct rtc_time *alm_tm = &alrm->time;
+ void __iomem *base = pdata->reg_base;
+ unsigned int alm_en;
+
+ clk_enable(pdata->clk);
+ alm_tm->tm_sec = readb(base + PIC32_ALRMSEC);
+ alm_tm->tm_min = readb(base + PIC32_ALRMMIN);
+ alm_tm->tm_hour = readb(base + PIC32_ALRMHOUR);
+ alm_tm->tm_mon = readb(base + PIC32_ALRMMON);
+ alm_tm->tm_mday = readb(base + PIC32_ALRMDAY);
+ alm_tm->tm_year = readb(base + PIC32_ALRMYEAR);
+
+ alm_en = readb(base + PIC32_RTCALRM);
+
+ alrm->enabled = (alm_en & PIC32_RTCALRM_ALRMEN) ? 1 : 0;
+
+ dev_dbg(dev, "getalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
+ alm_en,
+ 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
+ alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
+
+ alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
+ alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
+ alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
+ alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
+ alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon) - 1;
+ alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
+
+ clk_disable(pdata->clk);
+ return 0;
+}
+
+static int pic32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alrm->time;
+ void __iomem *base = pdata->reg_base;
+
+ clk_enable(pdata->clk);
+ dev_dbg(dev, "setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
+ alrm->enabled,
+ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ writel(0x00, base + PIC32_ALRMTIME);
+ writel(0x00, base + PIC32_ALRMDATE);
+
+ pic32_rtc_setaie(dev, alrm->enabled);
+
+ clk_disable(pdata->clk);
+ return 0;
+}
+
+static int pic32_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
+ void __iomem *base = pdata->reg_base;
+ unsigned int repeat;
+
+ clk_enable(pdata->clk);
+
+ repeat = readw(base + PIC32_RTCALRM);
+ repeat &= PIC32_RTCALRM_ARPT;
+ seq_printf(seq, "periodic_IRQ\t: %s\n", repeat ? "yes" : "no");
+
+ clk_disable(pdata->clk);
+ return 0;
+}
+
+static const struct rtc_class_ops pic32_rtcops = {
+ .read_time = pic32_rtc_gettime,
+ .set_time = pic32_rtc_settime,
+ .read_alarm = pic32_rtc_getalarm,
+ .set_alarm = pic32_rtc_setalarm,
+ .proc = pic32_rtc_proc,
+ .alarm_irq_enable = pic32_rtc_setaie,
+};
+
+static void pic32_rtc_enable(struct pic32_rtc_dev *pdata, int en)
+{
+ void __iomem *base = pdata->reg_base;
+
+ if (!base)
+ return;
+
+ clk_enable(pdata->clk);
+ if (!en) {
+ writel(PIC32_RTCCON_ON, base + PIC32_CLR(PIC32_RTCCON));
+ } else {
+ pic32_syskey_unlock();
+
+ writel(PIC32_RTCCON_RTCWREN, base + PIC32_SET(PIC32_RTCCON));
+ writel(3 << 9, base + PIC32_CLR(PIC32_RTCCON));
+
+ if (!(readl(base + PIC32_RTCCON) & PIC32_RTCCON_ON))
+ writel(PIC32_RTCCON_ON, base + PIC32_SET(PIC32_RTCCON));
+ }
+ clk_disable(pdata->clk);
+}
+
+static int pic32_rtc_remove(struct platform_device *pdev)
+{
+ struct pic32_rtc_dev *pdata = platform_get_drvdata(pdev);
+
+ pic32_rtc_setaie(&pdev->dev, 0);
+ clk_unprepare(pdata->clk);
+ pdata->clk = NULL;
+
+ return 0;
+}
+
+static int pic32_rtc_probe(struct platform_device *pdev)
+{
+ struct pic32_rtc_dev *pdata;
+ struct resource *res;
+ int ret;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, pdata);
+
+ pdata->alarm_irq = platform_get_irq(pdev, 0);
+ if (pdata->alarm_irq < 0) {
+ dev_err(&pdev->dev, "no irq for alarm\n");
+ return pdata->alarm_irq;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pdata->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pdata->reg_base))
+ return PTR_ERR(pdata->reg_base);
+
+ pdata->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pdata->clk)) {
+ dev_err(&pdev->dev, "failed to find rtc clock source\n");
+ ret = PTR_ERR(pdata->clk);
+ pdata->clk = NULL;
+ return ret;
+ }
+
+ spin_lock_init(&pdata->alarm_lock);
+
+ clk_prepare_enable(pdata->clk);
+
+ pic32_rtc_enable(pdata, 1);
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &pic32_rtcops,
+ THIS_MODULE);
+ if (IS_ERR(pdata->rtc)) {
+ ret = PTR_ERR(pdata->rtc);
+ goto err_nortc;
+ }
+
+ pdata->rtc->max_user_freq = 128;
+
+ pic32_rtc_setfreq(&pdev->dev, 1);
+ ret = devm_request_irq(&pdev->dev, pdata->alarm_irq,
+ pic32_rtc_alarmirq, 0,
+ dev_name(&pdev->dev), pdata);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "IRQ %d error %d\n", pdata->alarm_irq, ret);
+ goto err_nortc;
+ }
+
+ clk_disable(pdata->clk);
+
+ return 0;
+
+err_nortc:
+ pic32_rtc_enable(pdata, 0);
+ clk_disable_unprepare(pdata->clk);
+
+ return ret;
+}
+
+static const struct of_device_id pic32_rtc_dt_ids[] = {
+ { .compatible = "microchip,pic32mzda-rtc" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids);
+
+static struct platform_driver pic32_rtc_driver = {
+ .probe = pic32_rtc_probe,
+ .remove = pic32_rtc_remove,
+ .driver = {
+ .name = "pic32-rtc",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pic32_rtc_dt_ids),
+ },
+};
+module_platform_driver(pic32_rtc_driver);
+
+MODULE_DESCRIPTION("Microchip PIC32 RTC Driver");
+MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
index e9ac5a43be1a..d0cbf08040cd 100644
--- a/drivers/rtc/rtc-rv3029c2.c
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -1,7 +1,8 @@
/*
- * Micro Crystal RV-3029C2 rtc class driver
+ * Micro Crystal RV-3029 rtc class driver
*
* Author: Gregory Hermant <gregory.hermant@calao-systems.com>
+ * Michael Buesch <m@bues.ch>
*
* based on previously existing rtc class drivers
*
@@ -9,89 +10,120 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * NOTE: Currently this driver only supports the bare minimum for read
- * and write the RTC and alarms. The extra features provided by this chip
- * (trickle charger, eeprom, T° compensation) are unavailable.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
/* Register map */
/* control section */
-#define RV3029C2_ONOFF_CTRL 0x00
-#define RV3029C2_IRQ_CTRL 0x01
-#define RV3029C2_IRQ_CTRL_AIE (1 << 0)
-#define RV3029C2_IRQ_FLAGS 0x02
-#define RV3029C2_IRQ_FLAGS_AF (1 << 0)
-#define RV3029C2_STATUS 0x03
-#define RV3029C2_STATUS_VLOW1 (1 << 2)
-#define RV3029C2_STATUS_VLOW2 (1 << 3)
-#define RV3029C2_STATUS_SR (1 << 4)
-#define RV3029C2_STATUS_PON (1 << 5)
-#define RV3029C2_STATUS_EEBUSY (1 << 7)
-#define RV3029C2_RST_CTRL 0x04
-#define RV3029C2_CONTROL_SECTION_LEN 0x05
+#define RV3029_ONOFF_CTRL 0x00
+#define RV3029_ONOFF_CTRL_WE BIT(0)
+#define RV3029_ONOFF_CTRL_TE BIT(1)
+#define RV3029_ONOFF_CTRL_TAR BIT(2)
+#define RV3029_ONOFF_CTRL_EERE BIT(3)
+#define RV3029_ONOFF_CTRL_SRON BIT(4)
+#define RV3029_ONOFF_CTRL_TD0 BIT(5)
+#define RV3029_ONOFF_CTRL_TD1 BIT(6)
+#define RV3029_ONOFF_CTRL_CLKINT BIT(7)
+#define RV3029_IRQ_CTRL 0x01
+#define RV3029_IRQ_CTRL_AIE BIT(0)
+#define RV3029_IRQ_CTRL_TIE BIT(1)
+#define RV3029_IRQ_CTRL_V1IE BIT(2)
+#define RV3029_IRQ_CTRL_V2IE BIT(3)
+#define RV3029_IRQ_CTRL_SRIE BIT(4)
+#define RV3029_IRQ_FLAGS 0x02
+#define RV3029_IRQ_FLAGS_AF BIT(0)
+#define RV3029_IRQ_FLAGS_TF BIT(1)
+#define RV3029_IRQ_FLAGS_V1IF BIT(2)
+#define RV3029_IRQ_FLAGS_V2IF BIT(3)
+#define RV3029_IRQ_FLAGS_SRF BIT(4)
+#define RV3029_STATUS 0x03
+#define RV3029_STATUS_VLOW1 BIT(2)
+#define RV3029_STATUS_VLOW2 BIT(3)
+#define RV3029_STATUS_SR BIT(4)
+#define RV3029_STATUS_PON BIT(5)
+#define RV3029_STATUS_EEBUSY BIT(7)
+#define RV3029_RST_CTRL 0x04
+#define RV3029_RST_CTRL_SYSR BIT(4)
+#define RV3029_CONTROL_SECTION_LEN 0x05
/* watch section */
-#define RV3029C2_W_SEC 0x08
-#define RV3029C2_W_MINUTES 0x09
-#define RV3029C2_W_HOURS 0x0A
-#define RV3029C2_REG_HR_12_24 (1<<6) /* 24h/12h mode */
-#define RV3029C2_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
-#define RV3029C2_W_DATE 0x0B
-#define RV3029C2_W_DAYS 0x0C
-#define RV3029C2_W_MONTHS 0x0D
-#define RV3029C2_W_YEARS 0x0E
-#define RV3029C2_WATCH_SECTION_LEN 0x07
+#define RV3029_W_SEC 0x08
+#define RV3029_W_MINUTES 0x09
+#define RV3029_W_HOURS 0x0A
+#define RV3029_REG_HR_12_24 BIT(6) /* 24h/12h mode */
+#define RV3029_REG_HR_PM BIT(5) /* PM/AM bit in 12h mode */
+#define RV3029_W_DATE 0x0B
+#define RV3029_W_DAYS 0x0C
+#define RV3029_W_MONTHS 0x0D
+#define RV3029_W_YEARS 0x0E
+#define RV3029_WATCH_SECTION_LEN 0x07
/* alarm section */
-#define RV3029C2_A_SC 0x10
-#define RV3029C2_A_MN 0x11
-#define RV3029C2_A_HR 0x12
-#define RV3029C2_A_DT 0x13
-#define RV3029C2_A_DW 0x14
-#define RV3029C2_A_MO 0x15
-#define RV3029C2_A_YR 0x16
-#define RV3029C2_ALARM_SECTION_LEN 0x07
+#define RV3029_A_SC 0x10
+#define RV3029_A_MN 0x11
+#define RV3029_A_HR 0x12
+#define RV3029_A_DT 0x13
+#define RV3029_A_DW 0x14
+#define RV3029_A_MO 0x15
+#define RV3029_A_YR 0x16
+#define RV3029_ALARM_SECTION_LEN 0x07
/* timer section */
-#define RV3029C2_TIMER_LOW 0x18
-#define RV3029C2_TIMER_HIGH 0x19
+#define RV3029_TIMER_LOW 0x18
+#define RV3029_TIMER_HIGH 0x19
/* temperature section */
-#define RV3029C2_TEMP_PAGE 0x20
+#define RV3029_TEMP_PAGE 0x20
/* eeprom data section */
-#define RV3029C2_E2P_EEDATA1 0x28
-#define RV3029C2_E2P_EEDATA2 0x29
+#define RV3029_E2P_EEDATA1 0x28
+#define RV3029_E2P_EEDATA2 0x29
+#define RV3029_E2PDATA_SECTION_LEN 0x02
/* eeprom control section */
-#define RV3029C2_CONTROL_E2P_EECTRL 0x30
-#define RV3029C2_TRICKLE_1K (1<<0) /* 1K resistance */
-#define RV3029C2_TRICKLE_5K (1<<1) /* 5K resistance */
-#define RV3029C2_TRICKLE_20K (1<<2) /* 20K resistance */
-#define RV3029C2_TRICKLE_80K (1<<3) /* 80K resistance */
-#define RV3029C2_CONTROL_E2P_XTALOFFSET 0x31
-#define RV3029C2_CONTROL_E2P_QCOEF 0x32
-#define RV3029C2_CONTROL_E2P_TURNOVER 0x33
+#define RV3029_CONTROL_E2P_EECTRL 0x30
+#define RV3029_EECTRL_THP BIT(0) /* temp scan interval */
+#define RV3029_EECTRL_THE BIT(1) /* thermometer enable */
+#define RV3029_EECTRL_FD0 BIT(2) /* CLKOUT */
+#define RV3029_EECTRL_FD1 BIT(3) /* CLKOUT */
+#define RV3029_TRICKLE_1K BIT(4) /* 1.5K resistance */
+#define RV3029_TRICKLE_5K BIT(5) /* 5K resistance */
+#define RV3029_TRICKLE_20K BIT(6) /* 20K resistance */
+#define RV3029_TRICKLE_80K BIT(7) /* 80K resistance */
+#define RV3029_TRICKLE_MASK (RV3029_TRICKLE_1K |\
+ RV3029_TRICKLE_5K |\
+ RV3029_TRICKLE_20K |\
+ RV3029_TRICKLE_80K)
+#define RV3029_TRICKLE_SHIFT 4
+#define RV3029_CONTROL_E2P_XOFFS 0x31 /* XTAL offset */
+#define RV3029_CONTROL_E2P_XOFFS_SIGN BIT(7) /* Sign: 1->pos, 0->neg */
+#define RV3029_CONTROL_E2P_QCOEF 0x32 /* XTAL temp drift coef */
+#define RV3029_CONTROL_E2P_TURNOVER 0x33 /* XTAL turnover temp (in *C) */
+#define RV3029_CONTROL_E2P_TOV_MASK 0x3F /* XTAL turnover temp mask */
/* user ram section */
-#define RV3029C2_USR1_RAM_PAGE 0x38
-#define RV3029C2_USR1_SECTION_LEN 0x04
-#define RV3029C2_USR2_RAM_PAGE 0x3C
-#define RV3029C2_USR2_SECTION_LEN 0x04
+#define RV3029_USR1_RAM_PAGE 0x38
+#define RV3029_USR1_SECTION_LEN 0x04
+#define RV3029_USR2_RAM_PAGE 0x3C
+#define RV3029_USR2_SECTION_LEN 0x04
static int
-rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf,
- unsigned len)
+rv3029_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf,
+ unsigned len)
{
int ret;
- if ((reg > RV3029C2_USR1_RAM_PAGE + 7) ||
- (reg + len > RV3029C2_USR1_RAM_PAGE + 8))
+ if ((reg > RV3029_USR1_RAM_PAGE + 7) ||
+ (reg + len > RV3029_USR1_RAM_PAGE + 8))
return -EINVAL;
ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf);
@@ -103,20 +135,38 @@ rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf,
}
static int
-rv3029c2_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[],
- unsigned len)
+rv3029_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[],
+ unsigned len)
{
- if ((reg > RV3029C2_USR1_RAM_PAGE + 7) ||
- (reg + len > RV3029C2_USR1_RAM_PAGE + 8))
+ if ((reg > RV3029_USR1_RAM_PAGE + 7) ||
+ (reg + len > RV3029_USR1_RAM_PAGE + 8))
return -EINVAL;
return i2c_smbus_write_i2c_block_data(client, reg, len, buf);
}
static int
-rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf)
+rv3029_i2c_update_bits(struct i2c_client *client, u8 reg, u8 mask, u8 set)
+{
+ u8 buf;
+ int ret;
+
+ ret = rv3029_i2c_read_regs(client, reg, &buf, 1);
+ if (ret < 0)
+ return ret;
+ buf &= ~mask;
+ buf |= set & mask;
+ ret = rv3029_i2c_write_regs(client, reg, &buf, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+rv3029_i2c_get_sr(struct i2c_client *client, u8 *buf)
{
- int ret = rv3029c2_i2c_read_regs(client, RV3029C2_STATUS, buf, 1);
+ int ret = rv3029_i2c_read_regs(client, RV3029_STATUS, buf, 1);
if (ret < 0)
return -EIO;
@@ -125,83 +175,224 @@ rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf)
}
static int
-rv3029c2_i2c_set_sr(struct i2c_client *client, u8 val)
+rv3029_i2c_set_sr(struct i2c_client *client, u8 val)
{
u8 buf[1];
int sr;
buf[0] = val;
- sr = rv3029c2_i2c_write_regs(client, RV3029C2_STATUS, buf, 1);
+ sr = rv3029_i2c_write_regs(client, RV3029_STATUS, buf, 1);
dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
if (sr < 0)
return -EIO;
return 0;
}
+static int rv3029_eeprom_busywait(struct i2c_client *client)
+{
+ int i, ret;
+ u8 sr;
+
+ for (i = 100; i > 0; i--) {
+ ret = rv3029_i2c_get_sr(client, &sr);
+ if (ret < 0)
+ break;
+ if (!(sr & RV3029_STATUS_EEBUSY))
+ break;
+ usleep_range(1000, 10000);
+ }
+ if (i <= 0) {
+ dev_err(&client->dev, "EEPROM busy wait timeout.\n");
+ return -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+static int rv3029_eeprom_exit(struct i2c_client *client)
+{
+ /* Re-enable eeprom refresh */
+ return rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL,
+ RV3029_ONOFF_CTRL_EERE,
+ RV3029_ONOFF_CTRL_EERE);
+}
+
+static int rv3029_eeprom_enter(struct i2c_client *client)
+{
+ int ret;
+ u8 sr;
+
+ /* Check whether we are in the allowed voltage range. */
+ ret = rv3029_i2c_get_sr(client, &sr);
+ if (ret < 0)
+ return ret;
+ if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
+ /* We clear the bits and retry once just in case
+ * we had a brown out in early startup.
+ */
+ sr &= ~RV3029_STATUS_VLOW1;
+ sr &= ~RV3029_STATUS_VLOW2;
+ ret = rv3029_i2c_set_sr(client, sr);
+ if (ret < 0)
+ return ret;
+ usleep_range(1000, 10000);
+ ret = rv3029_i2c_get_sr(client, &sr);
+ if (ret < 0)
+ return ret;
+ if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
+ dev_err(&client->dev,
+ "Supply voltage is too low to safely access the EEPROM.\n");
+ return -ENODEV;
+ }
+ }
+
+ /* Disable eeprom refresh. */
+ ret = rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL,
+ RV3029_ONOFF_CTRL_EERE, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Wait for any previous eeprom accesses to finish. */
+ ret = rv3029_eeprom_busywait(client);
+ if (ret < 0)
+ rv3029_eeprom_exit(client);
+
+ return ret;
+}
+
+static int rv3029_eeprom_read(struct i2c_client *client, u8 reg,
+ u8 buf[], size_t len)
+{
+ int ret, err;
+
+ err = rv3029_eeprom_enter(client);
+ if (err < 0)
+ return err;
+
+ ret = rv3029_i2c_read_regs(client, reg, buf, len);
+
+ err = rv3029_eeprom_exit(client);
+ if (err < 0)
+ return err;
+
+ return ret;
+}
+
+static int rv3029_eeprom_write(struct i2c_client *client, u8 reg,
+ u8 const buf[], size_t len)
+{
+ int ret, err;
+ size_t i;
+ u8 tmp;
+
+ err = rv3029_eeprom_enter(client);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < len; i++, reg++) {
+ ret = rv3029_i2c_read_regs(client, reg, &tmp, 1);
+ if (ret < 0)
+ break;
+ if (tmp != buf[i]) {
+ ret = rv3029_i2c_write_regs(client, reg, &buf[i], 1);
+ if (ret < 0)
+ break;
+ }
+ ret = rv3029_eeprom_busywait(client);
+ if (ret < 0)
+ break;
+ }
+
+ err = rv3029_eeprom_exit(client);
+ if (err < 0)
+ return err;
+
+ return ret;
+}
+
+static int rv3029_eeprom_update_bits(struct i2c_client *client,
+ u8 reg, u8 mask, u8 set)
+{
+ u8 buf;
+ int ret;
+
+ ret = rv3029_eeprom_read(client, reg, &buf, 1);
+ if (ret < 0)
+ return ret;
+ buf &= ~mask;
+ buf |= set & mask;
+ ret = rv3029_eeprom_write(client, reg, &buf, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int
-rv3029c2_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
+rv3029_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
{
u8 buf[1];
int ret;
- u8 regs[RV3029C2_WATCH_SECTION_LEN] = { 0, };
+ u8 regs[RV3029_WATCH_SECTION_LEN] = { 0, };
- ret = rv3029c2_i2c_get_sr(client, buf);
+ ret = rv3029_i2c_get_sr(client, buf);
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return -EIO;
}
- ret = rv3029c2_i2c_read_regs(client, RV3029C2_W_SEC , regs,
- RV3029C2_WATCH_SECTION_LEN);
+ ret = rv3029_i2c_read_regs(client, RV3029_W_SEC, regs,
+ RV3029_WATCH_SECTION_LEN);
if (ret < 0) {
dev_err(&client->dev, "%s: reading RTC section failed\n",
__func__);
return ret;
}
- tm->tm_sec = bcd2bin(regs[RV3029C2_W_SEC-RV3029C2_W_SEC]);
- tm->tm_min = bcd2bin(regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC]);
+ tm->tm_sec = bcd2bin(regs[RV3029_W_SEC-RV3029_W_SEC]);
+ tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES-RV3029_W_SEC]);
/* HR field has a more complex interpretation */
{
- const u8 _hr = regs[RV3029C2_W_HOURS-RV3029C2_W_SEC];
- if (_hr & RV3029C2_REG_HR_12_24) {
+ const u8 _hr = regs[RV3029_W_HOURS-RV3029_W_SEC];
+
+ if (_hr & RV3029_REG_HR_12_24) {
/* 12h format */
tm->tm_hour = bcd2bin(_hr & 0x1f);
- if (_hr & RV3029C2_REG_HR_PM) /* PM flag set */
+ if (_hr & RV3029_REG_HR_PM) /* PM flag set */
tm->tm_hour += 12;
} else /* 24h format */
tm->tm_hour = bcd2bin(_hr & 0x3f);
}
- tm->tm_mday = bcd2bin(regs[RV3029C2_W_DATE-RV3029C2_W_SEC]);
- tm->tm_mon = bcd2bin(regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC]) - 1;
- tm->tm_year = bcd2bin(regs[RV3029C2_W_YEARS-RV3029C2_W_SEC]) + 100;
- tm->tm_wday = bcd2bin(regs[RV3029C2_W_DAYS-RV3029C2_W_SEC]) - 1;
+ tm->tm_mday = bcd2bin(regs[RV3029_W_DATE-RV3029_W_SEC]);
+ tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS-RV3029_W_SEC]) - 1;
+ tm->tm_year = bcd2bin(regs[RV3029_W_YEARS-RV3029_W_SEC]) + 100;
+ tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS-RV3029_W_SEC]) - 1;
return 0;
}
-static int rv3029c2_rtc_read_time(struct device *dev, struct rtc_time *tm)
+static int rv3029_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- return rv3029c2_i2c_read_time(to_i2c_client(dev), tm);
+ return rv3029_i2c_read_time(to_i2c_client(dev), tm);
}
static int
-rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
+rv3029_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
{
struct rtc_time *const tm = &alarm->time;
int ret;
u8 regs[8];
- ret = rv3029c2_i2c_get_sr(client, regs);
+ ret = rv3029_i2c_get_sr(client, regs);
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return -EIO;
}
- ret = rv3029c2_i2c_read_regs(client, RV3029C2_A_SC, regs,
- RV3029C2_ALARM_SECTION_LEN);
+ ret = rv3029_i2c_read_regs(client, RV3029_A_SC, regs,
+ RV3029_ALARM_SECTION_LEN);
if (ret < 0) {
dev_err(&client->dev, "%s: reading alarm section failed\n",
@@ -209,51 +400,42 @@ rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
return ret;
}
- tm->tm_sec = bcd2bin(regs[RV3029C2_A_SC-RV3029C2_A_SC] & 0x7f);
- tm->tm_min = bcd2bin(regs[RV3029C2_A_MN-RV3029C2_A_SC] & 0x7f);
- tm->tm_hour = bcd2bin(regs[RV3029C2_A_HR-RV3029C2_A_SC] & 0x3f);
- tm->tm_mday = bcd2bin(regs[RV3029C2_A_DT-RV3029C2_A_SC] & 0x3f);
- tm->tm_mon = bcd2bin(regs[RV3029C2_A_MO-RV3029C2_A_SC] & 0x1f) - 1;
- tm->tm_year = bcd2bin(regs[RV3029C2_A_YR-RV3029C2_A_SC] & 0x7f) + 100;
- tm->tm_wday = bcd2bin(regs[RV3029C2_A_DW-RV3029C2_A_SC] & 0x07) - 1;
+ tm->tm_sec = bcd2bin(regs[RV3029_A_SC-RV3029_A_SC] & 0x7f);
+ tm->tm_min = bcd2bin(regs[RV3029_A_MN-RV3029_A_SC] & 0x7f);
+ tm->tm_hour = bcd2bin(regs[RV3029_A_HR-RV3029_A_SC] & 0x3f);
+ tm->tm_mday = bcd2bin(regs[RV3029_A_DT-RV3029_A_SC] & 0x3f);
+ tm->tm_mon = bcd2bin(regs[RV3029_A_MO-RV3029_A_SC] & 0x1f) - 1;
+ tm->tm_year = bcd2bin(regs[RV3029_A_YR-RV3029_A_SC] & 0x7f) + 100;
+ tm->tm_wday = bcd2bin(regs[RV3029_A_DW-RV3029_A_SC] & 0x07) - 1;
return 0;
}
static int
-rv3029c2_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+rv3029_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- return rv3029c2_i2c_read_alarm(to_i2c_client(dev), alarm);
+ return rv3029_i2c_read_alarm(to_i2c_client(dev), alarm);
}
-static int rv3029c2_rtc_i2c_alarm_set_irq(struct i2c_client *client,
+static int rv3029_rtc_i2c_alarm_set_irq(struct i2c_client *client,
int enable)
{
int ret;
- u8 buf[1];
-
- /* enable AIE irq */
- ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_CTRL, buf, 1);
- if (ret < 0) {
- dev_err(&client->dev, "can't read INT reg\n");
- return ret;
- }
- if (enable)
- buf[0] |= RV3029C2_IRQ_CTRL_AIE;
- else
- buf[0] &= ~RV3029C2_IRQ_CTRL_AIE;
- ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_CTRL, buf, 1);
+ /* enable/disable AIE irq */
+ ret = rv3029_i2c_update_bits(client, RV3029_IRQ_CTRL,
+ RV3029_IRQ_CTRL_AIE,
+ (enable ? RV3029_IRQ_CTRL_AIE : 0));
if (ret < 0) {
- dev_err(&client->dev, "can't set INT reg\n");
+ dev_err(&client->dev, "can't update INT reg\n");
return ret;
}
return 0;
}
-static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client,
- struct rtc_wkalrm *alarm)
+static int rv3029_rtc_i2c_set_alarm(struct i2c_client *client,
+ struct rtc_wkalrm *alarm)
{
struct rtc_time *const tm = &alarm->time;
int ret;
@@ -267,50 +449,41 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client,
if (tm->tm_year < 100)
return -EINVAL;
- ret = rv3029c2_i2c_get_sr(client, regs);
+ ret = rv3029_i2c_get_sr(client, regs);
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return -EIO;
}
- regs[RV3029C2_A_SC-RV3029C2_A_SC] = bin2bcd(tm->tm_sec & 0x7f);
- regs[RV3029C2_A_MN-RV3029C2_A_SC] = bin2bcd(tm->tm_min & 0x7f);
- regs[RV3029C2_A_HR-RV3029C2_A_SC] = bin2bcd(tm->tm_hour & 0x3f);
- regs[RV3029C2_A_DT-RV3029C2_A_SC] = bin2bcd(tm->tm_mday & 0x3f);
- regs[RV3029C2_A_MO-RV3029C2_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1);
- regs[RV3029C2_A_DW-RV3029C2_A_SC] = bin2bcd((tm->tm_wday & 7) - 1);
- regs[RV3029C2_A_YR-RV3029C2_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100);
-
- ret = rv3029c2_i2c_write_regs(client, RV3029C2_A_SC, regs,
- RV3029C2_ALARM_SECTION_LEN);
+ regs[RV3029_A_SC-RV3029_A_SC] = bin2bcd(tm->tm_sec & 0x7f);
+ regs[RV3029_A_MN-RV3029_A_SC] = bin2bcd(tm->tm_min & 0x7f);
+ regs[RV3029_A_HR-RV3029_A_SC] = bin2bcd(tm->tm_hour & 0x3f);
+ regs[RV3029_A_DT-RV3029_A_SC] = bin2bcd(tm->tm_mday & 0x3f);
+ regs[RV3029_A_MO-RV3029_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1);
+ regs[RV3029_A_DW-RV3029_A_SC] = bin2bcd((tm->tm_wday & 7) - 1);
+ regs[RV3029_A_YR-RV3029_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100);
+
+ ret = rv3029_i2c_write_regs(client, RV3029_A_SC, regs,
+ RV3029_ALARM_SECTION_LEN);
if (ret < 0)
return ret;
if (alarm->enabled) {
- u8 buf[1];
-
/* clear AF flag */
- ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_FLAGS,
- buf, 1);
- if (ret < 0) {
- dev_err(&client->dev, "can't read alarm flag\n");
- return ret;
- }
- buf[0] &= ~RV3029C2_IRQ_FLAGS_AF;
- ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_FLAGS,
- buf, 1);
+ ret = rv3029_i2c_update_bits(client, RV3029_IRQ_FLAGS,
+ RV3029_IRQ_FLAGS_AF, 0);
if (ret < 0) {
- dev_err(&client->dev, "can't set alarm flag\n");
+ dev_err(&client->dev, "can't clear alarm flag\n");
return ret;
}
/* enable AIE irq */
- ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1);
+ ret = rv3029_rtc_i2c_alarm_set_irq(client, 1);
if (ret)
return ret;
dev_dbg(&client->dev, "alarm IRQ armed\n");
} else {
/* disable AIE irq */
- ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 0);
+ ret = rv3029_rtc_i2c_alarm_set_irq(client, 0);
if (ret)
return ret;
@@ -320,13 +493,13 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client,
return 0;
}
-static int rv3029c2_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+static int rv3029_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- return rv3029c2_rtc_i2c_set_alarm(to_i2c_client(dev), alarm);
+ return rv3029_rtc_i2c_set_alarm(to_i2c_client(dev), alarm);
}
static int
-rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
+rv3029_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
{
u8 regs[8];
int ret;
@@ -339,26 +512,26 @@ rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
if (tm->tm_year < 100)
return -EINVAL;
- regs[RV3029C2_W_SEC-RV3029C2_W_SEC] = bin2bcd(tm->tm_sec);
- regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC] = bin2bcd(tm->tm_min);
- regs[RV3029C2_W_HOURS-RV3029C2_W_SEC] = bin2bcd(tm->tm_hour);
- regs[RV3029C2_W_DATE-RV3029C2_W_SEC] = bin2bcd(tm->tm_mday);
- regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC] = bin2bcd(tm->tm_mon+1);
- regs[RV3029C2_W_DAYS-RV3029C2_W_SEC] = bin2bcd((tm->tm_wday & 7)+1);
- regs[RV3029C2_W_YEARS-RV3029C2_W_SEC] = bin2bcd(tm->tm_year - 100);
+ regs[RV3029_W_SEC-RV3029_W_SEC] = bin2bcd(tm->tm_sec);
+ regs[RV3029_W_MINUTES-RV3029_W_SEC] = bin2bcd(tm->tm_min);
+ regs[RV3029_W_HOURS-RV3029_W_SEC] = bin2bcd(tm->tm_hour);
+ regs[RV3029_W_DATE-RV3029_W_SEC] = bin2bcd(tm->tm_mday);
+ regs[RV3029_W_MONTHS-RV3029_W_SEC] = bin2bcd(tm->tm_mon+1);
+ regs[RV3029_W_DAYS-RV3029_W_SEC] = bin2bcd((tm->tm_wday & 7)+1);
+ regs[RV3029_W_YEARS-RV3029_W_SEC] = bin2bcd(tm->tm_year - 100);
- ret = rv3029c2_i2c_write_regs(client, RV3029C2_W_SEC, regs,
- RV3029C2_WATCH_SECTION_LEN);
+ ret = rv3029_i2c_write_regs(client, RV3029_W_SEC, regs,
+ RV3029_WATCH_SECTION_LEN);
if (ret < 0)
return ret;
- ret = rv3029c2_i2c_get_sr(client, regs);
+ ret = rv3029_i2c_get_sr(client, regs);
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return ret;
}
/* clear PON bit */
- ret = rv3029c2_i2c_set_sr(client, (regs[0] & ~RV3029C2_STATUS_PON));
+ ret = rv3029_i2c_set_sr(client, (regs[0] & ~RV3029_STATUS_PON));
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return ret;
@@ -367,26 +540,238 @@ rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
return 0;
}
-static int rv3029c2_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static int rv3029_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- return rv3029c2_i2c_set_time(to_i2c_client(dev), tm);
+ return rv3029_i2c_set_time(to_i2c_client(dev), tm);
}
-static const struct rtc_class_ops rv3029c2_rtc_ops = {
- .read_time = rv3029c2_rtc_read_time,
- .set_time = rv3029c2_rtc_set_time,
- .read_alarm = rv3029c2_rtc_read_alarm,
- .set_alarm = rv3029c2_rtc_set_alarm,
+static const struct rv3029_trickle_tab_elem {
+ u32 r; /* resistance in ohms */
+ u8 conf; /* trickle config bits */
+} rv3029_trickle_tab[] = {
+ {
+ .r = 1076,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
+ RV3029_TRICKLE_20K | RV3029_TRICKLE_80K,
+ }, {
+ .r = 1091,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
+ RV3029_TRICKLE_20K,
+ }, {
+ .r = 1137,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
+ RV3029_TRICKLE_80K,
+ }, {
+ .r = 1154,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K,
+ }, {
+ .r = 1371,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K |
+ RV3029_TRICKLE_80K,
+ }, {
+ .r = 1395,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K,
+ }, {
+ .r = 1472,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K,
+ }, {
+ .r = 1500,
+ .conf = RV3029_TRICKLE_1K,
+ }, {
+ .r = 3810,
+ .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K |
+ RV3029_TRICKLE_80K,
+ }, {
+ .r = 4000,
+ .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K,
+ }, {
+ .r = 4706,
+ .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K,
+ }, {
+ .r = 5000,
+ .conf = RV3029_TRICKLE_5K,
+ }, {
+ .r = 16000,
+ .conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K,
+ }, {
+ .r = 20000,
+ .conf = RV3029_TRICKLE_20K,
+ }, {
+ .r = 80000,
+ .conf = RV3029_TRICKLE_80K,
+ },
};
-static struct i2c_device_id rv3029c2_id[] = {
+static void rv3029_trickle_config(struct i2c_client *client)
+{
+ struct device_node *of_node = client->dev.of_node;
+ const struct rv3029_trickle_tab_elem *elem;
+ int i, err;
+ u32 ohms;
+ u8 trickle_set_bits;
+
+ if (!of_node)
+ return;
+
+ /* Configure the trickle charger. */
+ err = of_property_read_u32(of_node, "trickle-resistor-ohms", &ohms);
+ if (err) {
+ /* Disable trickle charger. */
+ trickle_set_bits = 0;
+ } else {
+ /* Enable trickle charger. */
+ for (i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++) {
+ elem = &rv3029_trickle_tab[i];
+ if (elem->r >= ohms)
+ break;
+ }
+ trickle_set_bits = elem->conf;
+ dev_info(&client->dev,
+ "Trickle charger enabled at %d ohms resistance.\n",
+ elem->r);
+ }
+ err = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL,
+ RV3029_TRICKLE_MASK,
+ trickle_set_bits);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Failed to update trickle charger config\n");
+ }
+}
+
+#ifdef CONFIG_RTC_DRV_RV3029_HWMON
+
+static int rv3029_read_temp(struct i2c_client *client, int *temp_mC)
+{
+ int ret;
+ u8 temp;
+
+ ret = rv3029_i2c_read_regs(client, RV3029_TEMP_PAGE, &temp, 1);
+ if (ret < 0)
+ return ret;
+
+ *temp_mC = ((int)temp - 60) * 1000;
+
+ return 0;
+}
+
+static ssize_t rv3029_hwmon_show_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = dev_get_drvdata(dev);
+ int ret, temp_mC;
+
+ ret = rv3029_read_temp(client, &temp_mC);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", temp_mC);
+}
+
+static ssize_t rv3029_hwmon_set_update_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct i2c_client *client = dev_get_drvdata(dev);
+ unsigned long interval_ms;
+ int ret;
+ u8 th_set_bits = 0;
+
+ ret = kstrtoul(buf, 10, &interval_ms);
+ if (ret < 0)
+ return ret;
+
+ if (interval_ms != 0) {
+ th_set_bits |= RV3029_EECTRL_THE;
+ if (interval_ms >= 16000)
+ th_set_bits |= RV3029_EECTRL_THP;
+ }
+ ret = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL,
+ RV3029_EECTRL_THE | RV3029_EECTRL_THP,
+ th_set_bits);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t rv3029_hwmon_show_update_interval(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = dev_get_drvdata(dev);
+ int ret, interval_ms;
+ u8 eectrl;
+
+ ret = rv3029_eeprom_read(client, RV3029_CONTROL_E2P_EECTRL,
+ &eectrl, 1);
+ if (ret < 0)
+ return ret;
+
+ if (eectrl & RV3029_EECTRL_THE) {
+ if (eectrl & RV3029_EECTRL_THP)
+ interval_ms = 16000;
+ else
+ interval_ms = 1000;
+ } else {
+ interval_ms = 0;
+ }
+
+ return sprintf(buf, "%d\n", interval_ms);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, rv3029_hwmon_show_temp,
+ NULL, 0);
+static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
+ rv3029_hwmon_show_update_interval,
+ rv3029_hwmon_set_update_interval, 0);
+
+static struct attribute *rv3029_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_update_interval.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(rv3029_hwmon);
+
+static void rv3029_hwmon_register(struct i2c_client *client)
+{
+ struct device *hwmon_dev;
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(
+ &client->dev, client->name, client, rv3029_hwmon_groups);
+ if (IS_ERR(hwmon_dev)) {
+ dev_warn(&client->dev,
+ "unable to register hwmon device %ld\n",
+ PTR_ERR(hwmon_dev));
+ }
+}
+
+#else /* CONFIG_RTC_DRV_RV3029_HWMON */
+
+static void rv3029_hwmon_register(struct i2c_client *client)
+{
+}
+
+#endif /* CONFIG_RTC_DRV_RV3029_HWMON */
+
+static const struct rtc_class_ops rv3029_rtc_ops = {
+ .read_time = rv3029_rtc_read_time,
+ .set_time = rv3029_rtc_set_time,
+ .read_alarm = rv3029_rtc_read_alarm,
+ .set_alarm = rv3029_rtc_set_alarm,
+};
+
+static struct i2c_device_id rv3029_id[] = {
+ { "rv3029", 0 },
{ "rv3029c2", 0 },
{ }
};
-MODULE_DEVICE_TABLE(i2c, rv3029c2_id);
+MODULE_DEVICE_TABLE(i2c, rv3029_id);
-static int rv3029c2_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int rv3029_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct rtc_device *rtc;
int rc = 0;
@@ -395,14 +780,17 @@ static int rv3029c2_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))
return -ENODEV;
- rc = rv3029c2_i2c_get_sr(client, buf);
+ rc = rv3029_i2c_get_sr(client, buf);
if (rc < 0) {
dev_err(&client->dev, "reading status failed\n");
return rc;
}
+ rv3029_trickle_config(client);
+ rv3029_hwmon_register(client);
+
rtc = devm_rtc_device_register(&client->dev, client->name,
- &rv3029c2_rtc_ops, THIS_MODULE);
+ &rv3029_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -412,16 +800,17 @@ static int rv3029c2_probe(struct i2c_client *client,
return 0;
}
-static struct i2c_driver rv3029c2_driver = {
+static struct i2c_driver rv3029_driver = {
.driver = {
.name = "rtc-rv3029c2",
},
- .probe = rv3029c2_probe,
- .id_table = rv3029c2_id,
+ .probe = rv3029_probe,
+ .id_table = rv3029_id,
};
-module_i2c_driver(rv3029c2_driver);
+module_i2c_driver(rv3029_driver);
MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>");
-MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver");
+MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
+MODULE_DESCRIPTION("Micro Crystal RV3029 RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index 7155c0816aa6..8d9f35ceb808 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -52,7 +52,7 @@
struct rv8803_data {
struct i2c_client *client;
struct rtc_device *rtc;
- spinlock_t flags_lock;
+ struct mutex flags_lock;
u8 ctrl;
};
@@ -63,11 +63,11 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
unsigned long events = 0;
int flags;
- spin_lock(&rv8803->flags_lock);
+ mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
if (flags <= 0) {
- spin_unlock(&rv8803->flags_lock);
+ mutex_unlock(&rv8803->flags_lock);
return IRQ_NONE;
}
@@ -102,7 +102,7 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
rv8803->ctrl);
}
- spin_unlock(&rv8803->flags_lock);
+ mutex_unlock(&rv8803->flags_lock);
return IRQ_HANDLED;
}
@@ -155,7 +155,6 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
u8 date[7];
int flags, ret;
- unsigned long irqflags;
if ((tm->tm_year < 100) || (tm->tm_year > 199))
return -EINVAL;
@@ -173,18 +172,18 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
if (ret < 0)
return ret;
- spin_lock_irqsave(&rv8803->flags_lock, irqflags);
+ mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG);
if (flags < 0) {
- spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
+ mutex_unlock(&rv8803->flags_lock);
return flags;
}
ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG,
flags & ~RV8803_FLAG_V2F);
- spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
+ mutex_unlock(&rv8803->flags_lock);
return ret;
}
@@ -226,7 +225,6 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
u8 alarmvals[3];
u8 ctrl[2];
int ret, err;
- unsigned long irqflags;
/* The alarm has no seconds, round up to nearest minute */
if (alrm->time.tm_sec) {
@@ -236,11 +234,11 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
rtc_time64_to_tm(alarm_time, &alrm->time);
}
- spin_lock_irqsave(&rv8803->flags_lock, irqflags);
+ mutex_lock(&rv8803->flags_lock);
ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl);
if (ret != 2) {
- spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
+ mutex_unlock(&rv8803->flags_lock);
return ret < 0 ? ret : -EIO;
}
@@ -253,14 +251,14 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
rv8803->ctrl);
if (err) {
- spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
+ mutex_unlock(&rv8803->flags_lock);
return err;
}
}
ctrl[1] &= ~RV8803_FLAG_AF;
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]);
- spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
+ mutex_unlock(&rv8803->flags_lock);
if (err)
return err;
@@ -289,7 +287,6 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
struct i2c_client *client = to_i2c_client(dev);
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
int ctrl, flags, err;
- unsigned long irqflags;
ctrl = rv8803->ctrl;
@@ -305,15 +302,15 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
ctrl &= ~RV8803_CTRL_AIE;
}
- spin_lock_irqsave(&rv8803->flags_lock, irqflags);
+ mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
if (flags < 0) {
- spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
+ mutex_unlock(&rv8803->flags_lock);
return flags;
}
flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF);
err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
- spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
+ mutex_unlock(&rv8803->flags_lock);
if (err)
return err;
@@ -333,7 +330,6 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
struct i2c_client *client = to_i2c_client(dev);
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
int flags, ret = 0;
- unsigned long irqflags;
switch (cmd) {
case RTC_VL_READ:
@@ -355,16 +351,16 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
return 0;
case RTC_VL_CLR:
- spin_lock_irqsave(&rv8803->flags_lock, irqflags);
+ mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
if (flags < 0) {
- spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
+ mutex_unlock(&rv8803->flags_lock);
return flags;
}
flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F);
ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
- spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
+ mutex_unlock(&rv8803->flags_lock);
if (ret < 0)
return ret;
@@ -441,6 +437,7 @@ static int rv8803_probe(struct i2c_client *client,
if (!rv8803)
return -ENOMEM;
+ mutex_init(&rv8803->flags_lock);
rv8803->client = client;
i2c_set_clientdata(client, rv8803);
diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c
new file mode 100644
index 000000000000..bbad00b233bc
--- /dev/null
+++ b/drivers/rtc/rtc-rx6110.c
@@ -0,0 +1,402 @@
+/*
+ * Driver for the Epson RTC module RX-6110 SA
+ *
+ * Copyright(C) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de>
+ * Copyright(C) SEIKO EPSON CORPORATION 2013. All rights reserved.
+ *
+ * This driver software is distributed as is, without any warranty of any kind,
+ * either express or implied as further specified in the GNU Public License.
+ * This software may be used and distributed according to the terms of the GNU
+ * Public License, version 2 as published by the Free Software Foundation.
+ * See the file COPYING in the main directory of this archive for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+
+/* RX-6110 Register definitions */
+#define RX6110_REG_SEC 0x10
+#define RX6110_REG_MIN 0x11
+#define RX6110_REG_HOUR 0x12
+#define RX6110_REG_WDAY 0x13
+#define RX6110_REG_MDAY 0x14
+#define RX6110_REG_MONTH 0x15
+#define RX6110_REG_YEAR 0x16
+#define RX6110_REG_RES1 0x17
+#define RX6110_REG_ALMIN 0x18
+#define RX6110_REG_ALHOUR 0x19
+#define RX6110_REG_ALWDAY 0x1A
+#define RX6110_REG_TCOUNT0 0x1B
+#define RX6110_REG_TCOUNT1 0x1C
+#define RX6110_REG_EXT 0x1D
+#define RX6110_REG_FLAG 0x1E
+#define RX6110_REG_CTRL 0x1F
+#define RX6110_REG_USER0 0x20
+#define RX6110_REG_USER1 0x21
+#define RX6110_REG_USER2 0x22
+#define RX6110_REG_USER3 0x23
+#define RX6110_REG_USER4 0x24
+#define RX6110_REG_USER5 0x25
+#define RX6110_REG_USER6 0x26
+#define RX6110_REG_USER7 0x27
+#define RX6110_REG_USER8 0x28
+#define RX6110_REG_USER9 0x29
+#define RX6110_REG_USERA 0x2A
+#define RX6110_REG_USERB 0x2B
+#define RX6110_REG_USERC 0x2C
+#define RX6110_REG_USERD 0x2D
+#define RX6110_REG_USERE 0x2E
+#define RX6110_REG_USERF 0x2F
+#define RX6110_REG_RES2 0x30
+#define RX6110_REG_RES3 0x31
+#define RX6110_REG_IRQ 0x32
+
+#define RX6110_BIT_ALARM_EN BIT(7)
+
+/* Extension Register (1Dh) bit positions */
+#define RX6110_BIT_EXT_TSEL0 BIT(0)
+#define RX6110_BIT_EXT_TSEL1 BIT(1)
+#define RX6110_BIT_EXT_TSEL2 BIT(2)
+#define RX6110_BIT_EXT_WADA BIT(3)
+#define RX6110_BIT_EXT_TE BIT(4)
+#define RX6110_BIT_EXT_USEL BIT(5)
+#define RX6110_BIT_EXT_FSEL0 BIT(6)
+#define RX6110_BIT_EXT_FSEL1 BIT(7)
+
+/* Flag Register (1Eh) bit positions */
+#define RX6110_BIT_FLAG_VLF BIT(1)
+#define RX6110_BIT_FLAG_AF BIT(3)
+#define RX6110_BIT_FLAG_TF BIT(4)
+#define RX6110_BIT_FLAG_UF BIT(5)
+
+/* Control Register (1Fh) bit positions */
+#define RX6110_BIT_CTRL_TBKE BIT(0)
+#define RX6110_BIT_CTRL_TBKON BIT(1)
+#define RX6110_BIT_CTRL_TSTP BIT(2)
+#define RX6110_BIT_CTRL_AIE BIT(3)
+#define RX6110_BIT_CTRL_TIE BIT(4)
+#define RX6110_BIT_CTRL_UIE BIT(5)
+#define RX6110_BIT_CTRL_STOP BIT(6)
+#define RX6110_BIT_CTRL_TEST BIT(7)
+
+enum {
+ RTC_SEC = 0,
+ RTC_MIN,
+ RTC_HOUR,
+ RTC_WDAY,
+ RTC_MDAY,
+ RTC_MONTH,
+ RTC_YEAR,
+ RTC_NR_TIME
+};
+
+#define RX6110_DRIVER_NAME "rx6110"
+
+struct rx6110_data {
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+};
+
+/**
+ * rx6110_rtc_tm_to_data - convert rtc_time to native time encoding
+ *
+ * @tm: holds date and time
+ * @data: holds the encoding in rx6110 native form
+ */
+static int rx6110_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+ pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+ /*
+ * The year in the RTC is a value between 0 and 99.
+ * Assume that this represents the current century
+ * and disregard all other values.
+ */
+ if (tm->tm_year < 100 || tm->tm_year >= 200)
+ return -EINVAL;
+
+ data[RTC_SEC] = bin2bcd(tm->tm_sec);
+ data[RTC_MIN] = bin2bcd(tm->tm_min);
+ data[RTC_HOUR] = bin2bcd(tm->tm_hour);
+ data[RTC_WDAY] = BIT(bin2bcd(tm->tm_wday));
+ data[RTC_MDAY] = bin2bcd(tm->tm_mday);
+ data[RTC_MONTH] = bin2bcd(tm->tm_mon + 1);
+ data[RTC_YEAR] = bin2bcd(tm->tm_year % 100);
+
+ return 0;
+}
+
+/**
+ * rx6110_data_to_rtc_tm - convert native time encoding to rtc_time
+ *
+ * @data: holds the encoding in rx6110 native form
+ * @tm: holds date and time
+ */
+static int rx6110_data_to_rtc_tm(u8 *data, struct rtc_time *tm)
+{
+ tm->tm_sec = bcd2bin(data[RTC_SEC] & 0x7f);
+ tm->tm_min = bcd2bin(data[RTC_MIN] & 0x7f);
+ /* only 24-hour clock */
+ tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f);
+ tm->tm_wday = ffs(data[RTC_WDAY] & 0x7f);
+ tm->tm_mday = bcd2bin(data[RTC_MDAY] & 0x3f);
+ tm->tm_mon = bcd2bin(data[RTC_MONTH] & 0x1f) - 1;
+ tm->tm_year = bcd2bin(data[RTC_YEAR]) + 100;
+
+ pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+ /*
+ * The year in the RTC is a value between 0 and 99.
+ * Assume that this represents the current century
+ * and disregard all other values.
+ */
+ if (tm->tm_year < 100 || tm->tm_year >= 200)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * rx6110_set_time - set the current time in the rx6110 registers
+ *
+ * @dev: the rtc device in use
+ * @tm: holds date and time
+ *
+ * BUG: The HW assumes every year that is a multiple of 4 to be a leap
+ * year. Next time this is wrong is 2100, which will not be a leap year
+ *
+ * Note: If STOP is not set/cleared, the clock will start when the seconds
+ * register is written
+ *
+ */
+static int rx6110_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rx6110_data *rx6110 = dev_get_drvdata(dev);
+ u8 data[RTC_NR_TIME];
+ int ret;
+
+ ret = rx6110_rtc_tm_to_data(tm, data);
+ if (ret < 0)
+ return ret;
+
+ /* set STOP bit before changing clock/calendar */
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL,
+ RX6110_BIT_CTRL_STOP, RX6110_BIT_CTRL_STOP);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_write(rx6110->regmap, RX6110_REG_SEC, data,
+ RTC_NR_TIME);
+ if (ret)
+ return ret;
+
+ /* The time in the RTC is valid. Be sure to have VLF cleared. */
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG,
+ RX6110_BIT_FLAG_VLF, 0);
+ if (ret)
+ return ret;
+
+ /* clear STOP bit after changing clock/calendar */
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL,
+ RX6110_BIT_CTRL_STOP, 0);
+
+ return ret;
+}
+
+/**
+ * rx6110_get_time - get the current time from the rx6110 registers
+ * @dev: the rtc device in use
+ * @tm: holds date and time
+ */
+static int rx6110_get_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rx6110_data *rx6110 = dev_get_drvdata(dev);
+ u8 data[RTC_NR_TIME];
+ int flags;
+ int ret;
+
+ ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags);
+ if (ret)
+ return -EINVAL;
+
+ /* check for VLF Flag (set at power-on) */
+ if ((flags & RX6110_BIT_FLAG_VLF)) {
+ dev_warn(dev, "Voltage low, data is invalid.\n");
+ return -EINVAL;
+ }
+
+ /* read registers to date */
+ ret = regmap_bulk_read(rx6110->regmap, RX6110_REG_SEC, data,
+ RTC_NR_TIME);
+ if (ret)
+ return ret;
+
+ ret = rx6110_data_to_rtc_tm(data, tm);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+ return rtc_valid_tm(tm);
+}
+
+static const struct reg_sequence rx6110_default_regs[] = {
+ { RX6110_REG_RES1, 0xB8 },
+ { RX6110_REG_RES2, 0x00 },
+ { RX6110_REG_RES3, 0x10 },
+ { RX6110_REG_IRQ, 0x00 },
+ { RX6110_REG_ALMIN, 0x00 },
+ { RX6110_REG_ALHOUR, 0x00 },
+ { RX6110_REG_ALWDAY, 0x00 },
+};
+
+/**
+ * rx6110_init - initialize the rx6110 registers
+ *
+ * @rx6110: pointer to the rx6110 struct in use
+ *
+ */
+static int rx6110_init(struct rx6110_data *rx6110)
+{
+ struct rtc_device *rtc = rx6110->rtc;
+ int flags;
+ int ret;
+
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_EXT,
+ RX6110_BIT_EXT_TE, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_register_patch(rx6110->regmap, rx6110_default_regs,
+ ARRAY_SIZE(rx6110_default_regs));
+ if (ret)
+ return ret;
+
+ ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags);
+ if (ret)
+ return ret;
+
+ /* check for VLF Flag (set at power-on) */
+ if ((flags & RX6110_BIT_FLAG_VLF))
+ dev_warn(&rtc->dev, "Voltage low, data loss detected.\n");
+
+ /* check for Alarm Flag */
+ if (flags & RX6110_BIT_FLAG_AF)
+ dev_warn(&rtc->dev, "An alarm may have been missed.\n");
+
+ /* check for Periodic Timer Flag */
+ if (flags & RX6110_BIT_FLAG_TF)
+ dev_warn(&rtc->dev, "Periodic timer was detected\n");
+
+ /* check for Update Timer Flag */
+ if (flags & RX6110_BIT_FLAG_UF)
+ dev_warn(&rtc->dev, "Update timer was detected\n");
+
+ /* clear all flags BUT VLF */
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG,
+ RX6110_BIT_FLAG_AF |
+ RX6110_BIT_FLAG_UF |
+ RX6110_BIT_FLAG_TF,
+ 0);
+
+ return ret;
+}
+
+static struct rtc_class_ops rx6110_rtc_ops = {
+ .read_time = rx6110_get_time,
+ .set_time = rx6110_set_time,
+};
+
+static struct regmap_config regmap_spi_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RX6110_REG_IRQ,
+ .read_flag_mask = 0x80,
+};
+
+/**
+ * rx6110_probe - initialize rtc driver
+ * @spi: pointer to spi device
+ */
+static int rx6110_probe(struct spi_device *spi)
+{
+ struct rx6110_data *rx6110;
+ int err;
+
+ if ((spi->bits_per_word && spi->bits_per_word != 8) ||
+ (spi->max_speed_hz > 2000000) ||
+ (spi->mode != (SPI_CS_HIGH | SPI_CPOL | SPI_CPHA))) {
+ dev_warn(&spi->dev, "SPI settings: bits_per_word: %d, max_speed_hz: %d, mode: %xh\n",
+ spi->bits_per_word, spi->max_speed_hz, spi->mode);
+ dev_warn(&spi->dev, "driving device in an unsupported mode");
+ }
+
+ rx6110 = devm_kzalloc(&spi->dev, sizeof(*rx6110), GFP_KERNEL);
+ if (!rx6110)
+ return -ENOMEM;
+
+ rx6110->regmap = devm_regmap_init_spi(spi, &regmap_spi_config);
+ if (IS_ERR(rx6110->regmap)) {
+ dev_err(&spi->dev, "regmap init failed for rtc rx6110\n");
+ return PTR_ERR(rx6110->regmap);
+ }
+
+ spi_set_drvdata(spi, rx6110);
+
+ rx6110->rtc = devm_rtc_device_register(&spi->dev,
+ RX6110_DRIVER_NAME,
+ &rx6110_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rx6110->rtc))
+ return PTR_ERR(rx6110->rtc);
+
+ err = rx6110_init(rx6110);
+ if (err)
+ return err;
+
+ rx6110->rtc->max_user_freq = 1;
+
+ return 0;
+}
+
+static int rx6110_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static const struct spi_device_id rx6110_id[] = {
+ { "rx6110", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, rx6110_id);
+
+static struct spi_driver rx6110_driver = {
+ .driver = {
+ .name = RX6110_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = rx6110_probe,
+ .remove = rx6110_remove,
+ .id_table = rx6110_id,
+};
+
+module_spi_driver(rx6110_driver);
+
+MODULE_AUTHOR("Val Krutov <val.krutov@erd.epson.com>");
+MODULE_DESCRIPTION("RX-6110 SA RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index bd911bafb809..b69647e0be23 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -65,7 +65,6 @@
static const struct i2c_device_id rx8025_id[] = {
{ "rx8025", 0 },
- { "rv8803", 1 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx8025_id);
@@ -147,8 +146,10 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
{
struct i2c_client *client = dev_id;
struct rx8025_data *rx8025 = i2c_get_clientdata(client);
+ struct mutex *lock = &rx8025->rtc->ops_lock;
int status;
+ mutex_lock(lock);
status = rx8025_read_reg(client, RX8025_REG_CTRL2);
if (status < 0)
goto out;
@@ -173,6 +174,8 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
}
out:
+ mutex_unlock(lock);
+
return IRQ_HANDLED;
}
@@ -341,7 +344,17 @@ static int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t)
if (client->irq <= 0)
return -EINVAL;
- /* Hardware alarm precision is 1 minute! */
+ /*
+ * Hardware alarm precision is 1 minute!
+ * round up to nearest minute
+ */
+ if (t->time.tm_sec) {
+ time64_t alarm_time = rtc_tm_to_time64(&t->time);
+
+ alarm_time += 60 - t->time.tm_sec;
+ rtc_time64_to_tm(alarm_time, &t->time);
+ }
+
ald[0] = bin2bcd(t->time.tm_min);
if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224)
ald[1] = bin2bcd(t->time.tm_hour);
@@ -539,8 +552,9 @@ static int rx8025_probe(struct i2c_client *client,
if (client->irq > 0) {
dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
- rx8025_handle_irq, 0, "rx8025",
- client);
+ rx8025_handle_irq,
+ IRQF_ONESHOT,
+ "rx8025", client);
if (err) {
dev_err(&client->dev, "unable to request IRQ, alarms disabled\n");
client->irq = 0;
@@ -549,6 +563,9 @@ static int rx8025_probe(struct i2c_client *client,
rx8025->rtc->max_user_freq = 1;
+ /* the rx8025 alarm only supports a minute accuracy */
+ rx8025->rtc->uie_unsupported = 1;
+
err = rx8025_sysfs_register(&client->dev);
return err;
}
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
index 7407d7394bb4..0477678d968f 100644
--- a/drivers/rtc/rtc-s5m.c
+++ b/drivers/rtc/rtc-s5m.c
@@ -216,7 +216,7 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data)
* Read RTC_UDR_CON register and wait till UDR field is cleared.
* This indicates that time/alarm update ended.
*/
-static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
+static int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
{
int ret, retry = UDR_READ_RETRY_CNT;
unsigned int data;
@@ -231,7 +231,7 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
return ret;
}
-static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
+static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
struct rtc_wkalrm *alarm)
{
int ret;
@@ -264,7 +264,7 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
return 0;
}
-static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
+static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
{
int ret;
unsigned int data;
@@ -288,7 +288,7 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
return ret;
}
-static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
+static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
{
int ret;
unsigned int data;
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 463e286064ab..63b9fb1318c2 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -218,6 +218,34 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RW(wakealarm);
+static ssize_t
+offset_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ssize_t retval;
+ long offset;
+
+ retval = rtc_read_offset(to_rtc_device(dev), &offset);
+ if (retval == 0)
+ retval = sprintf(buf, "%ld\n", offset);
+
+ return retval;
+}
+
+static ssize_t
+offset_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ ssize_t retval;
+ long offset;
+
+ retval = kstrtol(buf, 10, &offset);
+ if (retval == 0)
+ retval = rtc_set_offset(to_rtc_device(dev), offset);
+
+ return (retval < 0) ? retval : n;
+}
+static DEVICE_ATTR_RW(offset);
+
static struct attribute *rtc_attrs[] = {
&dev_attr_name.attr,
&dev_attr_date.attr,
@@ -226,6 +254,7 @@ static struct attribute *rtc_attrs[] = {
&dev_attr_max_user_freq.attr,
&dev_attr_hctosys.attr,
&dev_attr_wakealarm.attr,
+ &dev_attr_offset.attr,
NULL,
};
@@ -249,9 +278,13 @@ static umode_t rtc_attr_is_visible(struct kobject *kobj,
struct rtc_device *rtc = to_rtc_device(dev);
umode_t mode = attr->mode;
- if (attr == &dev_attr_wakealarm.attr)
+ if (attr == &dev_attr_wakealarm.attr) {
if (!rtc_does_wakealarm(rtc))
mode = 0;
+ } else if (attr == &dev_attr_offset.attr) {
+ if (!rtc->ops->set_offset)
+ mode = 0;
+ }
return mode;
}
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index 3b6ce80a769c..e404faac6851 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -286,7 +286,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
tps6586x_rtc_irq,
- IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ IRQF_ONESHOT,
dev_name(&pdev->dev), rtc);
if (ret < 0) {
dev_err(&pdev->dev, "request IRQ(%d) failed with ret %d\n",
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
index f42aa2b2dcba..5a3d53caa485 100644
--- a/drivers/rtc/rtc-tps65910.c
+++ b/drivers/rtc/rtc-tps65910.c
@@ -268,7 +268,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
}
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
- tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME,
+ tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
dev_name(&pdev->dev), &pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n");
diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c
index 27e254cde715..737f26eb284a 100644
--- a/drivers/rtc/rtc-tps80031.c
+++ b/drivers/rtc/rtc-tps80031.c
@@ -287,7 +287,7 @@ static int tps80031_rtc_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
tps80031_rtc_irq,
- IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ IRQF_ONESHOT,
dev_name(&pdev->dev), rtc);
if (ret < 0) {
dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n",
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index f64c282275b3..e1b86bb01062 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -272,12 +272,13 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id)
}
static const struct rtc_class_ops vr41xx_rtc_ops = {
- .release = vr41xx_rtc_release,
- .ioctl = vr41xx_rtc_ioctl,
- .read_time = vr41xx_rtc_read_time,
- .set_time = vr41xx_rtc_set_time,
- .read_alarm = vr41xx_rtc_read_alarm,
- .set_alarm = vr41xx_rtc_set_alarm,
+ .release = vr41xx_rtc_release,
+ .ioctl = vr41xx_rtc_ioctl,
+ .read_time = vr41xx_rtc_read_time,
+ .set_time = vr41xx_rtc_set_time,
+ .read_alarm = vr41xx_rtc_read_alarm,
+ .set_alarm = vr41xx_rtc_set_alarm,
+ .alarm_irq_enable = vr41xx_rtc_alarm_irq_enable,
};
static int rtc_probe(struct platform_device *pdev)
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 41605dac8309..c78db05e75b1 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -3035,6 +3035,7 @@ static void dasd_setup_queue(struct dasd_block *block)
max = block->base->discipline->max_blocks << block->s2b_shift;
}
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, block->request_queue);
+ block->request_queue->limits.max_dev_sectors = max;
blk_queue_logical_block_size(block->request_queue,
block->bp_block);
blk_queue_max_hw_sectors(block->request_queue, max);
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 184b1dbeb554..17ad5749e91d 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -185,14 +185,12 @@ static void _free_lcu(struct alias_lcu *lcu)
*/
int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
unsigned long flags;
struct alias_server *server, *newserver;
struct alias_lcu *lcu, *newlcu;
struct dasd_uid uid;
- private = (struct dasd_eckd_private *) device->private;
-
device->discipline->get_uid(device, &uid);
spin_lock_irqsave(&aliastree.lock, flags);
server = _find_server(&uid);
@@ -244,14 +242,13 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
*/
void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
unsigned long flags;
struct alias_lcu *lcu;
struct alias_server *server;
int was_pending;
struct dasd_uid uid;
- private = (struct dasd_eckd_private *) device->private;
lcu = private->lcu;
/* nothing to do if already disconnected */
if (!lcu)
@@ -264,8 +261,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
spin_unlock_irqrestore(&lcu->lock, flags);
cancel_work_sync(&lcu->suc_data.worker);
spin_lock_irqsave(&lcu->lock, flags);
- if (device == lcu->suc_data.device)
+ if (device == lcu->suc_data.device) {
+ dasd_put_device(device);
lcu->suc_data.device = NULL;
+ }
}
was_pending = 0;
if (device == lcu->ruac_data.device) {
@@ -273,8 +272,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
was_pending = 1;
cancel_delayed_work_sync(&lcu->ruac_data.dwork);
spin_lock_irqsave(&lcu->lock, flags);
- if (device == lcu->ruac_data.device)
+ if (device == lcu->ruac_data.device) {
+ dasd_put_device(device);
lcu->ruac_data.device = NULL;
+ }
}
private->lcu = NULL;
spin_unlock_irqrestore(&lcu->lock, flags);
@@ -312,25 +313,15 @@ static int _add_device_to_lcu(struct alias_lcu *lcu,
struct dasd_device *pos)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
struct alias_pav_group *group;
struct dasd_uid uid;
- unsigned long flags;
-
- private = (struct dasd_eckd_private *) device->private;
- /* only lock if not already locked */
- if (device != pos)
- spin_lock_irqsave_nested(get_ccwdev_lock(device->cdev), flags,
- CDEV_NESTED_SECOND);
private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type;
private->uid.base_unit_addr =
lcu->uac->unit[private->uid.real_unit_addr].base_ua;
uid = private->uid;
- if (device != pos)
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-
/* if we have no PAV anyway, we don't need to bother with PAV groups */
if (lcu->pav == NO_PAV) {
list_move(&device->alias_list, &lcu->active_devices);
@@ -366,10 +357,9 @@ static int _add_device_to_lcu(struct alias_lcu *lcu,
static void _remove_device_from_lcu(struct alias_lcu *lcu,
struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
struct alias_pav_group *group;
- private = (struct dasd_eckd_private *) device->private;
list_move(&device->alias_list, &lcu->inactive_devices);
group = private->pavgroup;
if (!group)
@@ -407,6 +397,130 @@ suborder_not_supported(struct dasd_ccw_req *cqr)
return 0;
}
+/*
+ * This function tries to lock all devices on an lcu via trylock
+ * return NULL on success otherwise return first failed device
+ */
+static struct dasd_device *_trylock_all_devices_on_lcu(struct alias_lcu *lcu,
+ struct dasd_device *pos)
+
+{
+ struct alias_pav_group *pavgroup;
+ struct dasd_device *device;
+
+ list_for_each_entry(device, &lcu->active_devices, alias_list) {
+ if (device == pos)
+ continue;
+ if (!spin_trylock(get_ccwdev_lock(device->cdev)))
+ return device;
+ }
+ list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+ if (device == pos)
+ continue;
+ if (!spin_trylock(get_ccwdev_lock(device->cdev)))
+ return device;
+ }
+ list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+ list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+ if (device == pos)
+ continue;
+ if (!spin_trylock(get_ccwdev_lock(device->cdev)))
+ return device;
+ }
+ list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
+ if (device == pos)
+ continue;
+ if (!spin_trylock(get_ccwdev_lock(device->cdev)))
+ return device;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * unlock all devices except the one that is specified as pos
+ * stop if enddev is specified and reached
+ */
+static void _unlock_all_devices_on_lcu(struct alias_lcu *lcu,
+ struct dasd_device *pos,
+ struct dasd_device *enddev)
+
+{
+ struct alias_pav_group *pavgroup;
+ struct dasd_device *device;
+
+ list_for_each_entry(device, &lcu->active_devices, alias_list) {
+ if (device == pos)
+ continue;
+ if (device == enddev)
+ return;
+ spin_unlock(get_ccwdev_lock(device->cdev));
+ }
+ list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+ if (device == pos)
+ continue;
+ if (device == enddev)
+ return;
+ spin_unlock(get_ccwdev_lock(device->cdev));
+ }
+ list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+ list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+ if (device == pos)
+ continue;
+ if (device == enddev)
+ return;
+ spin_unlock(get_ccwdev_lock(device->cdev));
+ }
+ list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
+ if (device == pos)
+ continue;
+ if (device == enddev)
+ return;
+ spin_unlock(get_ccwdev_lock(device->cdev));
+ }
+ }
+}
+
+/*
+ * this function is needed because the locking order
+ * device lock -> lcu lock
+ * needs to be assured when iterating over devices in an LCU
+ *
+ * if a device is specified in pos then the device lock is already hold
+ */
+static void _trylock_and_lock_lcu_irqsave(struct alias_lcu *lcu,
+ struct dasd_device *pos,
+ unsigned long *flags)
+{
+ struct dasd_device *failed;
+
+ do {
+ spin_lock_irqsave(&lcu->lock, *flags);
+ failed = _trylock_all_devices_on_lcu(lcu, pos);
+ if (failed) {
+ _unlock_all_devices_on_lcu(lcu, pos, failed);
+ spin_unlock_irqrestore(&lcu->lock, *flags);
+ cpu_relax();
+ }
+ } while (failed);
+}
+
+static void _trylock_and_lock_lcu(struct alias_lcu *lcu,
+ struct dasd_device *pos)
+{
+ struct dasd_device *failed;
+
+ do {
+ spin_lock(&lcu->lock);
+ failed = _trylock_all_devices_on_lcu(lcu, pos);
+ if (failed) {
+ _unlock_all_devices_on_lcu(lcu, pos, failed);
+ spin_unlock(&lcu->lock);
+ cpu_relax();
+ }
+ } while (failed);
+}
+
static int read_unit_address_configuration(struct dasd_device *device,
struct alias_lcu *lcu)
{
@@ -483,13 +597,13 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
list_for_each_entry_safe(device, tempdev, &pavgroup->baselist,
alias_list) {
list_move(&device->alias_list, &lcu->active_devices);
- private = (struct dasd_eckd_private *) device->private;
+ private = device->private;
private->pavgroup = NULL;
}
list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist,
alias_list) {
list_move(&device->alias_list, &lcu->active_devices);
- private = (struct dasd_eckd_private *) device->private;
+ private = device->private;
private->pavgroup = NULL;
}
list_del(&pavgroup->group);
@@ -501,10 +615,7 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
if (rc)
return rc;
- /* need to take cdev lock before lcu lock */
- spin_lock_irqsave_nested(get_ccwdev_lock(refdev->cdev), flags,
- CDEV_NESTED_FIRST);
- spin_lock(&lcu->lock);
+ _trylock_and_lock_lcu_irqsave(lcu, NULL, &flags);
lcu->pav = NO_PAV;
for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) {
switch (lcu->uac->unit[i].ua_type) {
@@ -523,8 +634,8 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
alias_list) {
_add_device_to_lcu(lcu, device, refdev);
}
- spin_unlock(&lcu->lock);
- spin_unlock_irqrestore(get_ccwdev_lock(refdev->cdev), flags);
+ _unlock_all_devices_on_lcu(lcu, NULL, NULL);
+ spin_unlock_irqrestore(&lcu->lock, flags);
return 0;
}
@@ -549,8 +660,10 @@ static void lcu_update_work(struct work_struct *work)
if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) {
DBF_DEV_EVENT(DBF_WARNING, device, "could not update"
" alias data in lcu (rc = %d), retry later", rc);
- schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
+ if (!schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ))
+ dasd_put_device(device);
} else {
+ dasd_put_device(device);
lcu->ruac_data.device = NULL;
lcu->flags &= ~UPDATE_PENDING;
}
@@ -593,23 +706,22 @@ static int _schedule_lcu_update(struct alias_lcu *lcu,
*/
if (!usedev)
return -EINVAL;
+ dasd_get_device(usedev);
lcu->ruac_data.device = usedev;
- schedule_delayed_work(&lcu->ruac_data.dwork, 0);
+ if (!schedule_delayed_work(&lcu->ruac_data.dwork, 0))
+ dasd_put_device(usedev);
return 0;
}
int dasd_alias_add_device(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
struct alias_lcu *lcu;
unsigned long flags;
int rc;
- private = (struct dasd_eckd_private *) device->private;
lcu = private->lcu;
rc = 0;
-
- /* need to take cdev lock before lcu lock */
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
spin_lock(&lcu->lock);
if (!(lcu->flags & UPDATE_PENDING)) {
@@ -628,20 +740,18 @@ int dasd_alias_add_device(struct dasd_device *device)
int dasd_alias_update_add_device(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
- private = (struct dasd_eckd_private *) device->private;
+ struct dasd_eckd_private *private = device->private;
+
private->lcu->flags |= UPDATE_PENDING;
return dasd_alias_add_device(device);
}
int dasd_alias_remove_device(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
- struct alias_lcu *lcu;
+ struct dasd_eckd_private *private = device->private;
+ struct alias_lcu *lcu = private->lcu;
unsigned long flags;
- private = (struct dasd_eckd_private *) device->private;
- lcu = private->lcu;
/* nothing to do if already removed */
if (!lcu)
return 0;
@@ -653,16 +763,12 @@ int dasd_alias_remove_device(struct dasd_device *device)
struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
{
-
+ struct dasd_eckd_private *alias_priv, *private = base_device->private;
+ struct alias_pav_group *group = private->pavgroup;
+ struct alias_lcu *lcu = private->lcu;
struct dasd_device *alias_device;
- struct alias_pav_group *group;
- struct alias_lcu *lcu;
- struct dasd_eckd_private *private, *alias_priv;
unsigned long flags;
- private = (struct dasd_eckd_private *) base_device->private;
- group = private->pavgroup;
- lcu = private->lcu;
if (!group || !lcu)
return NULL;
if (lcu->pav == NO_PAV ||
@@ -698,7 +804,7 @@ struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
group->next = list_first_entry(&alias_device->alias_list,
struct dasd_device, alias_list);
spin_unlock_irqrestore(&lcu->lock, flags);
- alias_priv = (struct dasd_eckd_private *) alias_device->private;
+ alias_priv = alias_device->private;
if ((alias_priv->count < private->count) && !alias_device->stopped &&
!test_bit(DASD_FLAG_OFFLINE, &alias_device->flags))
return alias_device;
@@ -723,7 +829,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu,
ASCEBC((char *) &cqr->magic, 4);
ccw = cqr->cpaddr;
ccw->cmd_code = DASD_ECKD_CCW_RSCK;
- ccw->flags = 0 ;
+ ccw->flags = CCW_FLAG_SLI;
ccw->count = 16;
ccw->cda = (__u32)(addr_t) cqr->data;
((char *)cqr->data)[0] = reason;
@@ -746,30 +852,19 @@ static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu)
struct alias_pav_group *pavgroup;
struct dasd_device *device;
struct dasd_eckd_private *private;
- unsigned long flags;
/* active and inactive list can contain alias as well as base devices */
list_for_each_entry(device, &lcu->active_devices, alias_list) {
- private = (struct dasd_eckd_private *) device->private;
- spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- if (private->uid.type != UA_BASE_DEVICE) {
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
- flags);
+ private = device->private;
+ if (private->uid.type != UA_BASE_DEVICE)
continue;
- }
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
dasd_schedule_block_bh(device->block);
dasd_schedule_device_bh(device);
}
list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
- private = (struct dasd_eckd_private *) device->private;
- spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- if (private->uid.type != UA_BASE_DEVICE) {
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
- flags);
+ private = device->private;
+ if (private->uid.type != UA_BASE_DEVICE)
continue;
- }
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
dasd_schedule_block_bh(device->block);
dasd_schedule_device_bh(device);
}
@@ -804,7 +899,7 @@ static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)
spin_lock_irqsave(&lcu->lock, flags);
list_for_each_entry_safe(device, temp, &lcu->active_devices,
alias_list) {
- private = (struct dasd_eckd_private *) device->private;
+ private = device->private;
if (private->uid.type == UA_BASE_DEVICE)
continue;
list_move(&device->alias_list, &active);
@@ -826,45 +921,27 @@ static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)
if (device == list_first_entry(&active,
struct dasd_device, alias_list)) {
list_move(&device->alias_list, &lcu->active_devices);
- private = (struct dasd_eckd_private *) device->private;
+ private = device->private;
private->pavgroup = NULL;
}
}
spin_unlock_irqrestore(&lcu->lock, flags);
}
-static void __stop_device_on_lcu(struct dasd_device *device,
- struct dasd_device *pos)
-{
- /* If pos == device then device is already locked! */
- if (pos == device) {
- dasd_device_set_stop_bits(pos, DASD_STOPPED_SU);
- return;
- }
- spin_lock(get_ccwdev_lock(pos->cdev));
- dasd_device_set_stop_bits(pos, DASD_STOPPED_SU);
- spin_unlock(get_ccwdev_lock(pos->cdev));
-}
-
-/*
- * This function is called in interrupt context, so the
- * cdev lock for device is already locked!
- */
-static void _stop_all_devices_on_lcu(struct alias_lcu *lcu,
- struct dasd_device *device)
+static void _stop_all_devices_on_lcu(struct alias_lcu *lcu)
{
struct alias_pav_group *pavgroup;
- struct dasd_device *pos;
+ struct dasd_device *device;
- list_for_each_entry(pos, &lcu->active_devices, alias_list)
- __stop_device_on_lcu(device, pos);
- list_for_each_entry(pos, &lcu->inactive_devices, alias_list)
- __stop_device_on_lcu(device, pos);
+ list_for_each_entry(device, &lcu->active_devices, alias_list)
+ dasd_device_set_stop_bits(device, DASD_STOPPED_SU);
+ list_for_each_entry(device, &lcu->inactive_devices, alias_list)
+ dasd_device_set_stop_bits(device, DASD_STOPPED_SU);
list_for_each_entry(pavgroup, &lcu->grouplist, group) {
- list_for_each_entry(pos, &pavgroup->baselist, alias_list)
- __stop_device_on_lcu(device, pos);
- list_for_each_entry(pos, &pavgroup->aliaslist, alias_list)
- __stop_device_on_lcu(device, pos);
+ list_for_each_entry(device, &pavgroup->baselist, alias_list)
+ dasd_device_set_stop_bits(device, DASD_STOPPED_SU);
+ list_for_each_entry(device, &pavgroup->aliaslist, alias_list)
+ dasd_device_set_stop_bits(device, DASD_STOPPED_SU);
}
}
@@ -872,33 +949,16 @@ static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu)
{
struct alias_pav_group *pavgroup;
struct dasd_device *device;
- unsigned long flags;
- list_for_each_entry(device, &lcu->active_devices, alias_list) {
- spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ list_for_each_entry(device, &lcu->active_devices, alias_list)
dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
- }
-
- list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
- spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ list_for_each_entry(device, &lcu->inactive_devices, alias_list)
dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
- }
-
list_for_each_entry(pavgroup, &lcu->grouplist, group) {
- list_for_each_entry(device, &pavgroup->baselist, alias_list) {
- spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ list_for_each_entry(device, &pavgroup->baselist, alias_list)
dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
- flags);
- }
- list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
- spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ list_for_each_entry(device, &pavgroup->aliaslist, alias_list)
dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
- flags);
- }
}
}
@@ -924,12 +984,14 @@ static void summary_unit_check_handling_work(struct work_struct *work)
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
reset_summary_unit_check(lcu, device, suc_data->reason);
- spin_lock_irqsave(&lcu->lock, flags);
+ _trylock_and_lock_lcu_irqsave(lcu, NULL, &flags);
_unstop_all_devices_on_lcu(lcu);
_restart_all_base_devices_on_lcu(lcu);
/* 3. read new alias configuration */
_schedule_lcu_update(lcu, device);
lcu->suc_data.device = NULL;
+ dasd_put_device(device);
+ _unlock_all_devices_on_lcu(lcu, NULL, NULL);
spin_unlock_irqrestore(&lcu->lock, flags);
}
@@ -939,13 +1001,11 @@ static void summary_unit_check_handling_work(struct work_struct *work)
void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
struct irb *irb)
{
+ struct dasd_eckd_private *private = device->private;
struct alias_lcu *lcu;
char reason;
- struct dasd_eckd_private *private;
char *sense;
- private = (struct dasd_eckd_private *) device->private;
-
sense = dasd_get_sense(irb);
if (sense) {
reason = sense[8];
@@ -965,10 +1025,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
" unit check (no lcu structure)");
return;
}
- spin_lock(&lcu->lock);
- _stop_all_devices_on_lcu(lcu, device);
- /* prepare for lcu_update */
- private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;
+ _trylock_and_lock_lcu(lcu, device);
/* If this device is about to be removed just return and wait for
* the next interrupt on a different device
*/
@@ -976,6 +1033,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"device is in offline processing,"
" don't do summary unit check handling");
+ _unlock_all_devices_on_lcu(lcu, device, NULL);
spin_unlock(&lcu->lock);
return;
}
@@ -984,11 +1042,18 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"previous instance of summary unit check worker"
" still pending");
+ _unlock_all_devices_on_lcu(lcu, device, NULL);
spin_unlock(&lcu->lock);
return ;
}
+ _stop_all_devices_on_lcu(lcu);
+ /* prepare for lcu_update */
+ private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;
lcu->suc_data.reason = reason;
lcu->suc_data.device = device;
+ dasd_get_device(device);
+ _unlock_all_devices_on_lcu(lcu, device, NULL);
spin_unlock(&lcu->lock);
- schedule_work(&lcu->suc_data.worker);
+ if (!schedule_work(&lcu->suc_data.worker))
+ dasd_put_device(device);
};
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 8286f742436b..2f18f61092b5 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -214,8 +214,8 @@ dasd_feature_list(char *str, char **endp)
else if (len == 8 && !strncmp(str, "failfast", 8))
features |= DASD_FEATURE_FAILFAST;
else {
- pr_warning("%*s is not a supported device option\n",
- len, str);
+ pr_warn("%*s is not a supported device option\n",
+ len, str);
rc = -EINVAL;
}
str += len;
@@ -224,8 +224,7 @@ dasd_feature_list(char *str, char **endp)
str++;
}
if (*str != ')') {
- pr_warning("A closing parenthesis ')' is missing in the "
- "dasd= parameter\n");
+ pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n");
rc = -EINVAL;
} else
str++;
@@ -348,8 +347,7 @@ dasd_parse_range( char *parsestring ) {
return str + 1;
if (*str == '\0')
return str;
- pr_warning("The dasd= parameter value %s has an invalid ending\n",
- str);
+ pr_warn("The dasd= parameter value %s has an invalid ending\n", str);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index cb61f300f8b5..5667146c6a0a 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -67,7 +67,7 @@ static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */
* and function code cmd.
* In case of an exception return 3. Otherwise return result of bitwise OR of
* resulting condition code and DIAG return code. */
-static inline int dia250(void *iob, int cmd)
+static inline int __dia250(void *iob, int cmd)
{
register unsigned long reg2 asm ("2") = (unsigned long) iob;
typedef union {
@@ -77,7 +77,6 @@ static inline int dia250(void *iob, int cmd)
int rc;
rc = 3;
- diag_stat_inc(DIAG_STAT_X250);
asm volatile(
" diag 2,%2,0x250\n"
"0: ipm %0\n"
@@ -91,6 +90,12 @@ static inline int dia250(void *iob, int cmd)
return rc;
}
+static inline int dia250(void *iob, int cmd)
+{
+ diag_stat_inc(DIAG_STAT_X250);
+ return __dia250(iob, cmd);
+}
+
/* Initialize block I/O to DIAG device using the specified blocksize and
* block offset. On success, return zero and set end_block to contain the
* number of blocks on the device minus the specified offset. Return non-zero
@@ -99,12 +104,10 @@ static inline int
mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
blocknum_t offset, blocknum_t *end_block)
{
- struct dasd_diag_private *private;
- struct dasd_diag_init_io *iib;
+ struct dasd_diag_private *private = device->private;
+ struct dasd_diag_init_io *iib = &private->iib;
int rc;
- private = (struct dasd_diag_private *) device->private;
- iib = &private->iib;
memset(iib, 0, sizeof (struct dasd_diag_init_io));
iib->dev_nr = private->dev_id.devno;
@@ -125,12 +128,10 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
static inline int
mdsk_term_io(struct dasd_device * device)
{
- struct dasd_diag_private *private;
- struct dasd_diag_init_io *iib;
+ struct dasd_diag_private *private = device->private;
+ struct dasd_diag_init_io *iib = &private->iib;
int rc;
- private = (struct dasd_diag_private *) device->private;
- iib = &private->iib;
memset(iib, 0, sizeof (struct dasd_diag_init_io));
iib->dev_nr = private->dev_id.devno;
rc = dia250(iib, TERM_BIO);
@@ -148,14 +149,13 @@ dasd_diag_erp(struct dasd_device *device)
rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
if (rc == 4) {
if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags)))
- pr_warning("%s: The access mode of a DIAG device "
- "changed to read-only\n",
- dev_name(&device->cdev->dev));
+ pr_warn("%s: The access mode of a DIAG device changed to read-only\n",
+ dev_name(&device->cdev->dev));
rc = 0;
}
if (rc)
- pr_warning("%s: DIAG ERP failed with "
- "rc=%d\n", dev_name(&device->cdev->dev), rc);
+ pr_warn("%s: DIAG ERP failed with rc=%d\n",
+ dev_name(&device->cdev->dev), rc);
}
/* Start a given request at the device. Return zero on success, non-zero
@@ -175,8 +175,8 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
cqr->status = DASD_CQR_ERROR;
return -EIO;
}
- private = (struct dasd_diag_private *) device->private;
- dreq = (struct dasd_diag_req *) cqr->data;
+ private = device->private;
+ dreq = cqr->data;
private->iob.dev_nr = private->dev_id.devno;
private->iob.key = 0;
@@ -315,18 +315,17 @@ static void dasd_ext_handler(struct ext_code ext_code,
static int
dasd_diag_check_device(struct dasd_device *device)
{
- struct dasd_block *block;
- struct dasd_diag_private *private;
+ struct dasd_diag_private *private = device->private;
struct dasd_diag_characteristics *rdc_data;
- struct dasd_diag_bio bio;
struct vtoc_cms_label *label;
- blocknum_t end_block;
+ struct dasd_block *block;
+ struct dasd_diag_bio bio;
unsigned int sb, bsize;
+ blocknum_t end_block;
int rc;
- private = (struct dasd_diag_private *) device->private;
if (private == NULL) {
- private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
+ private = kzalloc(sizeof(*private), GFP_KERNEL);
if (private == NULL) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"Allocating memory for private DASD data "
@@ -334,7 +333,7 @@ dasd_diag_check_device(struct dasd_device *device)
return -ENOMEM;
}
ccw_device_get_id(device->cdev, &private->dev_id);
- device->private = (void *) private;
+ device->private = private;
}
block = dasd_alloc_block();
if (IS_ERR(block)) {
@@ -348,7 +347,7 @@ dasd_diag_check_device(struct dasd_device *device)
block->base = device;
/* Read Device Characteristics */
- rdc_data = (void *) &(private->rdc_data);
+ rdc_data = &private->rdc_data;
rdc_data->dev_nr = private->dev_id.devno;
rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics);
@@ -372,9 +371,9 @@ dasd_diag_check_device(struct dasd_device *device)
private->pt_block = 2;
break;
default:
- pr_warning("%s: Device type %d is not supported "
- "in DIAG mode\n", dev_name(&device->cdev->dev),
- private->rdc_data.vdev_class);
+ pr_warn("%s: Device type %d is not supported in DIAG mode\n",
+ dev_name(&device->cdev->dev),
+ private->rdc_data.vdev_class);
rc = -EOPNOTSUPP;
goto out;
}
@@ -415,8 +414,8 @@ dasd_diag_check_device(struct dasd_device *device)
private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
rc = dia250(&private->iob, RW_BIO);
if (rc == 3) {
- pr_warning("%s: A 64-bit DIAG call failed\n",
- dev_name(&device->cdev->dev));
+ pr_warn("%s: A 64-bit DIAG call failed\n",
+ dev_name(&device->cdev->dev));
rc = -EOPNOTSUPP;
goto out_label;
}
@@ -425,9 +424,8 @@ dasd_diag_check_device(struct dasd_device *device)
break;
}
if (bsize > PAGE_SIZE) {
- pr_warning("%s: Accessing the DASD failed because of an "
- "incorrect format (rc=%d)\n",
- dev_name(&device->cdev->dev), rc);
+ pr_warn("%s: Accessing the DASD failed because of an incorrect format (rc=%d)\n",
+ dev_name(&device->cdev->dev), rc);
rc = -EIO;
goto out_label;
}
@@ -445,8 +443,8 @@ dasd_diag_check_device(struct dasd_device *device)
block->s2b_shift++;
rc = mdsk_init_io(device, block->bp_block, 0, NULL);
if (rc && (rc != 4)) {
- pr_warning("%s: DIAG initialization failed with rc=%d\n",
- dev_name(&device->cdev->dev), rc);
+ pr_warn("%s: DIAG initialization failed with rc=%d\n",
+ dev_name(&device->cdev->dev), rc);
rc = -EIO;
} else {
if (rc == 4)
@@ -596,16 +594,14 @@ static int
dasd_diag_fill_info(struct dasd_device * device,
struct dasd_information2_t * info)
{
- struct dasd_diag_private *private;
+ struct dasd_diag_private *private = device->private;
- private = (struct dasd_diag_private *) device->private;
info->label_block = (unsigned int) private->pt_block;
info->FBA_layout = 1;
info->format = DASD_FORMAT_LDL;
- info->characteristics_size = sizeof (struct dasd_diag_characteristics);
- memcpy(info->characteristics,
- &((struct dasd_diag_private *) device->private)->rdc_data,
- sizeof (struct dasd_diag_characteristics));
+ info->characteristics_size = sizeof(private->rdc_data);
+ memcpy(info->characteristics, &private->rdc_data,
+ sizeof(private->rdc_data));
info->confdata_size = 0;
return 0;
}
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 9083247f55a8..75c032dcf173 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -212,10 +212,9 @@ check_XRC (struct ccw1 *de_ccw,
struct DE_eckd_data *data,
struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
int rc;
- private = (struct dasd_eckd_private *) device->private;
if (!private->rdc_data.facilities.XRC_supported)
return 0;
@@ -237,13 +236,11 @@ static int
define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
unsigned int totrk, int cmd, struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
u32 begcyl, endcyl;
u16 heads, beghead, endhead;
int rc = 0;
- private = (struct dasd_eckd_private *) device->private;
-
ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
ccw->flags = 0;
ccw->count = 16;
@@ -322,10 +319,9 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
int rc;
- private = (struct dasd_eckd_private *) device->private;
if (!private->rdc_data.facilities.XRC_supported)
return 0;
@@ -346,12 +342,10 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk,
struct dasd_device *device, unsigned int reclen,
unsigned int tlf)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
int sector;
int dn, d;
- private = (struct dasd_eckd_private *) device->private;
-
memset(data, 0, sizeof(*data));
sector = 0;
if (rec_on_trk) {
@@ -488,8 +482,8 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
u16 heads, beghead, endhead;
int rc = 0;
- basepriv = (struct dasd_eckd_private *) basedev->private;
- startpriv = (struct dasd_eckd_private *) startdev->private;
+ basepriv = basedev->private;
+ startpriv = startdev->private;
dedata = &pfxdata->define_extent;
lredata = &pfxdata->locate_record;
@@ -631,12 +625,10 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk,
unsigned int rec_on_trk, int no_rec, int cmd,
struct dasd_device * device, int reclen)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
int sector;
int dn, d;
- private = (struct dasd_eckd_private *) device->private;
-
DBF_DEV_EVENT(DBF_INFO, device,
"Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d",
trk, rec_on_trk, no_rec, cmd, reclen);
@@ -800,10 +792,9 @@ static void create_uid(struct dasd_eckd_private *private)
*/
static int dasd_eckd_generate_uid(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
unsigned long flags;
- private = (struct dasd_eckd_private *) device->private;
if (!private)
return -ENODEV;
if (!private->ned || !private->gneq)
@@ -816,11 +807,10 @@ static int dasd_eckd_generate_uid(struct dasd_device *device)
static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
unsigned long flags;
- if (device->private) {
- private = (struct dasd_eckd_private *)device->private;
+ if (private) {
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
*uid = private->uid;
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
@@ -1034,10 +1024,9 @@ static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len)
static void dasd_eckd_clear_conf_data(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
int i;
- private = (struct dasd_eckd_private *) device->private;
private->conf_data = NULL;
private->conf_len = 0;
for (i = 0; i < 8; i++) {
@@ -1058,7 +1047,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
struct dasd_uid *uid;
char print_path_uid[60], print_device_uid[60];
- private = (struct dasd_eckd_private *) device->private;
+ private = device->private;
path_data = &device->path_data;
opm = ccw_device_get_path_mask(device->cdev);
conf_data_saved = 0;
@@ -1191,11 +1180,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
int mdc;
u32 fcx_max_data;
- private = (struct dasd_eckd_private *) device->private;
if (private->fcx_max_data) {
mdc = ccw_device_get_mdc(device->cdev, lpm);
if ((mdc < 0)) {
@@ -1221,15 +1209,10 @@ static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm)
static int rebuild_device_uid(struct dasd_device *device,
struct path_verification_work_data *data)
{
- struct dasd_eckd_private *private;
- struct dasd_path *path_data;
- __u8 lpm, opm;
- int rc;
-
- rc = -ENODEV;
- private = (struct dasd_eckd_private *) device->private;
- path_data = &device->path_data;
- opm = device->path_data.opm;
+ struct dasd_eckd_private *private = device->private;
+ struct dasd_path *path_data = &device->path_data;
+ __u8 lpm, opm = path_data->opm;
+ int rc = -ENODEV;
for (lpm = 0x80; lpm; lpm >>= 1) {
if (!(lpm & opm))
@@ -1463,14 +1446,13 @@ static int dasd_eckd_verify_path(struct dasd_device *device, __u8 lpm)
static int dasd_eckd_read_features(struct dasd_device *device)
{
+ struct dasd_eckd_private *private = device->private;
struct dasd_psf_prssd_data *prssdp;
struct dasd_rssd_features *features;
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
int rc;
- struct dasd_eckd_private *private;
- private = (struct dasd_eckd_private *) device->private;
memset(&private->features, 0, sizeof(struct dasd_rssd_features));
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
(sizeof(struct dasd_psf_prssd_data) +
@@ -1605,11 +1587,9 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav,
static int dasd_eckd_validate_server(struct dasd_device *device,
unsigned long flags)
{
- int rc;
- struct dasd_eckd_private *private;
- int enable_pav;
+ struct dasd_eckd_private *private = device->private;
+ int enable_pav, rc;
- private = (struct dasd_eckd_private *) device->private;
if (private->uid.type == UA_BASE_PAV_ALIAS ||
private->uid.type == UA_HYPER_PAV_ALIAS)
return 0;
@@ -1662,14 +1642,13 @@ static void dasd_eckd_kick_validate_server(struct dasd_device *device)
static u32 get_fcx_max_data(struct dasd_device *device)
{
- int tpm, mdc;
+ struct dasd_eckd_private *private = device->private;
int fcx_in_css, fcx_in_gneq, fcx_in_features;
- struct dasd_eckd_private *private;
+ int tpm, mdc;
if (dasd_nofcx)
return 0;
/* is transport mode supported? */
- private = (struct dasd_eckd_private *) device->private;
fcx_in_css = css_general_characteristics.fcx;
fcx_in_gneq = private->gneq->reserved2[7] & 0x04;
fcx_in_features = private->features.feature[40] & 0x80;
@@ -1694,7 +1673,7 @@ static u32 get_fcx_max_data(struct dasd_device *device)
static int
dasd_eckd_check_characteristics(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
struct dasd_block *block;
struct dasd_uid temp_uid;
int rc, i;
@@ -1713,7 +1692,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
dev_info(&device->cdev->dev,
"The DASD is not operating in multipath mode\n");
}
- private = (struct dasd_eckd_private *) device->private;
if (!private) {
private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
if (!private) {
@@ -1722,7 +1700,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
"failed\n");
return -ENOMEM;
}
- device->private = (void *) private;
+ device->private = private;
} else {
memset(private, 0, sizeof(*private));
}
@@ -1837,10 +1815,9 @@ out_err1:
static void dasd_eckd_uncheck_device(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
int i;
- private = (struct dasd_eckd_private *) device->private;
dasd_alias_disconnect_device_from_lcu(device);
private->ned = NULL;
private->sneq = NULL;
@@ -1863,7 +1840,7 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device)
static struct dasd_ccw_req *
dasd_eckd_analysis_ccw(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
struct eckd_count *count_data;
struct LO_eckd_data *LO_data;
struct dasd_ccw_req *cqr;
@@ -1871,8 +1848,6 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
int cplength, datasize;
int i;
- private = (struct dasd_eckd_private *) device->private;
-
cplength = 8;
datasize = sizeof(struct DE_eckd_data) + 2*sizeof(struct LO_eckd_data);
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device);
@@ -1946,11 +1921,9 @@ static int dasd_eckd_analysis_evaluation(struct dasd_ccw_req *init_cqr)
static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr,
void *data)
{
- struct dasd_eckd_private *private;
- struct dasd_device *device;
+ struct dasd_device *device = init_cqr->startdev;
+ struct dasd_eckd_private *private = device->private;
- device = init_cqr->startdev;
- private = (struct dasd_eckd_private *) device->private;
private->init_cqr_status = dasd_eckd_analysis_evaluation(init_cqr);
dasd_sfree_request(init_cqr, device);
dasd_kick_device(device);
@@ -1977,15 +1950,13 @@ static int dasd_eckd_start_analysis(struct dasd_block *block)
static int dasd_eckd_end_analysis(struct dasd_block *block)
{
- struct dasd_device *device;
- struct dasd_eckd_private *private;
+ struct dasd_device *device = block->base;
+ struct dasd_eckd_private *private = device->private;
struct eckd_count *count_area;
unsigned int sb, blk_per_trk;
int status, i;
struct dasd_ccw_req *init_cqr;
- device = block->base;
- private = (struct dasd_eckd_private *) device->private;
status = private->init_cqr_status;
private->init_cqr_status = -1;
if (status == INIT_CQR_ERROR) {
@@ -2083,9 +2054,8 @@ raw:
static int dasd_eckd_do_analysis(struct dasd_block *block)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = block->base->private;
- private = (struct dasd_eckd_private *) block->base->private;
if (private->init_cqr_status < 0)
return dasd_eckd_start_analysis(block);
else
@@ -2112,9 +2082,8 @@ static int dasd_eckd_basic_to_known(struct dasd_device *device)
static int
dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = block->base->private;
- private = (struct dasd_eckd_private *) block->base->private;
if (dasd_check_blocksize(block->bp_block) == 0) {
geo->sectors = recs_per_track(&private->rdc_data,
0, block->bp_block);
@@ -2151,8 +2120,8 @@ dasd_eckd_build_format(struct dasd_device *base,
if (!startdev)
startdev = base;
- start_priv = (struct dasd_eckd_private *) startdev->private;
- base_priv = (struct dasd_eckd_private *) base->private;
+ start_priv = startdev->private;
+ base_priv = base->private;
rpt = recs_per_track(&base_priv->rdc_data, 0, fdata->blksize);
@@ -2349,14 +2318,14 @@ dasd_eckd_build_format(struct dasd_device *base,
* when formatting CDL
*/
if ((intensity & 0x08) &&
- fdata->start_unit == 0) {
+ address.cyl == 0 && address.head == 0) {
if (i < 3) {
ect->kl = 4;
ect->dl = sizes_trk0[i] - 4;
}
}
if ((intensity & 0x08) &&
- fdata->start_unit == 1) {
+ address.cyl == 0 && address.head == 1) {
ect->kl = 44;
ect->dl = LABEL_SIZE - 44;
}
@@ -2386,23 +2355,24 @@ dasd_eckd_build_format(struct dasd_device *base,
return fcp;
}
-static int
-dasd_eckd_format_device(struct dasd_device *base,
- struct format_data_t *fdata,
- int enable_pav)
+/*
+ * Wrapper function to build a CCW request depending on input data
+ */
+static struct dasd_ccw_req *
+dasd_eckd_format_build_ccw_req(struct dasd_device *base,
+ struct format_data_t *fdata, int enable_pav)
{
- struct dasd_ccw_req *cqr, *n;
- struct dasd_block *block;
- struct dasd_eckd_private *private;
- struct list_head format_queue;
- struct dasd_device *device;
- int old_stop, format_step;
- int step, rc = 0, sleep_rc;
+ return dasd_eckd_build_format(base, fdata, enable_pav);
+}
- block = base->block;
- private = (struct dasd_eckd_private *) base->private;
+/*
+ * Sanity checks on format_data
+ */
+static int dasd_eckd_format_sanity_checks(struct dasd_device *base,
+ struct format_data_t *fdata)
+{
+ struct dasd_eckd_private *private = base->private;
- /* Sanity checks. */
if (fdata->start_unit >=
(private->real_cyl * private->rdc_data.trk_per_cyl)) {
dev_warn(&base->cdev->dev,
@@ -2429,75 +2399,98 @@ dasd_eckd_format_device(struct dasd_device *base,
fdata->blksize);
return -EINVAL;
}
+ return 0;
+}
+
+/*
+ * This function will process format_data originally coming from an IOCTL
+ */
+static int dasd_eckd_format_process_data(struct dasd_device *base,
+ struct format_data_t *fdata,
+ int enable_pav)
+{
+ struct dasd_eckd_private *private = base->private;
+ struct dasd_ccw_req *cqr, *n;
+ struct list_head format_queue;
+ struct dasd_device *device;
+ int old_start, old_stop, format_step;
+ int step, retry;
+ int rc;
+
+ rc = dasd_eckd_format_sanity_checks(base, fdata);
+ if (rc)
+ return rc;
INIT_LIST_HEAD(&format_queue);
+ old_start = fdata->start_unit;
old_stop = fdata->stop_unit;
- while (fdata->start_unit <= 1) {
- fdata->stop_unit = fdata->start_unit;
- cqr = dasd_eckd_build_format(base, fdata, enable_pav);
- list_add(&cqr->blocklist, &format_queue);
-
- fdata->stop_unit = old_stop;
- fdata->start_unit++;
- if (fdata->start_unit > fdata->stop_unit)
- goto sleep;
- }
+ format_step = DASD_CQR_MAX_CCW / recs_per_track(&private->rdc_data, 0,
+ fdata->blksize);
+ do {
+ retry = 0;
+ while (fdata->start_unit <= old_stop) {
+ step = fdata->stop_unit - fdata->start_unit + 1;
+ if (step > format_step) {
+ fdata->stop_unit =
+ fdata->start_unit + format_step - 1;
+ }
-retry:
- format_step = 255 / recs_per_track(&private->rdc_data, 0,
- fdata->blksize);
- while (fdata->start_unit <= old_stop) {
- step = fdata->stop_unit - fdata->start_unit + 1;
- if (step > format_step)
- fdata->stop_unit = fdata->start_unit + format_step - 1;
+ cqr = dasd_eckd_format_build_ccw_req(base, fdata,
+ enable_pav);
+ if (IS_ERR(cqr)) {
+ rc = PTR_ERR(cqr);
+ if (rc == -ENOMEM) {
+ if (list_empty(&format_queue))
+ goto out;
+ /*
+ * not enough memory available, start
+ * requests retry after first requests
+ * were finished
+ */
+ retry = 1;
+ break;
+ }
+ goto out_err;
+ }
+ list_add_tail(&cqr->blocklist, &format_queue);
- cqr = dasd_eckd_build_format(base, fdata, enable_pav);
- if (IS_ERR(cqr)) {
- if (PTR_ERR(cqr) == -ENOMEM) {
- /*
- * not enough memory available
- * go to out and start requests
- * retry after first requests were finished
- */
- fdata->stop_unit = old_stop;
- goto sleep;
- } else
- return PTR_ERR(cqr);
+ fdata->start_unit = fdata->stop_unit + 1;
+ fdata->stop_unit = old_stop;
}
- list_add(&cqr->blocklist, &format_queue);
- fdata->start_unit = fdata->stop_unit + 1;
- fdata->stop_unit = old_stop;
- }
+ rc = dasd_sleep_on_queue(&format_queue);
-sleep:
- sleep_rc = dasd_sleep_on_queue(&format_queue);
+out_err:
+ list_for_each_entry_safe(cqr, n, &format_queue, blocklist) {
+ device = cqr->startdev;
+ private = device->private;
+ if (cqr->status == DASD_CQR_FAILED)
+ rc = -EIO;
+ list_del_init(&cqr->blocklist);
+ dasd_sfree_request(cqr, device);
+ private->count--;
+ }
- list_for_each_entry_safe(cqr, n, &format_queue, blocklist) {
- device = cqr->startdev;
- private = (struct dasd_eckd_private *) device->private;
- if (cqr->status == DASD_CQR_FAILED)
- rc = -EIO;
- list_del_init(&cqr->blocklist);
- dasd_sfree_request(cqr, device);
- private->count--;
- }
+ if (rc)
+ goto out;
- if (sleep_rc)
- return sleep_rc;
+ } while (retry);
- /*
- * in case of ENOMEM we need to retry after
- * first requests are finished
- */
- if (fdata->start_unit <= fdata->stop_unit)
- goto retry;
+out:
+ fdata->start_unit = old_start;
+ fdata->stop_unit = old_stop;
return rc;
}
+static int dasd_eckd_format_device(struct dasd_device *base,
+ struct format_data_t *fdata, int enable_pav)
+{
+ return dasd_eckd_format_process_data(base, fdata, enable_pav);
+}
+
static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
{
if (cqr->retries < 0) {
@@ -2543,9 +2536,8 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
{
char mask;
char *sense = NULL;
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
- private = (struct dasd_eckd_private *) device->private;
/* first of all check for state change pending interrupt */
mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
if ((scsw_dstat(&irb->scsw) & mask) == mask) {
@@ -2634,7 +2626,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
struct dasd_device *basedev;
basedev = block->base;
- private = (struct dasd_eckd_private *) basedev->private;
+ private = basedev->private;
if (rq_data_dir(req) == READ)
cmd = DASD_ECKD_CCW_READ_MT;
else if (rq_data_dir(req) == WRITE)
@@ -2990,8 +2982,8 @@ static int prepare_itcw(struct itcw *itcw,
/* setup prefix data */
- basepriv = (struct dasd_eckd_private *) basedev->private;
- startpriv = (struct dasd_eckd_private *) startdev->private;
+ basepriv = basedev->private;
+ startpriv = startdev->private;
dedata = &pfxdata.define_extent;
lredata = &pfxdata.locate_record;
@@ -3278,7 +3270,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
struct dasd_ccw_req *cqr;
basedev = block->base;
- private = (struct dasd_eckd_private *) basedev->private;
+ private = basedev->private;
/* Calculate number of blocks/records per track. */
blksize = block->bp_block;
@@ -3503,7 +3495,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
if (!dasd_page_cache)
goto out;
- private = (struct dasd_eckd_private *) cqr->block->base->private;
+ private = cqr->block->base->private;
blksize = cqr->block->bp_block;
blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
recid = blk_rq_pos(req) >> cqr->block->s2b_shift;
@@ -3587,7 +3579,7 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
startdev = dasd_alias_get_start_dev(base);
if (!startdev)
startdev = base;
- private = (struct dasd_eckd_private *) startdev->private;
+ private = startdev->private;
if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE)
return ERR_PTR(-EBUSY);
@@ -3610,7 +3602,7 @@ static int dasd_eckd_free_alias_cp(struct dasd_ccw_req *cqr,
unsigned long flags;
spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags);
- private = (struct dasd_eckd_private *) cqr->memdev->private;
+ private = cqr->memdev->private;
private->count--;
spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags);
return dasd_eckd_free_cp(cqr, req);
@@ -3620,15 +3612,14 @@ static int
dasd_eckd_fill_info(struct dasd_device * device,
struct dasd_information2_t * info)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
- private = (struct dasd_eckd_private *) device->private;
info->label_block = 2;
info->FBA_layout = private->uses_cdl ? 0 : 1;
info->format = private->uses_cdl ? DASD_FORMAT_CDL : DASD_FORMAT_LDL;
- info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
+ info->characteristics_size = sizeof(private->rdc_data);
memcpy(info->characteristics, &private->rdc_data,
- sizeof(struct dasd_eckd_characteristics));
+ sizeof(private->rdc_data));
info->confdata_size = min((unsigned long)private->conf_len,
sizeof(info->configuration_data));
memcpy(info->configuration_data, private->conf_data,
@@ -3941,8 +3932,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
static int
dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp)
{
- struct dasd_eckd_private *private =
- (struct dasd_eckd_private *)device->private;
+ struct dasd_eckd_private *private = device->private;
struct attrib_data_t attrib = private->attrib;
int rc;
@@ -3966,8 +3956,7 @@ dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp)
static int
dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
{
- struct dasd_eckd_private *private =
- (struct dasd_eckd_private *)device->private;
+ struct dasd_eckd_private *private = device->private;
struct attrib_data_t attrib;
if (!capable(CAP_SYS_ADMIN))
@@ -4430,15 +4419,13 @@ static int dasd_eckd_pm_freeze(struct dasd_device *device)
static int dasd_eckd_restore_device(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
struct dasd_eckd_characteristics temp_rdc_data;
int rc;
struct dasd_uid temp_uid;
unsigned long flags;
unsigned long cqr_flags = 0;
- private = (struct dasd_eckd_private *) device->private;
-
/* Read Configuration Data */
rc = dasd_eckd_read_conf(device);
if (rc) {
@@ -4502,14 +4489,12 @@ out_err:
static int dasd_eckd_reload_device(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
int rc, old_base;
char print_uid[60];
struct dasd_uid uid;
unsigned long flags;
- private = (struct dasd_eckd_private *) device->private;
-
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
old_base = private->uid.base_unit_addr;
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
@@ -4556,12 +4541,10 @@ static int dasd_eckd_read_message_buffer(struct dasd_device *device,
{
struct dasd_rssd_messages *message_buf;
struct dasd_psf_prssd_data *prssdp;
- struct dasd_eckd_private *private;
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
int rc;
- private = (struct dasd_eckd_private *) device->private;
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
(sizeof(struct dasd_psf_prssd_data) +
sizeof(struct dasd_rssd_messages)),
@@ -4686,11 +4669,10 @@ static struct dasd_conf_data *dasd_eckd_get_ref_conf(struct dasd_device *device,
__u8 lpum,
struct dasd_cuir_message *cuir)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *private = device->private;
struct dasd_conf_data *conf_data;
int path, pos;
- private = (struct dasd_eckd_private *) device->private;
if (cuir->record_selector == 0)
goto out;
for (path = 0x80, pos = 0; path; path >>= 1, pos++) {
@@ -4715,9 +4697,9 @@ out:
static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum,
struct dasd_cuir_message *cuir)
{
+ struct dasd_eckd_private *private = device->private;
struct dasd_conf_data *ref_conf_data;
unsigned long bitmask = 0, mask = 0;
- struct dasd_eckd_private *private;
struct dasd_conf_data *conf_data;
unsigned int pos, path;
char *ref_gneq, *gneq;
@@ -4730,7 +4712,6 @@ static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum,
!(cuir->neq_map[0] | cuir->neq_map[1] | cuir->neq_map[2]))
return lpum;
- private = (struct dasd_eckd_private *) device->private;
/* get reference conf data */
ref_conf_data = dasd_eckd_get_ref_conf(device, lpum, cuir);
/* reference ned is determined by ned_map field */
@@ -4829,14 +4810,13 @@ static int dasd_eckd_cuir_quiesce(struct dasd_device *device, __u8 lpum,
struct subchannel_id sch_id,
struct dasd_cuir_message *cuir)
{
+ struct dasd_eckd_private *private = device->private;
struct alias_pav_group *pavgroup, *tempgroup;
- struct dasd_eckd_private *private;
struct dasd_device *dev, *n;
unsigned long paths = 0;
unsigned long flags;
int tbcpm;
- private = (struct dasd_eckd_private *) device->private;
/* active devices */
list_for_each_entry_safe(dev, n, &private->lcu->active_devices,
alias_list) {
@@ -4892,13 +4872,12 @@ static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum,
struct subchannel_id sch_id,
struct dasd_cuir_message *cuir)
{
+ struct dasd_eckd_private *private = device->private;
struct alias_pav_group *pavgroup, *tempgroup;
- struct dasd_eckd_private *private;
struct dasd_device *dev, *n;
unsigned long paths = 0;
int tbcpm;
- private = (struct dasd_eckd_private *) device->private;
/*
* the path may have been added through a generic path event before
* only trigger path verification if the path is not already in use
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index c9262e78938b..d7b5b550364b 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -125,13 +125,11 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
static int
dasd_fba_check_characteristics(struct dasd_device *device)
{
- struct dasd_block *block;
- struct dasd_fba_private *private;
+ struct dasd_fba_private *private = device->private;
struct ccw_device *cdev = device->cdev;
- int rc;
- int readonly;
+ struct dasd_block *block;
+ int readonly, rc;
- private = (struct dasd_fba_private *) device->private;
if (!private) {
private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
if (!private) {
@@ -140,7 +138,7 @@ dasd_fba_check_characteristics(struct dasd_device *device)
"data failed\n");
return -ENOMEM;
}
- device->private = (void *) private;
+ device->private = private;
} else {
memset(private, 0, sizeof(*private));
}
@@ -192,10 +190,9 @@ dasd_fba_check_characteristics(struct dasd_device *device)
static int dasd_fba_do_analysis(struct dasd_block *block)
{
- struct dasd_fba_private *private;
+ struct dasd_fba_private *private = block->base->private;
int sb, rc;
- private = (struct dasd_fba_private *) block->base->private;
rc = dasd_check_blocksize(private->rdc_data.blk_size);
if (rc) {
DBF_DEV_EVENT(DBF_WARNING, block->base, "unknown blocksize %d",
@@ -254,7 +251,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
struct dasd_block *block,
struct request *req)
{
- struct dasd_fba_private *private;
+ struct dasd_fba_private *private = block->base->private;
unsigned long *idaws;
struct LO_fba_data *LO_data;
struct dasd_ccw_req *cqr;
@@ -267,7 +264,6 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
unsigned int blksize, off;
unsigned char cmd;
- private = (struct dasd_fba_private *) block->base->private;
if (rq_data_dir(req) == READ) {
cmd = DASD_FBA_CCW_READ;
} else if (rq_data_dir(req) == WRITE) {
@@ -379,7 +375,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
static int
dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
{
- struct dasd_fba_private *private;
+ struct dasd_fba_private *private = cqr->block->base->private;
struct ccw1 *ccw;
struct req_iterator iter;
struct bio_vec bv;
@@ -389,7 +385,6 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
if (!dasd_page_cache)
goto out;
- private = (struct dasd_fba_private *) cqr->block->base->private;
blksize = cqr->block->bp_block;
ccw = cqr->cpaddr;
/* Skip over define extent & locate record. */
@@ -436,13 +431,14 @@ static int
dasd_fba_fill_info(struct dasd_device * device,
struct dasd_information2_t * info)
{
+ struct dasd_fba_private *private = device->private;
+
info->label_block = 1;
info->FBA_layout = 1;
info->format = DASD_FORMAT_LDL;
- info->characteristics_size = sizeof(struct dasd_fba_characteristics);
- memcpy(info->characteristics,
- &((struct dasd_fba_private *) device->private)->rdc_data,
- sizeof (struct dasd_fba_characteristics));
+ info->characteristics_size = sizeof(private->rdc_data);
+ memcpy(info->characteristics, &private->rdc_data,
+ sizeof(private->rdc_data));
info->confdata_size = 0;
return 0;
}
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index ef1d9fb06cab..31d544a87ba9 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -178,8 +178,8 @@ int dasd_gendisk_init(void)
/* Register to static dasd major 94 */
rc = register_blkdev(DASD_MAJOR, "dasd");
if (rc != 0) {
- pr_warning("Registering the device driver with major number "
- "%d failed\n", DASD_MAJOR);
+ pr_warn("Registering the device driver with major number %d failed\n",
+ DASD_MAJOR);
return rc;
}
return 0;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 4aed5ed70836..8de29be32a56 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -241,6 +241,13 @@ struct dasd_ccw_req {
typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *);
/*
+ * A single CQR can only contain a maximum of 255 CCWs. It is limited by
+ * the locate record and locate record extended count value which can only hold
+ * 1 Byte max.
+ */
+#define DASD_CQR_MAX_CCW 255
+
+/*
* Unique identifier for dasd device.
*/
#define UA_NOT_CONFIGURED 0x00
@@ -438,7 +445,7 @@ struct dasd_device {
/* Device discipline stuff. */
struct dasd_discipline *discipline;
struct dasd_discipline *base_discipline;
- char *private;
+ void *private;
struct dasd_path path_data;
/* Device state and target state. */
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 02837d0ad942..90f30cc31561 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -203,9 +203,7 @@ static int
dasd_format(struct dasd_block *block, struct format_data_t *fdata)
{
struct dasd_device *base;
- int enable_pav = 1;
- int rc, retries;
- int start, stop;
+ int rc;
base = block->base;
if (base->discipline->format_device == NULL)
@@ -233,30 +231,11 @@ dasd_format(struct dasd_block *block, struct format_data_t *fdata)
bdput(bdev);
}
- retries = 255;
- /* backup start- and endtrack for retries */
- start = fdata->start_unit;
- stop = fdata->stop_unit;
- do {
- rc = base->discipline->format_device(base, fdata, enable_pav);
- if (rc) {
- if (rc == -EAGAIN) {
- retries--;
- /* disable PAV in case of errors */
- enable_pav = 0;
- fdata->start_unit = start;
- fdata->stop_unit = stop;
- } else
- return rc;
- } else
- /* success */
- break;
- } while (retries);
-
- if (!retries)
- return -EIO;
- else
- return 0;
+ rc = base->discipline->format_device(base, fdata, 1);
+ if (rc == -EAGAIN)
+ rc = base->discipline->format_device(base, fdata, 0);
+
+ return rc;
}
/*
@@ -286,9 +265,8 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
return -EFAULT;
}
if (bdev != bdev->bd_contains) {
- pr_warning("%s: The specified DASD is a partition and cannot "
- "be formatted\n",
- dev_name(&base->cdev->dev));
+ pr_warn("%s: The specified DASD is a partition and cannot be formatted\n",
+ dev_name(&base->cdev->dev));
dasd_put_device(base);
return -EINVAL;
}
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index aa7bb2d1da81..bad7a196bf84 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -322,13 +322,12 @@ static ssize_t dasd_stats_proc_write(struct file *file,
return user_len;
out_parse_error:
rc = -EINVAL;
- pr_warning("%s is not a supported value for /proc/dasd/statistics\n",
- str);
+ pr_warn("%s is not a supported value for /proc/dasd/statistics\n", str);
out_error:
vfree(buffer);
return rc;
#else
- pr_warning("/proc/dasd/statistics: is not activated in this kernel\n");
+ pr_warn("/proc/dasd/statistics: is not activated in this kernel\n");
return user_len;
#endif /* CONFIG_DASD_PROFILE */
}
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index ce7b70181740..1bce9cf51b1e 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -738,15 +738,15 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch
dev_info = dcssblk_get_device_by_name(local_buf);
if (dev_info == NULL) {
up_write(&dcssblk_devices_sem);
- pr_warning("Device %s cannot be removed because it is not a "
- "known device\n", local_buf);
+ pr_warn("Device %s cannot be removed because it is not a known device\n",
+ local_buf);
rc = -ENODEV;
goto out_buf;
}
if (atomic_read(&dev_info->use_count) != 0) {
up_write(&dcssblk_devices_sem);
- pr_warning("Device %s cannot be removed while it is in "
- "use\n", local_buf);
+ pr_warn("Device %s cannot be removed while it is in use\n",
+ local_buf);
rc = -EBUSY;
goto out_buf;
}
@@ -850,9 +850,8 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio)
case SEG_TYPE_SC:
/* cannot write to these segments */
if (bio_data_dir(bio) == WRITE) {
- pr_warning("Writing to %s failed because it "
- "is a read-only device\n",
- dev_name(&dev_info->dev));
+ pr_warn("Writing to %s failed because it is a read-only device\n",
+ dev_name(&dev_info->dev));
goto fail;
}
}
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 7d82bbcb12df..e7e078b3c7e6 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -643,7 +643,6 @@ static void raw3215_shutdown(struct raw3215_info *raw)
if ((raw->flags & RAW3215_WORKING) ||
raw->queued_write != NULL ||
raw->queued_read != NULL) {
- raw->port.flags |= ASYNC_CLOSING;
add_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -651,7 +650,7 @@ static void raw3215_shutdown(struct raw3215_info *raw)
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
remove_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_RUNNING);
- raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING);
+ raw->port.flags &= ~ASYNC_INITIALIZED;
}
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index fc94bfdceb95..ebdeaa53182d 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -257,7 +257,7 @@ static void mon_iucv_message_pending(struct iucv_path *path,
memcpy(&monpriv->msg_array[monpriv->write_index]->msg,
msg, sizeof(*msg));
if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
- pr_warning("The read queue for monitor data is full\n");
+ pr_warn("The read queue for monitor data is full\n");
monpriv->msg_array[monpriv->write_index]->msglim_reached = 1;
}
monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM;
@@ -342,8 +342,8 @@ static int mon_close(struct inode *inode, struct file *filp)
if (monpriv->path) {
rc = iucv_path_sever(monpriv->path, user_data_sever);
if (rc)
- pr_warning("Disconnecting the z/VM *MONITOR system "
- "service failed with rc=%i\n", rc);
+ pr_warn("Disconnecting the z/VM *MONITOR system service failed with rc=%i\n",
+ rc);
iucv_path_free(monpriv->path);
}
@@ -469,8 +469,8 @@ static int monreader_freeze(struct device *dev)
if (monpriv->path) {
rc = iucv_path_sever(monpriv->path, user_data_sever);
if (rc)
- pr_warning("Disconnecting the z/VM *MONITOR system "
- "service failed with rc=%i\n", rc);
+ pr_warn("Disconnecting the z/VM *MONITOR system service failed with rc=%i\n",
+ rc);
iucv_path_free(monpriv->path);
}
atomic_set(&monpriv->iucv_severed, 0);
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 806239c2cf2f..d3947ea3e351 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -67,8 +67,8 @@ int sclp_sync_request_timeout(sclp_cmdw_t cmd, void *sccb, int timeout)
/* Check response. */
if (request->status != SCLP_REQ_DONE) {
- pr_warning("sync request failed (cmd=0x%08x, "
- "status=0x%02x)\n", cmd, request->status);
+ pr_warn("sync request failed (cmd=0x%08x, status=0x%02x)\n",
+ cmd, request->status);
rc = -EIO;
}
out:
@@ -122,8 +122,8 @@ int sclp_get_core_info(struct sclp_core_info *info)
if (rc)
goto out;
if (sccb->header.response_code != 0x0010) {
- pr_warning("readcpuinfo failed (response=0x%04x)\n",
- sccb->header.response_code);
+ pr_warn("readcpuinfo failed (response=0x%04x)\n",
+ sccb->header.response_code);
rc = -EIO;
goto out;
}
@@ -160,9 +160,8 @@ static int do_core_configure(sclp_cmdw_t cmd)
case 0x0120:
break;
default:
- pr_warning("configure cpu failed (cmd=0x%08x, "
- "response=0x%04x)\n", cmd,
- sccb->header.response_code);
+ pr_warn("configure cpu failed (cmd=0x%08x, response=0x%04x)\n",
+ cmd, sccb->header.response_code);
rc = -EIO;
break;
}
@@ -230,9 +229,8 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn)
case 0x0120:
break;
default:
- pr_warning("assign storage failed (cmd=0x%08x, "
- "response=0x%04x, rn=0x%04x)\n", cmd,
- sccb->header.response_code, rn);
+ pr_warn("assign storage failed (cmd=0x%08x, response=0x%04x, rn=0x%04x)\n",
+ cmd, sccb->header.response_code, rn);
rc = -EIO;
break;
}
@@ -675,9 +673,8 @@ static int do_chp_configure(sclp_cmdw_t cmd)
case 0x0450:
break;
default:
- pr_warning("configure channel-path failed "
- "(cmd=0x%08x, response=0x%04x)\n", cmd,
- sccb->header.response_code);
+ pr_warn("configure channel-path failed (cmd=0x%08x, response=0x%04x)\n",
+ cmd, sccb->header.response_code);
rc = -EIO;
break;
}
@@ -744,8 +741,8 @@ int sclp_chp_read_info(struct sclp_chp_info *info)
if (rc)
goto out;
if (sccb->header.response_code != 0x0010) {
- pr_warning("read channel-path info failed "
- "(response=0x%04x)\n", sccb->header.response_code);
+ pr_warn("read channel-path info failed (response=0x%04x)\n",
+ sccb->header.response_code);
rc = -EIO;
goto out;
}
diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c
index 2acea809e2ac..f344e5bd2d9f 100644
--- a/drivers/s390/char/sclp_cpi_sys.c
+++ b/drivers/s390/char/sclp_cpi_sys.c
@@ -154,16 +154,14 @@ static int cpi_req(void)
wait_for_completion(&completion);
if (req->status != SCLP_REQ_DONE) {
- pr_warning("request failed (status=0x%02x)\n",
- req->status);
+ pr_warn("request failed (status=0x%02x)\n", req->status);
rc = -EIO;
goto out_free_req;
}
response = ((struct cpi_sccb *) req->sccb)->header.response_code;
if (response != 0x0020) {
- pr_warning("request failed with response code 0x%x\n",
- response);
+ pr_warn("request failed with response code 0x%x\n", response);
rc = -EIO;
}
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index f3b5123faf08..3c379da2eef8 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -699,8 +699,8 @@ tape_generic_remove(struct ccw_device *cdev)
*/
DBF_EVENT(3, "(%08x): Drive in use vanished!\n",
device->cdev_id);
- pr_warning("%s: A tape unit was detached while in "
- "use\n", dev_name(&device->cdev->dev));
+ pr_warn("%s: A tape unit was detached while in use\n",
+ dev_name(&device->cdev->dev));
tape_state_set(device, TS_NOT_OPER);
__tape_discard_requests(device);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 799c1524c779..e883063c7258 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -343,8 +343,7 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp)
if (logptr->autorecording) {
ret = vmlogrdr_recording(logptr,1,logptr->autopurge);
if (ret)
- pr_warning("vmlogrdr: failed to start "
- "recording automatically\n");
+ pr_warn("vmlogrdr: failed to start recording automatically\n");
}
/* create connection to the system service */
@@ -396,8 +395,7 @@ static int vmlogrdr_release (struct inode *inode, struct file *filp)
if (logptr->autorecording) {
ret = vmlogrdr_recording(logptr,0,logptr->autopurge);
if (ret)
- pr_warning("vmlogrdr: failed to stop "
- "recording automatically\n");
+ pr_warn("vmlogrdr: failed to stop recording automatically\n");
}
logptr->dev_in_use = 0;
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 20314aad7ab7..9082476b51db 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -51,9 +51,8 @@ static int blacklist_range(range_action action, unsigned int from_ssid,
{
if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
if (msgtrigger)
- pr_warning("0.%x.%04x to 0.%x.%04x is not a valid "
- "range for cio_ignore\n", from_ssid, from,
- to_ssid, to);
+ pr_warn("0.%x.%04x to 0.%x.%04x is not a valid range for cio_ignore\n",
+ from_ssid, from, to_ssid, to);
return 1;
}
@@ -140,8 +139,8 @@ static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid,
rc = 0;
out:
if (rc && msgtrigger)
- pr_warning("%s is not a valid device for the cio_ignore "
- "kernel parameter\n", str);
+ pr_warn("%s is not a valid device for the cio_ignore kernel parameter\n",
+ str);
return rc;
}
diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c
index 79f59915f71b..2782100b2c07 100644
--- a/drivers/s390/cio/ccwreq.c
+++ b/drivers/s390/cio/ccwreq.c
@@ -333,13 +333,12 @@ void ccw_request_timeout(struct ccw_device *cdev)
for (chp = 0; chp < 8; chp++) {
if ((0x80 >> chp) & sch->schib.pmcw.lpum)
- pr_warning("%s: No interrupt was received within %lus "
- "(CS=%02x, DS=%02x, CHPID=%x.%02x)\n",
- dev_name(&cdev->dev), req->timeout / HZ,
- scsw_cstat(&sch->schib.scsw),
- scsw_dstat(&sch->schib.scsw),
- sch->schid.cssid,
- sch->schib.pmcw.chpid[chp]);
+ pr_warn("%s: No interrupt was received within %lus (CS=%02x, DS=%02x, CHPID=%x.%02x)\n",
+ dev_name(&cdev->dev), req->timeout / HZ,
+ scsw_cstat(&sch->schib.scsw),
+ scsw_dstat(&sch->schib.scsw),
+ sch->schid.cssid,
+ sch->schib.pmcw.chpid[chp]);
}
if (!ccwreq_next_path(cdev)) {
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 39a8ae54e9c1..de6fccc13124 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -656,7 +656,7 @@ struct subchannel *cio_probe_console(void)
sch_no = cio_get_console_sch_no();
if (sch_no == -1) {
- pr_warning("No CCW console was found\n");
+ pr_warn("No CCW console was found\n");
return ERR_PTR(-ENODEV);
}
init_subchannel_id(&schid);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 6aae68412802..7ada078ffdd0 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -364,11 +364,11 @@ int ccw_device_set_offline(struct ccw_device *cdev)
cdev->private->state == DEV_STATE_DISCONNECTED));
/* Inform the user if set offline failed. */
if (cdev->private->state == DEV_STATE_BOXED) {
- pr_warning("%s: The device entered boxed state while "
- "being set offline\n", dev_name(&cdev->dev));
+ pr_warn("%s: The device entered boxed state while being set offline\n",
+ dev_name(&cdev->dev));
} else if (cdev->private->state == DEV_STATE_NOT_OPER) {
- pr_warning("%s: The device stopped operating while "
- "being set offline\n", dev_name(&cdev->dev));
+ pr_warn("%s: The device stopped operating while being set offline\n",
+ dev_name(&cdev->dev));
}
/* Give up reference from ccw_device_set_online(). */
put_device(&cdev->dev);
@@ -429,13 +429,11 @@ int ccw_device_set_online(struct ccw_device *cdev)
spin_unlock_irq(cdev->ccwlock);
/* Inform the user that set online failed. */
if (cdev->private->state == DEV_STATE_BOXED) {
- pr_warning("%s: Setting the device online failed "
- "because it is boxed\n",
- dev_name(&cdev->dev));
+ pr_warn("%s: Setting the device online failed because it is boxed\n",
+ dev_name(&cdev->dev));
} else if (cdev->private->state == DEV_STATE_NOT_OPER) {
- pr_warning("%s: Setting the device online failed "
- "because it is not operational\n",
- dev_name(&cdev->dev));
+ pr_warn("%s: Setting the device online failed because it is not operational\n",
+ dev_name(&cdev->dev));
}
/* Give up online reference since onlining failed. */
put_device(&cdev->dev);
@@ -619,9 +617,8 @@ initiate_logging(struct device *dev, struct device_attribute *attr,
rc = chsc_siosl(sch->schid);
if (rc < 0) {
- pr_warning("Logging for subchannel 0.%x.%04x failed with "
- "errno=%d\n",
- sch->schid.ssid, sch->schid.sch_no, rc);
+ pr_warn("Logging for subchannel 0.%x.%04x failed with errno=%d\n",
+ sch->schid.ssid, sch->schid.sch_no, rc);
return rc;
}
pr_notice("Logging for subchannel 0.%x.%04x was triggered\n",
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 2f5b518b0e78..251db0a02e73 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1761,8 +1761,8 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd)
lcs_schedule_recovery(card);
break;
case LCS_CMD_STOPLAN:
- pr_warning("Stoplan for %s initiated by LGW.\n",
- card->dev->name);
+ pr_warn("Stoplan for %s initiated by LGW\n",
+ card->dev->name);
if (card->dev)
netif_carrier_off(card->dev);
break;
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 7c8c68c26540..ac544330daeb 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3624,7 +3624,7 @@ static int qeth_l3_register_notifiers(void)
return rc;
}
#else
- pr_warning("There is no IPv6 support for the layer 3 discipline\n");
+ pr_warn("There is no IPv6 support for the layer 3 discipline\n");
#endif
return 0;
}
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index e2f31c93717d..e80768f8e579 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -596,6 +596,7 @@ config XEN_SCSI_FRONTEND
config HYPERV_STORAGE
tristate "Microsoft Hyper-V virtual storage driver"
depends on SCSI && HYPERV
+ depends on m || SCSI_FC_ATTRS != m
default HYPERV
help
Select this option to enable the Hyper-V virtual storage driver.
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index d72867257346..3eff2a69fe08 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -760,7 +760,7 @@ static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
struct NCR5380_cmd *ncmd;
struct scsi_cmnd *cmd;
- if (list_empty(&hostdata->autosense)) {
+ if (hostdata->sensing || list_empty(&hostdata->autosense)) {
list_for_each_entry(ncmd, &hostdata->unissued, list) {
cmd = NCR5380_to_scmd(ncmd);
dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
@@ -793,7 +793,7 @@ static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
- if (hostdata->sensing) {
+ if (hostdata->sensing == cmd) {
scsi_eh_restore_cmnd(cmd, &hostdata->ses);
list_add(&ncmd->list, &hostdata->autosense);
hostdata->sensing = NULL;
@@ -815,15 +815,17 @@ static void NCR5380_main(struct work_struct *work)
struct NCR5380_hostdata *hostdata =
container_of(work, struct NCR5380_hostdata, main_task);
struct Scsi_Host *instance = hostdata->host;
- struct scsi_cmnd *cmd;
int done;
do {
done = 1;
spin_lock_irq(&hostdata->lock);
- while (!hostdata->connected &&
- (cmd = dequeue_next_cmd(instance))) {
+ while (!hostdata->connected && !hostdata->selecting) {
+ struct scsi_cmnd *cmd = dequeue_next_cmd(instance);
+
+ if (!cmd)
+ break;
dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
@@ -840,8 +842,7 @@ static void NCR5380_main(struct work_struct *work)
* entire unit.
*/
- cmd = NCR5380_select(instance, cmd);
- if (!cmd) {
+ if (!NCR5380_select(instance, cmd)) {
dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
} else {
dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
@@ -1056,6 +1057,11 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
/* Reselection interrupt */
goto out;
}
+ if (!hostdata->selecting) {
+ /* Command was aborted */
+ NCR5380_write(MODE_REG, MR_BASE);
+ goto out;
+ }
if (err < 0) {
NCR5380_write(MODE_REG, MR_BASE);
shost_printk(KERN_ERR, instance,
@@ -1759,9 +1765,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
unsigned char msgout = NOP;
int sink = 0;
int len;
-#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
int transfersize;
-#endif
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
struct scsi_cmnd *cmd;
@@ -1798,6 +1802,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
do_abort(instance);
cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
+ hostdata->connected = NULL;
return;
#endif
case PHASE_DATAIN:
@@ -1847,20 +1852,23 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- complete_cmd(instance, cmd);
/* XXX - need to source or sink data here, as appropriate */
} else
cmd->SCp.this_residual -= transfersize - len;
} else
#endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */
{
- spin_unlock_irq(&hostdata->lock);
- NCR5380_transfer_pio(instance, &phase,
- (int *)&cmd->SCp.this_residual,
+ /* Break up transfer into 3 ms chunks,
+ * presuming 6 accesses per handshake.
+ */
+ transfersize = min((unsigned long)cmd->SCp.this_residual,
+ hostdata->accesses_per_ms / 2);
+ len = transfersize;
+ NCR5380_transfer_pio(instance, &phase, &len,
(unsigned char **)&cmd->SCp.ptr);
- spin_lock_irq(&hostdata->lock);
+ cmd->SCp.this_residual -= transfersize - len;
}
- break;
+ return;
case PHASE_MSGIN:
len = 1;
data = &tmp;
@@ -2292,14 +2300,17 @@ static bool list_del_cmd(struct list_head *haystack,
* [disconnected -> connected ->]...
* [autosense -> connected ->] done
*
- * If cmd is unissued then just remove it.
- * If cmd is disconnected, try to select the target.
- * If cmd is connected, try to send an abort message.
- * If cmd is waiting for autosense, give it a chance to complete but check
- * that it isn't left connected.
* If cmd was not found at all then presumably it has already been completed,
* in which case return SUCCESS to try to avoid further EH measures.
+ *
* If the command has not completed yet, we must not fail to find it.
+ * We have no option but to forget the aborted command (even if it still
+ * lacks sense data). The mid-layer may re-issue a command that is in error
+ * recovery (see scsi_send_eh_cmnd), but the logic and data structures in
+ * this driver are such that a command can appear on one queue only.
+ *
+ * The lock protects driver data structures, but EH handlers also use it
+ * to serialize their own execution and prevent their own re-entry.
*/
static int NCR5380_abort(struct scsi_cmnd *cmd)
@@ -2322,6 +2333,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
"abort: removed %p from issue queue\n", cmd);
cmd->result = DID_ABORT << 16;
cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
+ goto out;
}
if (hostdata->selecting == cmd) {
@@ -2336,58 +2348,21 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
if (list_del_cmd(&hostdata->disconnected, cmd)) {
dsprintk(NDEBUG_ABORT, instance,
"abort: removed %p from disconnected list\n", cmd);
- cmd->result = DID_ERROR << 16;
- if (!hostdata->connected)
- NCR5380_select(instance, cmd);
- if (hostdata->connected != cmd) {
- complete_cmd(instance, cmd);
- result = FAILED;
- goto out;
- }
+ /* Can't call NCR5380_select() and send ABORT because that
+ * means releasing the lock. Need a bus reset.
+ */
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
}
if (hostdata->connected == cmd) {
dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
hostdata->connected = NULL;
- if (do_abort(instance)) {
- set_host_byte(cmd, DID_ERROR);
- complete_cmd(instance, cmd);
- result = FAILED;
- goto out;
- }
- set_host_byte(cmd, DID_ABORT);
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
- if (cmd->cmnd[0] == REQUEST_SENSE)
- complete_cmd(instance, cmd);
- else {
- struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
-
- /* Perform autosense for this command */
- list_add(&ncmd->list, &hostdata->autosense);
- }
- }
-
- if (list_find_cmd(&hostdata->autosense, cmd)) {
- dsprintk(NDEBUG_ABORT, instance,
- "abort: found %p on sense queue\n", cmd);
- spin_unlock_irqrestore(&hostdata->lock, flags);
- queue_work(hostdata->work_q, &hostdata->main_task);
- msleep(1000);
- spin_lock_irqsave(&hostdata->lock, flags);
- if (list_del_cmd(&hostdata->autosense, cmd)) {
- dsprintk(NDEBUG_ABORT, instance,
- "abort: removed %p from sense queue\n", cmd);
- set_host_byte(cmd, DID_ABORT);
- complete_cmd(instance, cmd);
- goto out;
- }
- }
-
- if (hostdata->connected == cmd) {
- dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
- hostdata->connected = NULL;
if (do_abort(instance)) {
set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd);
@@ -2395,9 +2370,14 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
goto out;
}
set_host_byte(cmd, DID_ABORT);
-#ifdef REAL_DMA
- hostdata->dma_len = 0;
-#endif
+ complete_cmd(instance, cmd);
+ goto out;
+ }
+
+ if (list_del_cmd(&hostdata->autosense, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from sense queue\n", cmd);
+ set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd);
}
@@ -2450,7 +2430,16 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
* commands!
*/
- hostdata->selecting = NULL;
+ if (list_del_cmd(&hostdata->unissued, cmd)) {
+ cmd->result = DID_RESET << 16;
+ cmd->scsi_done(cmd);
+ }
+
+ if (hostdata->selecting) {
+ hostdata->selecting->result = DID_RESET << 16;
+ complete_cmd(instance, hostdata->selecting);
+ hostdata->selecting = NULL;
+ }
list_for_each_entry(ncmd, &hostdata->disconnected, list) {
struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
@@ -2458,6 +2447,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
set_host_byte(cmd, DID_RESET);
cmd->scsi_done(cmd);
}
+ INIT_LIST_HEAD(&hostdata->disconnected);
list_for_each_entry(ncmd, &hostdata->autosense, list) {
struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
@@ -2465,6 +2455,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
set_host_byte(cmd, DID_RESET);
cmd->scsi_done(cmd);
}
+ INIT_LIST_HEAD(&hostdata->autosense);
if (hostdata->connected) {
set_host_byte(hostdata->connected, DID_RESET);
@@ -2472,12 +2463,6 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
hostdata->connected = NULL;
}
- if (hostdata->sensing) {
- set_host_byte(hostdata->connected, DID_RESET);
- complete_cmd(instance, hostdata->sensing);
- hostdata->sensing = NULL;
- }
-
for (i = 0; i < 8; ++i)
hostdata->busy[i] = 0;
#ifdef REAL_DMA
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index e4c243748a97..7dfd0fa27255 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -323,7 +323,6 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
return 0;
}
scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
@@ -331,7 +330,6 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
if (unlikely(!device || !scsi_device_online(device))) {
dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
return 0;
}
return 1;
@@ -541,7 +539,6 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
scsicmd->scsi_done(scsicmd);
}
@@ -557,7 +554,8 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
- if (!(cmd_fibcontext = aac_fib_alloc(dev)))
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext)
return -ENOMEM;
aac_fib_init(cmd_fibcontext);
@@ -586,7 +584,6 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
aac_fib_complete(cmd_fibcontext);
- aac_fib_free(cmd_fibcontext);
return -1;
}
@@ -1024,7 +1021,6 @@ static void get_container_serial_callback(void *context, struct fib * fibptr)
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
scsicmd->scsi_done(scsicmd);
}
@@ -1040,7 +1036,8 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
- if (!(cmd_fibcontext = aac_fib_alloc(dev)))
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext)
return -ENOMEM;
aac_fib_init(cmd_fibcontext);
@@ -1068,7 +1065,6 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
aac_fib_complete(cmd_fibcontext);
- aac_fib_free(cmd_fibcontext);
return -1;
}
@@ -1869,7 +1865,6 @@ static void io_callback(void *context, struct fib * fibptr)
break;
}
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
scsicmd->scsi_done(scsicmd);
}
@@ -1954,7 +1949,8 @@ static int aac_read(struct scsi_cmnd * scsicmd)
/*
* Alocate and initialize a Fib
*/
- if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext) {
printk(KERN_WARNING "aac_read: fib allocation failed\n");
return -1;
}
@@ -2051,7 +2047,8 @@ static int aac_write(struct scsi_cmnd * scsicmd)
/*
* Allocate and initialize a Fib then setup a BlockWrite command
*/
- if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext) {
/* FIB temporarily unavailable,not catastrophic failure */
/* scsicmd->result = DID_ERROR << 16;
@@ -2285,7 +2282,7 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd)
/*
* Allocate and initialize a Fib
*/
- cmd_fibcontext = aac_fib_alloc(aac);
+ cmd_fibcontext = aac_fib_alloc_tag(aac, scsicmd);
if (!cmd_fibcontext)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -3157,7 +3154,6 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
scsicmd->result |= le32_to_cpu(srbreply->scsi_status);
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
scsicmd->scsi_done(scsicmd);
}
@@ -3187,9 +3183,10 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
/*
* Allocate and initialize a Fib then setup a BlockWrite command
*/
- if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext)
return -1;
- }
+
status = aac_adapter_scsi(cmd_fibcontext, scsicmd);
/*
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 074878b55a0b..efa493cf1bc6 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -62,7 +62,7 @@ enum {
#define PMC_GLOBAL_INT_BIT0 0x00000001
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 41010
+# define AAC_DRIVER_BUILD 41052
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -94,6 +94,13 @@ enum {
#define aac_phys_to_logical(x) ((x)+1)
#define aac_logical_to_phys(x) ((x)?(x)-1:0)
+/*
+ * These macros are for keeping track of
+ * character device state.
+ */
+#define AAC_CHARDEV_UNREGISTERED (-1)
+#define AAC_CHARDEV_NEEDS_REINIT (-2)
+
/* #define AAC_DETAILED_STATUS_INFO */
struct diskparm
@@ -944,6 +951,7 @@ struct fib {
*/
struct list_head fiblink;
void *data;
+ u32 vector_no;
struct hw_fib *hw_fib_va; /* Actual shared object */
dma_addr_t hw_fib_pa; /* physical address of hw_fib*/
};
@@ -1123,6 +1131,7 @@ struct aac_dev
struct fib *free_fib;
spinlock_t fib_lock;
+ struct mutex ioctl_mutex;
struct aac_queue_block *queues;
/*
* The user API will use an IOCTL to register itself to receive
@@ -1234,6 +1243,7 @@ struct aac_dev
struct msix_entry msixentry[AAC_MAX_MSIX];
struct aac_msix_ctx aac_msix[AAC_MAX_MSIX]; /* context */
u8 adapter_shutdown;
+ u32 handle_pci_error;
};
#define aac_adapter_interrupt(dev) \
@@ -2113,7 +2123,9 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
int aac_acquire_irq(struct aac_dev *dev);
void aac_free_irq(struct aac_dev *dev);
const char *aac_driverinfo(struct Scsi_Host *);
+void aac_fib_vector_assign(struct aac_dev *dev);
struct fib *aac_fib_alloc(struct aac_dev *dev);
+struct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd);
int aac_fib_setup(struct aac_dev *dev);
void aac_fib_map_free(struct aac_dev *dev);
void aac_fib_free(struct fib * context);
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 54195a117f72..4b3bb52b5108 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -855,13 +855,20 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
{
int status;
+ mutex_lock(&dev->ioctl_mutex);
+
+ if (dev->adapter_shutdown) {
+ status = -EACCES;
+ goto cleanup;
+ }
+
/*
* HBA gets first crack
*/
status = aac_dev_ioctl(dev, cmd, arg);
if (status != -ENOTTY)
- return status;
+ goto cleanup;
switch (cmd) {
case FSACTL_MINIPORT_REV_CHECK:
@@ -890,6 +897,10 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
status = -ENOTTY;
break;
}
+
+cleanup:
+ mutex_unlock(&dev->ioctl_mutex);
+
return status;
}
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 0e954e37f0b5..2b4e75380ae6 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -212,8 +212,11 @@ int aac_send_shutdown(struct aac_dev * dev)
return -ENOMEM;
aac_fib_init(fibctx);
- cmd = (struct aac_close *) fib_data(fibctx);
+ mutex_lock(&dev->ioctl_mutex);
+ dev->adapter_shutdown = 1;
+ mutex_unlock(&dev->ioctl_mutex);
+ cmd = (struct aac_close *) fib_data(fibctx);
cmd->command = cpu_to_le32(VM_CloseAll);
cmd->cid = cpu_to_le32(0xfffffffe);
@@ -229,7 +232,6 @@ int aac_send_shutdown(struct aac_dev * dev)
/* FIB should be freed only after getting the response from the F/W */
if (status != -ERESTARTSYS)
aac_fib_free(fibctx);
- dev->adapter_shutdown = 1;
if ((dev->pdev->device == PMC_DEVICE_S7 ||
dev->pdev->device == PMC_DEVICE_S8 ||
dev->pdev->device == PMC_DEVICE_S9) &&
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index a1f90fe849c9..511bbc575062 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -83,13 +83,38 @@ static int fib_map_alloc(struct aac_dev *dev)
void aac_fib_map_free(struct aac_dev *dev)
{
- pci_free_consistent(dev->pdev,
- dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
- dev->hw_fib_va, dev->hw_fib_pa);
+ if (dev->hw_fib_va && dev->max_fib_size) {
+ pci_free_consistent(dev->pdev,
+ (dev->max_fib_size *
+ (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)),
+ dev->hw_fib_va, dev->hw_fib_pa);
+ }
dev->hw_fib_va = NULL;
dev->hw_fib_pa = 0;
}
+void aac_fib_vector_assign(struct aac_dev *dev)
+{
+ u32 i = 0;
+ u32 vector = 1;
+ struct fib *fibptr = NULL;
+
+ for (i = 0, fibptr = &dev->fibs[i];
+ i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
+ i++, fibptr++) {
+ if ((dev->max_msix == 1) ||
+ (i > ((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1)
+ - dev->vector_cap))) {
+ fibptr->vector_no = 0;
+ } else {
+ fibptr->vector_no = vector;
+ vector++;
+ if (vector == dev->max_msix)
+ vector = 1;
+ }
+ }
+}
+
/**
* aac_fib_setup - setup the fibs
* @dev: Adapter to set up
@@ -137,6 +162,7 @@ int aac_fib_setup(struct aac_dev * dev)
i++, fibptr++)
{
fibptr->flags = 0;
+ fibptr->size = sizeof(struct fib);
fibptr->dev = dev;
fibptr->hw_fib_va = hw_fib;
fibptr->data = (void *) fibptr->hw_fib_va->data;
@@ -151,18 +177,49 @@ int aac_fib_setup(struct aac_dev * dev)
hw_fib_pa = hw_fib_pa +
dev->max_fib_size + sizeof(struct aac_fib_xporthdr);
}
+
+ /*
+ *Assign vector numbers to fibs
+ */
+ aac_fib_vector_assign(dev);
+
/*
* Add the fib chain to the free list
*/
dev->fibs[dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1].next = NULL;
/*
- * Enable this to debug out of queue space
- */
- dev->free_fib = &dev->fibs[0];
+ * Set 8 fibs aside for management tools
+ */
+ dev->free_fib = &dev->fibs[dev->scsi_host_ptr->can_queue];
return 0;
}
/**
+ * aac_fib_alloc_tag-allocate a fib using tags
+ * @dev: Adapter to allocate the fib for
+ *
+ * Allocate a fib from the adapter fib pool using tags
+ * from the blk layer.
+ */
+
+struct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd)
+{
+ struct fib *fibptr;
+
+ fibptr = &dev->fibs[scmd->request->tag];
+ /*
+ * Null out fields that depend on being zero at the start of
+ * each I/O
+ */
+ fibptr->hw_fib_va->header.XferState = 0;
+ fibptr->type = FSAFS_NTC_FIB_CONTEXT;
+ fibptr->callback_data = NULL;
+ fibptr->callback = NULL;
+
+ return fibptr;
+}
+
+/**
* aac_fib_alloc - allocate a fib
* @dev: Adapter to allocate the fib for
*
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index da9d9936e995..d677b52860ae 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -394,7 +394,6 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
fib->callback(fib->callback_data, fib);
} else {
aac_fib_complete(fib);
- aac_fib_free(fib);
}
} else {
unsigned long flagv;
@@ -416,7 +415,6 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
fib->done = 0;
spin_unlock_irqrestore(&fib->event_lock, flagv);
aac_fib_complete(fib);
- aac_fib_free(fib);
}
}
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 76eaa38ffd6e..21a67ed047e8 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -38,6 +38,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
+#include <linux/aer.h>
#include <linux/pci-aspm.h>
#include <linux/slab.h>
#include <linux/mutex.h>
@@ -79,7 +80,7 @@ MODULE_VERSION(AAC_DRIVER_FULL_VERSION);
static DEFINE_MUTEX(aac_mutex);
static LIST_HEAD(aac_devices);
-static int aac_cfg_major = -1;
+static int aac_cfg_major = AAC_CHARDEV_UNREGISTERED;
char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
/*
@@ -454,6 +455,8 @@ static int aac_slave_configure(struct scsi_device *sdev)
} else
scsi_change_queue_depth(sdev, 1);
+ sdev->tagged_supported = 1;
+
return 0;
}
@@ -700,23 +703,18 @@ static int aac_cfg_open(struct inode *inode, struct file *file)
static long aac_cfg_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- int ret;
- struct aac_dev *aac;
- aac = (struct aac_dev *)file->private_data;
- if (!capable(CAP_SYS_RAWIO) || aac->adapter_shutdown)
+ struct aac_dev *aac = (struct aac_dev *)file->private_data;
+
+ if (!capable(CAP_SYS_RAWIO))
return -EPERM;
- mutex_lock(&aac_mutex);
- ret = aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
- mutex_unlock(&aac_mutex);
- return ret;
+ return aac_do_ioctl(aac, cmd, (void __user *)arg);
}
#ifdef CONFIG_COMPAT
static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg)
{
long ret;
- mutex_lock(&aac_mutex);
switch (cmd) {
case FSACTL_MINIPORT_REV_CHECK:
case FSACTL_SENDFIB:
@@ -750,7 +748,6 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
ret = -ENOIOCTLCMD;
break;
}
- mutex_unlock(&aac_mutex);
return ret;
}
@@ -1075,6 +1072,8 @@ static void __aac_shutdown(struct aac_dev * aac)
int i;
int cpu;
+ aac_send_shutdown(aac);
+
if (aac->aif_thread) {
int i;
/* Clear out events first */
@@ -1086,7 +1085,6 @@ static void __aac_shutdown(struct aac_dev * aac)
}
kthread_stop(aac->thread);
}
- aac_send_shutdown(aac);
aac_adapter_disable_int(aac);
cpu = cpumask_first(cpu_online_mask);
if (aac->pdev->device == PMC_DEVICE_S6 ||
@@ -1120,6 +1118,13 @@ static void __aac_shutdown(struct aac_dev * aac)
else if (aac->max_msix > 1)
pci_disable_msix(aac->pdev);
}
+static void aac_init_char(void)
+{
+ aac_cfg_major = register_chrdev(0, "aac", &aac_cfg_fops);
+ if (aac_cfg_major < 0) {
+ pr_err("aacraid: unable to register \"aac\" device.\n");
+ }
+}
static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
@@ -1132,6 +1137,12 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
u64 dmamask;
extern int aac_sync_mode;
+ /*
+ * Only series 7 needs freset.
+ */
+ if (pdev->device == PMC_DEVICE_S7)
+ pdev->needs_freset = 1;
+
list_for_each_entry(aac, &aac_devices, entry) {
if (aac->id > unique_id)
break;
@@ -1171,6 +1182,9 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
shost->max_cmd_len = 16;
shost->use_cmd_list = 1;
+ if (aac_cfg_major == AAC_CHARDEV_NEEDS_REINIT)
+ aac_init_char();
+
aac = (struct aac_dev *)shost->hostdata;
aac->base_start = pci_resource_start(pdev, 0);
aac->scsi_host_ptr = shost;
@@ -1185,6 +1199,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_free_host;
spin_lock_init(&aac->fib_lock);
+ mutex_init(&aac->ioctl_mutex);
/*
* Map in the registers from the adapter.
*/
@@ -1296,6 +1311,9 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_deinit;
scsi_scan_host(shost);
+ pci_enable_pcie_error_reporting(pdev);
+ pci_save_state(pdev);
+
return 0;
out_deinit:
@@ -1317,7 +1335,6 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
return error;
}
-#if (defined(CONFIG_PM))
static void aac_release_resources(struct aac_dev *aac)
{
int i;
@@ -1404,14 +1421,26 @@ static int aac_acquire_resources(struct aac_dev *dev)
aac_adapter_enable_int(dev);
- if (!dev->sync_mode)
+ /*max msix may change after EEH
+ * Re-assign vectors to fibs
+ */
+ aac_fib_vector_assign(dev);
+
+ if (!dev->sync_mode) {
+ /* After EEH recovery or suspend resume, max_msix count
+ * may change, therfore updating in init as well.
+ */
aac_adapter_start(dev);
+ dev->init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix);
+ }
return 0;
error_iounmap:
return -1;
}
+
+#if (defined(CONFIG_PM))
static int aac_suspend(struct pci_dev *pdev, pm_message_t state)
{
@@ -1495,10 +1524,142 @@ static void aac_remove_one(struct pci_dev *pdev)
pci_disable_device(pdev);
if (list_empty(&aac_devices)) {
unregister_chrdev(aac_cfg_major, "aac");
- aac_cfg_major = -1;
+ aac_cfg_major = AAC_CHARDEV_NEEDS_REINIT;
+ }
+}
+
+static void aac_flush_ios(struct aac_dev *aac)
+{
+ int i;
+ struct scsi_cmnd *cmd;
+
+ for (i = 0; i < aac->scsi_host_ptr->can_queue; i++) {
+ cmd = (struct scsi_cmnd *)aac->fibs[i].callback_data;
+ if (cmd && (cmd->SCp.phase == AAC_OWNER_FIRMWARE)) {
+ scsi_dma_unmap(cmd);
+
+ if (aac->handle_pci_error)
+ cmd->result = DID_NO_CONNECT << 16;
+ else
+ cmd->result = DID_RESET << 16;
+
+ cmd->scsi_done(cmd);
+ }
+ }
+}
+
+static pci_ers_result_t aac_pci_error_detected(struct pci_dev *pdev,
+ enum pci_channel_state error)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct aac_dev *aac = shost_priv(shost);
+
+ dev_err(&pdev->dev, "aacraid: PCI error detected %x\n", error);
+
+ switch (error) {
+ case pci_channel_io_normal:
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ aac->handle_pci_error = 1;
+
+ scsi_block_requests(aac->scsi_host_ptr);
+ aac_flush_ios(aac);
+ aac_release_resources(aac);
+
+ pci_disable_pcie_error_reporting(pdev);
+ aac_adapter_ioremap(aac, 0);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ aac->handle_pci_error = 1;
+
+ aac_flush_ios(aac);
+ return PCI_ERS_RESULT_DISCONNECT;
}
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t aac_pci_mmio_enabled(struct pci_dev *pdev)
+{
+ dev_err(&pdev->dev, "aacraid: PCI error - mmio enabled\n");
+ return PCI_ERS_RESULT_NEED_RESET;
}
+static pci_ers_result_t aac_pci_slot_reset(struct pci_dev *pdev)
+{
+ dev_err(&pdev->dev, "aacraid: PCI error - slot reset\n");
+ pci_restore_state(pdev);
+ if (pci_enable_device(pdev)) {
+ dev_warn(&pdev->dev,
+ "aacraid: failed to enable slave\n");
+ goto fail_device;
+ }
+
+ pci_set_master(pdev);
+
+ if (pci_enable_device_mem(pdev)) {
+ dev_err(&pdev->dev, "pci_enable_device_mem failed\n");
+ goto fail_device;
+ }
+
+ return PCI_ERS_RESULT_RECOVERED;
+
+fail_device:
+ dev_err(&pdev->dev, "aacraid: PCI error - slot reset failed\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+}
+
+
+static void aac_pci_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct scsi_device *sdev = NULL;
+ struct aac_dev *aac = (struct aac_dev *)shost_priv(shost);
+
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+
+ if (aac_adapter_ioremap(aac, aac->base_size)) {
+
+ dev_err(&pdev->dev, "aacraid: ioremap failed\n");
+ /* remap failed, go back ... */
+ aac->comm_interface = AAC_COMM_PRODUCER;
+ if (aac_adapter_ioremap(aac, AAC_MIN_FOOTPRINT_SIZE)) {
+ dev_warn(&pdev->dev,
+ "aacraid: unable to map adapter.\n");
+
+ return;
+ }
+ }
+
+ msleep(10000);
+
+ aac_acquire_resources(aac);
+
+ /*
+ * reset this flag to unblock ioctl() as it was set
+ * at aac_send_shutdown() to block ioctls from upperlayer
+ */
+ aac->adapter_shutdown = 0;
+ aac->handle_pci_error = 0;
+
+ shost_for_each_device(sdev, shost)
+ if (sdev->sdev_state == SDEV_OFFLINE)
+ sdev->sdev_state = SDEV_RUNNING;
+ scsi_unblock_requests(aac->scsi_host_ptr);
+ scsi_scan_host(aac->scsi_host_ptr);
+ pci_save_state(pdev);
+
+ dev_err(&pdev->dev, "aacraid: PCI error - resume\n");
+}
+
+static struct pci_error_handlers aac_pci_err_handler = {
+ .error_detected = aac_pci_error_detected,
+ .mmio_enabled = aac_pci_mmio_enabled,
+ .slot_reset = aac_pci_slot_reset,
+ .resume = aac_pci_resume,
+};
+
static struct pci_driver aac_pci_driver = {
.name = AAC_DRIVERNAME,
.id_table = aac_pci_tbl,
@@ -1509,6 +1670,7 @@ static struct pci_driver aac_pci_driver = {
.resume = aac_resume,
#endif
.shutdown = aac_shutdown,
+ .err_handler = &aac_pci_err_handler,
};
static int __init aac_init(void)
@@ -1522,11 +1684,8 @@ static int __init aac_init(void)
if (error < 0)
return error;
- aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops);
- if (aac_cfg_major < 0) {
- printk(KERN_WARNING
- "aacraid: unable to register \"aac\" device.\n");
- }
+ aac_init_char();
+
return 0;
}
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index 2aa34ea8ceb1..bc0203f3d243 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -156,8 +156,8 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id)
break;
if (dev->msi_enabled && dev->max_msix > 1)
atomic_dec(&dev->rrq_outstanding[vector_no]);
- aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
dev->host_rrq[index++] = 0;
+ aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
if (index == (vector_no + 1) * dev->vector_cap)
index = vector_no * dev->vector_cap;
dev->host_rrq_idx[vector_no] = index;
@@ -452,36 +452,20 @@ static int aac_src_deliver_message(struct fib *fib)
#endif
u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size);
+ u16 vector_no;
atomic_inc(&q->numpending);
if (dev->msi_enabled && fib->hw_fib_va->header.Command != AifRequest &&
dev->max_msix > 1) {
- u_int16_t vector_no, first_choice = 0xffff;
-
- vector_no = dev->fibs_pushed_no % dev->max_msix;
- do {
- vector_no += 1;
- if (vector_no == dev->max_msix)
- vector_no = 1;
- if (atomic_read(&dev->rrq_outstanding[vector_no]) <
- dev->vector_cap)
- break;
- if (0xffff == first_choice)
- first_choice = vector_no;
- else if (vector_no == first_choice)
- break;
- } while (1);
- if (vector_no == first_choice)
- vector_no = 0;
- atomic_inc(&dev->rrq_outstanding[vector_no]);
- if (dev->fibs_pushed_no == 0xffffffff)
- dev->fibs_pushed_no = 0;
- else
- dev->fibs_pushed_no++;
+ vector_no = fib->vector_no;
fib->hw_fib_va->header.Handle += (vector_no << 16);
+ } else {
+ vector_no = 0;
}
+ atomic_inc(&dev->rrq_outstanding[vector_no]);
+
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
/* Calculate the amount to the fibsize bits */
fibsize = (hdr_size + 127) / 128 - 1;
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 5b8b2937a3fe..7db448ec8beb 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -403,6 +403,9 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
cptr = kmalloc(sizeof(*cptr) * sg_count, GFP_KERNEL | GFP_DMA);
if (!cptr)
return SCSI_MLQUEUE_HOST_BUSY;
+ } else {
+ sg_count = 0;
+ cptr = NULL;
}
/* Use the outgoing mailboxes in a round-robin fashion, because this
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index b846a4683562..fc6a83188c1e 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -1336,6 +1336,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
case AHC_DEV_Q_TAGGED:
scsi_change_queue_depth(sdev,
dev->openings + dev->active);
+ break;
default:
/*
* We allow the OS to queue 2 untagged transactions to
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index deaaf84989cd..12b88294d667 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -677,7 +677,8 @@ int round_period(unsigned int period)
* Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
*/
static
-unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
+unsigned char __maybe_unused calc_sync_xfer(unsigned int period,
+ unsigned int offset)
{
return sync_xfer_table[round_period(period)].reg_value |
((offset < SDTR_SIZE) ? offset : SDTR_SIZE);
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index decdc71b6b86..24388795ee9a 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -98,6 +98,7 @@ static int level_mask = LOG_ERROR;
module_param(level_mask, int, 0644);
+#ifndef MODULE
static int __init fas216_log_setup(char *str)
{
char *s;
@@ -138,6 +139,7 @@ static int __init fas216_log_setup(char *str)
}
__setup("fas216_logging=", fas216_log_setup);
+#endif
static inline unsigned char fas216_readb(FAS216_Info *info, unsigned int reg)
{
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index e65478651ca9..389825ba5d96 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -862,7 +862,7 @@ static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
struct NCR5380_cmd *ncmd;
struct scsi_cmnd *cmd;
- if (list_empty(&hostdata->autosense)) {
+ if (hostdata->sensing || list_empty(&hostdata->autosense)) {
list_for_each_entry(ncmd, &hostdata->unissued, list) {
cmd = NCR5380_to_scmd(ncmd);
dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
@@ -901,7 +901,7 @@ static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
- if (hostdata->sensing) {
+ if (hostdata->sensing == cmd) {
scsi_eh_restore_cmnd(cmd, &hostdata->ses);
list_add(&ncmd->list, &hostdata->autosense);
hostdata->sensing = NULL;
@@ -923,7 +923,6 @@ static void NCR5380_main(struct work_struct *work)
struct NCR5380_hostdata *hostdata =
container_of(work, struct NCR5380_hostdata, main_task);
struct Scsi_Host *instance = hostdata->host;
- struct scsi_cmnd *cmd;
int done;
/*
@@ -936,8 +935,11 @@ static void NCR5380_main(struct work_struct *work)
done = 1;
spin_lock_irq(&hostdata->lock);
- while (!hostdata->connected &&
- (cmd = dequeue_next_cmd(instance))) {
+ while (!hostdata->connected && !hostdata->selecting) {
+ struct scsi_cmnd *cmd = dequeue_next_cmd(instance);
+
+ if (!cmd)
+ break;
dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
@@ -960,8 +962,7 @@ static void NCR5380_main(struct work_struct *work)
#ifdef SUPPORT_TAGS
cmd_get_tag(cmd, cmd->cmnd[0] != REQUEST_SENSE);
#endif
- cmd = NCR5380_select(instance, cmd);
- if (!cmd) {
+ if (!NCR5380_select(instance, cmd)) {
dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
maybe_release_dma_irq(instance);
} else {
@@ -1257,6 +1258,11 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
/* Reselection interrupt */
goto out;
}
+ if (!hostdata->selecting) {
+ /* Command was aborted */
+ NCR5380_write(MODE_REG, MR_BASE);
+ goto out;
+ }
if (err < 0) {
NCR5380_write(MODE_REG, MR_BASE);
shost_printk(KERN_ERR, instance,
@@ -1838,9 +1844,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
unsigned char msgout = NOP;
int sink = 0;
int len;
-#if defined(REAL_DMA)
int transfersize;
-#endif
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
struct scsi_cmnd *cmd;
@@ -1909,6 +1913,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
do_abort(instance);
cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
+ hostdata->connected = NULL;
return;
#endif
case PHASE_DATAIN:
@@ -1966,7 +1971,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- complete_cmd(instance, cmd);
/* XXX - need to source or sink data here, as appropriate */
} else {
#ifdef REAL_DMA
@@ -1983,18 +1987,22 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
} else
#endif /* defined(REAL_DMA) */
{
- spin_unlock_irq(&hostdata->lock);
- NCR5380_transfer_pio(instance, &phase,
- (int *)&cmd->SCp.this_residual,
+ /* Break up transfer into 3 ms chunks,
+ * presuming 6 accesses per handshake.
+ */
+ transfersize = min((unsigned long)cmd->SCp.this_residual,
+ hostdata->accesses_per_ms / 2);
+ len = transfersize;
+ NCR5380_transfer_pio(instance, &phase, &len,
(unsigned char **)&cmd->SCp.ptr);
- spin_lock_irq(&hostdata->lock);
+ cmd->SCp.this_residual -= transfersize - len;
}
#if defined(CONFIG_SUN3) && defined(REAL_DMA)
/* if we had intended to dma that command clear it */
if (sun3_dma_setup_done == cmd)
sun3_dma_setup_done = NULL;
#endif
- break;
+ return;
case PHASE_MSGIN:
len = 1;
data = &tmp;
@@ -2487,14 +2495,17 @@ static bool list_del_cmd(struct list_head *haystack,
* [disconnected -> connected ->]...
* [autosense -> connected ->] done
*
- * If cmd is unissued then just remove it.
- * If cmd is disconnected, try to select the target.
- * If cmd is connected, try to send an abort message.
- * If cmd is waiting for autosense, give it a chance to complete but check
- * that it isn't left connected.
* If cmd was not found at all then presumably it has already been completed,
* in which case return SUCCESS to try to avoid further EH measures.
+ *
* If the command has not completed yet, we must not fail to find it.
+ * We have no option but to forget the aborted command (even if it still
+ * lacks sense data). The mid-layer may re-issue a command that is in error
+ * recovery (see scsi_send_eh_cmnd), but the logic and data structures in
+ * this driver are such that a command can appear on one queue only.
+ *
+ * The lock protects driver data structures, but EH handlers also use it
+ * to serialize their own execution and prevent their own re-entry.
*/
static int NCR5380_abort(struct scsi_cmnd *cmd)
@@ -2517,6 +2528,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
"abort: removed %p from issue queue\n", cmd);
cmd->result = DID_ABORT << 16;
cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
+ goto out;
}
if (hostdata->selecting == cmd) {
@@ -2531,58 +2543,21 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
if (list_del_cmd(&hostdata->disconnected, cmd)) {
dsprintk(NDEBUG_ABORT, instance,
"abort: removed %p from disconnected list\n", cmd);
- cmd->result = DID_ERROR << 16;
- if (!hostdata->connected)
- NCR5380_select(instance, cmd);
- if (hostdata->connected != cmd) {
- complete_cmd(instance, cmd);
- result = FAILED;
- goto out;
- }
+ /* Can't call NCR5380_select() and send ABORT because that
+ * means releasing the lock. Need a bus reset.
+ */
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
}
if (hostdata->connected == cmd) {
dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
hostdata->connected = NULL;
- if (do_abort(instance)) {
- set_host_byte(cmd, DID_ERROR);
- complete_cmd(instance, cmd);
- result = FAILED;
- goto out;
- }
- set_host_byte(cmd, DID_ABORT);
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
- if (cmd->cmnd[0] == REQUEST_SENSE)
- complete_cmd(instance, cmd);
- else {
- struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
-
- /* Perform autosense for this command */
- list_add(&ncmd->list, &hostdata->autosense);
- }
- }
-
- if (list_find_cmd(&hostdata->autosense, cmd)) {
- dsprintk(NDEBUG_ABORT, instance,
- "abort: found %p on sense queue\n", cmd);
- spin_unlock_irqrestore(&hostdata->lock, flags);
- queue_work(hostdata->work_q, &hostdata->main_task);
- msleep(1000);
- spin_lock_irqsave(&hostdata->lock, flags);
- if (list_del_cmd(&hostdata->autosense, cmd)) {
- dsprintk(NDEBUG_ABORT, instance,
- "abort: removed %p from sense queue\n", cmd);
- set_host_byte(cmd, DID_ABORT);
- complete_cmd(instance, cmd);
- goto out;
- }
- }
-
- if (hostdata->connected == cmd) {
- dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
- hostdata->connected = NULL;
if (do_abort(instance)) {
set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd);
@@ -2590,9 +2565,14 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
goto out;
}
set_host_byte(cmd, DID_ABORT);
-#ifdef REAL_DMA
- hostdata->dma_len = 0;
-#endif
+ complete_cmd(instance, cmd);
+ goto out;
+ }
+
+ if (list_del_cmd(&hostdata->autosense, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from sense queue\n", cmd);
+ set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd);
}
@@ -2646,7 +2626,16 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
* commands!
*/
- hostdata->selecting = NULL;
+ if (list_del_cmd(&hostdata->unissued, cmd)) {
+ cmd->result = DID_RESET << 16;
+ cmd->scsi_done(cmd);
+ }
+
+ if (hostdata->selecting) {
+ hostdata->selecting->result = DID_RESET << 16;
+ complete_cmd(instance, hostdata->selecting);
+ hostdata->selecting = NULL;
+ }
list_for_each_entry(ncmd, &hostdata->disconnected, list) {
struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
@@ -2654,6 +2643,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
set_host_byte(cmd, DID_RESET);
cmd->scsi_done(cmd);
}
+ INIT_LIST_HEAD(&hostdata->disconnected);
list_for_each_entry(ncmd, &hostdata->autosense, list) {
struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
@@ -2661,6 +2651,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
set_host_byte(cmd, DID_RESET);
cmd->scsi_done(cmd);
}
+ INIT_LIST_HEAD(&hostdata->autosense);
if (hostdata->connected) {
set_host_byte(hostdata->connected, DID_RESET);
@@ -2668,12 +2659,6 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
hostdata->connected = NULL;
}
- if (hostdata->sensing) {
- set_host_byte(hostdata->connected, DID_RESET);
- complete_cmd(instance, hostdata->sensing);
- hostdata->sensing = NULL;
- }
-
#ifdef SUPPORT_TAGS
free_all_tags(hostdata);
#endif
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index a41c6432f444..ee5ace873535 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -42,7 +42,7 @@ struct be_queue_info {
u16 id;
u16 tail, head;
bool created;
- atomic_t used; /* Number of valid elements in the queue */
+ u16 used; /* Number of valid elements in the queue */
};
static inline u32 MODULO(u16 val, u16 limit)
@@ -110,10 +110,9 @@ struct be_mcc_obj {
};
struct beiscsi_mcc_tag_state {
-#define MCC_TAG_STATE_COMPLETED 0x00
-#define MCC_TAG_STATE_RUNNING 0x01
-#define MCC_TAG_STATE_TIMEOUT 0x02
- uint8_t tag_state;
+ unsigned long tag_state;
+#define MCC_TAG_STATE_RUNNING 1
+#define MCC_TAG_STATE_TIMEOUT 2
struct be_dma_mem tag_mem_state;
};
@@ -124,7 +123,7 @@ struct be_ctrl_info {
struct pci_dev *pdev;
/* Mbox used for cmd request/response */
- spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */
+ struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
struct be_dma_mem mbox_mem;
/* Mbox mem is adjusted to align to 16 bytes. The allocated addr
* is stored for freeing purpose */
@@ -133,11 +132,10 @@ struct be_ctrl_info {
/* MCC Rings */
struct be_mcc_obj mcc_obj;
spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */
- spinlock_t mcc_cq_lock;
wait_queue_head_t mcc_wait[MAX_MCC_CMD + 1];
unsigned int mcc_tag[MAX_MCC_CMD];
- unsigned int mcc_numtag[MAX_MCC_CMD + 1];
+ unsigned int mcc_tag_status[MAX_MCC_CMD + 1];
unsigned short mcc_alloc_index;
unsigned short mcc_free_index;
unsigned int mcc_tag_available;
@@ -147,6 +145,12 @@ struct be_ctrl_info {
#include "be_cmds.h"
+/* WRB index mask for MCC_Q_LEN queue entries */
+#define MCC_Q_WRB_IDX_MASK CQE_STATUS_WRB_MASK
+#define MCC_Q_WRB_IDX_SHIFT CQE_STATUS_WRB_SHIFT
+/* TAG is from 1...MAX_MCC_CMD, MASK includes MAX_MCC_CMD */
+#define MCC_Q_CMD_TAG_MASK ((MAX_MCC_CMD << 1) - 1)
+
#define PAGE_SHIFT_4K 12
#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
#define mcc_timeout 120000 /* 12s timeout */
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index 2778089b01a5..a55eaeea37e7 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -104,24 +104,16 @@ int be_chk_reset_complete(struct beiscsi_hba *phba)
return 0;
}
-void be_mcc_notify(struct beiscsi_hba *phba)
-{
- struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
- u32 val = 0;
-
- val |= mccq->id & DB_MCCQ_RING_ID_MASK;
- val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
- iowrite32(val, phba->db_va + DB_MCCQ_OFFSET);
-}
-
unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
{
unsigned int tag = 0;
+ spin_lock(&phba->ctrl.mcc_lock);
if (phba->ctrl.mcc_tag_available) {
tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index];
phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0;
- phba->ctrl.mcc_numtag[tag] = 0;
+ phba->ctrl.mcc_tag_status[tag] = 0;
+ phba->ctrl.ptag_state[tag].tag_state = 0;
}
if (tag) {
phba->ctrl.mcc_tag_available--;
@@ -130,11 +122,89 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
else
phba->ctrl.mcc_alloc_index++;
}
+ spin_unlock(&phba->ctrl.mcc_lock);
return tag;
}
+struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
+ unsigned int *ref_tag)
+{
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ struct be_mcc_wrb *wrb = NULL;
+ unsigned int tag;
+
+ spin_lock_bh(&phba->ctrl.mcc_lock);
+ if (mccq->used == mccq->len) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT |
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : MCC queue full: WRB used %u tag avail %u\n",
+ mccq->used, phba->ctrl.mcc_tag_available);
+ goto alloc_failed;
+ }
+
+ if (!phba->ctrl.mcc_tag_available)
+ goto alloc_failed;
+
+ tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index];
+ if (!tag) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT |
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : MCC tag 0 allocated: tag avail %u alloc index %u\n",
+ phba->ctrl.mcc_tag_available,
+ phba->ctrl.mcc_alloc_index);
+ goto alloc_failed;
+ }
+
+ /* return this tag for further reference */
+ *ref_tag = tag;
+ phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0;
+ phba->ctrl.mcc_tag_status[tag] = 0;
+ phba->ctrl.ptag_state[tag].tag_state = 0;
+ phba->ctrl.mcc_tag_available--;
+ if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1))
+ phba->ctrl.mcc_alloc_index = 0;
+ else
+ phba->ctrl.mcc_alloc_index++;
+
+ wrb = queue_head_node(mccq);
+ memset(wrb, 0, sizeof(*wrb));
+ wrb->tag0 = tag;
+ wrb->tag0 |= (mccq->head << MCC_Q_WRB_IDX_SHIFT) & MCC_Q_WRB_IDX_MASK;
+ queue_head_inc(mccq);
+ mccq->used++;
+
+alloc_failed:
+ spin_unlock_bh(&phba->ctrl.mcc_lock);
+ return wrb;
+}
+
+void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag)
+{
+ struct be_queue_info *mccq = &ctrl->mcc_obj.q;
+
+ spin_lock_bh(&ctrl->mcc_lock);
+ tag = tag & MCC_Q_CMD_TAG_MASK;
+ ctrl->mcc_tag[ctrl->mcc_free_index] = tag;
+ if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1))
+ ctrl->mcc_free_index = 0;
+ else
+ ctrl->mcc_free_index++;
+ ctrl->mcc_tag_available++;
+ mccq->used--;
+ spin_unlock_bh(&ctrl->mcc_lock);
+}
+
+/**
+ * beiscsi_fail_session(): Closing session with appropriate error
+ * @cls_session: ptr to session
+ **/
+void beiscsi_fail_session(struct iscsi_cls_session *cls_session)
+{
+ iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
+}
+
/*
- * beiscsi_mccq_compl()- Wait for completion of MBX
+ * beiscsi_mccq_compl_wait()- Process completion in MCC CQ
* @phba: Driver private structure
* @tag: Tag for the MBX Command
* @wrb: the WRB used for the MBX Command
@@ -146,43 +216,40 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
* Success: 0
* Failure: Non-Zero
**/
-int beiscsi_mccq_compl(struct beiscsi_hba *phba,
- uint32_t tag, struct be_mcc_wrb **wrb,
- struct be_dma_mem *mbx_cmd_mem)
+int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
+ uint32_t tag, struct be_mcc_wrb **wrb,
+ struct be_dma_mem *mbx_cmd_mem)
{
int rc = 0;
- uint32_t mcc_tag_response;
+ uint32_t mcc_tag_status;
uint16_t status = 0, addl_status = 0, wrb_num = 0;
struct be_mcc_wrb *temp_wrb;
struct be_cmd_req_hdr *mbx_hdr;
struct be_cmd_resp_hdr *mbx_resp_hdr;
struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
- if (beiscsi_error(phba)) {
- free_mcc_tag(&phba->ctrl, tag);
+ if (beiscsi_error(phba))
return -EPERM;
- }
-
- /* Set MBX Tag state to Active */
- spin_lock(&phba->ctrl.mbox_lock);
- phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_RUNNING;
- spin_unlock(&phba->ctrl.mbox_lock);
/* wait for the mccq completion */
rc = wait_event_interruptible_timeout(
phba->ctrl.mcc_wait[tag],
- phba->ctrl.mcc_numtag[tag],
+ phba->ctrl.mcc_tag_status[tag],
msecs_to_jiffies(
BEISCSI_HOST_MBX_TIMEOUT));
-
+ /**
+ * If MBOX cmd timeout expired, tag and resource allocated
+ * for cmd is not freed until FW returns completion.
+ */
if (rc <= 0) {
struct be_dma_mem *tag_mem;
- /* Set MBX Tag state to timeout */
- spin_lock(&phba->ctrl.mbox_lock);
- phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_TIMEOUT;
- spin_unlock(&phba->ctrl.mbox_lock);
- /* Store resource addr to be freed later */
+ /**
+ * PCI/DMA memory allocated and posted in non-embedded mode
+ * will have mbx_cmd_mem != NULL.
+ * Save virtual and bus addresses for the command so that it
+ * can be freed later.
+ **/
tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state;
if (mbx_cmd_mem) {
tag_mem->size = mbx_cmd_mem->size;
@@ -191,28 +258,28 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
} else
tag_mem->size = 0;
+ /* first make tag_mem_state visible to all */
+ wmb();
+ set_bit(MCC_TAG_STATE_TIMEOUT,
+ &phba->ctrl.ptag_state[tag].tag_state);
+
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
BEISCSI_LOG_CONFIG,
"BC_%d : MBX Cmd Completion timed out\n");
return -EBUSY;
- } else {
- rc = 0;
- /* Set MBX Tag state to completed */
- spin_lock(&phba->ctrl.mbox_lock);
- phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
- spin_unlock(&phba->ctrl.mbox_lock);
}
- mcc_tag_response = phba->ctrl.mcc_numtag[tag];
- status = (mcc_tag_response & CQE_STATUS_MASK);
- addl_status = ((mcc_tag_response & CQE_STATUS_ADDL_MASK) >>
+ rc = 0;
+ mcc_tag_status = phba->ctrl.mcc_tag_status[tag];
+ status = (mcc_tag_status & CQE_STATUS_MASK);
+ addl_status = ((mcc_tag_status & CQE_STATUS_ADDL_MASK) >>
CQE_STATUS_ADDL_SHIFT);
if (mbx_cmd_mem) {
mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va;
} else {
- wrb_num = (mcc_tag_response & CQE_STATUS_WRB_MASK) >>
+ wrb_num = (mcc_tag_status & CQE_STATUS_WRB_MASK) >>
CQE_STATUS_WRB_SHIFT;
temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num);
mbx_hdr = embedded_payload(temp_wrb);
@@ -231,7 +298,7 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
mbx_hdr->subsystem,
mbx_hdr->opcode,
status, addl_status);
-
+ rc = -EIO;
if (status == MCC_STATUS_INSUFFICIENT_BUFFER) {
mbx_resp_hdr = (struct be_cmd_resp_hdr *) mbx_hdr;
beiscsi_log(phba, KERN_WARNING,
@@ -241,70 +308,16 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
"Resp_Len : %d Actual_Resp_Len : %d\n",
mbx_resp_hdr->response_length,
mbx_resp_hdr->actual_resp_len);
-
rc = -EAGAIN;
- goto release_mcc_tag;
}
- rc = -EIO;
}
-release_mcc_tag:
- /* Release the MCC entry */
- free_mcc_tag(&phba->ctrl, tag);
-
+ free_mcc_wrb(&phba->ctrl, tag);
return rc;
}
-void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag)
-{
- spin_lock(&ctrl->mbox_lock);
- tag = tag & 0x000000FF;
- ctrl->mcc_tag[ctrl->mcc_free_index] = tag;
- if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1))
- ctrl->mcc_free_index = 0;
- else
- ctrl->mcc_free_index++;
- ctrl->mcc_tag_available++;
- spin_unlock(&ctrl->mbox_lock);
-}
-
-bool is_link_state_evt(u32 trailer)
-{
- return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
- ASYNC_TRAILER_EVENT_CODE_MASK) ==
- ASYNC_EVENT_CODE_LINK_STATE);
-}
-
-static bool is_iscsi_evt(u32 trailer)
-{
- return ((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
- ASYNC_TRAILER_EVENT_CODE_MASK) ==
- ASYNC_EVENT_CODE_ISCSI;
-}
-
-static int iscsi_evt_type(u32 trailer)
-{
- return (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) &
- ASYNC_TRAILER_EVENT_TYPE_MASK;
-}
-
-static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
-{
- if (compl->flags != 0) {
- compl->flags = le32_to_cpu(compl->flags);
- WARN_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0);
- return true;
- } else
- return false;
-}
-
-static inline void be_mcc_compl_use(struct be_mcc_compl *compl)
-{
- compl->flags = 0;
-}
-
/*
- * be_mcc_compl_process()- Check the MBX comapletion status
+ * beiscsi_process_mbox_compl()- Check the MBX completion status
* @ctrl: Function specific MBX data structure
* @compl: Completion status of MBX Command
*
@@ -314,8 +327,8 @@ static inline void be_mcc_compl_use(struct be_mcc_compl *compl)
* Success: Zero
* Failure: Non-Zero
**/
-static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
- struct be_mcc_compl *compl)
+static int beiscsi_process_mbox_compl(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl)
{
u16 compl_status, extd_status;
struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
@@ -323,206 +336,228 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
struct be_cmd_req_hdr *hdr = embedded_payload(wrb);
struct be_cmd_resp_hdr *resp_hdr;
- be_dws_le_to_cpu(compl, 4);
-
- compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
- CQE_STATUS_COMPL_MASK;
- if (compl_status != MCC_STATUS_SUCCESS) {
- extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
- CQE_STATUS_EXTD_MASK;
-
+ /**
+ * To check if valid bit is set, check the entire word as we don't know
+ * the endianness of the data (old entry is host endian while a new
+ * entry is little endian)
+ */
+ if (!compl->flags) {
beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : error in cmd completion: "
- "Subsystem : %d Opcode : %d "
- "status(compl/extd)=%d/%d\n",
- hdr->subsystem, hdr->opcode,
- compl_status, extd_status);
-
- if (compl_status == MCC_STATUS_INSUFFICIENT_BUFFER) {
- resp_hdr = (struct be_cmd_resp_hdr *) hdr;
- if (resp_hdr->response_length)
- return 0;
- }
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : BMBX busy, no completion\n");
return -EBUSY;
}
- return 0;
-}
-
-int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
- struct be_mcc_compl *compl)
-{
- struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
- u16 compl_status, extd_status;
- unsigned short tag;
+ compl->flags = le32_to_cpu(compl->flags);
+ WARN_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0);
+ /**
+ * Just swap the status to host endian;
+ * mcc tag is opaquely copied from mcc_wrb.
+ */
be_dws_le_to_cpu(compl, 4);
-
compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
- CQE_STATUS_COMPL_MASK;
- /* The ctrl.mcc_numtag[tag] is filled with
- * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status,
- * [7:0] = compl_status
- */
- tag = (compl->tag0 & 0x000000FF);
+ CQE_STATUS_COMPL_MASK;
extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
- CQE_STATUS_EXTD_MASK;
+ CQE_STATUS_EXTD_MASK;
+ /* Need to reset the entire word that houses the valid bit */
+ compl->flags = 0;
- ctrl->mcc_numtag[tag] = 0x80000000;
- ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000);
- ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8;
- ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF);
+ if (compl_status == MCC_STATUS_SUCCESS)
+ return 0;
- if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_RUNNING) {
- wake_up_interruptible(&ctrl->mcc_wait[tag]);
- } else if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_TIMEOUT) {
- struct be_dma_mem *tag_mem;
- tag_mem = &ctrl->ptag_state[tag].tag_mem_state;
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : error in cmd completion: Subsystem : %d Opcode : %d status(compl/extd)=%d/%d\n",
+ hdr->subsystem, hdr->opcode, compl_status, extd_status);
- beiscsi_log(phba, KERN_WARNING,
- BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT |
- BEISCSI_LOG_CONFIG,
- "BC_%d : MBX Completion for timeout Command "
- "from FW\n");
- /* Check if memory needs to be freed */
- if (tag_mem->size)
- pci_free_consistent(ctrl->pdev, tag_mem->size,
- tag_mem->va, tag_mem->dma);
-
- /* Change tag state */
- spin_lock(&phba->ctrl.mbox_lock);
- ctrl->ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
- spin_unlock(&phba->ctrl.mbox_lock);
-
- /* Free MCC Tag */
- free_mcc_tag(ctrl, tag);
+ if (compl_status == MCC_STATUS_INSUFFICIENT_BUFFER) {
+ /* if status is insufficient buffer, check the length */
+ resp_hdr = (struct be_cmd_resp_hdr *) hdr;
+ if (resp_hdr->response_length)
+ return 0;
}
-
- return 0;
+ return -EINVAL;
}
-static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba)
+static void beiscsi_process_async_link(struct beiscsi_hba *phba,
+ struct be_mcc_compl *compl)
{
- struct be_queue_info *mcc_cq = &phba->ctrl.mcc_obj.cq;
- struct be_mcc_compl *compl = queue_tail_node(mcc_cq);
+ struct be_async_event_link_state *evt;
+
+ evt = (struct be_async_event_link_state *)compl;
- if (be_mcc_compl_is_new(compl)) {
- queue_tail_inc(mcc_cq);
- return compl;
+ phba->port_speed = evt->port_speed;
+ /**
+ * Check logical link status in ASYNC event.
+ * This has been newly introduced in SKH-R Firmware 10.0.338.45.
+ **/
+ if (evt->port_link_status & BE_ASYNC_LINK_UP_MASK) {
+ phba->state = BE_ADAPTER_LINK_UP | BE_ADAPTER_CHECK_BOOT;
+ phba->get_boot = BE_GET_BOOT_RETRIES;
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : Link Up on Port %d tag 0x%x\n",
+ evt->physical_port, evt->event_tag);
+ } else {
+ phba->state = BE_ADAPTER_LINK_DOWN;
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : Link Down on Port %d tag 0x%x\n",
+ evt->physical_port, evt->event_tag);
+ iscsi_host_for_each_session(phba->shost,
+ beiscsi_fail_session);
}
- return NULL;
}
-/**
- * be2iscsi_fail_session(): Closing session with appropriate error
- * @cls_session: ptr to session
- *
- * Depending on adapter state appropriate error flag is passed.
- **/
-void be2iscsi_fail_session(struct iscsi_cls_session *cls_session)
+static char *beiscsi_port_misconf_event_msg[] = {
+ "Physical Link is functional.",
+ "Optics faulted/incorrectly installed/not installed - Reseat optics, if issue not resolved, replace.",
+ "Optics of two types installed - Remove one optic or install matching pair of optics.",
+ "Incompatible optics - Replace with compatible optics for card to function.",
+ "Unqualified optics - Replace with Avago optics for Warranty and Technical Support.",
+ "Uncertified optics - Replace with Avago Certified optics to enable link operation."
+};
+
+static void beiscsi_process_async_sli(struct beiscsi_hba *phba,
+ struct be_mcc_compl *compl)
{
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- struct beiscsi_hba *phba = iscsi_host_priv(shost);
- uint32_t iscsi_err_flag;
+ struct be_async_event_sli *async_sli;
+ u8 evt_type, state, old_state, le;
+ char *sev = KERN_WARNING;
+ char *msg = NULL;
+
+ evt_type = compl->flags >> ASYNC_TRAILER_EVENT_TYPE_SHIFT;
+ evt_type &= ASYNC_TRAILER_EVENT_TYPE_MASK;
+
+ /* processing only MISCONFIGURED physical port event */
+ if (evt_type != ASYNC_SLI_EVENT_TYPE_MISCONFIGURED)
+ return;
+
+ async_sli = (struct be_async_event_sli *)compl;
+ state = async_sli->event_data1 >>
+ (phba->fw_config.phys_port * 8) & 0xff;
+ le = async_sli->event_data2 >>
+ (phba->fw_config.phys_port * 8) & 0xff;
+
+ old_state = phba->optic_state;
+ phba->optic_state = state;
+
+ if (state >= ARRAY_SIZE(beiscsi_port_misconf_event_msg)) {
+ /* fw is reporting a state we don't know, log and return */
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : Port %c: Unrecognized optic state 0x%x\n",
+ phba->port_name, async_sli->event_data1);
+ return;
+ }
- if (phba->state & BE_ADAPTER_STATE_SHUTDOWN)
- iscsi_err_flag = ISCSI_ERR_INVALID_HOST;
- else
- iscsi_err_flag = ISCSI_ERR_CONN_FAILED;
+ if (ASYNC_SLI_LINK_EFFECT_VALID(le)) {
+ /* log link effect for unqualified-4, uncertified-5 optics */
+ if (state > 3)
+ msg = (ASYNC_SLI_LINK_EFFECT_STATE(le)) ?
+ " Link is non-operational." :
+ " Link is operational.";
+ /* 1 - info */
+ if (ASYNC_SLI_LINK_EFFECT_SEV(le) == 1)
+ sev = KERN_INFO;
+ /* 2 - error */
+ if (ASYNC_SLI_LINK_EFFECT_SEV(le) == 2)
+ sev = KERN_ERR;
+ }
- iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
+ if (old_state != phba->optic_state)
+ __beiscsi_log(phba, sev, "BC_%d : Port %c: %s%s\n",
+ phba->port_name,
+ beiscsi_port_misconf_event_msg[state],
+ !msg ? "" : msg);
}
-void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
- struct be_async_event_link_state *evt)
+void beiscsi_process_async_event(struct beiscsi_hba *phba,
+ struct be_mcc_compl *compl)
{
- if ((evt->port_link_status == ASYNC_EVENT_LINK_DOWN) ||
- ((evt->port_link_status & ASYNC_EVENT_LOGICAL) &&
- (evt->port_fault != BEISCSI_PHY_LINK_FAULT_NONE))) {
- phba->state = BE_ADAPTER_LINK_DOWN;
-
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT,
- "BC_%d : Link Down on Port %d\n",
- evt->physical_port);
-
- iscsi_host_for_each_session(phba->shost,
- be2iscsi_fail_session);
- } else if ((evt->port_link_status & ASYNC_EVENT_LINK_UP) ||
- ((evt->port_link_status & ASYNC_EVENT_LOGICAL) &&
- (evt->port_fault == BEISCSI_PHY_LINK_FAULT_NONE))) {
- phba->state = BE_ADAPTER_LINK_UP | BE_ADAPTER_CHECK_BOOT;
+ char *sev = KERN_INFO;
+ u8 evt_code;
+
+ /* interpret flags as an async trailer */
+ evt_code = compl->flags >> ASYNC_TRAILER_EVENT_CODE_SHIFT;
+ evt_code &= ASYNC_TRAILER_EVENT_CODE_MASK;
+ switch (evt_code) {
+ case ASYNC_EVENT_CODE_LINK_STATE:
+ beiscsi_process_async_link(phba, compl);
+ break;
+ case ASYNC_EVENT_CODE_ISCSI:
+ phba->state |= BE_ADAPTER_CHECK_BOOT;
phba->get_boot = BE_GET_BOOT_RETRIES;
-
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT,
- "BC_%d : Link UP on Port %d\n",
- evt->physical_port);
+ sev = KERN_ERR;
+ break;
+ case ASYNC_EVENT_CODE_SLI:
+ beiscsi_process_async_sli(phba, compl);
+ break;
+ default:
+ /* event not registered */
+ sev = KERN_ERR;
}
+
+ beiscsi_log(phba, sev, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : ASYNC Event %x: status 0x%08x flags 0x%08x\n",
+ evt_code, compl->status, compl->flags);
}
-int beiscsi_process_mcc(struct beiscsi_hba *phba)
+int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl)
{
- struct be_mcc_compl *compl;
- int num = 0, status = 0;
- struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
+ u16 compl_status, extd_status;
+ struct be_dma_mem *tag_mem;
+ unsigned int tag, wrb_idx;
- spin_lock_bh(&phba->ctrl.mcc_cq_lock);
- while ((compl = be_mcc_compl_get(phba))) {
- if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
- /* Interpret flags as an async trailer */
- if (is_link_state_evt(compl->flags))
- /* Interpret compl as a async link evt */
- beiscsi_async_link_state_process(phba,
- (struct be_async_event_link_state *) compl);
- else if (is_iscsi_evt(compl->flags)) {
- switch (iscsi_evt_type(compl->flags)) {
- case ASYNC_EVENT_NEW_ISCSI_TGT_DISC:
- case ASYNC_EVENT_NEW_ISCSI_CONN:
- case ASYNC_EVENT_NEW_TCP_CONN:
- phba->state |= BE_ADAPTER_CHECK_BOOT;
- phba->get_boot = BE_GET_BOOT_RETRIES;
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG |
- BEISCSI_LOG_MBOX,
- "BC_%d : Async iscsi Event,"
- " flags handled = 0x%08x\n",
- compl->flags);
- break;
- default:
- phba->state |= BE_ADAPTER_CHECK_BOOT;
- phba->get_boot = BE_GET_BOOT_RETRIES;
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG |
- BEISCSI_LOG_MBOX,
- "BC_%d : Unsupported Async"
- " Event, flags = 0x%08x\n",
- compl->flags);
- }
- } else
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG |
- BEISCSI_LOG_MBOX,
- "BC_%d : Unsupported Async Event, flags"
- " = 0x%08x\n", compl->flags);
-
- } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
- status = be_mcc_compl_process(ctrl, compl);
- atomic_dec(&phba->ctrl.mcc_obj.q.used);
- }
- be_mcc_compl_use(compl);
- num++;
+ be_dws_le_to_cpu(compl, 4);
+ tag = (compl->tag0 & MCC_Q_CMD_TAG_MASK);
+ wrb_idx = (compl->tag0 & CQE_STATUS_WRB_MASK) >> CQE_STATUS_WRB_SHIFT;
+
+ if (!test_bit(MCC_TAG_STATE_RUNNING,
+ &ctrl->ptag_state[tag].tag_state)) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_MBOX |
+ BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
+ "BC_%d : MBX cmd completed but not posted\n");
+ return 0;
}
- if (num)
- hwi_ring_cq_db(phba, phba->ctrl.mcc_obj.cq.id, num, 1, 0);
+ if (test_bit(MCC_TAG_STATE_TIMEOUT, &ctrl->ptag_state[tag].tag_state)) {
+ beiscsi_log(phba, KERN_WARNING,
+ BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT |
+ BEISCSI_LOG_CONFIG,
+ "BC_%d : MBX Completion for timeout Command from FW\n");
+ /**
+ * Check for the size before freeing resource.
+ * Only for non-embedded cmd, PCI resource is allocated.
+ **/
+ tag_mem = &ctrl->ptag_state[tag].tag_mem_state;
+ if (tag_mem->size)
+ pci_free_consistent(ctrl->pdev, tag_mem->size,
+ tag_mem->va, tag_mem->dma);
+ free_mcc_wrb(ctrl, tag);
+ return 0;
+ }
- spin_unlock_bh(&phba->ctrl.mcc_cq_lock);
- return status;
+ compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
+ CQE_STATUS_COMPL_MASK;
+ extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
+ CQE_STATUS_EXTD_MASK;
+ /* The ctrl.mcc_tag_status[tag] is filled with
+ * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status,
+ * [7:0] = compl_status
+ */
+ ctrl->mcc_tag_status[tag] = CQE_VALID_MASK;
+ ctrl->mcc_tag_status[tag] |= (wrb_idx << CQE_STATUS_WRB_SHIFT);
+ ctrl->mcc_tag_status[tag] |= (extd_status << CQE_STATUS_ADDL_SHIFT) &
+ CQE_STATUS_ADDL_MASK;
+ ctrl->mcc_tag_status[tag] |= (compl_status & CQE_STATUS_MASK);
+
+ /* write ordering forced in wake_up_interruptible */
+ clear_bit(MCC_TAG_STATE_RUNNING, &ctrl->ptag_state[tag].tag_state);
+ wake_up_interruptible(&ctrl->mcc_wait[tag]);
+ return 0;
}
/*
- * be_mcc_wait_compl()- Wait for MBX completion
+ * be_mcc_compl_poll()- Wait for MBX completion
* @phba: driver private structure
*
* Wait till no more pending mcc requests are present
@@ -532,50 +567,57 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba)
* Failure: Non-Zero
*
**/
-static int be_mcc_wait_compl(struct beiscsi_hba *phba)
+int be_mcc_compl_poll(struct beiscsi_hba *phba, unsigned int tag)
{
- int i, status;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ int i;
+
+ if (!test_bit(MCC_TAG_STATE_RUNNING,
+ &ctrl->ptag_state[tag].tag_state)) {
+ beiscsi_log(phba, KERN_ERR,
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d: tag %u state not running\n", tag);
+ return 0;
+ }
for (i = 0; i < mcc_timeout; i++) {
if (beiscsi_error(phba))
return -EIO;
- status = beiscsi_process_mcc(phba);
- if (status)
- return status;
-
- if (atomic_read(&phba->ctrl.mcc_obj.q.used) == 0)
+ beiscsi_process_mcc_cq(phba);
+ /* after polling, wrb and tag need to be released */
+ if (!test_bit(MCC_TAG_STATE_RUNNING,
+ &ctrl->ptag_state[tag].tag_state)) {
+ free_mcc_wrb(ctrl, tag);
break;
+ }
udelay(100);
}
- if (i == mcc_timeout) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : FW Timed Out\n");
- phba->fw_timeout = true;
- beiscsi_ue_detect(phba);
- return -EBUSY;
- }
- return 0;
+
+ if (i < mcc_timeout)
+ return 0;
+
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : FW Timed Out\n");
+ phba->fw_timeout = true;
+ beiscsi_ue_detect(phba);
+ return -EBUSY;
}
-/*
- * be_mcc_notify_wait()- Notify and wait for Compl
- * @phba: driver private structure
- *
- * Notify MCC requests and wait for completion
- *
- * return
- * Success: 0
- * Failure: Non-Zero
- **/
-int be_mcc_notify_wait(struct beiscsi_hba *phba)
+void be_mcc_notify(struct beiscsi_hba *phba, unsigned int tag)
{
- be_mcc_notify(phba);
- return be_mcc_wait_compl(phba);
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ u32 val = 0;
+
+ set_bit(MCC_TAG_STATE_RUNNING, &phba->ctrl.ptag_state[tag].tag_state);
+ val |= mccq->id & DB_MCCQ_RING_ID_MASK;
+ val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
+ /* make request available for DMA */
+ wmb();
+ iowrite32(val, phba->db_va + DB_MCCQ_OFFSET);
}
/*
- * be_mbox_db_ready_wait()- Check ready status
+ * be_mbox_db_ready_poll()- Check ready status
* @ctrl: Function specific MBX data structure
*
* Check for the ready status of FW to send BMBX
@@ -585,49 +627,45 @@ int be_mcc_notify_wait(struct beiscsi_hba *phba)
* Success: 0
* Failure: Non-Zero
**/
-static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
+static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl)
{
-#define BEISCSI_MBX_RDY_BIT_TIMEOUT 4000 /* 4sec */
+ /* wait 30s for generic non-flash MBOX operation */
+#define BEISCSI_MBX_RDY_BIT_TIMEOUT 30000
void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
unsigned long timeout;
- bool read_flag = false;
- int ret = 0, i;
u32 ready;
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(rdybit_check_q);
- if (beiscsi_error(phba))
- return -EIO;
+ /*
+ * This BMBX busy wait path is used during init only.
+ * For the commands executed during init, 5s should suffice.
+ */
+ timeout = jiffies + msecs_to_jiffies(BEISCSI_MBX_RDY_BIT_TIMEOUT);
+ do {
+ if (beiscsi_error(phba))
+ return -EIO;
- timeout = jiffies + (HZ * 110);
+ ready = ioread32(db);
+ if (ready == 0xffffffff)
+ return -EIO;
- do {
- for (i = 0; i < BEISCSI_MBX_RDY_BIT_TIMEOUT; i++) {
- ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
- if (ready) {
- read_flag = true;
- break;
- }
- mdelay(1);
- }
+ ready &= MPU_MAILBOX_DB_RDY_MASK;
+ if (ready)
+ return 0;
- if (!read_flag) {
- wait_event_timeout(rdybit_check_q,
- (read_flag != true),
- HZ * 5);
- }
- } while ((time_before(jiffies, timeout)) && !read_flag);
+ if (time_after(jiffies, timeout))
+ break;
+ msleep(20);
+ } while (!ready);
- if (!read_flag) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : FW Timed Out\n");
- phba->fw_timeout = true;
- beiscsi_ue_detect(phba);
- ret = -EBUSY;
- }
+ beiscsi_log(phba, KERN_ERR,
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : FW Timed Out\n");
+
+ phba->fw_timeout = true;
+ beiscsi_ue_detect(phba);
- return ret;
+ return -EBUSY;
}
/*
@@ -648,10 +686,8 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
struct be_dma_mem *mbox_mem = &ctrl->mbox_mem;
struct be_mcc_mailbox *mbox = mbox_mem->va;
- struct be_mcc_compl *compl = &mbox->compl;
- struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
- status = be_mbox_db_ready_wait(ctrl);
+ status = be_mbox_db_ready_poll(ctrl);
if (status)
return status;
@@ -660,7 +696,7 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
iowrite32(val, db);
- status = be_mbox_db_ready_wait(ctrl);
+ status = be_mbox_db_ready_poll(ctrl);
if (status)
return status;
@@ -670,81 +706,15 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
val |= (u32) (mbox_mem->dma >> 4) << 2;
iowrite32(val, db);
- status = be_mbox_db_ready_wait(ctrl);
+ status = be_mbox_db_ready_poll(ctrl);
if (status)
return status;
- if (be_mcc_compl_is_new(compl)) {
- status = be_mcc_compl_process(ctrl, &mbox->compl);
- be_mcc_compl_use(compl);
- if (status) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : After be_mcc_compl_process\n");
-
- return status;
- }
- } else {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : Invalid Mailbox Completion\n");
-
- return -EBUSY;
- }
- return 0;
-}
-
-/*
- * Insert the mailbox address into the doorbell in two steps
- * Polls on the mbox doorbell till a command completion (or a timeout) occurs
- */
-static int be_mbox_notify_wait(struct beiscsi_hba *phba)
-{
- int status;
- u32 val = 0;
- void __iomem *db = phba->ctrl.db + MPU_MAILBOX_DB_OFFSET;
- struct be_dma_mem *mbox_mem = &phba->ctrl.mbox_mem;
- struct be_mcc_mailbox *mbox = mbox_mem->va;
- struct be_mcc_compl *compl = &mbox->compl;
- struct be_ctrl_info *ctrl = &phba->ctrl;
-
- status = be_mbox_db_ready_wait(ctrl);
- if (status)
- return status;
-
- val |= MPU_MAILBOX_DB_HI_MASK;
- /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
- val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
- iowrite32(val, db);
-
- /* wait for ready to be set */
- status = be_mbox_db_ready_wait(ctrl);
- if (status != 0)
- return status;
-
- val = 0;
- /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */
- val |= (u32)(mbox_mem->dma >> 4) << 2;
- iowrite32(val, db);
+ /* RDY is set; small delay before CQE read. */
+ udelay(1);
- status = be_mbox_db_ready_wait(ctrl);
- if (status != 0)
- return status;
-
- /* A cq entry has been made now */
- if (be_mcc_compl_is_new(compl)) {
- status = be_mcc_compl_process(ctrl, &mbox->compl);
- be_mcc_compl_use(compl);
- if (status)
- return status;
- } else {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : invalid mailbox completion\n");
-
- return -EBUSY;
- }
- return 0;
+ status = beiscsi_process_mbox_compl(ctrl, &mbox->compl);
+ return status;
}
void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
@@ -809,21 +779,6 @@ struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem)
return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb;
}
-struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba)
-{
- struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
- struct be_mcc_wrb *wrb;
-
- WARN_ON(atomic_read(&mccq->used) >= mccq->len);
- wrb = queue_head_node(mccq);
- memset(wrb, 0, sizeof(*wrb));
- wrb->tag0 = (mccq->head & 0x000000FF) << 16;
- queue_head_inc(mccq);
- atomic_inc(&mccq->used);
- return wrb;
-}
-
-
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *eq, int eq_delay)
{
@@ -833,7 +788,7 @@ int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_dma_mem *q_mem = &eq->dma_mem;
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -860,7 +815,7 @@ int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
eq->id = le16_to_cpu(resp->eq_id);
eq->created = true;
}
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -881,7 +836,7 @@ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
int status;
u8 *endian_check;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
endian_check = (u8 *) wrb;
@@ -900,7 +855,7 @@ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BC_%d : be_cmd_fw_initialize Failed\n");
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -921,7 +876,7 @@ int be_cmd_fw_uninit(struct be_ctrl_info *ctrl)
int status;
u8 *endian_check;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
endian_check = (u8 *) wrb;
@@ -941,7 +896,7 @@ int be_cmd_fw_uninit(struct be_ctrl_info *ctrl)
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BC_%d : be_cmd_fw_uninit Failed\n");
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -957,7 +912,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
void *ctxt = &req->context;
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1007,7 +962,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
"BC_%d : In be_cmd_cq_create, status=ox%08x\n",
status);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1025,13 +980,13 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
struct be_queue_info *cq)
{
struct be_mcc_wrb *wrb;
- struct be_cmd_req_mcc_create *req;
+ struct be_cmd_req_mcc_create_ext *req;
struct be_dma_mem *q_mem = &mccq->dma_mem;
struct be_ctrl_info *ctrl;
void *ctxt;
int status;
- spin_lock(&phba->ctrl.mbox_lock);
+ mutex_lock(&phba->ctrl.mbox_lock);
ctrl = &phba->ctrl;
wrb = wrb_from_mbox(&ctrl->mbox_mem);
memset(wrb, 0, sizeof(*wrb));
@@ -1041,9 +996,12 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_MCC_CREATE, sizeof(*req));
+ OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req));
req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+ req->async_evt_bitmap = 1 << ASYNC_EVENT_CODE_LINK_STATE;
+ req->async_evt_bitmap |= 1 << ASYNC_EVENT_CODE_ISCSI;
+ req->async_evt_bitmap |= 1 << ASYNC_EVENT_CODE_SLI;
AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt,
PCI_FUNC(phba->pcidev->devfn));
@@ -1056,13 +1014,13 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
- status = be_mbox_notify_wait(phba);
+ status = be_mbox_notify(ctrl);
if (!status) {
struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb);
mccq->id = le16_to_cpu(resp->id);
mccq->created = true;
}
- spin_unlock(&phba->ctrl.mbox_lock);
+ mutex_unlock(&phba->ctrl.mbox_lock);
return status;
}
@@ -1080,7 +1038,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
"BC_%d : In beiscsi_cmd_q_destroy "
"queue_type : %d\n", queue_type);
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1110,7 +1068,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
opcode = OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES;
break;
default:
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
BUG();
return -ENXIO;
}
@@ -1120,7 +1078,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
status = be_mbox_notify(ctrl);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1155,7 +1113,7 @@ int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
void *ctxt = &req->context;
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1227,7 +1185,7 @@ int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
defq_ring->doorbell_offset = resp->doorbell_offset;
}
}
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1255,7 +1213,7 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1286,7 +1244,7 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl,
pwrb_context->doorbell_offset = resp->doorbell_offset;
}
}
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1297,7 +1255,7 @@ int be_cmd_iscsi_post_template_hdr(struct be_ctrl_info *ctrl,
struct be_post_template_pages_req *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1310,7 +1268,7 @@ int be_cmd_iscsi_post_template_hdr(struct be_ctrl_info *ctrl,
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
status = be_mbox_notify(ctrl);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1320,7 +1278,7 @@ int be_cmd_iscsi_remove_template_hdr(struct be_ctrl_info *ctrl)
struct be_remove_template_pages_req *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1331,7 +1289,7 @@ int be_cmd_iscsi_remove_template_hdr(struct be_ctrl_info *ctrl)
req->type = BEISCSI_TEMPLATE_HDR_TYPE_ISCSI;
status = be_mbox_notify(ctrl);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1350,7 +1308,7 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
if (num_pages == 0xff)
num_pages = 1;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
do {
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1379,7 +1337,7 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
}
} while (num_pages > 0);
error:
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
if (status != 0)
beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
return status;
@@ -1392,15 +1350,15 @@ int beiscsi_cmd_reset_function(struct beiscsi_hba *phba)
struct be_post_sgl_pages_req *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_FUNCTION_RESET, sizeof(*req));
- status = be_mbox_notify_wait(phba);
+ status = be_mbox_notify(ctrl);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1417,21 +1375,20 @@ int beiscsi_cmd_reset_function(struct beiscsi_hba *phba)
int be_cmd_set_vlan(struct beiscsi_hba *phba,
uint16_t vlan_tag)
{
- unsigned int tag = 0;
+ unsigned int tag;
struct be_mcc_wrb *wrb;
struct be_cmd_set_vlan_req *req;
struct be_ctrl_info *ctrl = &phba->ctrl;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return 0;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*wrb), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
OPCODE_COMMON_ISCSI_NTWK_SET_VLAN,
@@ -1440,8 +1397,8 @@ int be_cmd_set_vlan(struct beiscsi_hba *phba,
req->interface_hndl = phba->interface_handle;
req->vlan_priority = vlan_tag;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 4bfca355fbe4..deeb951e6874 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -58,15 +58,16 @@ struct be_mcc_wrb {
#define MCC_STATUS_ILLEGAL_FIELD 0x3
#define MCC_STATUS_INSUFFICIENT_BUFFER 0x4
-#define CQE_STATUS_COMPL_MASK 0xFFFF
-#define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */
-#define CQE_STATUS_EXTD_MASK 0xFFFF
-#define CQE_STATUS_EXTD_SHIFT 16 /* bits 0 - 15 */
+#define CQE_STATUS_COMPL_MASK 0xFFFF
+#define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */
+#define CQE_STATUS_EXTD_MASK 0xFFFF
+#define CQE_STATUS_EXTD_SHIFT 16 /* bits 31 - 16 */
#define CQE_STATUS_ADDL_MASK 0xFF00
-#define CQE_STATUS_MASK 0xFF
-#define CQE_STATUS_ADDL_SHIFT 0x08
+#define CQE_STATUS_ADDL_SHIFT 8
+#define CQE_STATUS_MASK 0xFF
#define CQE_STATUS_WRB_MASK 0xFF0000
#define CQE_STATUS_WRB_SHIFT 16
+
#define BEISCSI_HOST_MBX_TIMEOUT (110 * 1000)
#define BEISCSI_FW_MBX_TIMEOUT 100
@@ -119,13 +120,22 @@ struct be_mcc_compl {
#define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF
#define ASYNC_EVENT_CODE_LINK_STATE 0x1
#define ASYNC_EVENT_CODE_ISCSI 0x4
+#define ASYNC_EVENT_CODE_SLI 0x11
#define ASYNC_TRAILER_EVENT_TYPE_SHIFT 16 /* bits 16 - 23 */
-#define ASYNC_TRAILER_EVENT_TYPE_MASK 0xF
+#define ASYNC_TRAILER_EVENT_TYPE_MASK 0xFF
+
+/* iSCSI events */
#define ASYNC_EVENT_NEW_ISCSI_TGT_DISC 0x4
#define ASYNC_EVENT_NEW_ISCSI_CONN 0x5
#define ASYNC_EVENT_NEW_TCP_CONN 0x7
+/* SLI events */
+#define ASYNC_SLI_EVENT_TYPE_MISCONFIGURED 0x9
+#define ASYNC_SLI_LINK_EFFECT_VALID(le) (le & 0x80)
+#define ASYNC_SLI_LINK_EFFECT_SEV(le) ((le >> 1) & 0x03)
+#define ASYNC_SLI_LINK_EFFECT_STATE(le) (le & 0x01)
+
struct be_async_event_trailer {
u32 code;
};
@@ -133,7 +143,6 @@ struct be_async_event_trailer {
enum {
ASYNC_EVENT_LINK_DOWN = 0x0,
ASYNC_EVENT_LINK_UP = 0x1,
- ASYNC_EVENT_LOGICAL = 0x2
};
/**
@@ -143,16 +152,39 @@ enum {
struct be_async_event_link_state {
u8 physical_port;
u8 port_link_status;
+/**
+ * ASYNC_EVENT_LINK_DOWN 0x0
+ * ASYNC_EVENT_LINK_UP 0x1
+ * ASYNC_EVENT_LINK_LOGICAL_DOWN 0x2
+ * ASYNC_EVENT_LINK_LOGICAL_UP 0x3
+ */
+#define BE_ASYNC_LINK_UP_MASK 0x01
u8 port_duplex;
u8 port_speed;
-#define BEISCSI_PHY_LINK_FAULT_NONE 0x00
-#define BEISCSI_PHY_LINK_FAULT_LOCAL 0x01
-#define BEISCSI_PHY_LINK_FAULT_REMOTE 0x02
+/* BE2ISCSI_LINK_SPEED_ZERO 0x00 - no link */
+#define BE2ISCSI_LINK_SPEED_10MBPS 0x01
+#define BE2ISCSI_LINK_SPEED_100MBPS 0x02
+#define BE2ISCSI_LINK_SPEED_1GBPS 0x03
+#define BE2ISCSI_LINK_SPEED_10GBPS 0x04
+#define BE2ISCSI_LINK_SPEED_25GBPS 0x06
+#define BE2ISCSI_LINK_SPEED_40GBPS 0x07
u8 port_fault;
- u8 rsvd0[7];
+ u8 event_reason;
+ u16 qos_link_speed;
+ u32 event_tag;
struct be_async_event_trailer trailer;
} __packed;
+/**
+ * When async-trailer is SLI event, mcc_compl is interpreted as
+ */
+struct be_async_event_sli {
+ u32 event_data1;
+ u32 event_data2;
+ u32 reserved;
+ u32 trailer;
+} __packed;
+
struct be_mcc_mailbox {
struct be_mcc_wrb wrb;
struct be_mcc_compl compl;
@@ -172,6 +204,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_CQ_CREATE 12
#define OPCODE_COMMON_EQ_CREATE 13
#define OPCODE_COMMON_MCC_CREATE 21
+#define OPCODE_COMMON_MCC_CREATE_EXT 90
#define OPCODE_COMMON_ADD_TEMPLATE_HEADER_BUFFERS 24
#define OPCODE_COMMON_REMOVE_TEMPLATE_HEADER_BUFFERS 25
#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32
@@ -183,6 +216,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_EQ_DESTROY 55
#define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58
#define OPCODE_COMMON_FUNCTION_RESET 61
+#define OPCODE_COMMON_GET_PORT_NAME 77
/**
* LIST of opcodes that are common between Initiator and Target
@@ -587,10 +621,11 @@ struct amap_mcc_context {
u8 rsvd2[32];
} __packed;
-struct be_cmd_req_mcc_create {
+struct be_cmd_req_mcc_create_ext {
struct be_cmd_req_hdr hdr;
u16 num_pages;
u16 rsvd0;
+ u32 async_evt_bitmap;
u8 context[sizeof(struct amap_mcc_context) / 8];
struct phys_addr pages[8];
} __packed;
@@ -653,20 +688,6 @@ struct be_cmd_req_modify_eq_delay {
/******************** Get MAC ADDR *******************/
-#define ETH_ALEN 6
-
-struct be_cmd_get_nic_conf_req {
- struct be_cmd_req_hdr hdr;
- u32 nic_port_count;
- u32 speed;
- u32 max_speed;
- u32 link_state;
- u32 max_frame_size;
- u16 size_of_structure;
- u8 mac_address[ETH_ALEN];
- u32 rsvd[23];
-};
-
struct be_cmd_get_nic_conf_resp {
struct be_cmd_resp_hdr hdr;
u32 nic_port_count;
@@ -675,9 +696,8 @@ struct be_cmd_get_nic_conf_resp {
u32 link_state;
u32 max_frame_size;
u16 size_of_structure;
- u8 mac_address[6];
- u32 rsvd[23];
-};
+ u8 mac_address[ETH_ALEN];
+} __packed;
#define BEISCSI_ALIAS_LEN 32
@@ -689,29 +709,6 @@ struct be_cmd_hba_name {
u8 initiator_alias[BEISCSI_ALIAS_LEN];
} __packed;
-struct be_cmd_ntwk_link_status_req {
- struct be_cmd_req_hdr hdr;
- u32 rsvd0;
-} __packed;
-
-/*** Port Speed Values ***/
-#define BE2ISCSI_LINK_SPEED_ZERO 0x00
-#define BE2ISCSI_LINK_SPEED_10MBPS 0x01
-#define BE2ISCSI_LINK_SPEED_100MBPS 0x02
-#define BE2ISCSI_LINK_SPEED_1GBPS 0x03
-#define BE2ISCSI_LINK_SPEED_10GBPS 0x04
-struct be_cmd_ntwk_link_status_resp {
- struct be_cmd_resp_hdr hdr;
- u8 phys_port;
- u8 mac_duplex;
- u8 mac_speed;
- u8 mac_fault;
- u8 mgmt_mac_duplex;
- u8 mgmt_mac_speed;
- u16 qos_link_speed;
- u32 logical_link_speed;
-} __packed;
-
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *eq, int eq_delay);
@@ -730,28 +727,28 @@ int be_poll_mcc(struct be_ctrl_info *ctrl);
int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba);
unsigned int be_cmd_get_initname(struct beiscsi_hba *phba);
-unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba);
-void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
+void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag);
int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *,
int num);
-int beiscsi_mccq_compl(struct beiscsi_hba *phba,
- uint32_t tag, struct be_mcc_wrb **wrb,
- struct be_dma_mem *mbx_cmd_mem);
+int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
+ uint32_t tag, struct be_mcc_wrb **wrb,
+ struct be_dma_mem *mbx_cmd_mem);
/*ISCSI Functuions */
int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
int be_cmd_fw_uninit(struct be_ctrl_info *ctrl);
struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem);
-struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba);
-int be_mcc_notify_wait(struct beiscsi_hba *phba);
-void be_mcc_notify(struct beiscsi_hba *phba);
-unsigned int alloc_mcc_tag(struct beiscsi_hba *phba);
-void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
- struct be_async_event_link_state *evt);
-int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
- struct be_mcc_compl *compl);
+int be_mcc_compl_poll(struct beiscsi_hba *phba, unsigned int tag);
+void be_mcc_notify(struct beiscsi_hba *phba, unsigned int tag);
+struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
+ unsigned int *ref_tag);
+void beiscsi_process_async_event(struct beiscsi_hba *phba,
+ struct be_mcc_compl *compl);
+int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl);
+
int be_mbox_notify(struct be_ctrl_info *ctrl);
@@ -777,8 +774,6 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
struct hwi_wrb_context *pwrb_context,
uint8_t ulp_num);
-bool is_link_state_evt(u32 trailer);
-
/* Configuration Functions */
int be_cmd_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag);
@@ -1137,6 +1132,21 @@ struct be_cmd_get_all_if_id_req {
u32 if_hndl_list[1];
} __packed;
+struct be_cmd_get_port_name {
+ union {
+ struct be_cmd_req_hdr req_hdr;
+ struct be_cmd_resp_hdr resp_hdr;
+ } h;
+ union {
+ struct {
+ u32 reserved;
+ } req;
+ struct {
+ u32 port_names;
+ } resp;
+ } p;
+} __packed;
+
#define ISCSI_OPCODE_SCSI_DATA_OUT 5
#define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5
#define OPCODE_COMMON_MODIFY_EQ_DELAY 41
@@ -1367,5 +1377,5 @@ void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
u8 subsystem, u8 opcode, int cmd_len);
-void be2iscsi_fail_session(struct iscsi_cls_session *cls_session);
+void beiscsi_fail_session(struct iscsi_cls_session *cls_session);
#endif /* !BEISCSI_CMDS_H */
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 022e87b62e40..09f89a3eaa87 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -367,13 +367,14 @@ beiscsi_set_vlan_tag(struct Scsi_Host *shost,
struct iscsi_iface_param_info *iface_param)
{
struct beiscsi_hba *phba = iscsi_host_priv(shost);
- int ret = 0;
+ int ret;
/* Get the Interface Handle */
- if (mgmt_get_all_if_id(phba)) {
+ ret = mgmt_get_all_if_id(phba);
+ if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BS_%d : Getting Interface Handle Failed\n");
- return -EIO;
+ return ret;
}
switch (iface_param->param) {
@@ -465,6 +466,10 @@ beiscsi_set_ipv6(struct Scsi_Host *shost,
ret = mgmt_set_ip(phba, iface_param, NULL,
ISCSI_BOOTPROTO_STATIC);
break;
+ case ISCSI_NET_PARAM_VLAN_ENABLED:
+ case ISCSI_NET_PARAM_VLAN_TAG:
+ ret = beiscsi_set_vlan_tag(shost, iface_param);
+ break;
default:
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BS_%d : Param %d not supported\n",
@@ -730,7 +735,7 @@ static int beiscsi_get_initname(char *buf, struct beiscsi_hba *phba)
return -EBUSY;
}
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
@@ -753,7 +758,7 @@ static void beiscsi_get_port_state(struct Scsi_Host *shost)
struct beiscsi_hba *phba = iscsi_host_priv(shost);
struct iscsi_cls_host *ihost = shost->shost_data;
- ihost->port_state = (phba->state == BE_ADAPTER_LINK_UP) ?
+ ihost->port_state = (phba->state & BE_ADAPTER_LINK_UP) ?
ISCSI_PORT_STATE_UP : ISCSI_PORT_STATE_DOWN;
}
@@ -761,34 +766,13 @@ static void beiscsi_get_port_state(struct Scsi_Host *shost)
* beiscsi_get_port_speed - Get the Port Speed from Adapter
* @shost : pointer to scsi_host structure
*
- * returns Success/Failure
*/
-static int beiscsi_get_port_speed(struct Scsi_Host *shost)
+static void beiscsi_get_port_speed(struct Scsi_Host *shost)
{
- int rc;
- unsigned int tag;
- struct be_mcc_wrb *wrb;
- struct be_cmd_ntwk_link_status_resp *resp;
struct beiscsi_hba *phba = iscsi_host_priv(shost);
struct iscsi_cls_host *ihost = shost->shost_data;
- tag = be_cmd_get_port_speed(phba);
- if (!tag) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Getting Port Speed Failed\n");
-
- return -EBUSY;
- }
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
- if (rc) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BS_%d : Port Speed MBX Failed\n");
- return rc;
- }
- resp = embedded_payload(wrb);
-
- switch (resp->mac_speed) {
+ switch (phba->port_speed) {
case BE2ISCSI_LINK_SPEED_10MBPS:
ihost->port_speed = ISCSI_PORT_SPEED_10MBPS;
break;
@@ -801,10 +785,15 @@ static int beiscsi_get_port_speed(struct Scsi_Host *shost)
case BE2ISCSI_LINK_SPEED_10GBPS:
ihost->port_speed = ISCSI_PORT_SPEED_10GBPS;
break;
+ case BE2ISCSI_LINK_SPEED_25GBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_25GBPS;
+ break;
+ case BE2ISCSI_LINK_SPEED_40GBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_40GBPS;
+ break;
default:
ihost->port_speed = ISCSI_PORT_SPEED_UNKNOWN;
}
- return 0;
}
/**
@@ -854,12 +843,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
status = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
break;
case ISCSI_HOST_PARAM_PORT_SPEED:
- status = beiscsi_get_port_speed(shost);
- if (status) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Retreiving Port Speed Failed\n");
- return status;
- }
+ beiscsi_get_port_speed(shost);
status = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
break;
default:
@@ -1159,7 +1143,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
return -EAGAIN;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ ret = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
if (ret) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
@@ -1293,7 +1277,7 @@ static void beiscsi_flush_cq(struct beiscsi_hba *phba)
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
irq_poll_disable(&pbe_eq->iopoll);
- beiscsi_process_cq(pbe_eq);
+ beiscsi_process_cq(pbe_eq, BE2_MAX_NUM_CQ_PROC);
irq_poll_enable(&pbe_eq->iopoll);
}
}
@@ -1318,7 +1302,7 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag)
ret = -EAGAIN;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ ret = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
/* Flush the CQ entries */
beiscsi_flush_cq(phba);
@@ -1393,7 +1377,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
beiscsi_ep->ep_cid);
}
- beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
beiscsi_close_conn(beiscsi_ep, tcp_upload_flag);
free_ep:
msleep(BEISCSI_LOGOUT_SYNC_DELAY);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index cb9072a841be..f05e7737107d 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -29,6 +29,7 @@
#include <linux/iscsi_boot_sysfs.h>
#include <linux/module.h>
#include <linux/bsg-lib.h>
+#include <linux/irq_poll.h>
#include <scsi/libiscsi.h>
#include <scsi/scsi_bsg_iscsi.h>
@@ -285,7 +286,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
return FAILED;
}
- rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
if (rc != -EBUSY)
pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
@@ -366,7 +367,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
return FAILED;
}
- rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
if (rc != -EBUSY)
pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
@@ -727,9 +728,8 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
- spin_lock_init(&ctrl->mbox_lock);
+ mutex_init(&ctrl->mbox_lock);
spin_lock_init(&phba->ctrl.mcc_lock);
- spin_lock_init(&phba->ctrl.mcc_cq_lock);
return status;
}
@@ -895,31 +895,17 @@ static irqreturn_t be_isr_mcc(int irq, void *dev_id)
static irqreturn_t be_isr_msix(int irq, void *dev_id)
{
struct beiscsi_hba *phba;
- struct be_eq_entry *eqe = NULL;
struct be_queue_info *eq;
- struct be_queue_info *cq;
- unsigned int num_eq_processed;
struct be_eq_obj *pbe_eq;
pbe_eq = dev_id;
eq = &pbe_eq->q;
- cq = pbe_eq->cq;
- eqe = queue_tail_node(eq);
phba = pbe_eq->phba;
- num_eq_processed = 0;
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
- irq_poll_sched(&pbe_eq->iopoll);
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
- num_eq_processed++;
- }
-
- if (num_eq_processed)
- hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1);
+ /* disable interrupt till iopoll completes */
+ hwi_ring_eq_db(phba, eq->id, 1, 0, 0, 1);
+ irq_poll_sched(&pbe_eq->iopoll);
return IRQ_HANDLED;
}
@@ -996,6 +982,7 @@ static irqreturn_t be_isr(int irq, void *dev_id)
return IRQ_NONE;
}
+
static int beiscsi_init_irqs(struct beiscsi_hba *phba)
{
struct pci_dev *pcidev = phba->pcidev;
@@ -1070,7 +1057,7 @@ free_msix_irqs:
void hwi_ring_cq_db(struct beiscsi_hba *phba,
unsigned int id, unsigned int num_processed,
- unsigned char rearm, unsigned char event)
+ unsigned char rearm)
{
u32 val = 0;
@@ -1145,6 +1132,7 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
{
struct sgl_handle *psgl_handle;
+ spin_lock_bh(&phba->io_sgl_lock);
if (phba->io_sgl_hndl_avbl) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO,
"BM_%d : In alloc_io_sgl_handle,"
@@ -1162,12 +1150,14 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
phba->io_sgl_alloc_index++;
} else
psgl_handle = NULL;
+ spin_unlock_bh(&phba->io_sgl_lock);
return psgl_handle;
}
static void
free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
{
+ spin_lock_bh(&phba->io_sgl_lock);
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO,
"BM_%d : In free_,io_sgl_free_index=%d\n",
phba->io_sgl_free_index);
@@ -1182,6 +1172,7 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
"value there=%p\n", phba->io_sgl_free_index,
phba->io_sgl_hndl_base
[phba->io_sgl_free_index]);
+ spin_unlock_bh(&phba->io_sgl_lock);
return;
}
phba->io_sgl_hndl_base[phba->io_sgl_free_index] = psgl_handle;
@@ -1190,6 +1181,25 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
phba->io_sgl_free_index = 0;
else
phba->io_sgl_free_index++;
+ spin_unlock_bh(&phba->io_sgl_lock);
+}
+
+static inline struct wrb_handle *
+beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context,
+ unsigned int wrbs_per_cxn)
+{
+ struct wrb_handle *pwrb_handle;
+
+ spin_lock_bh(&pwrb_context->wrb_lock);
+ pwrb_handle = pwrb_context->pwrb_handle_base[pwrb_context->alloc_index];
+ pwrb_context->wrb_handles_available--;
+ if (pwrb_context->alloc_index == (wrbs_per_cxn - 1))
+ pwrb_context->alloc_index = 0;
+ else
+ pwrb_context->alloc_index++;
+ spin_unlock_bh(&pwrb_context->wrb_lock);
+
+ return pwrb_handle;
}
/**
@@ -1201,30 +1211,32 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
* This happens under session_lock until submission to chip
*/
struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
- struct hwi_wrb_context **pcontext)
+ struct hwi_wrb_context **pcontext)
{
struct hwi_wrb_context *pwrb_context;
struct hwi_controller *phwi_ctrlr;
- struct wrb_handle *pwrb_handle;
uint16_t cri_index = BE_GET_CRI_FROM_CID(cid);
phwi_ctrlr = phba->phwi_ctrlr;
pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
- if (pwrb_context->wrb_handles_available >= 2) {
- pwrb_handle = pwrb_context->pwrb_handle_base[
- pwrb_context->alloc_index];
- pwrb_context->wrb_handles_available--;
- if (pwrb_context->alloc_index ==
- (phba->params.wrbs_per_cxn - 1))
- pwrb_context->alloc_index = 0;
- else
- pwrb_context->alloc_index++;
+ /* return the context address */
+ *pcontext = pwrb_context;
+ return beiscsi_get_wrb_handle(pwrb_context, phba->params.wrbs_per_cxn);
+}
- /* Return the context address */
- *pcontext = pwrb_context;
- } else
- pwrb_handle = NULL;
- return pwrb_handle;
+static inline void
+beiscsi_put_wrb_handle(struct hwi_wrb_context *pwrb_context,
+ struct wrb_handle *pwrb_handle,
+ unsigned int wrbs_per_cxn)
+{
+ spin_lock_bh(&pwrb_context->wrb_lock);
+ pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle;
+ pwrb_context->wrb_handles_available++;
+ if (pwrb_context->free_index == (wrbs_per_cxn - 1))
+ pwrb_context->free_index = 0;
+ else
+ pwrb_context->free_index++;
+ spin_unlock_bh(&pwrb_context->wrb_lock);
}
/**
@@ -1239,13 +1251,9 @@ static void
free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
struct wrb_handle *pwrb_handle)
{
- pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle;
- pwrb_context->wrb_handles_available++;
- if (pwrb_context->free_index == (phba->params.wrbs_per_cxn - 1))
- pwrb_context->free_index = 0;
- else
- pwrb_context->free_index++;
-
+ beiscsi_put_wrb_handle(pwrb_context,
+ pwrb_handle,
+ phba->params.wrbs_per_cxn);
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
"BM_%d : FREE WRB: pwrb_handle=%p free_index=0x%x"
@@ -1258,6 +1266,7 @@ static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
{
struct sgl_handle *psgl_handle;
+ spin_lock_bh(&phba->mgmt_sgl_lock);
if (phba->eh_sgl_hndl_avbl) {
psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index];
phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL;
@@ -1275,13 +1284,14 @@ static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
phba->eh_sgl_alloc_index++;
} else
psgl_handle = NULL;
+ spin_unlock_bh(&phba->mgmt_sgl_lock);
return psgl_handle;
}
void
free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
{
-
+ spin_lock_bh(&phba->mgmt_sgl_lock);
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BM_%d : In free_mgmt_sgl_handle,"
"eh_sgl_free_index=%d\n",
@@ -1296,6 +1306,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
"BM_%d : Double Free in eh SGL ,"
"eh_sgl_free_index=%d\n",
phba->eh_sgl_free_index);
+ spin_unlock_bh(&phba->mgmt_sgl_lock);
return;
}
phba->eh_sgl_hndl_base[phba->eh_sgl_free_index] = psgl_handle;
@@ -1305,6 +1316,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
phba->eh_sgl_free_index = 0;
else
phba->eh_sgl_free_index++;
+ spin_unlock_bh(&phba->mgmt_sgl_lock);
}
static void
@@ -2029,7 +2041,7 @@ static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn,
phwi_ctrlr, cri_index));
}
-static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba)
+void beiscsi_process_mcc_cq(struct beiscsi_hba *phba)
{
struct be_queue_info *mcc_cq;
struct be_mcc_compl *mcc_compl;
@@ -2039,31 +2051,15 @@ static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba)
mcc_compl = queue_tail_node(mcc_cq);
mcc_compl->flags = le32_to_cpu(mcc_compl->flags);
while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) {
-
if (num_processed >= 32) {
hwi_ring_cq_db(phba, mcc_cq->id,
- num_processed, 0, 0);
+ num_processed, 0);
num_processed = 0;
}
if (mcc_compl->flags & CQE_FLAGS_ASYNC_MASK) {
- /* Interpret flags as an async trailer */
- if (is_link_state_evt(mcc_compl->flags))
- /* Interpret compl as a async link evt */
- beiscsi_async_link_state_process(phba,
- (struct be_async_event_link_state *) mcc_compl);
- else {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_MBOX,
- "BM_%d : Unsupported Async Event, flags"
- " = 0x%08x\n",
- mcc_compl->flags);
- if (phba->state & BE_ADAPTER_LINK_UP) {
- phba->state |= BE_ADAPTER_CHECK_BOOT;
- phba->get_boot = BE_GET_BOOT_RETRIES;
- }
- }
+ beiscsi_process_async_event(phba, mcc_compl);
} else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) {
- be_mcc_compl_process_isr(&phba->ctrl, mcc_compl);
- atomic_dec(&phba->ctrl.mcc_obj.q.used);
+ beiscsi_process_mcc_compl(&phba->ctrl, mcc_compl);
}
mcc_compl->flags = 0;
@@ -2074,24 +2070,24 @@ static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba)
}
if (num_processed > 0)
- hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1, 0);
-
+ hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1);
}
/**
* beiscsi_process_cq()- Process the Completion Queue
* @pbe_eq: Event Q on which the Completion has come
+ * @budget: Max number of events to processed
*
* return
* Number of Completion Entries processed.
**/
-unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
+unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
{
struct be_queue_info *cq;
struct sol_cqe *sol;
struct dmsg_cqe *dmsg;
+ unsigned int total = 0;
unsigned int num_processed = 0;
- unsigned int tot_nump = 0;
unsigned short code = 0, cid = 0;
uint16_t cri_index = 0;
struct beiscsi_conn *beiscsi_conn;
@@ -2142,12 +2138,12 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
beiscsi_ep = ep->dd_data;
beiscsi_conn = beiscsi_ep->conn;
- if (num_processed >= 32) {
- hwi_ring_cq_db(phba, cq->id,
- num_processed, 0, 0);
- tot_nump += num_processed;
+ /* replenish cq */
+ if (num_processed == 32) {
+ hwi_ring_cq_db(phba, cq->id, 32, 0);
num_processed = 0;
}
+ total++;
switch (code) {
case SOL_CMD_COMPLETE:
@@ -2192,7 +2188,13 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
"BM_%d : Ignoring %s[%d] on CID : %d\n",
cqe_desc[code], code, cid);
break;
+ case CXN_KILLED_HDR_DIGEST_ERR:
case SOL_CMD_KILLED_DATA_DIGEST_ERR:
+ beiscsi_log(phba, KERN_ERR,
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
+ "BM_%d : Cmd Notification %s[%d] on CID : %d\n",
+ cqe_desc[code], code, cid);
+ break;
case CMD_KILLED_INVALID_STATSN_RCVD:
case CMD_KILLED_INVALID_R2T_RCVD:
case CMD_CXN_KILLED_LUN_INVALID:
@@ -2218,7 +2220,6 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
case CXN_KILLED_PDU_SIZE_EXCEEDS_DSL:
case CXN_KILLED_BURST_LEN_MISMATCH:
case CXN_KILLED_AHS_RCVD:
- case CXN_KILLED_HDR_DIGEST_ERR:
case CXN_KILLED_UNKNOWN_HDR:
case CXN_KILLED_STALE_ITT_TTT_RCVD:
case CXN_KILLED_INVALID_ITT_TTT_RCVD:
@@ -2253,13 +2254,12 @@ proc_next_cqe:
queue_tail_inc(cq);
sol = queue_tail_node(cq);
num_processed++;
+ if (total == budget)
+ break;
}
- if (num_processed > 0) {
- tot_nump += num_processed;
- hwi_ring_cq_db(phba, cq->id, num_processed, 1, 0);
- }
- return tot_nump;
+ hwi_ring_cq_db(phba, cq->id, num_processed, 1);
+ return total;
}
void beiscsi_process_all_cqs(struct work_struct *work)
@@ -2279,14 +2279,14 @@ void beiscsi_process_all_cqs(struct work_struct *work)
spin_lock_irqsave(&phba->isr_lock, flags);
pbe_eq->todo_mcc_cq = false;
spin_unlock_irqrestore(&phba->isr_lock, flags);
- beiscsi_process_mcc_isr(phba);
+ beiscsi_process_mcc_cq(phba);
}
if (pbe_eq->todo_cq) {
spin_lock_irqsave(&phba->isr_lock, flags);
pbe_eq->todo_cq = false;
spin_unlock_irqrestore(&phba->isr_lock, flags);
- beiscsi_process_cq(pbe_eq);
+ beiscsi_process_cq(pbe_eq, BE2_MAX_NUM_CQ_PROC);
}
/* rearm EQ for further interrupts */
@@ -2295,20 +2295,36 @@ void beiscsi_process_all_cqs(struct work_struct *work)
static int be_iopoll(struct irq_poll *iop, int budget)
{
- unsigned int ret;
+ unsigned int ret, num_eq_processed;
struct beiscsi_hba *phba;
struct be_eq_obj *pbe_eq;
+ struct be_eq_entry *eqe = NULL;
+ struct be_queue_info *eq;
+ num_eq_processed = 0;
pbe_eq = container_of(iop, struct be_eq_obj, iopoll);
- ret = beiscsi_process_cq(pbe_eq);
+ phba = pbe_eq->phba;
+ eq = &pbe_eq->q;
+ eqe = queue_tail_node(eq);
+
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] &
+ EQE_VALID_MASK) {
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
+ }
+
+ hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1);
+
+ ret = beiscsi_process_cq(pbe_eq, budget);
pbe_eq->cq_count += ret;
if (ret < budget) {
- phba = pbe_eq->phba;
irq_poll_complete(iop);
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
- "BM_%d : rearm pbe_eq->q.id =%d\n",
- pbe_eq->q.id);
+ "BM_%d : rearm pbe_eq->q.id =%d ret %d\n",
+ pbe_eq->q.id, ret);
hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
}
return ret;
@@ -2502,7 +2518,7 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
* @pwrb: ptr to the WRB entry
* @task: iscsi task which is to be executed
**/
-static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
+static int hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
{
struct iscsi_sge *psgl;
struct beiscsi_io_task *io_task = task->dd_data;
@@ -2534,6 +2550,9 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
task->data,
task->data_count,
PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(phba->pcidev,
+ io_task->mtask_addr))
+ return -ENOMEM;
io_task->mtask_data_count = task->data_count;
} else
io_task->mtask_addr = 0;
@@ -2578,6 +2597,7 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106);
}
AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1);
+ return 0;
}
/**
@@ -2706,8 +2726,10 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba)
phwi_ctrlr->wrb_context = kzalloc(sizeof(struct hwi_wrb_context) *
phba->params.cxns_per_ctrl,
GFP_KERNEL);
- if (!phwi_ctrlr->wrb_context)
+ if (!phwi_ctrlr->wrb_context) {
+ kfree(phba->phwi_ctrlr);
return -ENOMEM;
+ }
phba->init_mem = kcalloc(SE_MEM_MAX, sizeof(*mem_descr),
GFP_KERNEL);
@@ -2904,6 +2926,7 @@ static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
}
num_cxn_wrbh--;
}
+ spin_lock_init(&pwrb_context->wrb_lock);
}
idx = 0;
for (index = 0; index < phba->params.cxns_per_ctrl; index++) {
@@ -3866,6 +3889,8 @@ static int hwi_init_port(struct beiscsi_hba *phba)
phwi_context->min_eqd = 0;
phwi_context->cur_eqd = 0;
be_cmd_fw_initialize(&phba->ctrl);
+ /* set optic state to unknown */
+ phba->optic_state = 0xff;
status = beiscsi_create_eqs(phba, phwi_context);
if (status != 0) {
@@ -4384,7 +4409,7 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
goto boot_freemem;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ ret = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
if (ret) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
@@ -4468,6 +4493,7 @@ put_shost:
scsi_host_put(phba->shost);
free_kset:
iscsi_boot_destroy_kset(phba->boot_kset);
+ phba->boot_kset = NULL;
return -ENOMEM;
}
@@ -4607,11 +4633,9 @@ beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn,
}
if (io_task->psgl_handle) {
- spin_lock_bh(&phba->mgmt_sgl_lock);
free_mgmt_sgl_handle(phba,
io_task->psgl_handle);
io_task->psgl_handle = NULL;
- spin_unlock_bh(&phba->mgmt_sgl_lock);
}
if (io_task->mtask_addr) {
@@ -4657,9 +4681,7 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
}
if (io_task->psgl_handle) {
- spin_lock(&phba->io_sgl_lock);
free_io_sgl_handle(phba, io_task->psgl_handle);
- spin_unlock(&phba->io_sgl_lock);
io_task->psgl_handle = NULL;
}
@@ -4714,6 +4736,20 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
iowrite32(doorbell, phba->db_va +
beiscsi_conn->doorbell_offset);
+
+ /*
+ * There is no completion for CONTEXT_UPDATE. The completion of next
+ * WRB posted guarantees FW's processing and DMA'ing of it.
+ * Use beiscsi_put_wrb_handle to put it back in the pool which makes
+ * sure zero'ing or reuse of the WRB only after wrbs_per_cxn.
+ */
+ beiscsi_put_wrb_handle(pwrb_context, pwrb_handle,
+ phba->params.wrbs_per_cxn);
+ beiscsi_log(phba, KERN_INFO,
+ BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
+ "BM_%d : put CONTEXT_UPDATE pwrb_handle=%p free_index=0x%x wrb_handles_available=%d\n",
+ pwrb_handle, pwrb_context->free_index,
+ pwrb_context->wrb_handles_available);
}
static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt,
@@ -4761,9 +4797,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
io_task->pwrb_handle = NULL;
if (task->sc) {
- spin_lock(&phba->io_sgl_lock);
io_task->psgl_handle = alloc_io_sgl_handle(phba);
- spin_unlock(&phba->io_sgl_lock);
if (!io_task->psgl_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
@@ -4788,10 +4822,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
beiscsi_conn->task = task;
if (!beiscsi_conn->login_in_progress) {
- spin_lock(&phba->mgmt_sgl_lock);
io_task->psgl_handle = (struct sgl_handle *)
alloc_mgmt_sgl_handle(phba);
- spin_unlock(&phba->mgmt_sgl_lock);
if (!io_task->psgl_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO |
@@ -4830,9 +4862,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
beiscsi_conn->plogin_wrb_handle;
}
} else {
- spin_lock(&phba->mgmt_sgl_lock);
io_task->psgl_handle = alloc_mgmt_sgl_handle(phba);
- spin_unlock(&phba->mgmt_sgl_lock);
if (!io_task->psgl_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO |
@@ -4867,15 +4897,11 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
return 0;
free_io_hndls:
- spin_lock(&phba->io_sgl_lock);
free_io_sgl_handle(phba, io_task->psgl_handle);
- spin_unlock(&phba->io_sgl_lock);
goto free_hndls;
free_mgmt_hndls:
- spin_lock(&phba->mgmt_sgl_lock);
free_mgmt_sgl_handle(phba, io_task->psgl_handle);
io_task->psgl_handle = NULL;
- spin_unlock(&phba->mgmt_sgl_lock);
free_hndls:
phwi_ctrlr = phba->phwi_ctrlr;
cri_index = BE_GET_CRI_FROM_CID(
@@ -4903,7 +4929,6 @@ int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg,
pwrb = io_task->pwrb_handle->pwrb;
- io_task->cmd_bhs->iscsi_hdr.exp_statsn = 0;
io_task->bhs_len = sizeof(struct be_cmd_bhs);
if (writedir) {
@@ -4964,7 +4989,6 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
unsigned int doorbell = 0;
pwrb = io_task->pwrb_handle->pwrb;
- io_task->cmd_bhs->iscsi_hdr.exp_statsn = 0;
io_task->bhs_len = sizeof(struct be_cmd_bhs);
if (writedir) {
@@ -5023,6 +5047,7 @@ static int beiscsi_mtask(struct iscsi_task *task)
unsigned int doorbell = 0;
unsigned int cid;
unsigned int pwrb_typeoffset = 0;
+ int ret = 0;
cid = beiscsi_conn->beiscsi_conn_cid;
pwrb = io_task->pwrb_handle->pwrb;
@@ -5071,7 +5096,7 @@ static int beiscsi_mtask(struct iscsi_task *task)
case ISCSI_OP_LOGIN:
AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1);
ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset);
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_NOOP_OUT:
if (task->hdr->ttt != ISCSI_RESERVED_TAG) {
@@ -5091,19 +5116,19 @@ static int beiscsi_mtask(struct iscsi_task *task)
AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
dmsg, pwrb, 0);
}
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_TEXT:
ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset);
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_SCSI_TMFUNC:
ADAPTER_SET_WRB_TYPE(pwrb, INI_TMF_CMD, pwrb_typeoffset);
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_LOGOUT:
ADAPTER_SET_WRB_TYPE(pwrb, HWH_TYPE_LOGOUT, pwrb_typeoffset);
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
default:
@@ -5114,6 +5139,9 @@ static int beiscsi_mtask(struct iscsi_task *task)
return -EINVAL;
}
+ if (ret)
+ return ret;
+
/* Set the task type */
io_task->wrb_type = (is_chip_be2_be3r(phba)) ?
AMAP_GET_BITS(struct amap_iscsi_wrb, type, pwrb) :
@@ -5132,23 +5160,21 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
{
struct beiscsi_io_task *io_task = task->dd_data;
struct scsi_cmnd *sc = task->sc;
- struct beiscsi_hba *phba = NULL;
+ struct beiscsi_hba *phba;
struct scatterlist *sg;
int num_sg;
unsigned int writedir = 0, xferlen = 0;
- phba = ((struct beiscsi_conn *)task->conn->dd_data)->phba;
+ if (!io_task->conn->login_in_progress)
+ task->hdr->exp_statsn = 0;
if (!sc)
return beiscsi_mtask(task);
io_task->scsi_cmnd = sc;
num_sg = scsi_dma_map(sc);
+ phba = io_task->conn->phba;
if (num_sg < 0) {
- struct iscsi_conn *conn = task->conn;
- struct beiscsi_hba *phba = NULL;
-
- phba = ((struct beiscsi_conn *)conn->dd_data)->phba;
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_ISCSI,
"BM_%d : scsi_dma_map Failed "
@@ -5211,12 +5237,13 @@ static int beiscsi_bsg_request(struct bsg_job *job)
rc = wait_event_interruptible_timeout(
phba->ctrl.mcc_wait[tag],
- phba->ctrl.mcc_numtag[tag],
+ phba->ctrl.mcc_tag_status[tag],
msecs_to_jiffies(
BEISCSI_HOST_MBX_TIMEOUT));
- extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
- status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
- free_mcc_tag(&phba->ctrl, tag);
+ extd_status = (phba->ctrl.mcc_tag_status[tag] &
+ CQE_STATUS_ADDL_MASK) >> CQE_STATUS_ADDL_SHIFT;
+ status = phba->ctrl.mcc_tag_status[tag] & CQE_STATUS_MASK;
+ free_mcc_wrb(&phba->ctrl, tag);
resp = (struct be_cmd_resp_hdr *)nonemb_cmd.va;
sg_copy_from_buffer(job->reply_payload.sg_list,
job->reply_payload.sg_cnt,
@@ -5277,15 +5304,12 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba,
if (phba->msix_enabled) {
for (i = 0; i <= phba->num_cpus; i++) {
msix_vec = phba->msix_entries[i].vector;
- synchronize_irq(msix_vec);
free_irq(msix_vec, &phwi_context->be_eq[i]);
kfree(phba->msi_name[i]);
}
} else
- if (phba->pcidev->irq) {
- synchronize_irq(phba->pcidev->irq);
+ if (phba->pcidev->irq)
free_irq(phba->pcidev->irq, phba);
- }
pci_disable_msix(phba->pcidev);
cancel_delayed_work_sync(&phba->beiscsi_hw_check_task);
@@ -5313,7 +5337,6 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba,
static void beiscsi_remove(struct pci_dev *pcidev)
{
-
struct beiscsi_hba *phba = NULL;
phba = pci_get_drvdata(pcidev);
@@ -5323,9 +5346,9 @@ static void beiscsi_remove(struct pci_dev *pcidev)
}
beiscsi_destroy_def_ifaces(phba);
- beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
iscsi_boot_destroy_kset(phba->boot_kset);
iscsi_host_remove(phba->shost);
+ beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
pci_dev_put(phba->pcidev);
iscsi_host_free(phba->shost);
pci_disable_pcie_error_reporting(pcidev);
@@ -5334,23 +5357,6 @@ static void beiscsi_remove(struct pci_dev *pcidev)
pci_disable_device(pcidev);
}
-static void beiscsi_shutdown(struct pci_dev *pcidev)
-{
-
- struct beiscsi_hba *phba = NULL;
-
- phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev);
- if (!phba) {
- dev_err(&pcidev->dev, "beiscsi_shutdown called with no phba\n");
- return;
- }
-
- phba->state = BE_ADAPTER_STATE_SHUTDOWN;
- iscsi_host_for_each_session(phba->shost, be2iscsi_fail_session);
- beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
- pci_disable_device(pcidev);
-}
-
static void beiscsi_msix_enable(struct beiscsi_hba *phba)
{
int i, status;
@@ -5413,7 +5419,7 @@ static void be_eqd_update(struct beiscsi_hba *phba)
if (num) {
tag = be_cmd_modify_eq_delay(phba, set_eqd, num);
if (tag)
- beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
}
}
@@ -5564,11 +5570,17 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
phba->shost->max_id = phba->params.cxns_per_ctrl;
phba->shost->can_queue = phba->params.ios_per_ctrl;
ret = hwi_init_controller(phba);
+ if (ret) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BM_%d : beiscsi_eeh_resume -"
+ "Failed to initialize beiscsi_hba.\n");
+ goto ret_err;
+ }
for (i = 0; i < MAX_MCC_CMD; i++) {
init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]);
phba->ctrl.mcc_tag[i] = i + 1;
- phba->ctrl.mcc_numtag[i + 1] = 0;
+ phba->ctrl.mcc_tag_status[i + 1] = 0;
phba->ctrl.mcc_tag_available++;
}
@@ -5670,6 +5682,9 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
goto hba_free;
}
+ /*
+ * FUNCTION_RESET should clean up any stale info in FW for this fn
+ */
ret = beiscsi_cmd_reset_function(phba);
if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
@@ -5693,6 +5708,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
"BM_%d : Error getting fw config\n");
goto free_port;
}
+ mgmt_get_port_name(&phba->ctrl, phba);
+ beiscsi_get_params(phba);
if (enable_msix)
find_num_cpus(phba);
@@ -5710,7 +5727,6 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
}
phba->shost->max_id = phba->params.cxns_per_ctrl;
- beiscsi_get_params(phba);
phba->shost->can_queue = phba->params.ios_per_ctrl;
ret = beiscsi_init_port(phba);
if (ret < 0) {
@@ -5723,7 +5739,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
for (i = 0; i < MAX_MCC_CMD; i++) {
init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]);
phba->ctrl.mcc_tag[i] = i + 1;
- phba->ctrl.mcc_numtag[i + 1] = 0;
+ phba->ctrl.mcc_tag_status[i + 1] = 0;
phba->ctrl.mcc_tag_available++;
memset(&phba->ctrl.ptag_state[i].tag_mem_state, 0,
sizeof(struct be_dma_mem));
@@ -5857,7 +5873,6 @@ static struct pci_driver beiscsi_pci_driver = {
.name = DRV_NAME,
.probe = beiscsi_dev_probe,
.remove = beiscsi_remove,
- .shutdown = beiscsi_shutdown,
.id_table = beiscsi_pci_id_table,
.err_handler = &beiscsi_eeh_handlers
};
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 5c67c0732241..30a4606d9a3b 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -36,7 +36,7 @@
#include <scsi/scsi_transport_iscsi.h>
#define DRV_NAME "be2iscsi"
-#define BUILD_STR "10.6.0.1"
+#define BUILD_STR "11.0.0.0"
#define BE_NAME "Emulex OneConnect" \
"Open-iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
@@ -63,6 +63,7 @@
#define BE2_SGE 32
#define BE2_DEFPDU_HDR_SZ 64
#define BE2_DEFPDU_DATA_SZ 8192
+#define BE2_MAX_NUM_CQ_PROC 512
#define MAX_CPUS 64
#define BEISCSI_MAX_NUM_CPUS 7
@@ -103,8 +104,7 @@
#define BE_ADAPTER_LINK_UP 0x001
#define BE_ADAPTER_LINK_DOWN 0x002
#define BE_ADAPTER_PCI_ERR 0x004
-#define BE_ADAPTER_STATE_SHUTDOWN 0x008
-#define BE_ADAPTER_CHECK_BOOT 0x010
+#define BE_ADAPTER_CHECK_BOOT 0x008
#define BEISCSI_CLEAN_UNLOAD 0x01
@@ -304,6 +304,7 @@ struct invalidate_command_table {
#define BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cri) \
(phwi_ctrlr->wrb_context[cri].ulp_num)
struct hwi_wrb_context {
+ spinlock_t wrb_lock;
struct list_head wrb_handle_list;
struct list_head wrb_handle_drvr_list;
struct wrb_handle **pwrb_handle_base;
@@ -398,7 +399,9 @@ struct beiscsi_hba {
* group together since they are used most frequently
* for cid to cri conversion
*/
+#define BEISCSI_PHYS_PORT_MAX 4
unsigned int phys_port;
+ /* valid values of phys_port id are 0, 1, 2, 3 */
unsigned int eqid_count;
unsigned int cqid_count;
unsigned int iscsi_cid_start[BEISCSI_ULP_COUNT];
@@ -416,6 +419,7 @@ struct beiscsi_hba {
} fw_config;
unsigned int state;
+ u8 optic_state;
int get_boot;
bool fw_timeout;
bool ue_detected;
@@ -423,6 +427,8 @@ struct beiscsi_hba {
bool mac_addr_set;
u8 mac_address[ETH_ALEN];
+ u8 port_name;
+ u8 port_speed;
char fw_ver_str[BEISCSI_VER_STRLEN];
char wq_name[20];
struct workqueue_struct *wq; /* The actuak work queue */
@@ -845,9 +851,10 @@ void beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn,
void hwi_ring_cq_db(struct beiscsi_hba *phba,
unsigned int id, unsigned int num_processed,
- unsigned char rearm, unsigned char event);
+ unsigned char rearm);
-unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq);
+unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget);
+void beiscsi_process_mcc_cq(struct beiscsi_hba *phba);
static inline bool beiscsi_error(struct beiscsi_hba *phba)
{
@@ -1074,12 +1081,14 @@ struct hwi_context_memory {
#define BEISCSI_LOG_CONFIG 0x0020 /* CONFIG Code Path */
#define BEISCSI_LOG_ISCSI 0x0040 /* SCSI/iSCSI Protocol related Logs */
+#define __beiscsi_log(phba, level, fmt, arg...) \
+ shost_printk(level, phba->shost, fmt, __LINE__, ##arg)
+
#define beiscsi_log(phba, level, mask, fmt, arg...) \
do { \
uint32_t log_value = phba->attr_log_enable; \
if (((mask) & log_value) || (level[1] <= '3')) \
- shost_printk(level, phba->shost, \
- fmt, __LINE__, ##arg); \
-} while (0)
+ __beiscsi_log(phba, level, fmt, ##arg); \
+} while (0);
#endif
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index aea3e6b9477d..83926e221f1e 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -161,20 +161,17 @@ int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
struct be_cmd_req_modify_eq_delay *req;
- unsigned int tag = 0;
+ unsigned int tag;
int i;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
-
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req));
@@ -187,8 +184,8 @@ int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
cpu_to_le32(set_eqd[i].delay_multiplier);
}
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -209,22 +206,20 @@ unsigned int mgmt_reopen_session(struct beiscsi_hba *phba,
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
struct be_cmd_reopen_session_req *req;
- unsigned int tag = 0;
+ unsigned int tag;
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : In bescsi_get_boot_target\n");
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS,
@@ -234,8 +229,8 @@ unsigned int mgmt_reopen_session(struct beiscsi_hba *phba,
req->reopen_type = reopen_type;
req->session_handle = sess_handle;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -244,29 +239,27 @@ unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba)
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
struct be_cmd_get_boot_target_req *req;
- unsigned int tag = 0;
+ unsigned int tag;
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : In bescsi_get_boot_target\n");
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET,
sizeof(struct be_cmd_get_boot_target_resp));
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -276,7 +269,7 @@ unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
{
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
- unsigned int tag = 0;
+ unsigned int tag;
struct be_cmd_get_session_req *req;
struct be_cmd_get_session_resp *resp;
struct be_sge *sge;
@@ -285,22 +278,17 @@ unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : In beiscsi_get_session_info\n");
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
nonemb_cmd->size = sizeof(*resp);
req = nonemb_cmd->va;
memset(req, 0, sizeof(*req));
- wrb = wrb_from_mccq(phba);
sge = nonembedded_sgl(wrb);
- wrb->tag0 |= tag;
-
-
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_SESSION_GET_A_SESSION,
@@ -310,12 +298,54 @@ unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(nonemb_cmd->size);
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
/**
+ * mgmt_get_port_name()- Get port name for the function
+ * @ctrl: ptr to Ctrl Info
+ * @phba: ptr to the dev priv structure
+ *
+ * Get the alphanumeric character for port
+ *
+ **/
+int mgmt_get_port_name(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba)
+{
+ int ret = 0;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_get_port_name *ioctl;
+
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ memset(wrb, 0, sizeof(*wrb));
+ ioctl = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*ioctl), true, 0);
+ be_cmd_hdr_prepare(&ioctl->h.req_hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_PORT_NAME,
+ EMBED_MBX_MAX_PAYLOAD_SIZE);
+ ret = be_mbox_notify(ctrl);
+ phba->port_name = 0;
+ if (!ret) {
+ phba->port_name = ioctl->p.resp.port_names >>
+ (phba->fw_config.phys_port * 8) & 0xff;
+ } else {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : GET_PORT_NAME ret 0x%x status 0x%x\n",
+ ret, ioctl->h.resp_hdr.status);
+ }
+
+ if (phba->port_name == 0)
+ phba->port_name = '?';
+
+ mutex_unlock(&ctrl->mbox_lock);
+ return ret;
+}
+
+/**
* mgmt_get_fw_config()- Get the FW config for the function
* @ctrl: ptr to Ctrl Info
* @phba: ptr to the dev priv structure
@@ -331,91 +361,147 @@ int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba)
{
struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
- struct be_fw_cfg *req = embedded_payload(wrb);
- int status = 0;
+ struct be_fw_cfg *pfw_cfg = embedded_payload(wrb);
+ uint32_t cid_count, icd_count;
+ int status = -EINVAL;
+ uint8_t ulp_num = 0;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*pfw_cfg), true, 0);
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
-
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ be_cmd_hdr_prepare(&pfw_cfg->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_QUERY_FIRMWARE_CONFIG,
EMBED_MBX_MAX_PAYLOAD_SIZE);
- status = be_mbox_notify(ctrl);
- if (!status) {
- uint8_t ulp_num = 0;
- struct be_fw_cfg *pfw_cfg;
- pfw_cfg = req;
- if (!is_chip_be2_be3r(phba)) {
- phba->fw_config.eqid_count = pfw_cfg->eqid_count;
- phba->fw_config.cqid_count = pfw_cfg->cqid_count;
+ if (be_mbox_notify(ctrl)) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : Failed in mgmt_get_fw_config\n");
+ goto fail_init;
+ }
- beiscsi_log(phba, KERN_INFO,
- BEISCSI_LOG_INIT,
- "BG_%d : EQ_Count : %d CQ_Count : %d\n",
- phba->fw_config.eqid_count,
+ /* FW response formats depend on port id */
+ phba->fw_config.phys_port = pfw_cfg->phys_port;
+ if (phba->fw_config.phys_port >= BEISCSI_PHYS_PORT_MAX) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : invalid physical port id %d\n",
+ phba->fw_config.phys_port);
+ goto fail_init;
+ }
+
+ /* populate and check FW config against min and max values */
+ if (!is_chip_be2_be3r(phba)) {
+ phba->fw_config.eqid_count = pfw_cfg->eqid_count;
+ phba->fw_config.cqid_count = pfw_cfg->cqid_count;
+ if (phba->fw_config.eqid_count == 0 ||
+ phba->fw_config.eqid_count > 2048) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : invalid EQ count %d\n",
+ phba->fw_config.eqid_count);
+ goto fail_init;
+ }
+ if (phba->fw_config.cqid_count == 0 ||
+ phba->fw_config.cqid_count > 4096) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : invalid CQ count %d\n",
phba->fw_config.cqid_count);
+ goto fail_init;
}
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : EQ_Count : %d CQ_Count : %d\n",
+ phba->fw_config.eqid_count,
+ phba->fw_config.cqid_count);
+ }
- for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
- if (pfw_cfg->ulp[ulp_num].ulp_mode &
- BEISCSI_ULP_ISCSI_INI_MODE)
- set_bit(ulp_num,
- &phba->fw_config.ulp_supported);
-
- phba->fw_config.phys_port = pfw_cfg->phys_port;
- for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
- if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
-
- phba->fw_config.iscsi_cid_start[ulp_num] =
- pfw_cfg->ulp[ulp_num].sq_base;
- phba->fw_config.iscsi_cid_count[ulp_num] =
- pfw_cfg->ulp[ulp_num].sq_count;
-
- phba->fw_config.iscsi_icd_start[ulp_num] =
- pfw_cfg->ulp[ulp_num].icd_base;
- phba->fw_config.iscsi_icd_count[ulp_num] =
- pfw_cfg->ulp[ulp_num].icd_count;
-
- phba->fw_config.iscsi_chain_start[ulp_num] =
- pfw_cfg->chain_icd[ulp_num].chain_base;
- phba->fw_config.iscsi_chain_count[ulp_num] =
- pfw_cfg->chain_icd[ulp_num].chain_count;
-
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BG_%d : Function loaded on ULP : %d\n"
- "\tiscsi_cid_count : %d\n"
- "\tiscsi_cid_start : %d\n"
- "\t iscsi_icd_count : %d\n"
- "\t iscsi_icd_start : %d\n",
- ulp_num,
- phba->fw_config.
- iscsi_cid_count[ulp_num],
- phba->fw_config.
- iscsi_cid_start[ulp_num],
- phba->fw_config.
- iscsi_icd_count[ulp_num],
- phba->fw_config.
- iscsi_icd_start[ulp_num]);
- }
+ /**
+ * Check on which all ULP iSCSI Protocol is loaded.
+ * Set the Bit for those ULP. This set flag is used
+ * at all places in the code to check on which ULP
+ * iSCSi Protocol is loaded
+ **/
+ for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
+ if (pfw_cfg->ulp[ulp_num].ulp_mode &
+ BEISCSI_ULP_ISCSI_INI_MODE) {
+ set_bit(ulp_num, &phba->fw_config.ulp_supported);
+
+ /* Get the CID, ICD and Chain count for each ULP */
+ phba->fw_config.iscsi_cid_start[ulp_num] =
+ pfw_cfg->ulp[ulp_num].sq_base;
+ phba->fw_config.iscsi_cid_count[ulp_num] =
+ pfw_cfg->ulp[ulp_num].sq_count;
+
+ phba->fw_config.iscsi_icd_start[ulp_num] =
+ pfw_cfg->ulp[ulp_num].icd_base;
+ phba->fw_config.iscsi_icd_count[ulp_num] =
+ pfw_cfg->ulp[ulp_num].icd_count;
+
+ phba->fw_config.iscsi_chain_start[ulp_num] =
+ pfw_cfg->chain_icd[ulp_num].chain_base;
+ phba->fw_config.iscsi_chain_count[ulp_num] =
+ pfw_cfg->chain_icd[ulp_num].chain_count;
+
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : Function loaded on ULP : %d\n"
+ "\tiscsi_cid_count : %d\n"
+ "\tiscsi_cid_start : %d\n"
+ "\t iscsi_icd_count : %d\n"
+ "\t iscsi_icd_start : %d\n",
+ ulp_num,
+ phba->fw_config.
+ iscsi_cid_count[ulp_num],
+ phba->fw_config.
+ iscsi_cid_start[ulp_num],
+ phba->fw_config.
+ iscsi_icd_count[ulp_num],
+ phba->fw_config.
+ iscsi_icd_start[ulp_num]);
}
+ }
- phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode &
- BEISCSI_FUNC_DUA_MODE);
+ if (phba->fw_config.ulp_supported == 0) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : iSCSI initiator mode not set: ULP0 %x ULP1 %x\n",
+ pfw_cfg->ulp[BEISCSI_ULP0].ulp_mode,
+ pfw_cfg->ulp[BEISCSI_ULP1].ulp_mode);
+ goto fail_init;
+ }
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BG_%d : DUA Mode : 0x%x\n",
- phba->fw_config.dual_ulp_aware);
+ /**
+ * ICD is shared among ULPs. Use icd_count of any one loaded ULP
+ **/
+ for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
+ if (test_bit(ulp_num, &phba->fw_config.ulp_supported))
+ break;
+ icd_count = phba->fw_config.iscsi_icd_count[ulp_num];
+ if (icd_count == 0 || icd_count > 65536) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d: invalid ICD count %d\n", icd_count);
+ goto fail_init;
+ }
- } else {
+ cid_count = BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP0) +
+ BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP1);
+ if (cid_count == 0 || cid_count > 4096) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : Failed in mgmt_get_fw_config\n");
- status = -EINVAL;
+ "BG_%d: invalid CID count %d\n", cid_count);
+ goto fail_init;
}
- spin_unlock(&ctrl->mbox_lock);
+ /**
+ * Check FW is dual ULP aware i.e. can handle either
+ * of the protocols.
+ */
+ phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode &
+ BEISCSI_FUNC_DUA_MODE);
+
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : DUA Mode : 0x%x\n",
+ phba->fw_config.dual_ulp_aware);
+
+ /* all set, continue using this FW config */
+ status = 0;
+fail_init:
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -440,7 +526,7 @@ int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes);
req = nonemb_cmd.va;
memset(req, 0, sizeof(*req));
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
@@ -470,7 +556,7 @@ int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
} else
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BG_%d : Failed in mgmt_check_supported_fw\n");
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
if (nonemb_cmd.va)
pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
@@ -501,8 +587,9 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
req->region = region;
req->sector = sector;
req->offset = offset;
- spin_lock(&ctrl->mbox_lock);
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return 0;
switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
case BEISCSI_WRITE_FLASH:
offset = sector * sector_size + offset;
@@ -521,28 +608,26 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
"BG_%d : Unsupported cmd = 0x%x\n\n",
bsg_req->rqst_data.h_vendor.vendor_cmd[0]);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return -ENOSYS;
}
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
mcc_sge = nonembedded_sgl(wrb);
be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false,
job->request_payload.sg_cnt);
mcc_sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
mcc_sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
mcc_sge->len = cpu_to_le32(nonemb_cmd->size);
- wrb->tag0 |= tag;
- be_mcc_notify(phba);
+ be_mcc_notify(phba, tag);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -558,12 +643,19 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
- struct iscsi_cleanup_req *req = embedded_payload(wrb);
- int status = 0;
+ struct be_mcc_wrb *wrb;
+ struct iscsi_cleanup_req *req;
+ unsigned int tag;
+ int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return -EBUSY;
+ }
+ req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req));
@@ -572,11 +664,12 @@ int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num)
req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba, ulp_num));
req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba, ulp_num));
- status = be_mcc_notify_wait(phba);
+ be_mcc_notify(phba, tag);
+ status = be_mcc_compl_poll(phba, tag);
if (status)
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT,
"BG_%d : mgmt_epfw_cleanup , FAILED\n");
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -590,20 +683,18 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
struct be_mcc_wrb *wrb;
struct be_sge *sge;
struct invalidate_commands_params_in *req;
- unsigned int i, tag = 0;
+ unsigned int i, tag;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
req = nonemb_cmd->va;
memset(req, 0, sizeof(*req));
- wrb = wrb_from_mccq(phba);
sge = nonembedded_sgl(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
@@ -621,8 +712,8 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(nonemb_cmd->size);
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -637,16 +728,14 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
struct iscsi_invalidate_connection_params_in *req;
unsigned int tag = 0;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
- wrb->tag0 |= tag;
- req = embedded_payload(wrb);
+ req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION,
@@ -658,8 +747,8 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
else
req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE;
req->save_cfg = savecfg_flag;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -669,25 +758,23 @@ unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
struct tcp_upload_params_in *req;
- unsigned int tag = 0;
+ unsigned int tag;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
- req = embedded_payload(wrb);
- wrb->tag0 |= tag;
+ req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD,
OPCODE_COMMON_TCP_UPLOAD, sizeof(*req));
req->id = (unsigned short)cid;
req->upload_type = (unsigned char)upload_flag;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -722,6 +809,13 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
unsigned short cid = beiscsi_ep->ep_cid;
struct be_sge *sge;
+ if (dst_addr->sa_family != PF_INET && dst_addr->sa_family != PF_INET6) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
+ "BG_%d : unknown addr family %d\n",
+ dst_addr->sa_family);
+ return -EINVAL;
+ }
+
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -732,18 +826,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
ptemplate_address = &template_address;
ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address);
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return 0;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
- sge = nonembedded_sgl(wrb);
+ sge = nonembedded_sgl(wrb);
req = nonemb_cmd->va;
memset(req, 0, sizeof(*req));
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
@@ -760,7 +853,8 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr;
beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port);
beiscsi_ep->ip_type = BE2_IPV4;
- } else if (dst_addr->sa_family == PF_INET6) {
+ } else {
+ /* else its PF_INET6 family */
req->ip_address.ip_type = BE2_IPV6;
memcpy(&req->ip_address.addr,
&daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
@@ -769,14 +863,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
memcpy(&beiscsi_ep->dst6_addr,
&daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
beiscsi_ep->ip_type = BE2_IPV6;
- } else{
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BG_%d : unknown addr family %d\n",
- dst_addr->sa_family);
- spin_unlock(&ctrl->mbox_lock);
- free_mcc_tag(&phba->ctrl, tag);
- return -EINVAL;
-
}
req->cid = cid;
i = phba->nxt_cqid++;
@@ -801,35 +887,45 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
req->tcp_window_scale_count = 2;
}
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
- struct be_cmd_get_all_if_id_req *req = embedded_payload(wrb);
- struct be_cmd_get_all_if_id_req *pbe_allid = req;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_get_all_if_id_req *req;
+ struct be_cmd_get_all_if_id_req *pbe_allid;
+ unsigned int tag;
int status = 0;
- memset(wrb, 0, sizeof(*wrb));
-
- spin_lock(&ctrl->mbox_lock);
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return -EINTR;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return -ENOMEM;
+ }
+ req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID,
sizeof(*req));
- status = be_mbox_notify(ctrl);
- if (!status)
- phba->interface_handle = pbe_allid->if_hndl_list[0];
- else {
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
+
+ status = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
+ if (status) {
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
"BG_%d : Failed in mgmt_get_all_if_id\n");
+ return -EBUSY;
}
- spin_unlock(&ctrl->mbox_lock);
+
+ pbe_allid = embedded_payload(wrb);
+ phba->interface_handle = pbe_allid->if_hndl_list[0];
return status;
}
@@ -852,27 +948,24 @@ static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
unsigned int tag;
int rc = 0;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
rc = -ENOMEM;
goto free_cmd;
}
- wrb = wrb_from_mccq(phba);
- wrb->tag0 |= tag;
sge = nonembedded_sgl(wrb);
-
be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1);
sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd->dma));
sge->len = cpu_to_le32(nonemb_cmd->size);
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
- rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, nonemb_cmd);
if (resp_buf)
memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
@@ -1003,8 +1096,9 @@ int mgmt_set_ip(struct beiscsi_hba *phba,
uint32_t ip_type;
int rc;
- if (mgmt_get_all_if_id(phba))
- return -EIO;
+ rc = mgmt_get_all_if_id(phba);
+ if (rc)
+ return rc;
ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
BE2_IPV6 : BE2_IPV4 ;
@@ -1173,8 +1267,9 @@ int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type,
uint32_t ioctl_size = sizeof(struct be_cmd_get_if_info_resp);
int rc;
- if (mgmt_get_all_if_id(phba))
- return -EIO;
+ rc = mgmt_get_all_if_id(phba);
+ if (rc)
+ return rc;
do {
rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
@@ -1245,55 +1340,27 @@ int mgmt_get_nic_conf(struct beiscsi_hba *phba,
unsigned int be_cmd_get_initname(struct beiscsi_hba *phba)
{
- unsigned int tag = 0;
+ unsigned int tag;
struct be_mcc_wrb *wrb;
struct be_cmd_hba_name *req;
struct be_ctrl_info *ctrl = &phba->ctrl;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return 0;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_CFG_GET_HBA_NAME,
sizeof(*req));
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
- return tag;
-}
-
-unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba)
-{
- unsigned int tag = 0;
- struct be_mcc_wrb *wrb;
- struct be_cmd_ntwk_link_status_req *req;
- struct be_ctrl_info *ctrl = &phba->ctrl;
-
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
- }
-
- wrb = wrb_from_mccq(phba);
- req = embedded_payload(wrb);
- wrb->tag0 |= tag;
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_NTWK_LINK_STATUS_QUERY,
- sizeof(*req));
-
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -1330,7 +1397,7 @@ int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
return -EAGAIN;
}
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
@@ -1364,7 +1431,7 @@ int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
return -EAGAIN;
}
- rc = beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
@@ -1406,7 +1473,7 @@ int mgmt_set_vlan(struct beiscsi_hba *phba,
return -EBUSY;
}
- rc = beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
(BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
@@ -1749,19 +1816,17 @@ int beiscsi_logout_fw_sess(struct beiscsi_hba *phba,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : In bescsi_logout_fwboot_sess\n");
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : MBX Tag Failure\n");
return -EINVAL;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_SESSION_LOGOUT_TARGET,
@@ -1769,10 +1834,10 @@ int beiscsi_logout_fw_sess(struct beiscsi_hba *phba,
/* Set the session handle */
req->session_handle = fw_sess_handle;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index c1dbb690ee27..f3a48a04b2ca 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -268,6 +268,8 @@ struct beiscsi_endpoint {
int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba);
+int mgmt_get_port_name(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba);
unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
struct beiscsi_endpoint *beiscsi_ep,
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index 2ea0db4b62a7..7209afad82f7 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -91,6 +91,25 @@ static bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = {
+void
+__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data)
+{
+ int tail = trcm->tail;
+ struct bfa_trc_s *trc = &trcm->trc[tail];
+
+ if (trcm->stopped)
+ return;
+
+ trc->fileno = (u16) fileno;
+ trc->line = (u16) line;
+ trc->data.u64 = data;
+ trc->timestamp = BFA_TRC_TS(trcm);
+
+ trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
+ if (trcm->tail == trcm->head)
+ trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
+}
+
static void
bfa_com_port_attach(struct bfa_s *bfa)
{
diff --git a/drivers/scsi/bfa/bfa_cs.h b/drivers/scsi/bfa/bfa_cs.h
index da9cf655be26..df6760ca0911 100644
--- a/drivers/scsi/bfa/bfa_cs.h
+++ b/drivers/scsi/bfa/bfa_cs.h
@@ -108,44 +108,11 @@ bfa_trc_stop(struct bfa_trc_mod_s *trcm)
trcm->stopped = 1;
}
-static inline void
-__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data)
-{
- int tail = trcm->tail;
- struct bfa_trc_s *trc = &trcm->trc[tail];
-
- if (trcm->stopped)
- return;
-
- trc->fileno = (u16) fileno;
- trc->line = (u16) line;
- trc->data.u64 = data;
- trc->timestamp = BFA_TRC_TS(trcm);
-
- trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
- if (trcm->tail == trcm->head)
- trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
-}
-
+void
+__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data);
-static inline void
-__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data)
-{
- int tail = trcm->tail;
- struct bfa_trc_s *trc = &trcm->trc[tail];
-
- if (trcm->stopped)
- return;
-
- trc->fileno = (u16) fileno;
- trc->line = (u16) line;
- trc->data.u32.u32 = data;
- trc->timestamp = BFA_TRC_TS(trcm);
-
- trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
- if (trcm->tail == trcm->head)
- trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
-}
+void
+__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data);
#define bfa_sm_fault(__mod, __event) do { \
bfa_trc(__mod, (((u32)0xDEAD << 16) | __event)); \
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 251e2ff8ff5f..a1ada4a31c97 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -2803,7 +2803,7 @@ void
bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)
{
memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
- memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+ strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
}
void
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index 67405c628864..d7029ea5d319 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -97,6 +97,15 @@ static void __exit bnx2fc_mod_exit(void);
unsigned int bnx2fc_debug_level;
module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug_logging,
+ "Option to enable extended logging,\n"
+ "\t\tDefault is 0 - no logging.\n"
+ "\t\t0x01 - SCSI cmd error, cleanup.\n"
+ "\t\t0x02 - Session setup, cleanup, etc.\n"
+ "\t\t0x04 - lport events, link, mtu, etc.\n"
+ "\t\t0x08 - ELS logs.\n"
+ "\t\t0x10 - fcoe L2 fame related logs.\n"
+ "\t\t0xff - LOG all messages.");
static int bnx2fc_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 0002caf687dd..2230dab67ca5 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1104,8 +1104,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
struct bnx2fc_cmd *io_req;
struct fc_lport *lport;
struct bnx2fc_rport *tgt;
- int rc = FAILED;
-
+ int rc;
rc = fc_block_scsi_eh(sc_cmd);
if (rc)
@@ -1114,7 +1113,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
lport = shost_priv(sc_cmd->device->host);
if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) {
printk(KERN_ERR PFX "eh_abort: link not ready\n");
- return rc;
+ return FAILED;
}
tgt = (struct bnx2fc_rport *)&rp[1];
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h
index 5ada9268a450..a8ac4c0a1493 100644
--- a/drivers/scsi/cxlflash/common.h
+++ b/drivers/scsi/cxlflash/common.h
@@ -34,7 +34,6 @@ extern const struct file_operations cxlflash_cxl_fops;
sectors
*/
-#define NUM_RRQ_ENTRY 16 /* for master issued cmds */
#define MAX_RHT_PER_CONTEXT (PAGE_SIZE / sizeof(struct sisl_rht_entry))
/* AFU command retry limit */
@@ -48,9 +47,12 @@ extern const struct file_operations cxlflash_cxl_fops;
index derivation
*/
-#define CXLFLASH_MAX_CMDS 16
+#define CXLFLASH_MAX_CMDS 256
#define CXLFLASH_MAX_CMDS_PER_LUN CXLFLASH_MAX_CMDS
+/* RRQ for master issued cmds */
+#define NUM_RRQ_ENTRY CXLFLASH_MAX_CMDS
+
static inline void check_sizes(void)
{
@@ -149,7 +151,7 @@ struct afu_cmd {
struct afu {
/* Stuff requiring alignment go first. */
- u64 rrq_entry[NUM_RRQ_ENTRY]; /* 128B RRQ */
+ u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */
/*
* Command & data for AFU commands.
*/
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index f6d90ce8f3b7..3879b46d79e1 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -726,11 +726,11 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level)
*/
static void term_afu(struct cxlflash_cfg *cfg)
{
- term_mc(cfg, UNDO_START);
-
if (cfg->afu)
stop_afu(cfg);
+ term_mc(cfg, UNDO_START);
+
pr_debug("%s: returning\n", __func__);
}
@@ -767,7 +767,6 @@ static void cxlflash_remove(struct pci_dev *pdev)
cancel_work_sync(&cfg->work_q);
term_afu(cfg);
case INIT_STATE_PCI:
- pci_release_regions(cfg->dev);
pci_disable_device(pdev);
case INIT_STATE_NONE:
free_mem(cfg);
@@ -840,15 +839,6 @@ static int init_pci(struct cxlflash_cfg *cfg)
struct pci_dev *pdev = cfg->dev;
int rc = 0;
- cfg->cxlflash_regs_pci = pci_resource_start(pdev, 0);
- rc = pci_request_regions(pdev, CXLFLASH_NAME);
- if (rc < 0) {
- dev_err(&pdev->dev,
- "%s: Couldn't register memory range of registers\n",
- __func__);
- goto out;
- }
-
rc = pci_enable_device(pdev);
if (rc || pci_channel_offline(pdev)) {
if (pci_channel_offline(pdev)) {
@@ -860,55 +850,13 @@ static int init_pci(struct cxlflash_cfg *cfg)
dev_err(&pdev->dev, "%s: Cannot enable adapter\n",
__func__);
cxlflash_wait_for_pci_err_recovery(cfg);
- goto out_release_regions;
- }
- }
-
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (rc < 0) {
- dev_dbg(&pdev->dev, "%s: Failed to set 64 bit PCI DMA mask\n",
- __func__);
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- }
-
- if (rc < 0) {
- dev_err(&pdev->dev, "%s: Failed to set PCI DMA mask\n",
- __func__);
- goto out_disable;
- }
-
- pci_set_master(pdev);
-
- if (pci_channel_offline(pdev)) {
- cxlflash_wait_for_pci_err_recovery(cfg);
- if (pci_channel_offline(pdev)) {
- rc = -EIO;
- goto out_msi_disable;
+ goto out;
}
}
- rc = pci_save_state(pdev);
-
- if (rc != PCIBIOS_SUCCESSFUL) {
- dev_err(&pdev->dev, "%s: Failed to save PCI config space\n",
- __func__);
- rc = -EIO;
- goto cleanup_nolog;
- }
-
out:
pr_debug("%s: returning rc=%d\n", __func__, rc);
return rc;
-
-cleanup_nolog:
-out_msi_disable:
- cxlflash_wait_for_pci_err_recovery(cfg);
-out_disable:
- pci_disable_device(pdev);
-out_release_regions:
- pci_release_regions(pdev);
- goto out;
-
}
/**
@@ -2149,6 +2097,16 @@ static ssize_t lun_mode_store(struct device *dev,
rc = kstrtouint(buf, 10, &lun_mode);
if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) {
afu->internal_lun = lun_mode;
+
+ /*
+ * When configured for internal LUN, there is only one channel,
+ * channel number 0, else there will be 2 (default).
+ */
+ if (afu->internal_lun)
+ shost->max_channel = 0;
+ else
+ shost->max_channel = NUM_FC_PORTS - 1;
+
afu_reset(cfg);
scsi_scan_host(cfg->host);
}
@@ -2295,7 +2253,7 @@ static struct scsi_host_template driver_template = {
.eh_device_reset_handler = cxlflash_eh_device_reset_handler,
.eh_host_reset_handler = cxlflash_eh_host_reset_handler,
.change_queue_depth = cxlflash_change_queue_depth,
- .cmd_per_lun = 16,
+ .cmd_per_lun = CXLFLASH_MAX_CMDS_PER_LUN,
.can_queue = CXLFLASH_MAX_CMDS,
.this_id = -1,
.sg_tablesize = SG_NONE, /* No scatter gather support */
@@ -2544,8 +2502,8 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev,
if (unlikely(rc))
dev_err(dev, "%s: Failed to mark user contexts!(%d)\n",
__func__, rc);
- term_mc(cfg, UNDO_START);
stop_afu(cfg);
+ term_mc(cfg, UNDO_START);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
cfg->state = STATE_FAILTERM;
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index f4020dbb55c3..d8a5cb3cd2bd 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -709,27 +709,32 @@ int cxlflash_disk_release(struct scsi_device *sdev,
* @cfg: Internal structure associated with the host.
* @ctxi: Context to release.
*
- * Note that the rht_lun member of the context was cut from a single
- * allocation when the context was created and therefore does not need
- * to be explicitly freed. Also note that we conditionally check for the
- * existence of the context control map before clearing the RHT registers
- * and context capabilities because it is possible to destroy a context
- * while the context is in the error state (previous mapping was removed
- * [so we don't have to worry about clearing] and context is waiting for
- * a new mapping).
+ * This routine is safe to be called with a a non-initialized context
+ * and is tolerant of being called with the context's mutex held (it
+ * will be unlocked if necessary before freeing). Also note that the
+ * routine conditionally checks for the existence of the context control
+ * map before clearing the RHT registers and context capabilities because
+ * it is possible to destroy a context while the context is in the error
+ * state (previous mapping was removed [so there is no need to worry about
+ * clearing] and context is waiting for a new mapping).
*/
static void destroy_context(struct cxlflash_cfg *cfg,
struct ctx_info *ctxi)
{
struct afu *afu = cfg->afu;
- WARN_ON(!list_empty(&ctxi->luns));
+ if (ctxi->initialized) {
+ WARN_ON(!list_empty(&ctxi->luns));
- /* Clear RHT registers and drop all capabilities for this context */
- if (afu->afu_map && ctxi->ctrl_map) {
- writeq_be(0, &ctxi->ctrl_map->rht_start);
- writeq_be(0, &ctxi->ctrl_map->rht_cnt_id);
- writeq_be(0, &ctxi->ctrl_map->ctx_cap);
+ /* Clear RHT registers and drop all capabilities for context */
+ if (afu->afu_map && ctxi->ctrl_map) {
+ writeq_be(0, &ctxi->ctrl_map->rht_start);
+ writeq_be(0, &ctxi->ctrl_map->rht_cnt_id);
+ writeq_be(0, &ctxi->ctrl_map->ctx_cap);
+ }
+
+ if (mutex_is_locked(&ctxi->mutex))
+ mutex_unlock(&ctxi->mutex);
}
/* Free memory associated with context */
@@ -742,23 +747,12 @@ static void destroy_context(struct cxlflash_cfg *cfg,
/**
* create_context() - allocates and initializes a context
* @cfg: Internal structure associated with the host.
- * @ctx: Previously obtained CXL context reference.
- * @ctxid: Previously obtained process element associated with CXL context.
- * @adap_fd: Previously obtained adapter fd associated with CXL context.
- * @file: Previously obtained file associated with CXL context.
- * @perms: User-specified permissions.
- *
- * The context's mutex is locked when an allocated context is returned.
*
* Return: Allocated context on success, NULL on failure
*/
-static struct ctx_info *create_context(struct cxlflash_cfg *cfg,
- struct cxl_context *ctx, int ctxid,
- int adap_fd, struct file *file,
- u32 perms)
+static struct ctx_info *create_context(struct cxlflash_cfg *cfg)
{
struct device *dev = &cfg->dev->dev;
- struct afu *afu = cfg->afu;
struct ctx_info *ctxi = NULL;
struct llun_info **lli = NULL;
u8 *ws = NULL;
@@ -781,28 +775,49 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg,
ctxi->rht_lun = lli;
ctxi->rht_needs_ws = ws;
ctxi->rht_start = rhte;
- ctxi->rht_perms = perms;
+out:
+ return ctxi;
+
+err:
+ kfree(ws);
+ kfree(lli);
+ kfree(ctxi);
+ ctxi = NULL;
+ goto out;
+}
+
+/**
+ * init_context() - initializes a previously allocated context
+ * @ctxi: Previously allocated context
+ * @cfg: Internal structure associated with the host.
+ * @ctx: Previously obtained CXL context reference.
+ * @ctxid: Previously obtained process element associated with CXL context.
+ * @adap_fd: Previously obtained adapter fd associated with CXL context.
+ * @file: Previously obtained file associated with CXL context.
+ * @perms: User-specified permissions.
+ *
+ * Upon return, the context is marked as initialized and the context's mutex
+ * is locked.
+ */
+static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg,
+ struct cxl_context *ctx, int ctxid, int adap_fd,
+ struct file *file, u32 perms)
+{
+ struct afu *afu = cfg->afu;
+ ctxi->rht_perms = perms;
ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl;
ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid);
ctxi->lfd = adap_fd;
ctxi->pid = current->tgid; /* tgid = pid */
ctxi->ctx = ctx;
ctxi->file = file;
+ ctxi->initialized = true;
mutex_init(&ctxi->mutex);
INIT_LIST_HEAD(&ctxi->luns);
INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */
mutex_lock(&ctxi->mutex);
-out:
- return ctxi;
-
-err:
- kfree(ws);
- kfree(lli);
- kfree(ctxi);
- ctxi = NULL;
- goto out;
}
/**
@@ -1300,9 +1315,9 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
u32 perms;
int ctxid = -1;
u64 rctxid = 0UL;
- struct file *file;
+ struct file *file = NULL;
- struct cxl_context *ctx;
+ struct cxl_context *ctx = NULL;
int fd = -1;
@@ -1356,7 +1371,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
if (unlikely(!lun_access)) {
dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__);
rc = -ENOMEM;
- goto err0;
+ goto err;
}
lun_access->lli = lli;
@@ -1371,53 +1386,56 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
goto out_attach;
}
+ ctxi = create_context(cfg);
+ if (unlikely(!ctxi)) {
+ dev_err(dev, "%s: Failed to create context! (%d)\n",
+ __func__, ctxid);
+ goto err;
+ }
+
ctx = cxl_dev_context_init(cfg->dev);
if (IS_ERR_OR_NULL(ctx)) {
dev_err(dev, "%s: Could not initialize context %p\n",
__func__, ctx);
rc = -ENODEV;
- goto err1;
+ goto err;
+ }
+
+ work = &ctxi->work;
+ work->num_interrupts = attach->num_interrupts;
+ work->flags = CXL_START_WORK_NUM_IRQS;
+
+ rc = cxl_start_work(ctx, work);
+ if (unlikely(rc)) {
+ dev_dbg(dev, "%s: Could not start context rc=%d\n",
+ __func__, rc);
+ goto err;
}
ctxid = cxl_process_element(ctx);
if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
rc = -EPERM;
- goto err2;
+ goto err;
}
file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd);
if (unlikely(fd < 0)) {
rc = -ENODEV;
dev_err(dev, "%s: Could not get file descriptor\n", __func__);
- goto err2;
+ goto err;
}
/* Translate read/write O_* flags from fcntl.h to AFU permission bits */
perms = SISL_RHT_PERM(attach->hdr.flags + 1);
- ctxi = create_context(cfg, ctx, ctxid, fd, file, perms);
- if (unlikely(!ctxi)) {
- dev_err(dev, "%s: Failed to create context! (%d)\n",
- __func__, ctxid);
- goto err3;
- }
-
- work = &ctxi->work;
- work->num_interrupts = attach->num_interrupts;
- work->flags = CXL_START_WORK_NUM_IRQS;
-
- rc = cxl_start_work(ctx, work);
- if (unlikely(rc)) {
- dev_dbg(dev, "%s: Could not start context rc=%d\n",
- __func__, rc);
- goto err4;
- }
+ /* Context mutex is locked upon return */
+ init_context(ctxi, cfg, ctx, ctxid, fd, file, perms);
rc = afu_attach(cfg, ctxi);
if (unlikely(rc)) {
dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc);
- goto err5;
+ goto err;
}
/*
@@ -1453,13 +1471,14 @@ out:
__func__, ctxid, fd, attach->block_size, rc, attach->last_lba);
return rc;
-err5:
- cxl_stop_context(ctx);
-err4:
- put_context(ctxi);
- destroy_context(cfg, ctxi);
- ctxi = NULL;
-err3:
+err:
+ /* Cleanup CXL context; okay to 'stop' even if it was not started */
+ if (!IS_ERR_OR_NULL(ctx)) {
+ cxl_stop_context(ctx);
+ cxl_release_context(ctx);
+ ctx = NULL;
+ }
+
/*
* Here, we're overriding the fops with a dummy all-NULL fops because
* fput() calls the release fop, which will cause us to mistakenly
@@ -1467,15 +1486,21 @@ err3:
* to that routine (cxlflash_cxl_release) we should try to fix the
* issue here.
*/
- file->f_op = &null_fops;
- fput(file);
- put_unused_fd(fd);
- fd = -1;
-err2:
- cxl_release_context(ctx);
-err1:
+ if (fd > 0) {
+ file->f_op = &null_fops;
+ fput(file);
+ put_unused_fd(fd);
+ fd = -1;
+ file = NULL;
+ }
+
+ /* Cleanup our context; safe to call even with mutex locked */
+ if (ctxi) {
+ destroy_context(cfg, ctxi);
+ ctxi = NULL;
+ }
+
kfree(lun_access);
-err0:
scsi_device_put(sdev);
goto out;
}
@@ -1507,24 +1532,24 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
goto out;
}
+ rc = cxl_start_work(ctx, &ctxi->work);
+ if (unlikely(rc)) {
+ dev_dbg(dev, "%s: Could not start context rc=%d\n",
+ __func__, rc);
+ goto err1;
+ }
+
ctxid = cxl_process_element(ctx);
if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
rc = -EPERM;
- goto err1;
+ goto err2;
}
file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd);
if (unlikely(fd < 0)) {
rc = -ENODEV;
dev_err(dev, "%s: Could not get file descriptor\n", __func__);
- goto err1;
- }
-
- rc = cxl_start_work(ctx, &ctxi->work);
- if (unlikely(rc)) {
- dev_dbg(dev, "%s: Could not start context rc=%d\n",
- __func__, rc);
goto err2;
}
@@ -1569,10 +1594,10 @@ out:
return rc;
err3:
- cxl_stop_context(ctx);
-err2:
fput(file);
put_unused_fd(fd);
+err2:
+ cxl_stop_context(ctx);
err1:
cxl_release_context(ctx);
goto out;
diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h
index bede574bcd77..5f9a091fda95 100644
--- a/drivers/scsi/cxlflash/superpipe.h
+++ b/drivers/scsi/cxlflash/superpipe.h
@@ -102,6 +102,7 @@ struct ctx_info {
u64 ctxid;
int lfd;
pid_t pid;
+ bool initialized;
bool unavail;
bool err_recovery_active;
struct mutex mutex; /* Context protection */
diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig
index e5647d59224f..0b331c9c0a8f 100644
--- a/drivers/scsi/device_handler/Kconfig
+++ b/drivers/scsi/device_handler/Kconfig
@@ -13,13 +13,13 @@ menuconfig SCSI_DH
config SCSI_DH_RDAC
tristate "LSI RDAC Device Handler"
- depends on SCSI_DH
+ depends on SCSI_DH && SCSI
help
If you have a LSI RDAC select y. Otherwise, say N.
config SCSI_DH_HP_SW
tristate "HP/COMPAQ MSA Device Handler"
- depends on SCSI_DH
+ depends on SCSI_DH && SCSI
help
If you have a HP/COMPAQ MSA device that requires START_STOP to
be sent to start it and cannot upgrade the firmware then select y.
@@ -27,13 +27,13 @@ config SCSI_DH_HP_SW
config SCSI_DH_EMC
tristate "EMC CLARiiON Device Handler"
- depends on SCSI_DH
+ depends on SCSI_DH && SCSI
help
If you have a EMC CLARiiON select y. Otherwise, say N.
config SCSI_DH_ALUA
tristate "SPC-3 ALUA Device Handler"
- depends on SCSI_DH
+ depends on SCSI_DH && SCSI
help
SCSI Device handler for generic SPC-3 Asymmetric Logical Unit
Access (ALUA).
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 5a328bf81836..5bcdf8dd6fb0 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -24,20 +24,13 @@
#include <linux/module.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_proto.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h>
#define ALUA_DH_NAME "alua"
-#define ALUA_DH_VER "1.3"
-
-#define TPGS_STATE_OPTIMIZED 0x0
-#define TPGS_STATE_NONOPTIMIZED 0x1
-#define TPGS_STATE_STANDBY 0x2
-#define TPGS_STATE_UNAVAILABLE 0x3
-#define TPGS_STATE_LBA_DEPENDENT 0x4
-#define TPGS_STATE_OFFLINE 0xe
-#define TPGS_STATE_TRANSITIONING 0xf
+#define ALUA_DH_VER "2.0"
#define TPGS_SUPPORT_NONE 0x00
#define TPGS_SUPPORT_OPTIMIZED 0x01
@@ -56,27 +49,62 @@
#define TPGS_MODE_IMPLICIT 0x1
#define TPGS_MODE_EXPLICIT 0x2
-#define ALUA_INQUIRY_SIZE 36
+#define ALUA_RTPG_SIZE 128
#define ALUA_FAILOVER_TIMEOUT 60
#define ALUA_FAILOVER_RETRIES 5
+#define ALUA_RTPG_DELAY_MSECS 5
/* device handler flags */
-#define ALUA_OPTIMIZE_STPG 1
-#define ALUA_RTPG_EXT_HDR_UNSUPP 2
+#define ALUA_OPTIMIZE_STPG 0x01
+#define ALUA_RTPG_EXT_HDR_UNSUPP 0x02
+#define ALUA_SYNC_STPG 0x04
+/* State machine flags */
+#define ALUA_PG_RUN_RTPG 0x10
+#define ALUA_PG_RUN_STPG 0x20
+#define ALUA_PG_RUNNING 0x40
-struct alua_dh_data {
+static uint optimize_stpg;
+module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
+
+static LIST_HEAD(port_group_list);
+static DEFINE_SPINLOCK(port_group_lock);
+static struct workqueue_struct *kaluad_wq;
+static struct workqueue_struct *kaluad_sync_wq;
+
+struct alua_port_group {
+ struct kref kref;
+ struct rcu_head rcu;
+ struct list_head node;
+ struct list_head dh_list;
+ unsigned char device_id_str[256];
+ int device_id_len;
int group_id;
- int rel_port;
int tpgs;
int state;
int pref;
unsigned flags; /* used for optimizing STPG */
- unsigned char inq[ALUA_INQUIRY_SIZE];
- unsigned char *buff;
- int bufflen;
unsigned char transition_tmo;
- unsigned char sense[SCSI_SENSE_BUFFERSIZE];
+ unsigned long expiry;
+ unsigned long interval;
+ struct delayed_work rtpg_work;
+ spinlock_t lock;
+ struct list_head rtpg_list;
+ struct scsi_device *rtpg_sdev;
+};
+
+struct alua_dh_data {
+ struct list_head node;
+ struct alua_port_group *pg;
+ int group_id;
+ spinlock_t pg_lock;
struct scsi_device *sdev;
+ int init_error;
+ struct mutex init_mutex;
+};
+
+struct alua_queue_data {
+ struct list_head entry;
activate_complete callback_fn;
void *callback_data;
};
@@ -84,179 +112,160 @@ struct alua_dh_data {
#define ALUA_POLICY_SWITCH_CURRENT 0
#define ALUA_POLICY_SWITCH_ALL 1
-static char print_alua_state(int);
+static void alua_rtpg_work(struct work_struct *work);
+static void alua_rtpg_queue(struct alua_port_group *pg,
+ struct scsi_device *sdev,
+ struct alua_queue_data *qdata, bool force);
+static void alua_check(struct scsi_device *sdev, bool force);
-static int realloc_buffer(struct alua_dh_data *h, unsigned len)
+static void release_port_group(struct kref *kref)
{
- if (h->buff && h->buff != h->inq)
- kfree(h->buff);
-
- h->buff = kmalloc(len, GFP_NOIO);
- if (!h->buff) {
- h->buff = h->inq;
- h->bufflen = ALUA_INQUIRY_SIZE;
- return 1;
- }
- h->bufflen = len;
- return 0;
-}
-
-static struct request *get_alua_req(struct scsi_device *sdev,
- void *buffer, unsigned buflen, int rw)
-{
- struct request *rq;
- struct request_queue *q = sdev->request_queue;
-
- rq = blk_get_request(q, rw, GFP_NOIO);
-
- if (IS_ERR(rq)) {
- sdev_printk(KERN_INFO, sdev,
- "%s: blk_get_request failed\n", __func__);
- return NULL;
- }
- blk_rq_set_block_pc(rq);
-
- if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
- blk_put_request(rq);
- sdev_printk(KERN_INFO, sdev,
- "%s: blk_rq_map_kern failed\n", __func__);
- return NULL;
- }
-
- rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
- rq->retries = ALUA_FAILOVER_RETRIES;
- rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ;
-
- return rq;
+ struct alua_port_group *pg;
+
+ pg = container_of(kref, struct alua_port_group, kref);
+ if (pg->rtpg_sdev)
+ flush_delayed_work(&pg->rtpg_work);
+ spin_lock(&port_group_lock);
+ list_del(&pg->node);
+ spin_unlock(&port_group_lock);
+ kfree_rcu(pg, rcu);
}
/*
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
+static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
+ int bufflen, struct scsi_sense_hdr *sshdr, int flags)
{
- struct request *rq;
- int err = 0;
-
- rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq) {
- err = DRIVER_BUSY << 24;
- goto done;
- }
+ u8 cdb[COMMAND_SIZE(MAINTENANCE_IN)];
+ int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
/* Prepare the command. */
- rq->cmd[0] = MAINTENANCE_IN;
- if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP))
- rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
+ memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_IN));
+ cdb[0] = MAINTENANCE_IN;
+ if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
+ cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
- rq->cmd[1] = MI_REPORT_TARGET_PGS;
- put_unaligned_be32(h->bufflen, &rq->cmd[6]);
- rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
-
- rq->sense = h->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = 0;
-
- blk_execute_rq(rq->q, NULL, rq, 1);
- if (rq->errors)
- err = rq->errors;
- blk_put_request(rq);
-done:
- return err;
+ cdb[1] = MI_REPORT_TARGET_PGS;
+ put_unaligned_be32(bufflen, &cdb[6]);
+
+ return scsi_execute_req_flags(sdev, cdb, DMA_FROM_DEVICE,
+ buff, bufflen, sshdr,
+ ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, NULL, req_flags);
}
/*
- * stpg_endio - Evaluate SET TARGET GROUP STATES
- * @sdev: the device to be evaluated
- * @state: the new target group state
+ * submit_stpg - Issue a SET TARGET PORT GROUP command
*
- * Evaluate a SET TARGET GROUP STATES command response.
+ * Currently we're only setting the current target port group state
+ * to 'active/optimized' and let the array firmware figure out
+ * the states of the remaining groups.
*/
-static void stpg_endio(struct request *req, int error)
+static int submit_stpg(struct scsi_device *sdev, int group_id,
+ struct scsi_sense_hdr *sshdr)
{
- struct alua_dh_data *h = req->end_io_data;
- struct scsi_sense_hdr sense_hdr;
- unsigned err = SCSI_DH_OK;
+ u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)];
+ unsigned char stpg_data[8];
+ int stpg_len = 8;
+ int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
- if (host_byte(req->errors) != DID_OK ||
- msg_byte(req->errors) != COMMAND_COMPLETE) {
- err = SCSI_DH_IO;
- goto done;
+ /* Prepare the data buffer */
+ memset(stpg_data, 0, stpg_len);
+ stpg_data[4] = SCSI_ACCESS_STATE_OPTIMAL;
+ put_unaligned_be16(group_id, &stpg_data[6]);
+
+ /* Prepare the command. */
+ memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_OUT));
+ cdb[0] = MAINTENANCE_OUT;
+ cdb[1] = MO_SET_TARGET_PGS;
+ put_unaligned_be32(stpg_len, &cdb[6]);
+
+ return scsi_execute_req_flags(sdev, cdb, DMA_TO_DEVICE,
+ stpg_data, stpg_len,
+ sshdr, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, NULL, req_flags);
+}
+
+struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size,
+ int group_id)
+{
+ struct alua_port_group *pg;
+
+ list_for_each_entry(pg, &port_group_list, node) {
+ if (pg->group_id != group_id)
+ continue;
+ if (pg->device_id_len != id_size)
+ continue;
+ if (strncmp(pg->device_id_str, id_str, id_size))
+ continue;
+ if (!kref_get_unless_zero(&pg->kref))
+ continue;
+ return pg;
}
- if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr)) {
- if (sense_hdr.sense_key == NOT_READY &&
- sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) {
- /* ALUA state transition already in progress */
- err = SCSI_DH_OK;
- goto done;
- }
- if (sense_hdr.sense_key == UNIT_ATTENTION) {
- err = SCSI_DH_RETRY;
- goto done;
- }
- sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
- ALUA_DH_NAME);
- scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr);
- err = SCSI_DH_IO;
- } else if (error)
- err = SCSI_DH_IO;
-
- if (err == SCSI_DH_OK) {
- h->state = TPGS_STATE_OPTIMIZED;
- sdev_printk(KERN_INFO, h->sdev,
- "%s: port group %02x switched to state %c\n",
- ALUA_DH_NAME, h->group_id,
- print_alua_state(h->state));
- }
-done:
- req->end_io_data = NULL;
- __blk_put_request(req->q, req);
- if (h->callback_fn) {
- h->callback_fn(h->callback_data, err);
- h->callback_fn = h->callback_data = NULL;
- }
- return;
+ return NULL;
}
/*
- * submit_stpg - Issue a SET TARGET GROUP STATES command
+ * alua_alloc_pg - Allocate a new port_group structure
+ * @sdev: scsi device
+ * @h: alua device_handler data
+ * @group_id: port group id
*
- * Currently we're only setting the current target port group state
- * to 'active/optimized' and let the array firmware figure out
- * the states of the remaining groups.
+ * Allocate a new port_group structure for a given
+ * device.
*/
-static unsigned submit_stpg(struct alua_dh_data *h)
+struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
+ int group_id, int tpgs)
{
- struct request *rq;
- int stpg_len = 8;
- struct scsi_device *sdev = h->sdev;
+ struct alua_port_group *pg, *tmp_pg;
- /* Prepare the data buffer */
- memset(h->buff, 0, stpg_len);
- h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
- put_unaligned_be16(h->group_id, &h->buff[6]);
-
- rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
- if (!rq)
- return SCSI_DH_RES_TEMP_UNAVAIL;
+ pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
+ if (!pg)
+ return ERR_PTR(-ENOMEM);
- /* Prepare the command. */
- rq->cmd[0] = MAINTENANCE_OUT;
- rq->cmd[1] = MO_SET_TARGET_PGS;
- put_unaligned_be32(stpg_len, &rq->cmd[6]);
- rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
+ pg->device_id_len = scsi_vpd_lun_id(sdev, pg->device_id_str,
+ sizeof(pg->device_id_str));
+ if (pg->device_id_len <= 0) {
+ /*
+ * Internal error: TPGS supported but no device
+ * identifcation found. Disable ALUA support.
+ */
+ kfree(pg);
+ sdev_printk(KERN_INFO, sdev,
+ "%s: No device descriptors found\n",
+ ALUA_DH_NAME);
+ return ERR_PTR(-ENXIO);
+ }
+ pg->group_id = group_id;
+ pg->tpgs = tpgs;
+ pg->state = SCSI_ACCESS_STATE_OPTIMAL;
+ if (optimize_stpg)
+ pg->flags |= ALUA_OPTIMIZE_STPG;
+ kref_init(&pg->kref);
+ INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work);
+ INIT_LIST_HEAD(&pg->rtpg_list);
+ INIT_LIST_HEAD(&pg->node);
+ INIT_LIST_HEAD(&pg->dh_list);
+ spin_lock_init(&pg->lock);
+
+ spin_lock(&port_group_lock);
+ tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
+ group_id);
+ if (tmp_pg) {
+ spin_unlock(&port_group_lock);
+ kfree(pg);
+ return tmp_pg;
+ }
- rq->sense = h->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = 0;
- rq->end_io_data = h;
+ list_add(&pg->node, &port_group_list);
+ spin_unlock(&port_group_lock);
- blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
- return SCSI_DH_OK;
+ return pg;
}
/*
@@ -318,9 +327,13 @@ static int alua_check_tpgs(struct scsi_device *sdev)
* Extract the relative target port and the target port group
* descriptor from the list of identificators.
*/
-static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
+ int tpgs)
{
int rel_port = -1, group_id;
+ struct alua_port_group *pg, *old_pg = NULL;
+ bool pg_updated;
+ unsigned long flags;
group_id = scsi_vpd_tpg_id(sdev, &rel_port);
if (group_id < 0) {
@@ -334,32 +347,63 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
ALUA_DH_NAME);
return SCSI_DH_DEV_UNSUPP;
}
- h->state = TPGS_STATE_OPTIMIZED;
- h->group_id = group_id;
+ pg = alua_alloc_pg(sdev, group_id, tpgs);
+ if (IS_ERR(pg)) {
+ if (PTR_ERR(pg) == -ENOMEM)
+ return SCSI_DH_NOMEM;
+ return SCSI_DH_DEV_UNSUPP;
+ }
sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x rel port %02x\n",
- ALUA_DH_NAME, h->group_id, h->rel_port);
+ "%s: device %s port group %x rel port %x\n",
+ ALUA_DH_NAME, pg->device_id_str, group_id, rel_port);
+
+ /* Check for existing port group references */
+ spin_lock(&h->pg_lock);
+ old_pg = h->pg;
+ if (old_pg != pg) {
+ /* port group has changed. Update to new port group */
+ if (h->pg) {
+ spin_lock_irqsave(&old_pg->lock, flags);
+ list_del_rcu(&h->node);
+ spin_unlock_irqrestore(&old_pg->lock, flags);
+ }
+ rcu_assign_pointer(h->pg, pg);
+ pg_updated = true;
+ }
- return 0;
+ spin_lock_irqsave(&pg->lock, flags);
+ if (sdev->synchronous_alua)
+ pg->flags |= ALUA_SYNC_STPG;
+ if (pg_updated)
+ list_add_rcu(&h->node, &pg->dh_list);
+ spin_unlock_irqrestore(&pg->lock, flags);
+
+ alua_rtpg_queue(h->pg, sdev, NULL, true);
+ spin_unlock(&h->pg_lock);
+
+ if (old_pg)
+ kref_put(&old_pg->kref, release_port_group);
+
+ return SCSI_DH_OK;
}
-static char print_alua_state(int state)
+static char print_alua_state(unsigned char state)
{
switch (state) {
- case TPGS_STATE_OPTIMIZED:
+ case SCSI_ACCESS_STATE_OPTIMAL:
return 'A';
- case TPGS_STATE_NONOPTIMIZED:
+ case SCSI_ACCESS_STATE_ACTIVE:
return 'N';
- case TPGS_STATE_STANDBY:
+ case SCSI_ACCESS_STATE_STANDBY:
return 'S';
- case TPGS_STATE_UNAVAILABLE:
+ case SCSI_ACCESS_STATE_UNAVAILABLE:
return 'U';
- case TPGS_STATE_LBA_DEPENDENT:
+ case SCSI_ACCESS_STATE_LBA:
return 'L';
- case TPGS_STATE_OFFLINE:
+ case SCSI_ACCESS_STATE_OFFLINE:
return 'O';
- case TPGS_STATE_TRANSITIONING:
+ case SCSI_ACCESS_STATE_TRANSITIONING:
return 'T';
default:
return 'X';
@@ -371,18 +415,24 @@ static int alua_check_sense(struct scsi_device *sdev,
{
switch (sense_hdr->sense_key) {
case NOT_READY:
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a)
+ if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
/*
* LUN Not Accessible - ALUA state transition
*/
- return ADD_TO_MLQUEUE;
+ alua_check(sdev, false);
+ return NEEDS_RETRY;
+ }
break;
case UNIT_ATTENTION:
- if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
+ if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
/*
- * Power On, Reset, or Bus Device Reset, just retry.
+ * Power On, Reset, or Bus Device Reset.
+ * Might have obscured a state transition,
+ * so schedule a recheck.
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
+ }
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
/*
* Device internal reset
@@ -393,16 +443,20 @@ static int alua_check_sense(struct scsi_device *sdev,
* Mode Parameters Changed
*/
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06)
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
/*
* ALUA state changed
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07)
+ }
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
/*
* Implicit ALUA state transition failed
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
+ }
if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
/*
* Inquiry data has changed
@@ -422,38 +476,71 @@ static int alua_check_sense(struct scsi_device *sdev,
}
/*
+ * alua_tur - Send a TEST UNIT READY
+ * @sdev: device to which the TEST UNIT READY command should be send
+ *
+ * Send a TEST UNIT READY to @sdev to figure out the device state
+ * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING,
+ * SCSI_DH_OK if no error occurred, and SCSI_DH_IO otherwise.
+ */
+static int alua_tur(struct scsi_device *sdev)
+{
+ struct scsi_sense_hdr sense_hdr;
+ int retval;
+
+ retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, &sense_hdr);
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+ return SCSI_DH_RETRY;
+ else if (retval)
+ return SCSI_DH_IO;
+ else
+ return SCSI_DH_OK;
+}
+
+/*
* alua_rtpg - Evaluate REPORT TARGET GROUP STATES
* @sdev: the device to be evaluated.
- * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for device to exit transitioning state
*
* Evaluate the Target Port Group State.
* Returns SCSI_DH_DEV_OFFLINED if the path is
* found to be unusable.
*/
-static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition)
+static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
{
struct scsi_sense_hdr sense_hdr;
- int len, k, off, valid_states = 0;
- unsigned char *ucp;
+ struct alua_port_group *tmp_pg;
+ int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
+ unsigned char *desc, *buff;
unsigned err, retval;
- unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
+ unsigned long flags;
- if (!h->transition_tmo)
- expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
- else
- expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
+ if (!pg->expiry) {
+ unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ;
+
+ if (pg->transition_tmo)
+ transition_tmo = pg->transition_tmo * HZ;
+
+ pg->expiry = round_jiffies_up(jiffies + transition_tmo);
+ }
+
+ buff = kzalloc(bufflen, GFP_KERNEL);
+ if (!buff)
+ return SCSI_DH_DEV_TEMP_BUSY;
retry:
- retval = submit_rtpg(sdev, h);
+ retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, pg->flags);
+
if (retval) {
- if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr)) {
+ if (!scsi_sense_valid(&sense_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: rtpg failed, result %d\n",
ALUA_DH_NAME, retval);
- if (driver_byte(retval) == DRIVER_BUSY)
+ kfree(buff);
+ if (driver_byte(retval) == DRIVER_ERROR)
return SCSI_DH_DEV_TEMP_BUSY;
return SCSI_DH_IO;
}
@@ -466,10 +553,10 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* The retry without rtpg_ext_hdr_req set
* handles this.
*/
- if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
+ if (!(pg->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
sense_hdr.sense_key == ILLEGAL_REQUEST &&
sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
- h->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
+ pg->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
goto retry;
}
/*
@@ -481,65 +568,96 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
err = SCSI_DH_RETRY;
else if (sense_hdr.sense_key == UNIT_ATTENTION)
err = SCSI_DH_RETRY;
- if (err == SCSI_DH_RETRY && time_before(jiffies, expiry)) {
+ if (err == SCSI_DH_RETRY &&
+ pg->expiry != 0 && time_before(jiffies, pg->expiry)) {
sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
- goto retry;
+ return err;
}
sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ kfree(buff);
+ pg->expiry = 0;
return SCSI_DH_IO;
}
- len = get_unaligned_be32(&h->buff[0]) + 4;
+ len = get_unaligned_be32(&buff[0]) + 4;
- if (len > h->bufflen) {
+ if (len > bufflen) {
/* Resubmit with the correct length */
- if (realloc_buffer(h, len)) {
+ kfree(buff);
+ bufflen = len;
+ buff = kmalloc(bufflen, GFP_KERNEL);
+ if (!buff) {
sdev_printk(KERN_WARNING, sdev,
"%s: kmalloc buffer failed\n",__func__);
/* Temporary failure, bypass */
+ pg->expiry = 0;
return SCSI_DH_DEV_TEMP_BUSY;
}
goto retry;
}
- orig_transition_tmo = h->transition_tmo;
- if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && h->buff[5] != 0)
- h->transition_tmo = h->buff[5];
+ orig_transition_tmo = pg->transition_tmo;
+ if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && buff[5] != 0)
+ pg->transition_tmo = buff[5];
else
- h->transition_tmo = ALUA_FAILOVER_TIMEOUT;
+ pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
- if (wait_for_transition && (orig_transition_tmo != h->transition_tmo)) {
+ if (orig_transition_tmo != pg->transition_tmo) {
sdev_printk(KERN_INFO, sdev,
"%s: transition timeout set to %d seconds\n",
- ALUA_DH_NAME, h->transition_tmo);
- expiry = jiffies + h->transition_tmo * HZ;
+ ALUA_DH_NAME, pg->transition_tmo);
+ pg->expiry = jiffies + pg->transition_tmo * HZ;
}
- if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
+ if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
tpg_desc_tbl_off = 8;
else
tpg_desc_tbl_off = 4;
- for (k = tpg_desc_tbl_off, ucp = h->buff + tpg_desc_tbl_off;
+ for (k = tpg_desc_tbl_off, desc = buff + tpg_desc_tbl_off;
k < len;
- k += off, ucp += off) {
-
- if (h->group_id == get_unaligned_be16(&ucp[2])) {
- h->state = ucp[0] & 0x0f;
- h->pref = ucp[0] >> 7;
- valid_states = ucp[1];
+ k += off, desc += off) {
+ u16 group_id = get_unaligned_be16(&desc[2]);
+
+ spin_lock_irqsave(&port_group_lock, flags);
+ tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
+ group_id);
+ spin_unlock_irqrestore(&port_group_lock, flags);
+ if (tmp_pg) {
+ if (spin_trylock_irqsave(&tmp_pg->lock, flags)) {
+ if ((tmp_pg == pg) ||
+ !(tmp_pg->flags & ALUA_PG_RUNNING)) {
+ struct alua_dh_data *h;
+
+ tmp_pg->state = desc[0] & 0x0f;
+ tmp_pg->pref = desc[0] >> 7;
+ rcu_read_lock();
+ list_for_each_entry_rcu(h,
+ &tmp_pg->dh_list, node) {
+ /* h->sdev should always be valid */
+ BUG_ON(!h->sdev);
+ h->sdev->access_state = desc[0];
+ }
+ rcu_read_unlock();
+ }
+ if (tmp_pg == pg)
+ valid_states = desc[1];
+ spin_unlock_irqrestore(&tmp_pg->lock, flags);
+ }
+ kref_put(&tmp_pg->kref, release_port_group);
}
- off = 8 + (ucp[7] * 4);
+ off = 8 + (desc[7] * 4);
}
+ spin_lock_irqsave(&pg->lock, flags);
sdev_printk(KERN_INFO, sdev,
"%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
- ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
- h->pref ? "preferred" : "non-preferred",
+ ALUA_DH_NAME, pg->group_id, print_alua_state(pg->state),
+ pg->pref ? "preferred" : "non-preferred",
valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l',
@@ -548,36 +666,236 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
- switch (h->state) {
- case TPGS_STATE_TRANSITIONING:
- if (wait_for_transition) {
- if (time_before(jiffies, expiry)) {
- /* State transition, retry */
- interval += 2000;
- msleep(interval);
- goto retry;
- }
+ switch (pg->state) {
+ case SCSI_ACCESS_STATE_TRANSITIONING:
+ if (time_before(jiffies, pg->expiry)) {
+ /* State transition, retry */
+ pg->interval = 2;
err = SCSI_DH_RETRY;
} else {
- err = SCSI_DH_OK;
- }
+ struct alua_dh_data *h;
- /* Transitioning time exceeded, set port to standby */
- h->state = TPGS_STATE_STANDBY;
+ /* Transitioning time exceeded, set port to standby */
+ err = SCSI_DH_IO;
+ pg->state = SCSI_ACCESS_STATE_STANDBY;
+ pg->expiry = 0;
+ rcu_read_lock();
+ list_for_each_entry_rcu(h, &pg->dh_list, node) {
+ BUG_ON(!h->sdev);
+ h->sdev->access_state =
+ (pg->state & SCSI_ACCESS_STATE_MASK);
+ if (pg->pref)
+ h->sdev->access_state |=
+ SCSI_ACCESS_STATE_PREFERRED;
+ }
+ rcu_read_unlock();
+ }
break;
- case TPGS_STATE_OFFLINE:
+ case SCSI_ACCESS_STATE_OFFLINE:
/* Path unusable */
err = SCSI_DH_DEV_OFFLINED;
+ pg->expiry = 0;
break;
default:
/* Useable path if active */
err = SCSI_DH_OK;
+ pg->expiry = 0;
break;
}
+ spin_unlock_irqrestore(&pg->lock, flags);
+ kfree(buff);
return err;
}
/*
+ * alua_stpg - Issue a SET TARGET PORT GROUP command
+ *
+ * Issue a SET TARGET PORT GROUP command and evaluate the
+ * response. Returns SCSI_DH_RETRY per default to trigger
+ * a re-evaluation of the target group state or SCSI_DH_OK
+ * if no further action needs to be taken.
+ */
+static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
+{
+ int retval;
+ struct scsi_sense_hdr sense_hdr;
+
+ if (!(pg->tpgs & TPGS_MODE_EXPLICIT)) {
+ /* Only implicit ALUA supported, retry */
+ return SCSI_DH_RETRY;
+ }
+ switch (pg->state) {
+ case SCSI_ACCESS_STATE_OPTIMAL:
+ return SCSI_DH_OK;
+ case SCSI_ACCESS_STATE_ACTIVE:
+ if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
+ !pg->pref &&
+ (pg->tpgs & TPGS_MODE_IMPLICIT))
+ return SCSI_DH_OK;
+ break;
+ case SCSI_ACCESS_STATE_STANDBY:
+ case SCSI_ACCESS_STATE_UNAVAILABLE:
+ break;
+ case SCSI_ACCESS_STATE_OFFLINE:
+ return SCSI_DH_IO;
+ case SCSI_ACCESS_STATE_TRANSITIONING:
+ break;
+ default:
+ sdev_printk(KERN_INFO, sdev,
+ "%s: stpg failed, unhandled TPGS state %d",
+ ALUA_DH_NAME, pg->state);
+ return SCSI_DH_NOSYS;
+ }
+ retval = submit_stpg(sdev, pg->group_id, &sense_hdr);
+
+ if (retval) {
+ if (!scsi_sense_valid(&sense_hdr)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: stpg failed, result %d",
+ ALUA_DH_NAME, retval);
+ if (driver_byte(retval) == DRIVER_ERROR)
+ return SCSI_DH_DEV_TEMP_BUSY;
+ } else {
+ sdev_printk(KERN_INFO, sdev, "%s: stpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ }
+ }
+ /* Retry RTPG */
+ return SCSI_DH_RETRY;
+}
+
+static void alua_rtpg_work(struct work_struct *work)
+{
+ struct alua_port_group *pg =
+ container_of(work, struct alua_port_group, rtpg_work.work);
+ struct scsi_device *sdev;
+ LIST_HEAD(qdata_list);
+ int err = SCSI_DH_OK;
+ struct alua_queue_data *qdata, *tmp;
+ unsigned long flags;
+ struct workqueue_struct *alua_wq = kaluad_wq;
+
+ spin_lock_irqsave(&pg->lock, flags);
+ sdev = pg->rtpg_sdev;
+ if (!sdev) {
+ WARN_ON(pg->flags & ALUA_PG_RUN_RTPG);
+ WARN_ON(pg->flags & ALUA_PG_RUN_STPG);
+ spin_unlock_irqrestore(&pg->lock, flags);
+ return;
+ }
+ if (pg->flags & ALUA_SYNC_STPG)
+ alua_wq = kaluad_sync_wq;
+ pg->flags |= ALUA_PG_RUNNING;
+ if (pg->flags & ALUA_PG_RUN_RTPG) {
+ int state = pg->state;
+
+ pg->flags &= ~ALUA_PG_RUN_RTPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ if (state == SCSI_ACCESS_STATE_TRANSITIONING) {
+ if (alua_tur(sdev) == SCSI_DH_RETRY) {
+ spin_lock_irqsave(&pg->lock, flags);
+ pg->flags &= ~ALUA_PG_RUNNING;
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ queue_delayed_work(alua_wq, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ /* Send RTPG on failure or if TUR indicates SUCCESS */
+ }
+ err = alua_rtpg(sdev, pg);
+ spin_lock_irqsave(&pg->lock, flags);
+ if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {
+ pg->flags &= ~ALUA_PG_RUNNING;
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ queue_delayed_work(alua_wq, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ if (err != SCSI_DH_OK)
+ pg->flags &= ~ALUA_PG_RUN_STPG;
+ }
+ if (pg->flags & ALUA_PG_RUN_STPG) {
+ pg->flags &= ~ALUA_PG_RUN_STPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ err = alua_stpg(sdev, pg);
+ spin_lock_irqsave(&pg->lock, flags);
+ if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ pg->interval = 0;
+ pg->flags &= ~ALUA_PG_RUNNING;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ queue_delayed_work(alua_wq, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ }
+
+ list_splice_init(&pg->rtpg_list, &qdata_list);
+ pg->rtpg_sdev = NULL;
+ spin_unlock_irqrestore(&pg->lock, flags);
+
+ list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) {
+ list_del(&qdata->entry);
+ if (qdata->callback_fn)
+ qdata->callback_fn(qdata->callback_data, err);
+ kfree(qdata);
+ }
+ spin_lock_irqsave(&pg->lock, flags);
+ pg->flags &= ~ALUA_PG_RUNNING;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ scsi_device_put(sdev);
+ kref_put(&pg->kref, release_port_group);
+}
+
+static void alua_rtpg_queue(struct alua_port_group *pg,
+ struct scsi_device *sdev,
+ struct alua_queue_data *qdata, bool force)
+{
+ int start_queue = 0;
+ unsigned long flags;
+ struct workqueue_struct *alua_wq = kaluad_wq;
+
+ if (!pg)
+ return;
+
+ spin_lock_irqsave(&pg->lock, flags);
+ if (qdata) {
+ list_add_tail(&qdata->entry, &pg->rtpg_list);
+ pg->flags |= ALUA_PG_RUN_STPG;
+ force = true;
+ }
+ if (pg->rtpg_sdev == NULL) {
+ pg->interval = 0;
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ kref_get(&pg->kref);
+ pg->rtpg_sdev = sdev;
+ scsi_device_get(sdev);
+ start_queue = 1;
+ } else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force) {
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ /* Do not queue if the worker is already running */
+ if (!(pg->flags & ALUA_PG_RUNNING)) {
+ kref_get(&pg->kref);
+ start_queue = 1;
+ }
+ }
+
+ if (pg->flags & ALUA_SYNC_STPG)
+ alua_wq = kaluad_sync_wq;
+ spin_unlock_irqrestore(&pg->lock, flags);
+
+ if (start_queue &&
+ !queue_delayed_work(alua_wq, &pg->rtpg_work,
+ msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS))) {
+ scsi_device_put(sdev);
+ kref_put(&pg->kref, release_port_group);
+ }
+}
+
+/*
* alua_initialize - Initialize ALUA state
* @sdev: the device to be initialized
*
@@ -586,21 +904,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
*/
static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int err = SCSI_DH_DEV_UNSUPP;
-
- h->tpgs = alua_check_tpgs(sdev);
- if (h->tpgs == TPGS_MODE_NONE)
- goto out;
-
- err = alua_check_vpd(sdev, h);
- if (err != SCSI_DH_OK)
- goto out;
-
- err = alua_rtpg(sdev, h, 0);
- if (err != SCSI_DH_OK)
- goto out;
-
-out:
+ int err = SCSI_DH_DEV_UNSUPP, tpgs;
+
+ mutex_lock(&h->init_mutex);
+ tpgs = alua_check_tpgs(sdev);
+ if (tpgs != TPGS_MODE_NONE)
+ err = alua_check_vpd(sdev, h, tpgs);
+ h->init_error = err;
+ mutex_unlock(&h->init_mutex);
return err;
}
/*
@@ -615,9 +926,11 @@ out:
static int alua_set_params(struct scsi_device *sdev, const char *params)
{
struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group __rcu *pg = NULL;
unsigned int optimize = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
+ unsigned long flags;
if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
return -EINVAL;
@@ -627,18 +940,23 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
return -EINVAL;
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+ spin_lock_irqsave(&pg->lock, flags);
if (optimize)
- h->flags |= ALUA_OPTIMIZE_STPG;
+ pg->flags |= ALUA_OPTIMIZE_STPG;
else
- h->flags &= ~ALUA_OPTIMIZE_STPG;
+ pg->flags &= ~ALUA_OPTIMIZE_STPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ rcu_read_unlock();
return result;
}
-static uint optimize_stpg;
-module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
-
/*
* alua_activate - activate a path
* @sdev: device on the path to be activated
@@ -654,48 +972,33 @@ static int alua_activate(struct scsi_device *sdev,
{
struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
- int stpg = 0;
+ struct alua_queue_data *qdata;
+ struct alua_port_group __rcu *pg;
- err = alua_rtpg(sdev, h, 1);
- if (err != SCSI_DH_OK)
+ qdata = kzalloc(sizeof(*qdata), GFP_KERNEL);
+ if (!qdata) {
+ err = SCSI_DH_RES_TEMP_UNAVAIL;
goto out;
-
- if (optimize_stpg)
- h->flags |= ALUA_OPTIMIZE_STPG;
-
- if (h->tpgs & TPGS_MODE_EXPLICIT) {
- switch (h->state) {
- case TPGS_STATE_NONOPTIMIZED:
- stpg = 1;
- if ((h->flags & ALUA_OPTIMIZE_STPG) &&
- (!h->pref) &&
- (h->tpgs & TPGS_MODE_IMPLICIT))
- stpg = 0;
- break;
- case TPGS_STATE_STANDBY:
- case TPGS_STATE_UNAVAILABLE:
- stpg = 1;
- break;
- case TPGS_STATE_OFFLINE:
- err = SCSI_DH_IO;
- break;
- case TPGS_STATE_TRANSITIONING:
- err = SCSI_DH_RETRY;
- break;
- default:
- break;
- }
}
-
- if (stpg) {
- h->callback_fn = fn;
- h->callback_data = data;
- err = submit_stpg(h);
- if (err == SCSI_DH_OK)
- return 0;
- h->callback_fn = h->callback_data = NULL;
+ qdata->callback_fn = fn;
+ qdata->callback_data = data;
+
+ mutex_lock(&h->init_mutex);
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg || !kref_get_unless_zero(&pg->kref)) {
+ rcu_read_unlock();
+ kfree(qdata);
+ err = h->init_error;
+ mutex_unlock(&h->init_mutex);
+ goto out;
}
+ fn = NULL;
+ rcu_read_unlock();
+ mutex_unlock(&h->init_mutex);
+ alua_rtpg_queue(pg, sdev, qdata, true);
+ kref_put(&pg->kref, release_port_group);
out:
if (fn)
fn(data, err);
@@ -703,6 +1006,29 @@ out:
}
/*
+ * alua_check - check path status
+ * @sdev: device on the path to be checked
+ *
+ * Check the device status
+ */
+static void alua_check(struct scsi_device *sdev, bool force)
+{
+ struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group *pg;
+
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg || !kref_get_unless_zero(&pg->kref)) {
+ rcu_read_unlock();
+ return;
+ }
+ rcu_read_unlock();
+
+ alua_rtpg_queue(pg, sdev, NULL, force);
+ kref_put(&pg->kref, release_port_group);
+}
+
+/*
* alua_prep_fn - request callback
*
* Fail I/O to all paths not in state
@@ -711,13 +1037,20 @@ out:
static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
{
struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group __rcu *pg;
+ unsigned char state = SCSI_ACCESS_STATE_OPTIMAL;
int ret = BLKPREP_OK;
- if (h->state == TPGS_STATE_TRANSITIONING)
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (pg)
+ state = pg->state;
+ rcu_read_unlock();
+ if (state == SCSI_ACCESS_STATE_TRANSITIONING)
ret = BLKPREP_DEFER;
- else if (h->state != TPGS_STATE_OPTIMIZED &&
- h->state != TPGS_STATE_NONOPTIMIZED &&
- h->state != TPGS_STATE_LBA_DEPENDENT) {
+ else if (state != SCSI_ACCESS_STATE_OPTIMAL &&
+ state != SCSI_ACCESS_STATE_ACTIVE &&
+ state != SCSI_ACCESS_STATE_LBA) {
ret = BLKPREP_KILL;
req->cmd_flags |= REQ_QUIET;
}
@@ -725,6 +1058,13 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
}
+static void alua_rescan(struct scsi_device *sdev)
+{
+ struct alua_dh_data *h = sdev->handler_data;
+
+ alua_initialize(sdev, h);
+}
+
/*
* alua_bus_attach - Attach device handler
* @sdev: device to be attached to
@@ -732,20 +1072,21 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
static int alua_bus_attach(struct scsi_device *sdev)
{
struct alua_dh_data *h;
- int err;
+ int err, ret = -EINVAL;
h = kzalloc(sizeof(*h) , GFP_KERNEL);
if (!h)
return -ENOMEM;
- h->tpgs = TPGS_MODE_UNINITIALIZED;
- h->state = TPGS_STATE_OPTIMIZED;
- h->group_id = -1;
- h->rel_port = -1;
- h->buff = h->inq;
- h->bufflen = ALUA_INQUIRY_SIZE;
+ spin_lock_init(&h->pg_lock);
+ rcu_assign_pointer(h->pg, NULL);
+ h->init_error = SCSI_DH_OK;
h->sdev = sdev;
+ INIT_LIST_HEAD(&h->node);
+ mutex_init(&h->init_mutex);
err = alua_initialize(sdev, h);
+ if (err == SCSI_DH_NOMEM)
+ ret = -ENOMEM;
if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
goto failed;
@@ -753,7 +1094,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
return 0;
failed:
kfree(h);
- return -EINVAL;
+ return ret;
}
/*
@@ -763,9 +1104,19 @@ failed:
static void alua_bus_detach(struct scsi_device *sdev)
{
struct alua_dh_data *h = sdev->handler_data;
-
- if (h->buff && h->inq != h->buff)
- kfree(h->buff);
+ struct alua_port_group *pg;
+
+ spin_lock(&h->pg_lock);
+ pg = h->pg;
+ rcu_assign_pointer(h->pg, NULL);
+ h->sdev = NULL;
+ spin_unlock(&h->pg_lock);
+ if (pg) {
+ spin_lock(&pg->lock);
+ list_del_rcu(&h->node);
+ spin_unlock(&pg->lock);
+ kref_put(&pg->kref, release_port_group);
+ }
sdev->handler_data = NULL;
kfree(h);
}
@@ -778,6 +1129,7 @@ static struct scsi_device_handler alua_dh = {
.prep_fn = alua_prep_fn,
.check_sense = alua_check_sense,
.activate = alua_activate,
+ .rescan = alua_rescan,
.set_params = alua_set_params,
};
@@ -785,16 +1137,31 @@ static int __init alua_init(void)
{
int r;
+ kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, 0);
+ if (!kaluad_wq) {
+ /* Temporary failure, bypass */
+ return SCSI_DH_DEV_TEMP_BUSY;
+ }
+ kaluad_sync_wq = create_workqueue("kaluad_sync");
+ if (!kaluad_sync_wq) {
+ destroy_workqueue(kaluad_wq);
+ return SCSI_DH_DEV_TEMP_BUSY;
+ }
r = scsi_register_device_handler(&alua_dh);
- if (r != 0)
+ if (r != 0) {
printk(KERN_ERR "%s: Failed to register scsi device handler",
ALUA_DH_NAME);
+ destroy_workqueue(kaluad_sync_wq);
+ destroy_workqueue(kaluad_wq);
+ }
return r;
}
static void __exit alua_exit(void)
{
scsi_unregister_device_handler(&alua_dh);
+ destroy_workqueue(kaluad_sync_wq);
+ destroy_workqueue(kaluad_wq);
}
module_init(alua_init);
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index e6fb97cb12f4..375d81850f15 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -199,7 +199,12 @@ static int parse_sp_info_reply(struct scsi_device *sdev,
csdev->lun_state = csdev->buffer[4];
csdev->current_sp = csdev->buffer[8];
csdev->port = csdev->buffer[7];
-
+ if (csdev->lun_state == CLARIION_LUN_OWNED)
+ sdev->access_state = SCSI_ACCESS_STATE_OPTIMAL;
+ else
+ sdev->access_state = SCSI_ACCESS_STATE_STANDBY;
+ if (csdev->default_sp == csdev->current_sp)
+ sdev->access_state |= SCSI_ACCESS_STATE_PREFERRED;
out:
return err;
}
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 93880ed6291c..06fbd0b0c68a 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -165,6 +165,7 @@ struct rdac_controller {
struct work_struct ms_work;
struct scsi_device *ms_sdev;
struct list_head ms_head;
+ struct list_head dh_list;
};
struct c2_inquiry {
@@ -181,7 +182,9 @@ struct c2_inquiry {
};
struct rdac_dh_data {
+ struct list_head node;
struct rdac_controller *ctlr;
+ struct scsi_device *sdev;
#define UNINITIALIZED_LUN (1 << 8)
unsigned lun;
@@ -392,6 +395,7 @@ static struct rdac_controller *get_controller(int index, char *array_name,
INIT_WORK(&ctlr->ms_work, send_mode_select);
INIT_LIST_HEAD(&ctlr->ms_head);
list_add(&ctlr->node, &ctlr_list);
+ INIT_LIST_HEAD(&ctlr->dh_list);
return ctlr;
}
@@ -455,7 +459,8 @@ static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
{
- int err;
+ int err, access_state;
+ struct rdac_dh_data *tmp;
struct c9_inquiry *inqp;
h->state = RDAC_STATE_ACTIVE;
@@ -471,19 +476,31 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
h->mode = RDAC_MODE; /* LUN in RDAC mode */
/* Update ownership */
- if (inqp->avte_cvp & 0x1)
+ if (inqp->avte_cvp & 0x1) {
h->lun_state = RDAC_LUN_OWNED;
- else {
+ access_state = SCSI_ACCESS_STATE_OPTIMAL;
+ } else {
h->lun_state = RDAC_LUN_UNOWNED;
- if (h->mode == RDAC_MODE)
+ if (h->mode == RDAC_MODE) {
h->state = RDAC_STATE_PASSIVE;
+ access_state = SCSI_ACCESS_STATE_STANDBY;
+ } else
+ access_state = SCSI_ACCESS_STATE_ACTIVE;
}
/* Update path prio*/
- if (inqp->path_prio & 0x1)
+ if (inqp->path_prio & 0x1) {
h->preferred = RDAC_PREFERRED;
- else
+ access_state |= SCSI_ACCESS_STATE_PREFERRED;
+ } else
h->preferred = RDAC_NON_PREFERRED;
+ rcu_read_lock();
+ list_for_each_entry_rcu(tmp, &h->ctlr->dh_list, node) {
+ /* h->sdev should always be valid */
+ BUG_ON(!tmp->sdev);
+ tmp->sdev->access_state = access_state;
+ }
+ rcu_read_unlock();
}
return err;
@@ -508,6 +525,10 @@ static int initialize_controller(struct scsi_device *sdev,
h->ctlr = get_controller(index, array_name, array_id, sdev);
if (!h->ctlr)
err = SCSI_DH_RES_TEMP_UNAVAIL;
+ else {
+ list_add_rcu(&h->node, &h->ctlr->dh_list);
+ h->sdev = sdev;
+ }
spin_unlock(&list_lock);
}
return err;
@@ -829,8 +850,11 @@ static void rdac_bus_detach( struct scsi_device *sdev )
flush_workqueue(kmpath_rdacd);
spin_lock(&list_lock);
- if (h->ctlr)
+ if (h->ctlr) {
+ list_del_rcu(&h->node);
+ h->sdev = NULL;
kref_put(&h->ctlr->kref, release_controller);
+ }
spin_unlock(&list_lock);
sdev->handler_data = NULL;
kfree(h);
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index d4cda5e9600e..21c8d210c456 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -180,11 +180,14 @@ static u8 adpt_read_blink_led(adpt_hba* host)
*============================================================================
*/
+#ifdef MODULE
static struct pci_device_id dptids[] = {
{ PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{ PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{ 0, }
};
+#endif
+
MODULE_DEVICE_TABLE(pci,dptids);
static int adpt_detect(struct scsi_host_template* sht)
diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c
index baf913047b48..3e8483410f61 100644
--- a/drivers/scsi/esas2r/esas2r_ioctl.c
+++ b/drivers/scsi/esas2r/esas2r_ioctl.c
@@ -1360,14 +1360,15 @@ int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg)
if (ioctl->header.channel == 0xFF) {
a = (struct esas2r_adapter *)hostdata;
} else {
- a = esas2r_adapters[ioctl->header.channel];
- if (ioctl->header.channel >= MAX_ADAPTERS || (a == NULL)) {
+ if (ioctl->header.channel >= MAX_ADAPTERS ||
+ esas2r_adapters[ioctl->header.channel] == NULL) {
ioctl->header.return_code = IOCTL_BAD_CHANNEL;
esas2r_log(ESAS2R_LOG_WARN, "bad channel value");
kfree(ioctl);
return -ENOTSUPP;
}
+ a = esas2r_adapters[ioctl->header.channel];
}
switch (cmd) {
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 34a1b1f333b4..3e83d485f743 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -1118,7 +1118,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
* If this is the first validated FCF, note the time and
* set a timer to trigger selection.
*/
- if (mtu_valid && !fip->sel_fcf && fcoe_ctlr_fcf_usable(fcf)) {
+ if (mtu_valid && !fip->sel_fcf && !fip->sel_time &&
+ fcoe_ctlr_fcf_usable(fcf)) {
fip->sel_time = jiffies +
msecs_to_jiffies(FCOE_CTLR_START_DELAY);
if (!timer_pending(&fip->timer) ||
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index eefe14d453db..b87ab38a4530 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -1768,7 +1768,7 @@ struct scsi_host_template fdomain_driver_template = {
};
#ifndef PCMCIA
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && defined(MODULE)
static struct pci_device_id fdomain_pci_tbl[] = {
{ PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 71e138044379..0a767740bf02 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -2838,7 +2838,6 @@ static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source,
u16 idx, gdth_evt_data *evt)
{
gdth_evt_str *e;
- struct timeval tv;
/* no GDTH_LOCK_HA() ! */
TRACE2(("gdth_store_event() source %d idx %d\n", source, idx));
@@ -2854,8 +2853,7 @@ static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source,
!strcmp((char *)&ebuffer[elastidx].event_data.event_string,
(char *)&evt->event_string)))) {
e = &ebuffer[elastidx];
- do_gettimeofday(&tv);
- e->last_stamp = tv.tv_sec;
+ e->last_stamp = (u32)ktime_get_real_seconds();
++e->same_count;
} else {
if (ebuffer[elastidx].event_source != 0) { /* entry not free ? */
@@ -2871,8 +2869,7 @@ static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source,
e = &ebuffer[elastidx];
e->event_source = source;
e->event_idx = idx;
- do_gettimeofday(&tv);
- e->first_stamp = e->last_stamp = tv.tv_sec;
+ e->first_stamp = e->last_stamp = (u32)ktime_get_real_seconds();
e->same_count = 1;
e->event_data = *evt;
e->application = 0;
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index e66e997992e3..be609db66807 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -148,7 +148,6 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
gdth_cmd_str *gdtcmd;
gdth_evt_str *estr;
char hrec[161];
- struct timeval tv;
char *buf;
gdth_dskstat_str *pds;
@@ -540,8 +539,14 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
if (estr->event_data.eu.driver.ionode == ha->hanum &&
estr->event_source == ES_ASYNC) {
gdth_log_event(&estr->event_data, hrec);
- do_gettimeofday(&tv);
- sec = (int)(tv.tv_sec - estr->first_stamp);
+
+ /*
+ * Elapsed seconds subtraction with unsigned operands is
+ * safe from wrap around in year 2106. Executes as:
+ * operand a + (2's complement operand b) + 1
+ */
+
+ sec = (int)((u32)ktime_get_real_seconds() - estr->first_stamp);
if (sec < 0) sec = 0;
seq_printf(m," date- %02d:%02d:%02d\t%s\n",
sec/3600, sec%3600/60, sec%60, hrec);
diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile
index 3e70eae81343..c6d3a1b5fcb9 100644
--- a/drivers/scsi/hisi_sas/Makefile
+++ b/drivers/scsi/hisi_sas/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_main.o
-obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_v1_hw.o
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_v1_hw.o hisi_sas_v2_hw.o
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 5af2e4187f01..29e89f340b64 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -12,22 +12,24 @@
#ifndef _HISI_SAS_H_
#define _HISI_SAS_H_
+#include <linux/acpi.h>
#include <linux/dmapool.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/regmap.h>
+#include <scsi/sas_ata.h>
#include <scsi/libsas.h>
-#define DRV_VERSION "v1.0"
+#define DRV_VERSION "v1.3"
#define HISI_SAS_MAX_PHYS 9
#define HISI_SAS_MAX_QUEUES 32
#define HISI_SAS_QUEUE_SLOTS 512
-#define HISI_SAS_MAX_ITCT_ENTRIES 4096
+#define HISI_SAS_MAX_ITCT_ENTRIES 2048
#define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES
-#define HISI_SAS_COMMAND_ENTRIES 8192
#define HISI_SAS_STATUS_BUF_SZ \
(sizeof(struct hisi_sas_err_record) + 1024)
@@ -36,6 +38,11 @@
#define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024)
#define HISI_SAS_MAX_SMP_RESP_SZ 1028
+#define HISI_SAS_MAX_STP_RESP_SZ 28
+
+#define DEV_IS_EXPANDER(type) \
+ ((type == SAS_EDGE_EXPANDER_DEVICE) || \
+ (type == SAS_FANOUT_EXPANDER_DEVICE))
struct hisi_hba;
@@ -105,6 +112,7 @@ struct hisi_sas_slot {
int cmplt_queue;
int cmplt_queue_slot;
int idx;
+ int abort;
void *cmd_hdr;
dma_addr_t cmd_hdr_dma;
void *status_buffer;
@@ -113,6 +121,7 @@ struct hisi_sas_slot {
dma_addr_t command_table_dma;
struct hisi_sas_sge_page *sge_page;
dma_addr_t sge_page_dma;
+ struct work_struct abort_slot;
};
struct hisi_sas_tmf_task {
@@ -132,6 +141,8 @@ struct hisi_sas_hw {
struct hisi_sas_tmf_task *tmf);
int (*prep_smp)(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot);
+ int (*prep_stp)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot);
int (*slot_complete)(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot, int abort);
void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
@@ -140,6 +151,7 @@ struct hisi_sas_hw {
void (*free_device)(struct hisi_hba *hisi_hba,
struct hisi_sas_device *dev);
int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
+ int max_command_entries;
int complete_hdr_size;
};
@@ -244,18 +256,7 @@ struct hisi_sas_itct {
__le64 sas_addr;
__le64 qw2;
__le64 qw3;
- __le64 qw4;
- __le64 qw_sata_ncq0_3;
- __le64 qw_sata_ncq7_4;
- __le64 qw_sata_ncq11_8;
- __le64 qw_sata_ncq15_12;
- __le64 qw_sata_ncq19_16;
- __le64 qw_sata_ncq23_20;
- __le64 qw_sata_ncq27_24;
- __le64 qw_sata_ncq31_28;
- __le64 qw_non_ncq_iptt;
- __le64 qw_rsvd0;
- __le64 qw_rsvd1;
+ __le64 qw4_15[12];
};
struct hisi_sas_iost {
@@ -266,17 +267,7 @@ struct hisi_sas_iost {
};
struct hisi_sas_err_record {
- /* dw0 */
- __le32 dma_err_type;
-
- /* dw1 */
- __le32 trans_tx_fail_type;
-
- /* dw2 */
- __le32 trans_rx_fail_type;
-
- /* dw3 */
- u32 rsvd;
+ u32 data[4];
};
struct hisi_sas_initial_fis {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 99b1950d751c..097ab4f27a6b 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -12,13 +12,12 @@
#include "hisi_sas.h"
#define DRV_NAME "hisi_sas"
-#define DEV_IS_EXPANDER(type) \
- ((type == SAS_EDGE_EXPANDER_DEVICE) || \
- (type == SAS_FANOUT_EXPANDER_DEVICE))
-
#define DEV_IS_GONE(dev) \
((!dev) || (dev->dev_type == SAS_PHY_UNUSED))
+static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
+ u8 *lun, struct hisi_sas_tmf_task *tmf);
+
static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
{
return device->port->ha->lldd_ha;
@@ -111,6 +110,50 @@ static int hisi_sas_task_prep_ssp(struct hisi_hba *hisi_hba,
return hisi_hba->hw->prep_ssp(hisi_hba, slot, is_tmf, tmf);
}
+static int hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ return hisi_hba->hw->prep_stp(hisi_hba, slot);
+}
+
+/*
+ * This function will issue an abort TMF regardless of whether the
+ * task is in the sdev or not. Then it will do the task complete
+ * cleanup and callbacks.
+ */
+static void hisi_sas_slot_abort(struct work_struct *work)
+{
+ struct hisi_sas_slot *abort_slot =
+ container_of(work, struct hisi_sas_slot, abort_slot);
+ struct sas_task *task = abort_slot->task;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct hisi_sas_tmf_task tmf_task;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct scsi_lun lun;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int tag = abort_slot->idx;
+
+ if (!(task->task_proto & SAS_PROTOCOL_SSP)) {
+ dev_err(dev, "cannot abort slot for non-ssp task\n");
+ goto out;
+ }
+
+ int_to_scsilun(cmnd->device->lun, &lun);
+ tmf_task.tmf = TMF_ABORT_TASK;
+ tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+ hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task);
+out:
+ /* Do cleanup for this task */
+ hisi_sas_slot_task_free(hisi_hba, task, abort_slot);
+ if (task->task_done)
+ task->task_done(task);
+ if (sas_dev && sas_dev->running_req)
+ sas_dev->running_req--;
+}
+
static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
int is_tmf, struct hisi_sas_tmf_task *tmf,
int *pass)
@@ -204,6 +247,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
slot->task = task;
slot->port = port;
task->lldd_task = slot;
+ INIT_WORK(&slot->abort_slot, hisi_sas_slot_abort);
slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool,
GFP_ATOMIC,
@@ -234,6 +278,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
case SAS_PROTOCOL_SATA:
case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ rc = hisi_sas_task_prep_ata(hisi_hba, slot);
+ break;
default:
dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n",
task->task_proto);
@@ -407,6 +453,19 @@ static int hisi_sas_dev_found(struct domain_device *device)
return 0;
}
+static int hisi_sas_slave_configure(struct scsi_device *sdev)
+{
+ struct domain_device *dev = sdev_to_domain_dev(sdev);
+ int ret = sas_slave_configure(sdev);
+
+ if (ret)
+ return ret;
+ if (!dev_is_sata(dev))
+ sas_change_queue_depth(sdev, 64);
+
+ return 0;
+}
+
static void hisi_sas_scan_start(struct Scsi_Host *shost)
{
struct hisi_hba *hisi_hba = shost_priv(shost);
@@ -657,7 +716,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_STAT_GOOD) {
+ task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
res = TMF_RESP_FUNC_COMPLETE;
break;
}
@@ -944,7 +1003,7 @@ static struct scsi_host_template hisi_sas_sht = {
.name = DRV_NAME,
.queuecommand = sas_queuecommand,
.target_alloc = sas_target_alloc,
- .slave_configure = sas_slave_configure,
+ .slave_configure = hisi_sas_slave_configure,
.scan_finished = hisi_sas_scan_finished,
.scan_start = hisi_sas_scan_start,
.change_queue_depth = sas_change_queue_depth,
@@ -977,9 +1036,9 @@ static struct sas_domain_function_template hisi_sas_transport_ops = {
static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
{
- int i, s;
struct platform_device *pdev = hisi_hba->pdev;
struct device *dev = &pdev->dev;
+ int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
spin_lock_init(&hisi_hba->lock);
for (i = 0; i < hisi_hba->n_phy; i++) {
@@ -1039,13 +1098,13 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
memset(hisi_hba->itct, 0, s);
- hisi_hba->slot_info = devm_kcalloc(dev, HISI_SAS_COMMAND_ENTRIES,
+ hisi_hba->slot_info = devm_kcalloc(dev, max_command_entries,
sizeof(struct hisi_sas_slot),
GFP_KERNEL);
if (!hisi_hba->slot_info)
goto err_out;
- s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost);
+ s = max_command_entries * sizeof(struct hisi_sas_iost);
hisi_hba->iost = dma_alloc_coherent(dev, s, &hisi_hba->iost_dma,
GFP_KERNEL);
if (!hisi_hba->iost)
@@ -1053,7 +1112,7 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
memset(hisi_hba->iost, 0, s);
- s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+ s = max_command_entries * sizeof(struct hisi_sas_breakpoint);
hisi_hba->breakpoint = dma_alloc_coherent(dev, s,
&hisi_hba->breakpoint_dma, GFP_KERNEL);
if (!hisi_hba->breakpoint)
@@ -1061,7 +1120,7 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
memset(hisi_hba->breakpoint, 0, s);
- hisi_hba->slot_index_count = HISI_SAS_COMMAND_ENTRIES;
+ hisi_hba->slot_index_count = max_command_entries;
s = hisi_hba->slot_index_count / sizeof(unsigned long);
hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL);
if (!hisi_hba->slot_index_tags)
@@ -1079,7 +1138,7 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
goto err_out;
memset(hisi_hba->initial_fis, 0, s);
- s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2;
+ s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2;
hisi_hba->sata_breakpoint = dma_alloc_coherent(dev, s,
&hisi_hba->sata_breakpoint_dma, GFP_KERNEL);
if (!hisi_hba->sata_breakpoint)
@@ -1102,7 +1161,7 @@ err_out:
static void hisi_sas_free(struct hisi_hba *hisi_hba)
{
struct device *dev = &hisi_hba->pdev->dev;
- int i, s;
+ int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
for (i = 0; i < hisi_hba->queue_count; i++) {
s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
@@ -1127,12 +1186,12 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba)
dma_free_coherent(dev, s,
hisi_hba->itct, hisi_hba->itct_dma);
- s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost);
+ s = max_command_entries * sizeof(struct hisi_sas_iost);
if (hisi_hba->iost)
dma_free_coherent(dev, s,
hisi_hba->iost, hisi_hba->iost_dma);
- s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+ s = max_command_entries * sizeof(struct hisi_sas_breakpoint);
if (hisi_hba->breakpoint)
dma_free_coherent(dev, s,
hisi_hba->breakpoint,
@@ -1145,7 +1204,7 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba)
hisi_hba->initial_fis,
hisi_hba->initial_fis_dma);
- s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2;
+ s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2;
if (hisi_hba->sata_breakpoint)
dma_free_coherent(dev, s,
hisi_hba->sata_breakpoint,
@@ -1163,7 +1222,6 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
struct hisi_hba *hisi_hba;
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
- struct property *sas_addr_prop;
shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba));
if (!shost)
@@ -1177,27 +1235,34 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
init_timer(&hisi_hba->timer);
- sas_addr_prop = of_find_property(np, "sas-addr", NULL);
- if (!sas_addr_prop || (sas_addr_prop->length != SAS_ADDR_SIZE))
+ if (device_property_read_u8_array(dev, "sas-addr", hisi_hba->sas_addr,
+ SAS_ADDR_SIZE))
goto err_out;
- memcpy(hisi_hba->sas_addr, sas_addr_prop->value, SAS_ADDR_SIZE);
- if (of_property_read_u32(np, "ctrl-reset-reg",
- &hisi_hba->ctrl_reset_reg))
- goto err_out;
+ if (np) {
+ hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(np,
+ "hisilicon,sas-syscon");
+ if (IS_ERR(hisi_hba->ctrl))
+ goto err_out;
- if (of_property_read_u32(np, "ctrl-reset-sts-reg",
- &hisi_hba->ctrl_reset_sts_reg))
- goto err_out;
+ if (device_property_read_u32(dev, "ctrl-reset-reg",
+ &hisi_hba->ctrl_reset_reg))
+ goto err_out;
- if (of_property_read_u32(np, "ctrl-clock-ena-reg",
- &hisi_hba->ctrl_clock_ena_reg))
- goto err_out;
+ if (device_property_read_u32(dev, "ctrl-reset-sts-reg",
+ &hisi_hba->ctrl_reset_sts_reg))
+ goto err_out;
- if (of_property_read_u32(np, "phy-count", &hisi_hba->n_phy))
+ if (device_property_read_u32(dev, "ctrl-clock-ena-reg",
+ &hisi_hba->ctrl_clock_ena_reg))
+ goto err_out;
+ }
+
+ if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy))
goto err_out;
- if (of_property_read_u32(np, "queue-count", &hisi_hba->queue_count))
+ if (device_property_read_u32(dev, "queue-count",
+ &hisi_hba->queue_count))
goto err_out;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1205,11 +1270,6 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
if (IS_ERR(hisi_hba->regs))
goto err_out;
- hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(
- np, "hisilicon,sas-syscon");
- if (IS_ERR(hisi_hba->ctrl))
- goto err_out;
-
if (hisi_sas_alloc(hisi_hba, shost)) {
hisi_sas_free(hisi_hba);
goto err_out;
@@ -1277,8 +1337,8 @@ int hisi_sas_probe(struct platform_device *pdev,
shost->max_channel = 1;
shost->max_cmd_len = 16;
shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
- shost->can_queue = HISI_SAS_COMMAND_ENTRIES;
- shost->cmd_per_lun = HISI_SAS_COMMAND_ENTRIES;
+ shost->can_queue = hisi_hba->hw->max_command_entries;
+ shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
sha->sas_ha_name = DRV_NAME;
sha->dev = &hisi_hba->pdev->dev;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index eea24d7531cf..1abbc2e162df 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -288,6 +288,20 @@ struct hisi_sas_complete_v1_hdr {
__le32 data;
};
+struct hisi_sas_err_record_v1 {
+ /* dw0 */
+ __le32 dma_err_type;
+
+ /* dw1 */
+ __le32 trans_tx_fail_type;
+
+ /* dw2 */
+ __le32 trans_rx_fail_type;
+
+ /* dw3 */
+ u32 rsvd;
+};
+
enum {
HISI_SAS_PHY_BCAST_ACK = 0,
HISI_SAS_PHY_SL_PHY_ENABLED,
@@ -392,6 +406,8 @@ enum {
TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x31a */
};
+#define HISI_SAS_COMMAND_ENTRIES_V1_HW 8192
+
#define HISI_SAS_PHY_MAX_INT_NR (HISI_SAS_PHY_INT_NR * HISI_SAS_MAX_PHYS)
#define HISI_SAS_CQ_MAX_INT_NR (HISI_SAS_MAX_QUEUES)
#define HISI_SAS_FATAL_INT_NR (2)
@@ -607,31 +623,42 @@ static int reset_hw_v1_hw(struct hisi_hba *hisi_hba)
return -EIO;
}
- /* Apply reset and disable clock */
- /* clk disable reg is offset by +4 bytes from clk enable reg */
- regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
- RESET_VALUE);
- regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
- RESET_VALUE);
- msleep(1);
- regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
- if (RESET_VALUE != (val & RESET_VALUE)) {
- dev_err(dev, "Reset failed\n");
- return -EIO;
- }
+ if (ACPI_HANDLE(dev)) {
+ acpi_status s;
- /* De-reset and enable clock */
- /* deassert rst reg is offset by +4 bytes from assert reg */
- regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
- RESET_VALUE);
- regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
- RESET_VALUE);
- msleep(1);
- regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
- if (val & RESET_VALUE) {
- dev_err(dev, "De-reset failed\n");
- return -EIO;
- }
+ s = acpi_evaluate_object(ACPI_HANDLE(dev), "_RST", NULL, NULL);
+ if (ACPI_FAILURE(s)) {
+ dev_err(dev, "Reset failed\n");
+ return -EIO;
+ }
+ } else if (hisi_hba->ctrl) {
+ /* Apply reset and disable clock */
+ /* clk disable reg is offset by +4 bytes from clk enable reg */
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
+ RESET_VALUE);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
+ RESET_VALUE);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (RESET_VALUE != (val & RESET_VALUE)) {
+ dev_err(dev, "Reset failed\n");
+ return -EIO;
+ }
+
+ /* De-reset and enable clock */
+ /* deassert rst reg is offset by +4 bytes from assert reg */
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
+ RESET_VALUE);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
+ RESET_VALUE);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (val & RESET_VALUE) {
+ dev_err(dev, "De-reset failed\n");
+ return -EIO;
+ }
+ } else
+ dev_warn(dev, "no reset method\n");
return 0;
}
@@ -1096,7 +1123,7 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot)
{
struct task_status_struct *ts = &task->task_status;
- struct hisi_sas_err_record *err_record = slot->status_buffer;
+ struct hisi_sas_err_record_v1 *err_record = slot->status_buffer;
struct device *dev = &hisi_hba->pdev->dev;
switch (task->task_proto) {
@@ -1185,6 +1212,14 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
ts->stat = SAS_NAK_R_ERR;
break;
}
+ case TRANS_TX_CREDIT_TIMEOUT_ERR:
+ case TRANS_TX_CLOSE_NORMAL_ERR:
+ {
+ /* This will request a retry */
+ ts->stat = SAS_QUEUE_FULL;
+ slot->abort = 1;
+ break;
+ }
default:
{
ts->stat = SAM_STAT_CHECK_CONDITION;
@@ -1220,7 +1255,6 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
struct domain_device *device;
enum exec_status sts;
struct hisi_sas_complete_v1_hdr *complete_queue =
- (struct hisi_sas_complete_v1_hdr *)
hisi_hba->complete_hdr[slot->cmplt_queue];
struct hisi_sas_complete_v1_hdr *complete_hdr;
u32 cmplt_hdr_data;
@@ -1293,6 +1327,11 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
!(cmplt_hdr_data & CMPLT_HDR_RSPNS_XFRD_MSK)) {
slot_err_v1_hw(hisi_hba, task, slot);
+ if (unlikely(slot->abort)) {
+ queue_work(hisi_hba->wq, &slot->abort_slot);
+ /* immediately return and do not complete */
+ return ts->stat;
+ }
goto out;
}
@@ -1796,6 +1835,7 @@ static const struct hisi_sas_hw hisi_sas_v1_hw = {
.phy_disable = disable_phy_v1_hw,
.phy_hard_reset = phy_hard_reset_v1_hw,
.get_wideport_bitmap = get_wideport_bitmap_v1_hw,
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V1_HW,
.complete_hdr_size = sizeof(struct hisi_sas_complete_v1_hdr),
};
@@ -1815,12 +1855,20 @@ static const struct of_device_id sas_v1_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sas_v1_of_match);
+static const struct acpi_device_id sas_v1_acpi_match[] = {
+ { "HISI0161", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(acpi, sas_v1_acpi_match);
+
static struct platform_driver hisi_sas_v1_driver = {
.probe = hisi_sas_v1_probe,
.remove = hisi_sas_v1_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = sas_v1_of_match,
+ .acpi_match_table = ACPI_PTR(sas_v1_acpi_match),
},
};
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
new file mode 100644
index 000000000000..b7337476454b
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -0,0 +1,2214 @@
+/*
+ * Copyright (c) 2016 Linaro Ltd.
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * 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.
+ *
+ */
+
+#include "hisi_sas.h"
+#define DRV_NAME "hisi_sas_v2_hw"
+
+/* global registers need init*/
+#define DLVRY_QUEUE_ENABLE 0x0
+#define IOST_BASE_ADDR_LO 0x8
+#define IOST_BASE_ADDR_HI 0xc
+#define ITCT_BASE_ADDR_LO 0x10
+#define ITCT_BASE_ADDR_HI 0x14
+#define IO_BROKEN_MSG_ADDR_LO 0x18
+#define IO_BROKEN_MSG_ADDR_HI 0x1c
+#define PHY_CONTEXT 0x20
+#define PHY_STATE 0x24
+#define PHY_PORT_NUM_MA 0x28
+#define PORT_STATE 0x2c
+#define PORT_STATE_PHY8_PORT_NUM_OFF 16
+#define PORT_STATE_PHY8_PORT_NUM_MSK (0xf << PORT_STATE_PHY8_PORT_NUM_OFF)
+#define PORT_STATE_PHY8_CONN_RATE_OFF 20
+#define PORT_STATE_PHY8_CONN_RATE_MSK (0xf << PORT_STATE_PHY8_CONN_RATE_OFF)
+#define PHY_CONN_RATE 0x30
+#define HGC_TRANS_TASK_CNT_LIMIT 0x38
+#define AXI_AHB_CLK_CFG 0x3c
+#define ITCT_CLR 0x44
+#define ITCT_CLR_EN_OFF 16
+#define ITCT_CLR_EN_MSK (0x1 << ITCT_CLR_EN_OFF)
+#define ITCT_DEV_OFF 0
+#define ITCT_DEV_MSK (0x7ff << ITCT_DEV_OFF)
+#define AXI_USER1 0x48
+#define AXI_USER2 0x4c
+#define IO_SATA_BROKEN_MSG_ADDR_LO 0x58
+#define IO_SATA_BROKEN_MSG_ADDR_HI 0x5c
+#define SATA_INITI_D2H_STORE_ADDR_LO 0x60
+#define SATA_INITI_D2H_STORE_ADDR_HI 0x64
+#define HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL 0x84
+#define HGC_SAS_TXFAIL_RETRY_CTRL 0x88
+#define HGC_GET_ITV_TIME 0x90
+#define DEVICE_MSG_WORK_MODE 0x94
+#define OPENA_WT_CONTI_TIME 0x9c
+#define I_T_NEXUS_LOSS_TIME 0xa0
+#define MAX_CON_TIME_LIMIT_TIME 0xa4
+#define BUS_INACTIVE_LIMIT_TIME 0xa8
+#define REJECT_TO_OPEN_LIMIT_TIME 0xac
+#define CFG_AGING_TIME 0xbc
+#define HGC_DFX_CFG2 0xc0
+#define HGC_IOMB_PROC1_STATUS 0x104
+#define CFG_1US_TIMER_TRSH 0xcc
+#define HGC_INVLD_DQE_INFO 0x148
+#define HGC_INVLD_DQE_INFO_FB_CH0_OFF 9
+#define HGC_INVLD_DQE_INFO_FB_CH0_MSK (0x1 << HGC_INVLD_DQE_INFO_FB_CH0_OFF)
+#define HGC_INVLD_DQE_INFO_FB_CH3_OFF 18
+#define INT_COAL_EN 0x19c
+#define OQ_INT_COAL_TIME 0x1a0
+#define OQ_INT_COAL_CNT 0x1a4
+#define ENT_INT_COAL_TIME 0x1a8
+#define ENT_INT_COAL_CNT 0x1ac
+#define OQ_INT_SRC 0x1b0
+#define OQ_INT_SRC_MSK 0x1b4
+#define ENT_INT_SRC1 0x1b8
+#define ENT_INT_SRC1_D2H_FIS_CH0_OFF 0
+#define ENT_INT_SRC1_D2H_FIS_CH0_MSK (0x1 << ENT_INT_SRC1_D2H_FIS_CH0_OFF)
+#define ENT_INT_SRC1_D2H_FIS_CH1_OFF 8
+#define ENT_INT_SRC1_D2H_FIS_CH1_MSK (0x1 << ENT_INT_SRC1_D2H_FIS_CH1_OFF)
+#define ENT_INT_SRC2 0x1bc
+#define ENT_INT_SRC3 0x1c0
+#define ENT_INT_SRC3_ITC_INT_OFF 15
+#define ENT_INT_SRC3_ITC_INT_MSK (0x1 << ENT_INT_SRC3_ITC_INT_OFF)
+#define ENT_INT_SRC_MSK1 0x1c4
+#define ENT_INT_SRC_MSK2 0x1c8
+#define ENT_INT_SRC_MSK3 0x1cc
+#define ENT_INT_SRC_MSK3_ENT95_MSK_OFF 31
+#define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF)
+#define SAS_ECC_INTR_MSK 0x1ec
+#define HGC_ERR_STAT_EN 0x238
+#define DLVRY_Q_0_BASE_ADDR_LO 0x260
+#define DLVRY_Q_0_BASE_ADDR_HI 0x264
+#define DLVRY_Q_0_DEPTH 0x268
+#define DLVRY_Q_0_WR_PTR 0x26c
+#define DLVRY_Q_0_RD_PTR 0x270
+#define HYPER_STREAM_ID_EN_CFG 0xc80
+#define OQ0_INT_SRC_MSK 0xc90
+#define COMPL_Q_0_BASE_ADDR_LO 0x4e0
+#define COMPL_Q_0_BASE_ADDR_HI 0x4e4
+#define COMPL_Q_0_DEPTH 0x4e8
+#define COMPL_Q_0_WR_PTR 0x4ec
+#define COMPL_Q_0_RD_PTR 0x4f0
+
+/* phy registers need init */
+#define PORT_BASE (0x2000)
+
+#define PHY_CFG (PORT_BASE + 0x0)
+#define HARD_PHY_LINKRATE (PORT_BASE + 0x4)
+#define PHY_CFG_ENA_OFF 0
+#define PHY_CFG_ENA_MSK (0x1 << PHY_CFG_ENA_OFF)
+#define PHY_CFG_DC_OPT_OFF 2
+#define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF)
+#define PROG_PHY_LINK_RATE (PORT_BASE + 0x8)
+#define PROG_PHY_LINK_RATE_MAX_OFF 0
+#define PROG_PHY_LINK_RATE_MAX_MSK (0xff << PROG_PHY_LINK_RATE_MAX_OFF)
+#define PHY_CTRL (PORT_BASE + 0x14)
+#define PHY_CTRL_RESET_OFF 0
+#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
+#define SAS_PHY_CTRL (PORT_BASE + 0x20)
+#define SL_CFG (PORT_BASE + 0x84)
+#define PHY_PCN (PORT_BASE + 0x44)
+#define SL_TOUT_CFG (PORT_BASE + 0x8c)
+#define SL_CONTROL (PORT_BASE + 0x94)
+#define SL_CONTROL_NOTIFY_EN_OFF 0
+#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
+#define TX_ID_DWORD0 (PORT_BASE + 0x9c)
+#define TX_ID_DWORD1 (PORT_BASE + 0xa0)
+#define TX_ID_DWORD2 (PORT_BASE + 0xa4)
+#define TX_ID_DWORD3 (PORT_BASE + 0xa8)
+#define TX_ID_DWORD4 (PORT_BASE + 0xaC)
+#define TX_ID_DWORD5 (PORT_BASE + 0xb0)
+#define TX_ID_DWORD6 (PORT_BASE + 0xb4)
+#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
+#define RX_IDAF_DWORD1 (PORT_BASE + 0xc8)
+#define RX_IDAF_DWORD2 (PORT_BASE + 0xcc)
+#define RX_IDAF_DWORD3 (PORT_BASE + 0xd0)
+#define RX_IDAF_DWORD4 (PORT_BASE + 0xd4)
+#define RX_IDAF_DWORD5 (PORT_BASE + 0xd8)
+#define RX_IDAF_DWORD6 (PORT_BASE + 0xdc)
+#define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
+#define DONE_RECEIVED_TIME (PORT_BASE + 0x11c)
+#define CHL_INT0 (PORT_BASE + 0x1b4)
+#define CHL_INT0_HOTPLUG_TOUT_OFF 0
+#define CHL_INT0_HOTPLUG_TOUT_MSK (0x1 << CHL_INT0_HOTPLUG_TOUT_OFF)
+#define CHL_INT0_SL_RX_BCST_ACK_OFF 1
+#define CHL_INT0_SL_RX_BCST_ACK_MSK (0x1 << CHL_INT0_SL_RX_BCST_ACK_OFF)
+#define CHL_INT0_SL_PHY_ENABLE_OFF 2
+#define CHL_INT0_SL_PHY_ENABLE_MSK (0x1 << CHL_INT0_SL_PHY_ENABLE_OFF)
+#define CHL_INT0_NOT_RDY_OFF 4
+#define CHL_INT0_NOT_RDY_MSK (0x1 << CHL_INT0_NOT_RDY_OFF)
+#define CHL_INT0_PHY_RDY_OFF 5
+#define CHL_INT0_PHY_RDY_MSK (0x1 << CHL_INT0_PHY_RDY_OFF)
+#define CHL_INT1 (PORT_BASE + 0x1b8)
+#define CHL_INT1_DMAC_TX_ECC_ERR_OFF 15
+#define CHL_INT1_DMAC_TX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_TX_ECC_ERR_OFF)
+#define CHL_INT1_DMAC_RX_ECC_ERR_OFF 17
+#define CHL_INT1_DMAC_RX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_RX_ECC_ERR_OFF)
+#define CHL_INT2 (PORT_BASE + 0x1bc)
+#define CHL_INT0_MSK (PORT_BASE + 0x1c0)
+#define CHL_INT1_MSK (PORT_BASE + 0x1c4)
+#define CHL_INT2_MSK (PORT_BASE + 0x1c8)
+#define CHL_INT_COAL_EN (PORT_BASE + 0x1d0)
+#define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0)
+#define PHYCTRL_NOT_RDY_MSK (PORT_BASE + 0x2b4)
+#define PHYCTRL_DWS_RESET_MSK (PORT_BASE + 0x2b8)
+#define PHYCTRL_PHY_ENA_MSK (PORT_BASE + 0x2bc)
+#define SL_RX_BCAST_CHK_MSK (PORT_BASE + 0x2c0)
+#define PHYCTRL_OOB_RESTART_MSK (PORT_BASE + 0x2c4)
+#define DMA_TX_STATUS (PORT_BASE + 0x2d0)
+#define DMA_TX_STATUS_BUSY_OFF 0
+#define DMA_TX_STATUS_BUSY_MSK (0x1 << DMA_TX_STATUS_BUSY_OFF)
+#define DMA_RX_STATUS (PORT_BASE + 0x2e8)
+#define DMA_RX_STATUS_BUSY_OFF 0
+#define DMA_RX_STATUS_BUSY_MSK (0x1 << DMA_RX_STATUS_BUSY_OFF)
+
+#define AXI_CFG (0x5100)
+#define AM_CFG_MAX_TRANS (0x5010)
+#define AM_CFG_SINGLE_PORT_MAX_TRANS (0x5014)
+
+/* HW dma structures */
+/* Delivery queue header */
+/* dw0 */
+#define CMD_HDR_RESP_REPORT_OFF 5
+#define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF)
+#define CMD_HDR_TLR_CTRL_OFF 6
+#define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF)
+#define CMD_HDR_PORT_OFF 18
+#define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF)
+#define CMD_HDR_PRIORITY_OFF 27
+#define CMD_HDR_PRIORITY_MSK (0x1 << CMD_HDR_PRIORITY_OFF)
+#define CMD_HDR_CMD_OFF 29
+#define CMD_HDR_CMD_MSK (0x7 << CMD_HDR_CMD_OFF)
+/* dw1 */
+#define CMD_HDR_DIR_OFF 5
+#define CMD_HDR_DIR_MSK (0x3 << CMD_HDR_DIR_OFF)
+#define CMD_HDR_RESET_OFF 7
+#define CMD_HDR_RESET_MSK (0x1 << CMD_HDR_RESET_OFF)
+#define CMD_HDR_VDTL_OFF 10
+#define CMD_HDR_VDTL_MSK (0x1 << CMD_HDR_VDTL_OFF)
+#define CMD_HDR_FRAME_TYPE_OFF 11
+#define CMD_HDR_FRAME_TYPE_MSK (0x1f << CMD_HDR_FRAME_TYPE_OFF)
+#define CMD_HDR_DEV_ID_OFF 16
+#define CMD_HDR_DEV_ID_MSK (0xffff << CMD_HDR_DEV_ID_OFF)
+/* dw2 */
+#define CMD_HDR_CFL_OFF 0
+#define CMD_HDR_CFL_MSK (0x1ff << CMD_HDR_CFL_OFF)
+#define CMD_HDR_NCQ_TAG_OFF 10
+#define CMD_HDR_NCQ_TAG_MSK (0x1f << CMD_HDR_NCQ_TAG_OFF)
+#define CMD_HDR_MRFL_OFF 15
+#define CMD_HDR_MRFL_MSK (0x1ff << CMD_HDR_MRFL_OFF)
+#define CMD_HDR_SG_MOD_OFF 24
+#define CMD_HDR_SG_MOD_MSK (0x3 << CMD_HDR_SG_MOD_OFF)
+#define CMD_HDR_FIRST_BURST_OFF 26
+#define CMD_HDR_FIRST_BURST_MSK (0x1 << CMD_HDR_SG_MOD_OFF)
+/* dw3 */
+#define CMD_HDR_IPTT_OFF 0
+#define CMD_HDR_IPTT_MSK (0xffff << CMD_HDR_IPTT_OFF)
+/* dw6 */
+#define CMD_HDR_DIF_SGL_LEN_OFF 0
+#define CMD_HDR_DIF_SGL_LEN_MSK (0xffff << CMD_HDR_DIF_SGL_LEN_OFF)
+#define CMD_HDR_DATA_SGL_LEN_OFF 16
+#define CMD_HDR_DATA_SGL_LEN_MSK (0xffff << CMD_HDR_DATA_SGL_LEN_OFF)
+
+/* Completion header */
+/* dw0 */
+#define CMPLT_HDR_RSPNS_XFRD_OFF 10
+#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
+#define CMPLT_HDR_ERX_OFF 12
+#define CMPLT_HDR_ERX_MSK (0x1 << CMPLT_HDR_ERX_OFF)
+/* dw1 */
+#define CMPLT_HDR_IPTT_OFF 0
+#define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF)
+#define CMPLT_HDR_DEV_ID_OFF 16
+#define CMPLT_HDR_DEV_ID_MSK (0xffff << CMPLT_HDR_DEV_ID_OFF)
+
+/* ITCT header */
+/* qw0 */
+#define ITCT_HDR_DEV_TYPE_OFF 0
+#define ITCT_HDR_DEV_TYPE_MSK (0x3 << ITCT_HDR_DEV_TYPE_OFF)
+#define ITCT_HDR_VALID_OFF 2
+#define ITCT_HDR_VALID_MSK (0x1 << ITCT_HDR_VALID_OFF)
+#define ITCT_HDR_MCR_OFF 5
+#define ITCT_HDR_MCR_MSK (0xf << ITCT_HDR_MCR_OFF)
+#define ITCT_HDR_VLN_OFF 9
+#define ITCT_HDR_VLN_MSK (0xf << ITCT_HDR_VLN_OFF)
+#define ITCT_HDR_PORT_ID_OFF 28
+#define ITCT_HDR_PORT_ID_MSK (0xf << ITCT_HDR_PORT_ID_OFF)
+/* qw2 */
+#define ITCT_HDR_INLT_OFF 0
+#define ITCT_HDR_INLT_MSK (0xffffULL << ITCT_HDR_INLT_OFF)
+#define ITCT_HDR_BITLT_OFF 16
+#define ITCT_HDR_BITLT_MSK (0xffffULL << ITCT_HDR_BITLT_OFF)
+#define ITCT_HDR_MCTLT_OFF 32
+#define ITCT_HDR_MCTLT_MSK (0xffffULL << ITCT_HDR_MCTLT_OFF)
+#define ITCT_HDR_RTOLT_OFF 48
+#define ITCT_HDR_RTOLT_MSK (0xffffULL << ITCT_HDR_RTOLT_OFF)
+
+struct hisi_sas_complete_v2_hdr {
+ __le32 dw0;
+ __le32 dw1;
+ __le32 act;
+ __le32 dw3;
+};
+
+struct hisi_sas_err_record_v2 {
+ /* dw0 */
+ __le32 trans_tx_fail_type;
+
+ /* dw1 */
+ __le32 trans_rx_fail_type;
+
+ /* dw2 */
+ __le16 dma_tx_err_type;
+ __le16 sipc_rx_err_type;
+
+ /* dw3 */
+ __le32 dma_rx_err_type;
+};
+
+enum {
+ HISI_SAS_PHY_PHY_UPDOWN,
+ HISI_SAS_PHY_CHNL_INT,
+ HISI_SAS_PHY_INT_NR
+};
+
+enum {
+ TRANS_TX_FAIL_BASE = 0x0, /* dw0 */
+ TRANS_RX_FAIL_BASE = 0x100, /* dw1 */
+ DMA_TX_ERR_BASE = 0x200, /* dw2 bit 15-0 */
+ SIPC_RX_ERR_BASE = 0x300, /* dw2 bit 31-16*/
+ DMA_RX_ERR_BASE = 0x400, /* dw3 */
+
+ /* trans tx*/
+ TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS = TRANS_TX_FAIL_BASE, /* 0x0 */
+ TRANS_TX_ERR_PHY_NOT_ENABLE, /* 0x1 */
+ TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION, /* 0x2 */
+ TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION, /* 0x3 */
+ TRANS_TX_OPEN_CNX_ERR_BY_OTHER, /* 0x4 */
+ RESERVED0, /* 0x5 */
+ TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT, /* 0x6 */
+ TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY, /* 0x7 */
+ TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED, /* 0x8 */
+ TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED, /* 0x9 */
+ TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION, /* 0xa */
+ TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD, /* 0xb */
+ TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER, /* 0xc */
+ TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED, /* 0xd */
+ TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT, /* 0xe */
+ TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION, /* 0xf */
+ TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED, /* 0x10 */
+ TRANS_TX_ERR_FRAME_TXED, /* 0x11 */
+ TRANS_TX_ERR_WITH_BREAK_TIMEOUT, /* 0x12 */
+ TRANS_TX_ERR_WITH_BREAK_REQUEST, /* 0x13 */
+ TRANS_TX_ERR_WITH_BREAK_RECEVIED, /* 0x14 */
+ TRANS_TX_ERR_WITH_CLOSE_TIMEOUT, /* 0x15 */
+ TRANS_TX_ERR_WITH_CLOSE_NORMAL, /* 0x16 for ssp*/
+ TRANS_TX_ERR_WITH_CLOSE_PHYDISALE, /* 0x17 */
+ TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x18 */
+ TRANS_TX_ERR_WITH_CLOSE_COMINIT, /* 0x19 */
+ TRANS_TX_ERR_WITH_NAK_RECEVIED, /* 0x1a for ssp*/
+ TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT, /* 0x1b for ssp*/
+ /*IO_TX_ERR_WITH_R_ERR_RECEVIED, [> 0x1b for sata/stp<] */
+ TRANS_TX_ERR_WITH_CREDIT_TIMEOUT, /* 0x1c for ssp */
+ /*IO_RX_ERR_WITH_SATA_DEVICE_LOST 0x1c for sata/stp */
+ TRANS_TX_ERR_WITH_IPTT_CONFLICT, /* 0x1d for ssp/smp */
+ TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS, /* 0x1e */
+ /*IO_TX_ERR_WITH_SYNC_RXD, [> 0x1e <] for sata/stp */
+ TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, /* 0x1f for sata/stp */
+
+ /* trans rx */
+ TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x100 */
+ TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x101 for sata/stp */
+ TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x102 for ssp/smp */
+ /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x102 <] for sata/stp */
+ TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x103 for sata/stp */
+ TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x104 for sata/stp */
+ TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x105 for smp */
+ /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x105 <] for sata/stp */
+ TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x106 for sata/stp*/
+ TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x107 */
+ TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x108 */
+ TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x109 */
+ TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x10a */
+ RESERVED1, /* 0x10b */
+ TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x10c */
+ TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x10d */
+ TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x10e */
+ TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x10f */
+ TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x110 for ssp/smp */
+ TRANS_RX_ERR_WITH_BAD_HASH, /* 0x111 for ssp */
+ /*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x111 <] for sata/stp */
+ TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x112 for ssp*/
+ /*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x112 <] for sata/stp */
+ TRANS_RX_SSP_FRM_LEN_ERR, /* 0x113 for ssp */
+ /*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x113 <] for sata */
+ RESERVED2, /* 0x114 */
+ RESERVED3, /* 0x115 */
+ RESERVED4, /* 0x116 */
+ RESERVED5, /* 0x117 */
+ TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x118 */
+ TRANS_RX_SMP_FRM_LEN_ERR, /* 0x119 */
+ TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x11a */
+ RESERVED6, /* 0x11b */
+ RESERVED7, /* 0x11c */
+ RESERVED8, /* 0x11d */
+ RESERVED9, /* 0x11e */
+ TRANS_RX_R_ERR, /* 0x11f */
+
+ /* dma tx */
+ DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x200 */
+ DMA_TX_DIF_APP_ERR, /* 0x201 */
+ DMA_TX_DIF_RPP_ERR, /* 0x202 */
+ DMA_TX_DATA_SGL_OVERFLOW, /* 0x203 */
+ DMA_TX_DIF_SGL_OVERFLOW, /* 0x204 */
+ DMA_TX_UNEXP_XFER_ERR, /* 0x205 */
+ DMA_TX_UNEXP_RETRANS_ERR, /* 0x206 */
+ DMA_TX_XFER_LEN_OVERFLOW, /* 0x207 */
+ DMA_TX_XFER_OFFSET_ERR, /* 0x208 */
+ DMA_TX_RAM_ECC_ERR, /* 0x209 */
+ DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x20a */
+
+ /* sipc rx */
+ SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x300 */
+ SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x301 */
+ SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x302 */
+ SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x303 */
+ SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x304 */
+ SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x305 */
+ SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x306 */
+ SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x307 */
+ SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x308 */
+ SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x309 */
+ SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x30a */
+
+ /* dma rx */
+ DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x400 */
+ DMA_RX_DIF_APP_ERR, /* 0x401 */
+ DMA_RX_DIF_RPP_ERR, /* 0x402 */
+ DMA_RX_DATA_SGL_OVERFLOW, /* 0x403 */
+ DMA_RX_DIF_SGL_OVERFLOW, /* 0x404 */
+ DMA_RX_DATA_LEN_OVERFLOW, /* 0x405 */
+ DMA_RX_DATA_LEN_UNDERFLOW, /* 0x406 */
+ DMA_RX_DATA_OFFSET_ERR, /* 0x407 */
+ RESERVED10, /* 0x408 */
+ DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x409 */
+ DMA_RX_RESP_BUF_OVERFLOW, /* 0x40a */
+ DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x40b */
+ DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x40c */
+ DMA_RX_UNEXP_RDFRAME_ERR, /* 0x40d */
+ DMA_RX_PIO_DATA_LEN_ERR, /* 0x40e */
+ DMA_RX_RDSETUP_STATUS_ERR, /* 0x40f */
+ DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x410 */
+ DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x411 */
+ DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x412 */
+ DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x413 */
+ DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x414 */
+ DMA_RX_RDSETUP_OFFSET_ERR, /* 0x415 */
+ DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x416 */
+ DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x417 */
+ DMA_RX_RAM_ECC_ERR, /* 0x418 */
+ DMA_RX_UNKNOWN_FRM_ERR, /* 0x419 */
+};
+
+#define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096
+
+#define DIR_NO_DATA 0
+#define DIR_TO_INI 1
+#define DIR_TO_DEVICE 2
+#define DIR_RESERVED 3
+
+#define SATA_PROTOCOL_NONDATA 0x1
+#define SATA_PROTOCOL_PIO 0x2
+#define SATA_PROTOCOL_DMA 0x4
+#define SATA_PROTOCOL_FPDMA 0x8
+#define SATA_PROTOCOL_ATAPI 0x10
+
+static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl(regs);
+}
+
+static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl_relaxed(regs);
+}
+
+static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ writel(val, regs);
+}
+
+static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba, int phy_no,
+ u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ writel(val, regs);
+}
+
+static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
+ int phy_no, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ return readl(regs);
+}
+
+static void config_phy_opt_mode_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_DC_OPT_MSK;
+ cfg |= 1 << PHY_CFG_DC_OPT_OFF;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void config_id_frame_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct sas_identify_frame identify_frame;
+ u32 *identify_buffer;
+
+ memset(&identify_frame, 0, sizeof(identify_frame));
+ identify_frame.dev_type = SAS_END_DEVICE;
+ identify_frame.frame_type = 0;
+ identify_frame._un1 = 1;
+ identify_frame.initiator_bits = SAS_PROTOCOL_ALL;
+ identify_frame.target_bits = SAS_PROTOCOL_NONE;
+ memcpy(&identify_frame._un4_11[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ memcpy(&identify_frame.sas_addr[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ identify_frame.phy_id = phy_no;
+ identify_buffer = (u32 *)(&identify_frame);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
+ __swab32(identify_buffer[0]));
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
+ identify_buffer[2]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
+ identify_buffer[1]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
+ identify_buffer[4]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
+ identify_buffer[3]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
+ __swab32(identify_buffer[5]));
+}
+
+static void init_id_frame_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ config_id_frame_v2_hw(hisi_hba, i);
+}
+
+static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ struct domain_device *device = sas_dev->sas_device;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u64 qw0, device_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
+ struct domain_device *parent_dev = device->parent;
+ struct hisi_sas_port *port = device->port->lldd_port;
+
+ memset(itct, 0, sizeof(*itct));
+
+ /* qw0 */
+ qw0 = 0;
+ switch (sas_dev->dev_type) {
+ case SAS_END_DEVICE:
+ case SAS_EDGE_EXPANDER_DEVICE:
+ case SAS_FANOUT_EXPANDER_DEVICE:
+ qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
+ break;
+ case SAS_SATA_DEV:
+ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
+ else
+ qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
+ break;
+ default:
+ dev_warn(dev, "setup itct: unsupported dev type (%d)\n",
+ sas_dev->dev_type);
+ }
+
+ qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
+ (device->max_linkrate << ITCT_HDR_MCR_OFF) |
+ (1 << ITCT_HDR_VLN_OFF) |
+ (port->id << ITCT_HDR_PORT_ID_OFF));
+ itct->qw0 = cpu_to_le64(qw0);
+
+ /* qw1 */
+ memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+ itct->sas_addr = __swab64(itct->sas_addr);
+
+ /* qw2 */
+ itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_INLT_OFF) |
+ (0xff00ULL << ITCT_HDR_BITLT_OFF) |
+ (0xff00ULL << ITCT_HDR_MCTLT_OFF) |
+ (0xff00ULL << ITCT_HDR_RTOLT_OFF));
+}
+
+static void free_device_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ u64 qw0, dev_id = sas_dev->device_id;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
+ u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+ int i;
+
+ /* clear the itct interrupt state */
+ if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
+ ENT_INT_SRC3_ITC_INT_MSK);
+
+ /* clear the itct int*/
+ for (i = 0; i < 2; i++) {
+ /* clear the itct table*/
+ reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
+ reg_val |= ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
+ hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
+
+ udelay(10);
+ reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+ if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) {
+ dev_dbg(dev, "got clear ITCT done interrupt\n");
+
+ /* invalid the itct state*/
+ qw0 = cpu_to_le64(itct->qw0);
+ qw0 &= ~(1 << ITCT_HDR_VALID_OFF);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
+ ENT_INT_SRC3_ITC_INT_MSK);
+ hisi_hba->devices[dev_id].dev_type = SAS_PHY_UNUSED;
+ hisi_hba->devices[dev_id].dev_status = HISI_SAS_DEV_NORMAL;
+
+ /* clear the itct */
+ hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
+ dev_dbg(dev, "clear ITCT ok\n");
+ break;
+ }
+ }
+}
+
+static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int i, reset_val;
+ u32 val;
+ unsigned long end_time;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ /* The mask needs to be set depending on the number of phys */
+ if (hisi_hba->n_phy == 9)
+ reset_val = 0x1fffff;
+ else
+ reset_val = 0x7ffff;
+
+ /* Disable all of the DQ */
+ for (i = 0; i < HISI_SAS_MAX_QUEUES; i++)
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0);
+
+ /* Disable all of the PHYs */
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 phy_cfg = hisi_sas_phy_read32(hisi_hba, i, PHY_CFG);
+
+ phy_cfg &= ~PHY_CTRL_RESET_MSK;
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CFG, phy_cfg);
+ }
+ udelay(50);
+
+ /* Ensure DMA tx & rx idle */
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 dma_tx_status, dma_rx_status;
+
+ end_time = jiffies + msecs_to_jiffies(1000);
+
+ while (1) {
+ dma_tx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_TX_STATUS);
+ dma_rx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_RX_STATUS);
+
+ if (!(dma_tx_status & DMA_TX_STATUS_BUSY_MSK) &&
+ !(dma_rx_status & DMA_RX_STATUS_BUSY_MSK))
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+ }
+
+ /* Ensure axi bus idle */
+ end_time = jiffies + msecs_to_jiffies(1000);
+ while (1) {
+ u32 axi_status =
+ hisi_sas_read32(hisi_hba, AXI_CFG);
+
+ if (axi_status == 0)
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+
+ /* reset and disable clock*/
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
+ reset_val);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
+ reset_val);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (reset_val != (val & reset_val)) {
+ dev_err(dev, "SAS reset fail.\n");
+ return -EIO;
+ }
+
+ /* De-reset and enable clock*/
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
+ reset_val);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
+ reset_val);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg,
+ &val);
+ if (val & reset_val) {
+ dev_err(dev, "SAS de-reset fail.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct device_node *np = dev->of_node;
+ int i;
+
+ /* Global registers init */
+
+ /* Deal with am-max-transmissions quirk */
+ if (of_get_property(np, "hip06-sas-v2-quirk-amt", NULL)) {
+ hisi_sas_write32(hisi_hba, AM_CFG_MAX_TRANS, 0x2020);
+ hisi_sas_write32(hisi_hba, AM_CFG_SINGLE_PORT_MAX_TRANS,
+ 0x2020);
+ } /* Else, use defaults -> do nothing */
+
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
+ (u32)((1ULL << hisi_hba->queue_count) - 1));
+ hisi_sas_write32(hisi_hba, AXI_USER1, 0xc0000000);
+ hisi_sas_write32(hisi_hba, AXI_USER2, 0x10000);
+ hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
+ hisi_sas_write32(hisi_hba, HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL, 0x7FF);
+ hisi_sas_write32(hisi_hba, OPENA_WT_CONTI_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x1F4);
+ hisi_sas_write32(hisi_hba, MAX_CON_TIME_LIMIT_TIME, 0x4E20);
+ hisi_sas_write32(hisi_hba, BUS_INACTIVE_LIMIT_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x1);
+ hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1);
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0x0);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC2, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0x7efefefe);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0x7efefefe);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0x7ffffffe);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xfffff3c0);
+ for (i = 0; i < hisi_hba->queue_count; i++)
+ hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0);
+
+ hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
+ hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
+ hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908);
+ hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x10);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff);
+ hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
+ hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x23f801fc);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT_COAL_EN, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199B694);
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ /* Delivery queue */
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+
+ /* Completion queue */
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+ }
+
+ /* itct */
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->itct_dma));
+
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->itct_dma));
+
+ /* iost */
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->iost_dma));
+
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->iost_dma));
+
+ /* breakpoint */
+ hisi_sas_write32(hisi_hba, IO_BROKEN_MSG_ADDR_LO,
+ lower_32_bits(hisi_hba->breakpoint_dma));
+
+ hisi_sas_write32(hisi_hba, IO_BROKEN_MSG_ADDR_HI,
+ upper_32_bits(hisi_hba->breakpoint_dma));
+
+ /* SATA broken msg */
+ hisi_sas_write32(hisi_hba, IO_SATA_BROKEN_MSG_ADDR_LO,
+ lower_32_bits(hisi_hba->sata_breakpoint_dma));
+
+ hisi_sas_write32(hisi_hba, IO_SATA_BROKEN_MSG_ADDR_HI,
+ upper_32_bits(hisi_hba->sata_breakpoint_dma));
+
+ /* SATA initial fis */
+ hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_LO,
+ lower_32_bits(hisi_hba->initial_fis_dma));
+
+ hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_HI,
+ upper_32_bits(hisi_hba->initial_fis_dma));
+}
+
+static int hw_init_v2_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ int rc;
+
+ rc = reset_hw_v2_hw(hisi_hba);
+ if (rc) {
+ dev_err(dev, "hisi_sas_reset_hw failed, rc=%d", rc);
+ return rc;
+ }
+
+ msleep(100);
+ init_reg_v2_hw(hisi_hba);
+
+ init_id_frame_v2_hw(hisi_hba);
+
+ return 0;
+}
+
+static void enable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg |= PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void start_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ config_id_frame_v2_hw(hisi_hba, phy_no);
+ config_phy_opt_mode_v2_hw(hisi_hba, phy_no);
+ enable_phy_v2_hw(hisi_hba, phy_no);
+}
+
+static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ disable_phy_v2_hw(hisi_hba, phy_no);
+}
+
+static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ stop_phy_v2_hw(hisi_hba, phy_no);
+ msleep(100);
+ start_phy_v2_hw(hisi_hba, phy_no);
+}
+
+static void start_phys_v2_hw(unsigned long data)
+{
+ struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ start_phy_v2_hw(hisi_hba, i);
+}
+
+static void phys_init_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ struct timer_list *timer = &hisi_hba->timer;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x6a);
+ hisi_sas_phy_read32(hisi_hba, i, CHL_INT2_MSK);
+ }
+
+ setup_timer(timer, start_phys_v2_hw, (unsigned long)hisi_hba);
+ mod_timer(timer, jiffies + HZ);
+}
+
+static void sl_notify_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 sl_control;
+
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control |= SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+ msleep(1);
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control &= ~SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+}
+
+static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
+{
+ int i, bitmap = 0;
+ u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+ u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ for (i = 0; i < (hisi_hba->n_phy < 9 ? hisi_hba->n_phy : 8); i++)
+ if (phy_state & 1 << i)
+ if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
+ bitmap |= 1 << i;
+
+ if (hisi_hba->n_phy == 9) {
+ u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
+
+ if (phy_state & 1 << 8)
+ if (((port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
+ PORT_STATE_PHY8_PORT_NUM_OFF) == port_id)
+ bitmap |= 1 << 9;
+ }
+
+ return bitmap;
+}
+
+/**
+ * This function allocates across all queues to load balance.
+ * Slots are allocated from queues in a round-robin fashion.
+ *
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, int *q, int *s)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 r, w;
+ int queue = hisi_hba->queue;
+
+ while (1) {
+ w = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_WR_PTR + (queue * 0x14));
+ r = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_RD_PTR + (queue * 0x14));
+ if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+ queue = (queue + 1) % hisi_hba->queue_count;
+ if (queue == hisi_hba->queue) {
+ dev_warn(dev, "could not find free slot\n");
+ return -EAGAIN;
+ }
+ continue;
+ }
+ break;
+ }
+ hisi_hba->queue = (queue + 1) % hisi_hba->queue_count;
+ *q = queue;
+ *s = w;
+ return 0;
+}
+
+static void start_delivery_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
+ int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+ ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS);
+}
+
+static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ struct hisi_sas_cmd_hdr *hdr,
+ struct scatterlist *scatter,
+ int n_elem)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct scatterlist *sg;
+ int i;
+
+ if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
+ dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
+ n_elem);
+ return -EINVAL;
+ }
+
+ slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+ &slot->sge_page_dma);
+ if (!slot->sge_page)
+ return -ENOMEM;
+
+ for_each_sg(scatter, sg, n_elem, i) {
+ struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
+
+ entry->addr = cpu_to_le64(sg_dma_address(sg));
+ entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+ entry->data_len = cpu_to_le32(sg_dma_len(sg));
+ entry->data_off = 0;
+ }
+
+ hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
+
+ hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+ return 0;
+}
+
+static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_port *port = slot->port;
+ struct scatterlist *sg_req, *sg_resp;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ dma_addr_t req_dma_addr;
+ unsigned int req_len, resp_len;
+ int elem, rc;
+
+ /*
+ * DMA-map SMP request, response buffers
+ */
+ /* req */
+ sg_req = &task->smp_task.smp_req;
+ elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
+ if (!elem)
+ return -ENOMEM;
+ req_len = sg_dma_len(sg_req);
+ req_dma_addr = sg_dma_address(sg_req);
+
+ /* resp */
+ sg_resp = &task->smp_task.smp_resp;
+ elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
+ if (!elem) {
+ rc = -ENOMEM;
+ goto err_out_req;
+ }
+ resp_len = sg_dma_len(sg_resp);
+ if ((req_len & 0x3) || (resp_len & 0x3)) {
+ rc = -EINVAL;
+ goto err_out_resp;
+ }
+
+ /* create header */
+ /* dw0 */
+ hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
+ (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */
+ (2 << CMD_HDR_CMD_OFF)); /* smp */
+
+ /* map itct entry */
+ hdr->dw1 = cpu_to_le32((sas_dev->device_id << CMD_HDR_DEV_ID_OFF) |
+ (1 << CMD_HDR_FRAME_TYPE_OFF) |
+ (DIR_NO_DATA << CMD_HDR_DIR_OFF));
+
+ /* dw2 */
+ hdr->dw2 = cpu_to_le32((((req_len - 4) / 4) << CMD_HDR_CFL_OFF) |
+ (HISI_SAS_MAX_SMP_RESP_SZ / 4 <<
+ CMD_HDR_MRFL_OFF));
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ return 0;
+
+err_out_resp:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+err_out_req:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ return rc;
+}
+
+static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_port *port = slot->port;
+ struct sas_ssp_task *ssp_task = &task->ssp_task;
+ struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
+ int has_data = 0, rc, priority = is_tmf;
+ u8 *buf_cmd;
+ u32 dw1 = 0, dw2 = 0;
+
+ hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
+ (2 << CMD_HDR_TLR_CTRL_OFF) |
+ (port->id << CMD_HDR_PORT_OFF) |
+ (priority << CMD_HDR_PRIORITY_OFF) |
+ (1 << CMD_HDR_CMD_OFF)); /* ssp */
+
+ dw1 = 1 << CMD_HDR_VDTL_OFF;
+ if (is_tmf) {
+ dw1 |= 2 << CMD_HDR_FRAME_TYPE_OFF;
+ dw1 |= DIR_NO_DATA << CMD_HDR_DIR_OFF;
+ } else {
+ dw1 |= 1 << CMD_HDR_FRAME_TYPE_OFF;
+ switch (scsi_cmnd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ has_data = 1;
+ dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
+ break;
+ case DMA_FROM_DEVICE:
+ has_data = 1;
+ dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
+ break;
+ default:
+ dw1 &= ~CMD_HDR_DIR_MSK;
+ }
+ }
+
+ /* map itct entry */
+ dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
+ hdr->dw1 = cpu_to_le32(dw1);
+
+ dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr)
+ + 3) / 4) << CMD_HDR_CFL_OFF) |
+ ((HISI_SAS_MAX_SSP_RESP_SZ / 4) << CMD_HDR_MRFL_OFF) |
+ (2 << CMD_HDR_SG_MOD_OFF);
+ hdr->dw2 = cpu_to_le32(dw2);
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx);
+
+ if (has_data) {
+ rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
+ slot->n_elem);
+ if (rc)
+ return rc;
+ }
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+ hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
+
+ memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+ if (!is_tmf) {
+ buf_cmd[9] = task->ssp_task.task_attr |
+ (task->ssp_task.task_prio << 3);
+ memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
+ task->ssp_task.cmd->cmd_len);
+ } else {
+ buf_cmd[10] = tmf->tmf;
+ switch (tmf->tmf) {
+ case TMF_ABORT_TASK:
+ case TMF_QUERY_TASK:
+ buf_cmd[12] =
+ (tmf->tag_of_task_to_be_managed >> 8) & 0xff;
+ buf_cmd[13] =
+ tmf->tag_of_task_to_be_managed & 0xff;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct task_status_struct *ts = &task->task_status;
+ struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf;
+ struct dev_to_host_fis *d2h = slot->status_buffer +
+ sizeof(struct hisi_sas_err_record);
+
+ resp->frame_len = sizeof(struct dev_to_host_fis);
+ memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis));
+
+ ts->buf_valid_size = sizeof(*resp);
+}
+
+/* by default, task resp is complete */
+static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
+ struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct task_status_struct *ts = &task->task_status;
+ struct hisi_sas_err_record_v2 *err_record = slot->status_buffer;
+ u32 trans_tx_fail_type = cpu_to_le32(err_record->trans_tx_fail_type);
+ u32 trans_rx_fail_type = cpu_to_le32(err_record->trans_rx_fail_type);
+ u16 dma_tx_err_type = cpu_to_le16(err_record->dma_tx_err_type);
+ u16 sipc_rx_err_type = cpu_to_le16(err_record->sipc_rx_err_type);
+ u32 dma_rx_err_type = cpu_to_le32(err_record->dma_rx_err_type);
+ int error = -1;
+
+ if (dma_rx_err_type) {
+ error = ffs(dma_rx_err_type)
+ - 1 + DMA_RX_ERR_BASE;
+ } else if (sipc_rx_err_type) {
+ error = ffs(sipc_rx_err_type)
+ - 1 + SIPC_RX_ERR_BASE;
+ } else if (dma_tx_err_type) {
+ error = ffs(dma_tx_err_type)
+ - 1 + DMA_TX_ERR_BASE;
+ } else if (trans_rx_fail_type) {
+ error = ffs(trans_rx_fail_type)
+ - 1 + TRANS_RX_FAIL_BASE;
+ } else if (trans_tx_fail_type) {
+ error = ffs(trans_tx_fail_type)
+ - 1 + TRANS_TX_FAIL_BASE;
+ }
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ switch (error) {
+ case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_NO_DEST;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_PATH_BLOCKED;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_EPROTO;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_BAD_DEST;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
+ {
+ /* not sure */
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ }
+ case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
+ {
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
+ {
+ ts->stat = SAS_OPEN_TO;
+ break;
+ }
+ case DMA_RX_DATA_LEN_OVERFLOW:
+ {
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ break;
+ }
+ case DMA_RX_DATA_LEN_UNDERFLOW:
+ case SIPC_RX_DATA_UNDERFLOW_ERR:
+ {
+ ts->residual = trans_tx_fail_type;
+ ts->stat = SAS_DATA_UNDERRUN;
+ break;
+ }
+ case TRANS_TX_ERR_FRAME_TXED:
+ {
+ /* This will request a retry */
+ ts->stat = SAS_QUEUE_FULL;
+ slot->abort = 1;
+ break;
+ }
+ case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
+ case TRANS_TX_ERR_PHY_NOT_ENABLE:
+ case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
+ case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+ case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
+ case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
+ case TRANS_TX_ERR_WITH_BREAK_REQUEST:
+ case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
+ case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
+ case TRANS_TX_ERR_WITH_NAK_RECEVIED:
+ case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
+ case TRANS_TX_ERR_WITH_IPTT_CONFLICT:
+ case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+ case TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR:
+ case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
+ case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+ case TRANS_RX_ERR_WITH_BREAK_TIMEOUT:
+ case TRANS_RX_ERR_WITH_BREAK_REQUEST:
+ case TRANS_RX_ERR_WITH_BREAK_RECEVIED:
+ case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+ case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
+ case TRANS_RX_ERR_WITH_DATA_LEN0:
+ case TRANS_RX_ERR_WITH_BAD_HASH:
+ case TRANS_RX_XRDY_WLEN_ZERO_ERR:
+ case TRANS_RX_SSP_FRM_LEN_ERR:
+ case TRANS_RX_ERR_WITH_BAD_FRM_TYPE:
+ case DMA_TX_UNEXP_XFER_ERR:
+ case DMA_TX_UNEXP_RETRANS_ERR:
+ case DMA_TX_XFER_LEN_OVERFLOW:
+ case DMA_TX_XFER_OFFSET_ERR:
+ case DMA_RX_DATA_OFFSET_ERR:
+ case DMA_RX_UNEXP_NORM_RESP_ERR:
+ case DMA_RX_UNEXP_RDFRAME_ERR:
+ case DMA_RX_UNKNOWN_FRM_ERR:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ break;
+ case SAS_PROTOCOL_SMP:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ {
+ switch (error) {
+ case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
+ case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+ case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
+ {
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
+ case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
+ case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
+ case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+ case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
+ case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
+ case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
+ {
+ ts->stat = SAS_OPEN_TO;
+ break;
+ }
+ case DMA_RX_DATA_LEN_OVERFLOW:
+ {
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
+ }
+ case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
+ case TRANS_TX_ERR_PHY_NOT_ENABLE:
+ case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
+ case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+ case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
+ case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
+ case TRANS_TX_ERR_WITH_BREAK_REQUEST:
+ case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
+ case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
+ case TRANS_TX_ERR_WITH_NAK_RECEVIED:
+ case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+ case TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT:
+ case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
+ case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+ case TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR:
+ case TRANS_RX_ERR_WITH_RXFIS_CRC_ERR:
+ case TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN:
+ case TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP:
+ case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
+ case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+ case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
+ case TRANS_RX_ERR_WITH_DATA_LEN0:
+ case TRANS_RX_ERR_WITH_BAD_HASH:
+ case TRANS_RX_XRDY_WLEN_ZERO_ERR:
+ case TRANS_RX_SSP_FRM_LEN_ERR:
+ case SIPC_RX_FIS_STATUS_ERR_BIT_VLD:
+ case SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR:
+ case SIPC_RX_FIS_STATUS_BSY_BIT_ERR:
+ case SIPC_RX_WRSETUP_LEN_ODD_ERR:
+ case SIPC_RX_WRSETUP_LEN_ZERO_ERR:
+ case SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR:
+ case SIPC_RX_SATA_UNEXP_FIS_ERR:
+ case DMA_RX_SATA_FRAME_TYPE_ERR:
+ case DMA_RX_UNEXP_RDFRAME_ERR:
+ case DMA_RX_PIO_DATA_LEN_ERR:
+ case DMA_RX_RDSETUP_STATUS_ERR:
+ case DMA_RX_RDSETUP_STATUS_DRQ_ERR:
+ case DMA_RX_RDSETUP_STATUS_BSY_ERR:
+ case DMA_RX_RDSETUP_LEN_ODD_ERR:
+ case DMA_RX_RDSETUP_LEN_ZERO_ERR:
+ case DMA_RX_RDSETUP_LEN_OVER_ERR:
+ case DMA_RX_RDSETUP_OFFSET_ERR:
+ case DMA_RX_RDSETUP_ACTIVE_ERR:
+ case DMA_RX_RDSETUP_ESTATUS_ERR:
+ case DMA_RX_UNKNOWN_FRM_ERR:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ }
+ default:
+ {
+ ts->stat = SAS_PROTO_RESPONSE;
+ break;
+ }
+ }
+ sata_done_v2_hw(hisi_hba, task, slot);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
+ int abort)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_device *sas_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct task_status_struct *ts;
+ struct domain_device *device;
+ enum exec_status sts;
+ struct hisi_sas_complete_v2_hdr *complete_queue =
+ hisi_hba->complete_hdr[slot->cmplt_queue];
+ struct hisi_sas_complete_v2_hdr *complete_hdr =
+ &complete_queue[slot->cmplt_queue_slot];
+
+ if (unlikely(!task || !task->lldd_task || !task->dev))
+ return -EINVAL;
+
+ ts = &task->task_status;
+ device = task->dev;
+ sas_dev = device->lldd_dev;
+
+ task->task_state_flags &=
+ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+
+ memset(ts, 0, sizeof(*ts));
+ ts->resp = SAS_TASK_COMPLETE;
+
+ if (unlikely(!sas_dev || abort)) {
+ if (!sas_dev)
+ dev_dbg(dev, "slot complete: port has not device\n");
+ ts->stat = SAS_PHY_DOWN;
+ goto out;
+ }
+
+ if ((complete_hdr->dw0 & CMPLT_HDR_ERX_MSK) &&
+ (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
+
+ slot_err_v2_hw(hisi_hba, task, slot);
+ if (unlikely(slot->abort)) {
+ queue_work(hisi_hba->wq, &slot->abort_slot);
+ /* immediately return and do not complete */
+ return ts->stat;
+ }
+ goto out;
+ }
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ struct ssp_response_iu *iu = slot->status_buffer +
+ sizeof(struct hisi_sas_err_record);
+
+ sas_ssp_task_response(dev, task, iu);
+ break;
+ }
+ case SAS_PROTOCOL_SMP:
+ {
+ struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+ void *to;
+
+ ts->stat = SAM_STAT_GOOD;
+ to = kmap_atomic(sg_page(sg_resp));
+
+ dma_unmap_sg(dev, &task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ memcpy(to + sg_resp->offset,
+ slot->status_buffer +
+ sizeof(struct hisi_sas_err_record),
+ sg_dma_len(sg_resp));
+ kunmap_atomic(to);
+ break;
+ }
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ {
+ ts->stat = SAM_STAT_GOOD;
+ sata_done_v2_hw(hisi_hba, task, slot);
+ break;
+ }
+ default:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+
+ if (!slot->port->port_attached) {
+ dev_err(dev, "slot complete: port %d has removed\n",
+ slot->port->sas_port.id);
+ ts->stat = SAS_PHY_DOWN;
+ }
+
+out:
+ if (sas_dev && sas_dev->running_req)
+ sas_dev->running_req--;
+
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
+ sts = ts->stat;
+
+ if (task->task_done)
+ task->task_done(task);
+
+ return sts;
+}
+
+static u8 get_ata_protocol(u8 cmd, int direction)
+{
+ switch (cmd) {
+ case ATA_CMD_FPDMA_WRITE:
+ case ATA_CMD_FPDMA_READ:
+ return SATA_PROTOCOL_FPDMA;
+
+ case ATA_CMD_ID_ATA:
+ case ATA_CMD_PMP_READ:
+ case ATA_CMD_READ_LOG_EXT:
+ case ATA_CMD_PIO_READ:
+ case ATA_CMD_PIO_READ_EXT:
+ case ATA_CMD_PMP_WRITE:
+ case ATA_CMD_WRITE_LOG_EXT:
+ case ATA_CMD_PIO_WRITE:
+ case ATA_CMD_PIO_WRITE_EXT:
+ return SATA_PROTOCOL_PIO;
+
+ case ATA_CMD_READ:
+ case ATA_CMD_READ_EXT:
+ case ATA_CMD_READ_LOG_DMA_EXT:
+ case ATA_CMD_WRITE:
+ case ATA_CMD_WRITE_EXT:
+ case ATA_CMD_WRITE_QUEUED:
+ case ATA_CMD_WRITE_LOG_DMA_EXT:
+ return SATA_PROTOCOL_DMA;
+
+ case ATA_CMD_DOWNLOAD_MICRO:
+ case ATA_CMD_DEV_RESET:
+ case ATA_CMD_CHK_POWER:
+ case ATA_CMD_FLUSH:
+ case ATA_CMD_FLUSH_EXT:
+ case ATA_CMD_VERIFY:
+ case ATA_CMD_VERIFY_EXT:
+ case ATA_CMD_SET_FEATURES:
+ case ATA_CMD_STANDBY:
+ case ATA_CMD_STANDBYNOW1:
+ return SATA_PROTOCOL_NONDATA;
+ default:
+ if (direction == DMA_NONE)
+ return SATA_PROTOCOL_NONDATA;
+ return SATA_PROTOCOL_PIO;
+ }
+}
+
+static int get_ncq_tag_v2_hw(struct sas_task *task, u32 *tag)
+{
+ struct ata_queued_cmd *qc = task->uldd_task;
+
+ if (qc) {
+ if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+ qc->tf.command == ATA_CMD_FPDMA_READ) {
+ *tag = qc->tag;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ struct sas_task *task = slot->task;
+ struct domain_device *device = task->dev;
+ struct domain_device *parent_dev = device->parent;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct hisi_sas_port *port = device->port->lldd_port;
+ u8 *buf_cmd;
+ int has_data = 0, rc = 0, hdr_tag = 0;
+ u32 dw1 = 0, dw2 = 0;
+
+ /* create header */
+ /* dw0 */
+ hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
+ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
+ else
+ hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF);
+
+ /* dw1 */
+ switch (task->data_dir) {
+ case DMA_TO_DEVICE:
+ has_data = 1;
+ dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
+ break;
+ case DMA_FROM_DEVICE:
+ has_data = 1;
+ dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
+ break;
+ default:
+ dw1 &= ~CMD_HDR_DIR_MSK;
+ }
+
+ if (0 == task->ata_task.fis.command)
+ dw1 |= 1 << CMD_HDR_RESET_OFF;
+
+ dw1 |= (get_ata_protocol(task->ata_task.fis.command, task->data_dir))
+ << CMD_HDR_FRAME_TYPE_OFF;
+ dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
+ hdr->dw1 = cpu_to_le32(dw1);
+
+ /* dw2 */
+ if (task->ata_task.use_ncq && get_ncq_tag_v2_hw(task, &hdr_tag)) {
+ task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
+ dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
+ }
+
+ dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / 4) << CMD_HDR_CFL_OFF |
+ 2 << CMD_HDR_SG_MOD_OFF;
+ hdr->dw2 = cpu_to_le32(dw2);
+
+ /* dw3 */
+ hdr->transfer_tags = cpu_to_le32(slot->idx);
+
+ if (has_data) {
+ rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
+ slot->n_elem);
+ if (rc)
+ return rc;
+ }
+
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+ hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ buf_cmd = slot->command_table;
+
+ if (likely(!task->ata_task.device_control_reg_update))
+ task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+ /* fill in command FIS */
+ memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
+
+ return 0;
+}
+
+static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+{
+ int i, res = 0;
+ u32 context, port_id, link_rate, hard_phy_linkrate;
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
+ struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
+
+ /* Check for SATA dev */
+ context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
+ if (context & (1 << phy_no))
+ goto end;
+
+ if (phy_no == 8) {
+ u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
+
+ port_id = (port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
+ PORT_STATE_PHY8_PORT_NUM_OFF;
+ link_rate = (port_state & PORT_STATE_PHY8_CONN_RATE_MSK) >>
+ PORT_STATE_PHY8_CONN_RATE_OFF;
+ } else {
+ port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+ port_id = (port_id >> (4 * phy_no)) & 0xf;
+ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+ }
+
+ if (port_id == 0xf) {
+ dev_err(dev, "phyup: phy%d invalid portid\n", phy_no);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ for (i = 0; i < 6; i++) {
+ u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no,
+ RX_IDAF_DWORD0 + (i * 4));
+ frame_rcvd[i] = __swab32(idaf);
+ }
+
+ /* Get the linkrates */
+ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+ sas_phy->linkrate = link_rate;
+ hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
+ HARD_PHY_LINKRATE);
+ phy->maximum_linkrate = hard_phy_linkrate & 0xf;
+ phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
+
+ sas_phy->oob_mode = SAS_OOB_MODE;
+ memcpy(sas_phy->attached_sas_addr, &id->sas_addr, SAS_ADDR_SIZE);
+ dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
+ phy->port_id = port_id;
+ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+ phy->phy_type |= PORT_TYPE_SAS;
+ phy->phy_attached = 1;
+ phy->identify.device_type = id->dev_type;
+ phy->frame_rcvd_size = sizeof(struct sas_identify_frame);
+ if (phy->identify.device_type == SAS_END_DEVICE)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SSP;
+ else if (phy->identify.device_type != SAS_PHY_UNUSED)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SMP;
+ queue_work(hisi_hba->wq, &phy->phyup_ws);
+
+end:
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
+ CHL_INT0_SL_PHY_ENABLE_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0);
+
+ return res;
+}
+
+static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+{
+ int res = 0;
+ u32 phy_cfg, phy_state;
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
+
+ phy_cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
+
+ return res;
+}
+
+static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ u32 irq_msk;
+ int phy_no = 0;
+ irqreturn_t res = IRQ_HANDLED;
+
+ irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO)
+ >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff;
+ while (irq_msk) {
+ if (irq_msk & 1) {
+ u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT0);
+
+ if (irq_value & CHL_INT0_SL_PHY_ENABLE_MSK)
+ /* phy up */
+ if (phy_up_v2_hw(phy_no, hisi_hba)) {
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ if (irq_value & CHL_INT0_NOT_RDY_MSK)
+ /* phy down */
+ if (phy_down_v2_hw(phy_no, hisi_hba)) {
+ res = IRQ_NONE;
+ goto end;
+ }
+ }
+ irq_msk >>= 1;
+ phy_no++;
+ }
+
+end:
+ return res;
+}
+
+static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+ unsigned long flags;
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1);
+
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
+ CHL_INT0_SL_RX_BCST_ACK_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
+}
+
+static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 ent_msk, ent_tmp, irq_msk;
+ int phy_no = 0;
+
+ ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3);
+ ent_tmp = ent_msk;
+ ent_msk |= ENT_INT_SRC_MSK3_ENT95_MSK_MSK;
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_msk);
+
+ irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO) >>
+ HGC_INVLD_DQE_INFO_FB_CH3_OFF) & 0x1ff;
+
+ while (irq_msk) {
+ if (irq_msk & (1 << phy_no)) {
+ u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT0);
+ u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT1);
+ u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT2);
+
+ if (irq_value1) {
+ if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
+ CHL_INT1_DMAC_TX_ECC_ERR_MSK))
+ panic("%s: DMAC RX/TX ecc bad error! (0x%x)",
+ dev_name(dev), irq_value1);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CHL_INT1, irq_value1);
+ }
+
+ if (irq_value2)
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CHL_INT2, irq_value2);
+
+
+ if (irq_value0) {
+ if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
+ phy_bcast_v2_hw(phy_no, hisi_hba);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CHL_INT0, irq_value0
+ & (~CHL_INT0_HOTPLUG_TOUT_MSK)
+ & (~CHL_INT0_SL_PHY_ENABLE_MSK)
+ & (~CHL_INT0_NOT_RDY_MSK));
+ }
+ }
+ irq_msk &= ~(1 << phy_no);
+ phy_no++;
+ }
+
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_tmp);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
+{
+ struct hisi_sas_cq *cq = p;
+ struct hisi_hba *hisi_hba = cq->hisi_hba;
+ struct hisi_sas_slot *slot;
+ struct hisi_sas_itct *itct;
+ struct hisi_sas_complete_v2_hdr *complete_queue;
+ u32 irq_value, rd_point, wr_point, dev_id;
+ int queue = cq->id;
+
+ complete_queue = hisi_hba->complete_hdr[queue];
+ irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC);
+
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
+
+ rd_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_RD_PTR +
+ (0x14 * queue));
+ wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
+ (0x14 * queue));
+
+ while (rd_point != wr_point) {
+ struct hisi_sas_complete_v2_hdr *complete_hdr;
+ int iptt;
+
+ complete_hdr = &complete_queue[rd_point];
+
+ /* Check for NCQ completion */
+ if (complete_hdr->act) {
+ u32 act_tmp = complete_hdr->act;
+ int ncq_tag_count = ffs(act_tmp);
+
+ dev_id = (complete_hdr->dw1 & CMPLT_HDR_DEV_ID_MSK) >>
+ CMPLT_HDR_DEV_ID_OFF;
+ itct = &hisi_hba->itct[dev_id];
+
+ /* The NCQ tags are held in the itct header */
+ while (ncq_tag_count) {
+ __le64 *ncq_tag = &itct->qw4_15[0];
+
+ ncq_tag_count -= 1;
+ iptt = (ncq_tag[ncq_tag_count / 5]
+ >> (ncq_tag_count % 5) * 12) & 0xfff;
+
+ slot = &hisi_hba->slot_info[iptt];
+ slot->cmplt_queue_slot = rd_point;
+ slot->cmplt_queue = queue;
+ slot_complete_v2_hw(hisi_hba, slot, 0);
+
+ act_tmp &= ~(1 << ncq_tag_count);
+ ncq_tag_count = ffs(act_tmp);
+ }
+ } else {
+ iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
+ slot = &hisi_hba->slot_info[iptt];
+ slot->cmplt_queue_slot = rd_point;
+ slot->cmplt_queue = queue;
+ slot_complete_v2_hw(hisi_hba, slot, 0);
+ }
+
+ if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
+ rd_point = 0;
+ }
+
+ /* update rd_point */
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_initial_fis *initial_fis;
+ struct dev_to_host_fis *fis;
+ u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate;
+ irqreturn_t res = IRQ_HANDLED;
+ u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
+ int phy_no;
+
+ phy_no = sas_phy->id;
+ initial_fis = &hisi_hba->initial_fis[phy_no];
+ fis = &initial_fis->fis;
+
+ ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK1);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, ent_msk | 1 << phy_no);
+
+ ent_int = hisi_sas_read32(hisi_hba, ENT_INT_SRC1);
+ ent_tmp = ent_int;
+ ent_int >>= ENT_INT_SRC1_D2H_FIS_CH1_OFF * (phy_no % 4);
+ if ((ent_int & ENT_INT_SRC1_D2H_FIS_CH0_MSK) == 0) {
+ dev_warn(dev, "sata int: phy%d did not receive FIS\n", phy_no);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, ent_tmp);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, ent_msk);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ if (unlikely(phy_no == 8)) {
+ u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
+
+ port_id = (port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
+ PORT_STATE_PHY8_PORT_NUM_OFF;
+ link_rate = (port_state & PORT_STATE_PHY8_CONN_RATE_MSK) >>
+ PORT_STATE_PHY8_CONN_RATE_OFF;
+ } else {
+ port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+ port_id = (port_id >> (4 * phy_no)) & 0xf;
+ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+ }
+
+ if (port_id == 0xf) {
+ dev_err(dev, "sata int: phy%d invalid portid\n", phy_no);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ sas_phy->linkrate = link_rate;
+ hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
+ HARD_PHY_LINKRATE);
+ phy->maximum_linkrate = hard_phy_linkrate & 0xf;
+ phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
+
+ sas_phy->oob_mode = SATA_OOB_MODE;
+ /* Make up some unique SAS address */
+ attached_sas_addr[0] = 0x50;
+ attached_sas_addr[7] = phy_no;
+ memcpy(sas_phy->attached_sas_addr, attached_sas_addr, SAS_ADDR_SIZE);
+ memcpy(sas_phy->frame_rcvd, fis, sizeof(struct dev_to_host_fis));
+ dev_info(dev, "sata int phyup: phy%d link_rate=%d\n", phy_no, link_rate);
+ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+ phy->port_id = port_id;
+ phy->phy_type |= PORT_TYPE_SATA;
+ phy->phy_attached = 1;
+ phy->identify.device_type = SAS_SATA_DEV;
+ phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
+ phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
+ queue_work(hisi_hba->wq, &phy->phyup_ws);
+
+end:
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, ent_tmp);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, ent_msk);
+
+ return res;
+}
+
+static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = {
+ int_phy_updown_v2_hw,
+ int_chnl_int_v2_hw,
+};
+
+/**
+ * There is a limitation in the hip06 chipset that we need
+ * to map in all mbigen interrupts, even if they are not used.
+ */
+static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
+{
+ struct platform_device *pdev = hisi_hba->pdev;
+ struct device *dev = &pdev->dev;
+ int i, irq, rc, irq_map[128];
+
+
+ for (i = 0; i < 128; i++)
+ irq_map[i] = platform_get_irq(pdev, i);
+
+ for (i = 0; i < HISI_SAS_PHY_INT_NR; i++) {
+ int idx = i;
+
+ irq = irq_map[idx + 1]; /* Phy up/down is irq1 */
+ if (!irq) {
+ dev_err(dev, "irq init: fail map phy interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, phy_interrupts[i], 0,
+ DRV_NAME " phy", hisi_hba);
+ if (rc) {
+ dev_err(dev, "irq init: could not request "
+ "phy interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+ int idx = i + 72; /* First SATA interrupt is irq72 */
+
+ irq = irq_map[idx];
+ if (!irq) {
+ dev_err(dev, "irq init: fail map phy interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0,
+ DRV_NAME " sata", phy);
+ if (rc) {
+ dev_err(dev, "irq init: could not request "
+ "sata interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ int idx = i + 96; /* First cq interrupt is irq96 */
+
+ irq = irq_map[idx];
+ if (!irq) {
+ dev_err(dev,
+ "irq init: could not map cq interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+ rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0,
+ DRV_NAME " cq", &hisi_hba->cq[i]);
+ if (rc) {
+ dev_err(dev,
+ "irq init: could not request cq interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
+
+static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
+{
+ int rc;
+
+ rc = hw_init_v2_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ rc = interrupt_init_v2_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ phys_init_v2_hw(hisi_hba);
+
+ return 0;
+}
+
+static const struct hisi_sas_hw hisi_sas_v2_hw = {
+ .hw_init = hisi_sas_v2_init,
+ .setup_itct = setup_itct_v2_hw,
+ .sl_notify = sl_notify_v2_hw,
+ .get_wideport_bitmap = get_wideport_bitmap_v2_hw,
+ .free_device = free_device_v2_hw,
+ .prep_smp = prep_smp_v2_hw,
+ .prep_ssp = prep_ssp_v2_hw,
+ .prep_stp = prep_ata_v2_hw,
+ .get_free_slot = get_free_slot_v2_hw,
+ .start_delivery = start_delivery_v2_hw,
+ .slot_complete = slot_complete_v2_hw,
+ .phy_enable = enable_phy_v2_hw,
+ .phy_disable = disable_phy_v2_hw,
+ .phy_hard_reset = phy_hard_reset_v2_hw,
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
+};
+
+static int hisi_sas_v2_probe(struct platform_device *pdev)
+{
+ return hisi_sas_probe(pdev, &hisi_sas_v2_hw);
+}
+
+static int hisi_sas_v2_remove(struct platform_device *pdev)
+{
+ return hisi_sas_remove(pdev);
+}
+
+static const struct of_device_id sas_v2_of_match[] = {
+ { .compatible = "hisilicon,hip06-sas-v2",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, sas_v2_of_match);
+
+static struct platform_driver hisi_sas_v2_driver = {
+ .probe = hisi_sas_v2_probe,
+ .remove = hisi_sas_v2_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = sas_v2_of_match,
+ },
+};
+
+module_platform_driver(hisi_sas_v2_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller v2 hw driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 82ac1cd818ac..94025c5cf797 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -33,7 +33,7 @@
#include <linux/transport_class.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-
+#include <linux/idr.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
@@ -42,7 +42,7 @@
#include "scsi_logging.h"
-static atomic_t scsi_host_next_hn = ATOMIC_INIT(0); /* host_no for next new host */
+static DEFINE_IDA(host_index_ida);
static void scsi_host_cls_release(struct device *dev)
@@ -355,6 +355,8 @@ static void scsi_host_dev_release(struct device *dev)
kfree(shost->shost_data);
+ ida_simple_remove(&host_index_ida, shost->host_no);
+
if (parent)
put_device(parent);
kfree(shost);
@@ -388,6 +390,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{
struct Scsi_Host *shost;
gfp_t gfp_mask = GFP_KERNEL;
+ int index;
if (sht->unchecked_isa_dma && privsize)
gfp_mask |= __GFP_DMA;
@@ -406,11 +409,11 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
init_waitqueue_head(&shost->host_wait);
mutex_init(&shost->scan_mutex);
- /*
- * subtract one because we increment first then return, but we need to
- * know what the next host number was before increment
- */
- shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1;
+ index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL);
+ if (index < 0)
+ goto fail_kfree;
+ shost->host_no = index;
+
shost->dma_channel = 0xff;
/* These three are default values which can be overridden */
@@ -495,7 +498,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost_printk(KERN_WARNING, shost,
"error handler thread failed to spawn, error = %ld\n",
PTR_ERR(shost->ehandler));
- goto fail_kfree;
+ goto fail_index_remove;
}
shost->tmf_work_q = alloc_workqueue("scsi_tmf_%d",
@@ -511,6 +514,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
fail_kthread:
kthread_stop(shost->ehandler);
+ fail_index_remove:
+ ida_simple_remove(&host_index_ida, shost->host_no);
fail_kfree:
kfree(shost);
return NULL;
@@ -606,6 +611,7 @@ int scsi_init_hosts(void)
void scsi_exit_hosts(void)
{
class_unregister(&shost_class);
+ ida_destroy(&host_index_ida);
}
int scsi_is_host_device(const struct device *dev)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 38ce0e308fbe..5be944c8b71c 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1,5 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
+ * Copyright 2016 Microsemi Corporation
* Copyright 2014-2015 PMC-Sierra, Inc.
* Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P.
*
@@ -12,7 +13,7 @@
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more details.
*
- * Questions/Comments/Bugfixes to storagedev@pmcs.com
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
*
*/
@@ -809,7 +810,8 @@ static ssize_t path_info_show(struct device *dev,
PAGE_SIZE - output_len,
"PORT: %.2s ",
phys_connector);
- if (hdev->devtype == TYPE_DISK && hdev->expose_device) {
+ if ((hdev->devtype == TYPE_DISK || hdev->devtype == TYPE_ZBC) &&
+ hdev->expose_device) {
if (box == 0 || box == 0xFF) {
output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len,
@@ -1166,6 +1168,7 @@ static void hpsa_show_dev_msg(const char *level, struct ctlr_info *h,
snprintf(label, LABEL_SIZE, "enclosure");
break;
case TYPE_DISK:
+ case TYPE_ZBC:
if (dev->external)
snprintf(label, LABEL_SIZE, "external");
else if (!is_logical_dev_addr_mode(dev->scsi3addr))
@@ -1636,6 +1639,8 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h,
continue;
if (dev[j]->devtype != TYPE_DISK)
continue;
+ if (dev[j]->devtype != TYPE_ZBC)
+ continue;
if (is_logical_device(dev[j]))
continue;
if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle)
@@ -1681,6 +1686,8 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h,
continue;
if (dev[i]->devtype != TYPE_DISK)
continue;
+ if (dev[i]->devtype != TYPE_ZBC)
+ continue;
if (!is_logical_device(dev[i]))
continue;
@@ -3208,8 +3215,10 @@ static void hpsa_get_enclosure_info(struct ctlr_info *h,
bmic_device_index = GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]);
- if (bmic_device_index == 0xFF00)
+ if (bmic_device_index == 0xFF00 || MASKED_DEVICE(&rle->lunid[0])) {
+ rc = IO_OK;
goto out;
+ }
bssbp = kzalloc(sizeof(*bssbp), GFP_KERNEL);
if (!bssbp)
@@ -3657,18 +3666,6 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h,
return rc;
}
-static void sanitize_inquiry_string(unsigned char *s, int len)
-{
- bool terminated = false;
-
- for (; len > 0; (--len, ++s)) {
- if (*s == 0)
- terminated = true;
- if (terminated || *s < 0x20 || *s > 0x7e)
- *s = ' ';
- }
-}
-
static int hpsa_update_device_info(struct ctlr_info *h,
unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device,
unsigned char *is_OBDR_device)
@@ -3699,8 +3696,8 @@ static int hpsa_update_device_info(struct ctlr_info *h,
goto bail_out;
}
- sanitize_inquiry_string(&inq_buff[8], 8);
- sanitize_inquiry_string(&inq_buff[16], 16);
+ scsi_sanitize_inquiry_string(&inq_buff[8], 8);
+ scsi_sanitize_inquiry_string(&inq_buff[16], 16);
this_device->devtype = (inq_buff[0] & 0x1f);
memcpy(this_device->scsi3addr, scsi3addr, 8);
@@ -3713,7 +3710,8 @@ static int hpsa_update_device_info(struct ctlr_info *h,
hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
sizeof(this_device->device_id));
- if (this_device->devtype == TYPE_DISK &&
+ if ((this_device->devtype == TYPE_DISK ||
+ this_device->devtype == TYPE_ZBC) &&
is_logical_dev_addr_mode(scsi3addr)) {
int volume_offline;
@@ -4181,6 +4179,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
ncurrent++;
break;
case TYPE_DISK:
+ case TYPE_ZBC:
if (this_device->physical_device) {
/* The disk is in HBA mode. */
/* Never use RAID mapper in HBA mode. */
@@ -4197,7 +4196,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
ncurrent++;
break;
case TYPE_ENCLOSURE:
- hpsa_get_enclosure_info(h, lunaddrbytes,
+ if (!this_device->external)
+ hpsa_get_enclosure_info(h, lunaddrbytes,
physdev_list, phys_dev_index,
this_device);
ncurrent++;
@@ -4970,6 +4970,8 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
return IO_ACCEL_INELIGIBLE;
c->phys_disk = dev->phys_disk[map_index];
+ if (!c->phys_disk)
+ return IO_ACCEL_INELIGIBLE;
disk_handle = dd[map_index].ioaccel_handle;
disk_block = le64_to_cpu(map->disk_starting_blk) +
@@ -5835,7 +5837,7 @@ static int hpsa_send_abort_ioaccel2(struct ctlr_info *h,
}
static int hpsa_send_abort_both_ways(struct ctlr_info *h,
- unsigned char *scsi3addr, struct CommandList *abort, int reply_queue)
+ struct hpsa_scsi_dev_t *dev, struct CommandList *abort, int reply_queue)
{
/*
* ioccelerator mode 2 commands should be aborted via the
@@ -5844,14 +5846,16 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h,
* Change abort to physical device reset when abort TMF is unsupported.
*/
if (abort->cmd_type == CMD_IOACCEL2) {
- if (HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags)
+ if ((HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags) ||
+ dev->physical_device)
return hpsa_send_abort_ioaccel2(h, abort,
reply_queue);
else
- return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr,
+ return hpsa_send_reset_as_abort_ioaccel2(h,
+ dev->scsi3addr,
abort, reply_queue);
}
- return hpsa_send_abort(h, scsi3addr, abort, reply_queue);
+ return hpsa_send_abort(h, dev->scsi3addr, abort, reply_queue);
}
/* Find out which reply queue a command was meant to return on */
@@ -5989,7 +5993,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
cmd_free(h, abort);
return FAILED;
}
- rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue);
+ rc = hpsa_send_abort_both_ways(h, dev, abort, reply_queue);
atomic_inc(&h->abort_cmds_available);
wake_up_all(&h->abort_cmd_wait_queue);
if (rc != 0) {
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index fdd39fc0b199..d06bb7417e36 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -1,5 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
+ * Copyright 2016 Microsemi Corporation
* Copyright 2014-2015 PMC-Sierra, Inc.
* Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P.
*
@@ -12,7 +13,7 @@
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more details.
*
- * Questions/Comments/Bugfixes to storagedev@pmcs.com
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
*
*/
#ifndef HPSA_H
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 6a919ada96b3..a5be153d92d4 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -1,5 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
+ * Copyright 2016 Microsemi Corporation
* Copyright 2014-2015 PMC-Sierra, Inc.
* Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P.
*
@@ -12,7 +13,7 @@
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more details.
*
- * Questions/Comments/Bugfixes to storagedev@pmcs.com
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
*
*/
#ifndef HPSA_CMD_H
@@ -289,7 +290,7 @@ struct SenseSubsystem_info {
#define BMIC_IDENTIFY_CONTROLLER 0x11
#define BMIC_SET_DIAG_OPTIONS 0xF4
#define BMIC_SENSE_DIAG_OPTIONS 0xF5
-#define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x40000000
+#define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x80000000
#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66
#define BMIC_SENSE_STORAGE_BOX_PARAMS 0x65
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 6aa317c303e2..fc523c3e5019 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -2636,7 +2636,8 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
struct ibmvfc_target *tgt;
ibmvfc_log(vhost, desc->log_level, "%s event received. scsi_id: %llx, wwpn: %llx,"
- " node_name: %llx%s\n", desc->desc, crq->scsi_id, crq->wwpn, crq->node_name,
+ " node_name: %llx%s\n", desc->desc, be64_to_cpu(crq->scsi_id),
+ be64_to_cpu(crq->wwpn), be64_to_cpu(crq->node_name),
ibmvfc_get_link_state(crq->link_state));
switch (be64_to_cpu(crq->event)) {
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index adfef9db6f1e..d9534ee6ef52 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -182,7 +182,7 @@ static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
spin_lock_irqsave(&queue->lock, flags);
crq = &queue->msgs[queue->cur];
- if (crq->valid & 0x80) {
+ if (crq->valid != VIOSRP_CRQ_FREE) {
if (++queue->cur == queue->size)
queue->cur = 0;
@@ -231,7 +231,7 @@ static void ibmvscsi_task(void *data)
/* Pull all the valid messages off the CRQ */
while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) {
ibmvscsi_handle_crq(crq, hostdata);
- crq->valid = 0x00;
+ crq->valid = VIOSRP_CRQ_FREE;
}
vio_enable_interrupts(vdev);
@@ -239,7 +239,7 @@ static void ibmvscsi_task(void *data)
if (crq != NULL) {
vio_disable_interrupts(vdev);
ibmvscsi_handle_crq(crq, hostdata);
- crq->valid = 0x00;
+ crq->valid = VIOSRP_CRQ_FREE;
} else {
done = 1;
}
@@ -248,25 +248,23 @@ static void ibmvscsi_task(void *data)
static void gather_partition_info(void)
{
- struct device_node *rootdn;
-
const char *ppartition_name;
const __be32 *p_number_ptr;
/* Retrieve information about this partition */
- rootdn = of_find_node_by_path("/");
- if (!rootdn) {
+ if (!of_root)
return;
- }
- ppartition_name = of_get_property(rootdn, "ibm,partition-name", NULL);
+ of_node_get(of_root);
+
+ ppartition_name = of_get_property(of_root, "ibm,partition-name", NULL);
if (ppartition_name)
strncpy(partition_name, ppartition_name,
sizeof(partition_name));
- p_number_ptr = of_get_property(rootdn, "ibm,partition-no", NULL);
+ p_number_ptr = of_get_property(of_root, "ibm,partition-no", NULL);
if (p_number_ptr)
partition_number = of_read_number(p_number_ptr, 1);
- of_node_put(rootdn);
+ of_node_put(of_root);
}
static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
@@ -283,8 +281,8 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
hostdata->madapter_info.partition_number =
cpu_to_be32(partition_number);
- hostdata->madapter_info.mad_version = cpu_to_be32(1);
- hostdata->madapter_info.os_type = cpu_to_be32(2);
+ hostdata->madapter_info.mad_version = cpu_to_be32(SRP_MAD_VERSION_1);
+ hostdata->madapter_info.os_type = cpu_to_be32(SRP_MAD_OS_LINUX);
}
/**
@@ -316,7 +314,7 @@ static int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
rc = plpar_hcall_norets(H_REG_CRQ,
vdev->unit_address,
queue->msg_token, PAGE_SIZE);
- if (rc == 2) {
+ if (rc == H_CLOSED) {
/* Adapter is good, but other end is not ready */
dev_warn(hostdata->dev, "Partner adapter not ready\n");
} else if (rc != 0) {
@@ -366,7 +364,7 @@ static int ibmvscsi_init_crq_queue(struct crq_queue *queue,
rc = ibmvscsi_reset_crq_queue(queue,
hostdata);
- if (rc == 2) {
+ if (rc == H_CLOSED) {
/* Adapter is good, but other end is not ready */
dev_warn(hostdata->dev, "Partner adapter not ready\n");
retrc = 0;
@@ -474,7 +472,7 @@ static int initialize_event_pool(struct event_pool *pool,
struct srp_event_struct *evt = &pool->events[i];
memset(&evt->crq, 0x00, sizeof(evt->crq));
atomic_set(&evt->free, 1);
- evt->crq.valid = 0x80;
+ evt->crq.valid = VIOSRP_CRQ_CMD_RSP;
evt->crq.IU_length = cpu_to_be16(sizeof(*evt->xfer_iu));
evt->crq.IU_data_ptr = cpu_to_be64(pool->iu_token +
sizeof(*evt->xfer_iu) * i);
@@ -1398,7 +1396,7 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
hostdata->host->max_sectors =
be32_to_cpu(hostdata->madapter_info.port_max_txu[0]) >> 9;
- if (be32_to_cpu(hostdata->madapter_info.os_type) == 3 &&
+ if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX &&
strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
hostdata->madapter_info.srp_version);
@@ -1407,7 +1405,7 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
}
- if (be32_to_cpu(hostdata->madapter_info.os_type) == 3) {
+ if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX) {
enable_fast_fail(hostdata);
return;
}
@@ -1767,9 +1765,9 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
struct srp_event_struct *evt_struct =
(__force struct srp_event_struct *)crq->IU_data_ptr;
switch (crq->valid) {
- case 0xC0: /* initialization */
+ case VIOSRP_CRQ_INIT_RSP: /* initialization */
switch (crq->format) {
- case 0x01: /* Initialization message */
+ case VIOSRP_CRQ_INIT: /* Initialization message */
dev_info(hostdata->dev, "partner initialized\n");
/* Send back a response */
rc = ibmvscsi_send_crq(hostdata, 0xC002000000000000LL, 0);
@@ -1781,7 +1779,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
}
break;
- case 0x02: /* Initialization response */
+ case VIOSRP_CRQ_INIT_COMPLETE: /* Initialization response */
dev_info(hostdata->dev, "partner initialization complete\n");
/* Now login */
@@ -1791,7 +1789,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
}
return;
- case 0xFF: /* Hypervisor telling us the connection is closed */
+ case VIOSRP_CRQ_XPORT_EVENT: /* Hypervisor telling us the connection is closed */
scsi_block_requests(hostdata->host);
atomic_set(&hostdata->request_limit, 0);
if (crq->format == 0x06) {
@@ -1807,7 +1805,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
ibmvscsi_reset_host(hostdata);
}
return;
- case 0x80: /* real payload */
+ case VIOSRP_CRQ_CMD_RSP: /* real payload */
break;
default:
dev_err(hostdata->dev, "got an invalid message type 0x%02x\n",
@@ -1855,62 +1853,6 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
}
/**
- * ibmvscsi_get_host_config: Send the command to the server to get host
- * configuration data. The data is opaque to us.
- */
-static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
- unsigned char *buffer, int length)
-{
- struct viosrp_host_config *host_config;
- struct srp_event_struct *evt_struct;
- unsigned long flags;
- dma_addr_t addr;
- int rc;
-
- evt_struct = get_event_struct(&hostdata->pool);
- if (!evt_struct) {
- dev_err(hostdata->dev, "couldn't allocate event for HOST_CONFIG!\n");
- return -1;
- }
-
- init_event_struct(evt_struct,
- sync_completion,
- VIOSRP_MAD_FORMAT,
- info_timeout);
-
- host_config = &evt_struct->iu.mad.host_config;
-
- /* The transport length field is only 16-bit */
- length = min(0xffff, length);
-
- /* Set up a lun reset SRP command */
- memset(host_config, 0x00, sizeof(*host_config));
- host_config->common.type = cpu_to_be32(VIOSRP_HOST_CONFIG_TYPE);
- host_config->common.length = cpu_to_be16(length);
- addr = dma_map_single(hostdata->dev, buffer, length, DMA_BIDIRECTIONAL);
-
- if (dma_mapping_error(hostdata->dev, addr)) {
- if (!firmware_has_feature(FW_FEATURE_CMO))
- dev_err(hostdata->dev,
- "dma_mapping error getting host config\n");
- free_event_struct(&hostdata->pool, evt_struct);
- return -1;
- }
-
- host_config->buffer = cpu_to_be64(addr);
-
- init_completion(&evt_struct->comp);
- spin_lock_irqsave(hostdata->host->host_lock, flags);
- rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
- spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- if (rc == 0)
- wait_for_completion(&evt_struct->comp);
- dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
-
- return rc;
-}
-
-/**
* ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
* @sdev: struct scsi_device device to configure
*
@@ -2041,7 +1983,7 @@ static ssize_t show_host_partition_number(struct device *dev,
int len;
len = snprintf(buf, PAGE_SIZE, "%d\n",
- hostdata->madapter_info.partition_number);
+ be32_to_cpu(hostdata->madapter_info.partition_number));
return len;
}
@@ -2061,7 +2003,7 @@ static ssize_t show_host_mad_version(struct device *dev,
int len;
len = snprintf(buf, PAGE_SIZE, "%d\n",
- hostdata->madapter_info.mad_version);
+ be32_to_cpu(hostdata->madapter_info.mad_version));
return len;
}
@@ -2080,7 +2022,8 @@ static ssize_t show_host_os_type(struct device *dev,
struct ibmvscsi_host_data *hostdata = shost_priv(shost);
int len;
- len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
+ len = snprintf(buf, PAGE_SIZE, "%d\n",
+ be32_to_cpu(hostdata->madapter_info.os_type));
return len;
}
@@ -2095,21 +2038,14 @@ static struct device_attribute ibmvscsi_host_os_type = {
static ssize_t show_host_config(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct Scsi_Host *shost = class_to_shost(dev);
- struct ibmvscsi_host_data *hostdata = shost_priv(shost);
-
- /* returns null-terminated host config data */
- if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0)
- return strlen(buf);
- else
- return 0;
+ return 0;
}
static struct device_attribute ibmvscsi_host_config = {
.attr = {
- .name = "config",
- .mode = S_IRUGO,
- },
+ .name = "config",
+ .mode = S_IRUGO,
+ },
.show = show_host_config,
};
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
index 116243087622..c1ab8a4c3161 100644
--- a/drivers/scsi/ibmvscsi/viosrp.h
+++ b/drivers/scsi/ibmvscsi/viosrp.h
@@ -51,13 +51,25 @@ union srp_iu {
u8 reserved[SRP_MAX_IU_LEN];
};
+enum viosrp_crq_headers {
+ VIOSRP_CRQ_FREE = 0x00,
+ VIOSRP_CRQ_CMD_RSP = 0x80,
+ VIOSRP_CRQ_INIT_RSP = 0xC0,
+ VIOSRP_CRQ_XPORT_EVENT = 0xFF
+};
+
+enum viosrp_crq_init_formats {
+ VIOSRP_CRQ_INIT = 0x01,
+ VIOSRP_CRQ_INIT_COMPLETE = 0x02
+};
+
enum viosrp_crq_formats {
VIOSRP_SRP_FORMAT = 0x01,
VIOSRP_MAD_FORMAT = 0x02,
VIOSRP_OS400_FORMAT = 0x03,
VIOSRP_AIX_FORMAT = 0x04,
- VIOSRP_LINUX_FORMAT = 0x06,
- VIOSRP_INLINE_FORMAT = 0x07
+ VIOSRP_LINUX_FORMAT = 0x05,
+ VIOSRP_INLINE_FORMAT = 0x06
};
enum viosrp_crq_status {
@@ -87,7 +99,6 @@ enum viosrp_mad_types {
VIOSRP_EMPTY_IU_TYPE = 0x01,
VIOSRP_ERROR_LOG_TYPE = 0x02,
VIOSRP_ADAPTER_INFO_TYPE = 0x03,
- VIOSRP_HOST_CONFIG_TYPE = 0x04,
VIOSRP_CAPABILITIES_TYPE = 0x05,
VIOSRP_ENABLE_FAST_FAIL = 0x08,
};
@@ -153,11 +164,6 @@ struct viosrp_adapter_info {
__be64 buffer;
};
-struct viosrp_host_config {
- struct mad_common common;
- __be64 buffer;
-};
-
struct viosrp_fast_fail {
struct mad_common common;
};
@@ -195,7 +201,6 @@ union mad_iu {
struct viosrp_empty_iu empty_iu;
struct viosrp_error_log error_log;
struct viosrp_adapter_info adapter_info;
- struct viosrp_host_config host_config;
struct viosrp_fast_fail fast_fail;
struct viosrp_capabilities capabilities;
};
@@ -209,7 +214,10 @@ struct mad_adapter_info_data {
char srp_version[8];
char partition_name[96];
__be32 partition_number;
+#define SRP_MAD_VERSION_1 1
__be32 mad_version;
+#define SRP_MAD_OS_LINUX 2
+#define SRP_MAD_OS_AIX 3
__be32 os_type;
__be32 port_max_txu[8]; /* per-port maximum transfer */
};
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index f8b88fa78e62..9164ce1249c1 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -77,9 +77,10 @@ static void imm_wakeup(void *ref)
spin_lock_irqsave(&arbitration_lock, flags);
if (dev->wanted) {
- parport_claim(dev->dev);
- got_it(dev);
- dev->wanted = 0;
+ if (parport_claim(dev->dev) == 0) {
+ got_it(dev);
+ dev->wanted = 0;
+ }
}
spin_unlock_irqrestore(&arbitration_lock, flags);
}
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 3b3e0998fa6e..d6a691e27d33 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -4002,6 +4002,7 @@ static ssize_t ipr_store_update_fw(struct device *dev,
struct ipr_sglist *sglist;
char fname[100];
char *src;
+ char *endline;
int result, dnld_size;
if (!capable(CAP_SYS_ADMIN))
@@ -4009,6 +4010,10 @@ static ssize_t ipr_store_update_fw(struct device *dev,
snprintf(fname, sizeof(fname), "%s", buf);
+ endline = strchr(fname, '\n');
+ if (endline)
+ *endline = '\0';
+
if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);
return -EIO;
diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c
index 680bf6f0ce76..8f0ea97cf31f 100644
--- a/drivers/scsi/iscsi_boot_sysfs.c
+++ b/drivers/scsi/iscsi_boot_sysfs.c
@@ -166,6 +166,7 @@ static struct attribute_group iscsi_boot_target_attr_group = {
iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX);
iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS);
iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR);
+iscsi_boot_rd_attr(eth_prefix, prefix-len, ISCSI_BOOT_ETH_PREFIX_LEN);
iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK);
iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN);
iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY);
@@ -181,6 +182,7 @@ static struct attribute *ethernet_attrs[] = {
&iscsi_boot_attr_eth_index.attr,
&iscsi_boot_attr_eth_flags.attr,
&iscsi_boot_attr_eth_ip.attr,
+ &iscsi_boot_attr_eth_prefix.attr,
&iscsi_boot_attr_eth_subnet.attr,
&iscsi_boot_attr_eth_origin.attr,
&iscsi_boot_attr_eth_gateway.attr,
@@ -208,6 +210,9 @@ static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj,
else if (attr == &iscsi_boot_attr_eth_ip.attr)
return boot_kobj->is_visible(boot_kobj->data,
ISCSI_BOOT_ETH_IP_ADDR);
+ else if (attr == &iscsi_boot_attr_eth_prefix.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_PREFIX_LEN);
else if (attr == &iscsi_boot_attr_eth_subnet.attr)
return boot_kobj->is_visible(boot_kobj->data,
ISCSI_BOOT_ETH_SUBNET_MASK);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 0b8af186e707..2e4c82f8329c 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -26,12 +26,12 @@
* Zhenyu Wang
*/
+#include <crypto/hash.h>
#include <linux/types.h>
#include <linux/inet.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/blkdev.h>
-#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
@@ -428,7 +428,7 @@ static void iscsi_sw_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr,
* sufficient room.
*/
if (conn->hdrdgst_en) {
- iscsi_tcp_dgst_header(&tcp_sw_conn->tx_hash, hdr, hdrlen,
+ iscsi_tcp_dgst_header(tcp_sw_conn->tx_hash, hdr, hdrlen,
hdr + hdrlen);
hdrlen += ISCSI_DIGEST_SIZE;
}
@@ -454,7 +454,7 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
{
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct hash_desc *tx_hash = NULL;
+ struct ahash_request *tx_hash = NULL;
unsigned int hdr_spec_len;
ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s\n", offset, len,
@@ -467,7 +467,7 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
if (conn->datadgst_en)
- tx_hash = &tcp_sw_conn->tx_hash;
+ tx_hash = tcp_sw_conn->tx_hash;
return iscsi_segment_seek_sg(&tcp_sw_conn->out.data_segment,
sg, count, offset, len,
@@ -480,7 +480,7 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data,
{
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct hash_desc *tx_hash = NULL;
+ struct ahash_request *tx_hash = NULL;
unsigned int hdr_spec_len;
ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s\n", len, conn->datadgst_en ?
@@ -492,7 +492,7 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data,
WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
if (conn->datadgst_en)
- tx_hash = &tcp_sw_conn->tx_hash;
+ tx_hash = tcp_sw_conn->tx_hash;
iscsi_segment_init_linear(&tcp_sw_conn->out.data_segment,
data, len, NULL, tx_hash);
@@ -543,6 +543,7 @@ iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn;
struct iscsi_tcp_conn *tcp_conn;
struct iscsi_sw_tcp_conn *tcp_sw_conn;
+ struct crypto_ahash *tfm;
cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*tcp_sw_conn),
conn_idx);
@@ -552,23 +553,28 @@ iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session,
tcp_conn = conn->dd_data;
tcp_sw_conn = tcp_conn->dd_data;
- tcp_sw_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
- CRYPTO_ALG_ASYNC);
- tcp_sw_conn->tx_hash.flags = 0;
- if (IS_ERR(tcp_sw_conn->tx_hash.tfm))
+ tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm))
goto free_conn;
- tcp_sw_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
- CRYPTO_ALG_ASYNC);
- tcp_sw_conn->rx_hash.flags = 0;
- if (IS_ERR(tcp_sw_conn->rx_hash.tfm))
- goto free_tx_tfm;
- tcp_conn->rx_hash = &tcp_sw_conn->rx_hash;
+ tcp_sw_conn->tx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!tcp_sw_conn->tx_hash)
+ goto free_tfm;
+ ahash_request_set_callback(tcp_sw_conn->tx_hash, 0, NULL, NULL);
+
+ tcp_sw_conn->rx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!tcp_sw_conn->rx_hash)
+ goto free_tx_hash;
+ ahash_request_set_callback(tcp_sw_conn->rx_hash, 0, NULL, NULL);
+
+ tcp_conn->rx_hash = tcp_sw_conn->rx_hash;
return cls_conn;
-free_tx_tfm:
- crypto_free_hash(tcp_sw_conn->tx_hash.tfm);
+free_tx_hash:
+ ahash_request_free(tcp_sw_conn->tx_hash);
+free_tfm:
+ crypto_free_ahash(tfm);
free_conn:
iscsi_conn_printk(KERN_ERR, conn,
"Could not create connection due to crc32c "
@@ -607,10 +613,14 @@ static void iscsi_sw_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
iscsi_sw_tcp_release_conn(conn);
- if (tcp_sw_conn->tx_hash.tfm)
- crypto_free_hash(tcp_sw_conn->tx_hash.tfm);
- if (tcp_sw_conn->rx_hash.tfm)
- crypto_free_hash(tcp_sw_conn->rx_hash.tfm);
+ ahash_request_free(tcp_sw_conn->rx_hash);
+ if (tcp_sw_conn->tx_hash) {
+ struct crypto_ahash *tfm;
+
+ tfm = crypto_ahash_reqtfm(tcp_sw_conn->tx_hash);
+ ahash_request_free(tcp_sw_conn->tx_hash);
+ crypto_free_ahash(tfm);
+ }
iscsi_tcp_conn_teardown(cls_conn);
}
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index f42ecb238af5..06d42d00a323 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -45,8 +45,8 @@ struct iscsi_sw_tcp_conn {
void (*old_write_space)(struct sock *);
/* data and header digests */
- struct hash_desc tx_hash; /* CRC32C (Tx) */
- struct hash_desc rx_hash; /* CRC32C (Rx) */
+ struct ahash_request *tx_hash; /* CRC32C (Tx) */
+ struct ahash_request *rx_hash; /* CRC32C (Rx) */
/* MIB custom statistics */
uint32_t sendpage_failures_cnt;
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 60cb6dc3c6f0..63a1d69ff515 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -26,13 +26,13 @@
* Zhenyu Wang
*/
+#include <crypto/hash.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/inet.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/blkdev.h>
-#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
@@ -214,7 +214,8 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
} else
sg_init_one(&sg, segment->data + segment->copied,
copied);
- crypto_hash_update(segment->hash, &sg, copied);
+ ahash_request_set_crypt(segment->hash, &sg, NULL, copied);
+ crypto_ahash_update(segment->hash);
}
segment->copied += copied;
@@ -260,7 +261,9 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
* is completely handled in hdr done function.
*/
if (segment->hash) {
- crypto_hash_final(segment->hash, segment->digest);
+ ahash_request_set_crypt(segment->hash, NULL,
+ segment->digest, 0);
+ crypto_ahash_final(segment->hash);
iscsi_tcp_segment_splice_digest(segment,
recv ? segment->recv_digest : segment->digest);
return 0;
@@ -310,13 +313,14 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
}
inline void
-iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr, size_t hdrlen,
- unsigned char digest[ISCSI_DIGEST_SIZE])
+iscsi_tcp_dgst_header(struct ahash_request *hash, const void *hdr,
+ size_t hdrlen, unsigned char digest[ISCSI_DIGEST_SIZE])
{
struct scatterlist sg;
sg_init_one(&sg, hdr, hdrlen);
- crypto_hash_digest(hash, &sg, hdrlen, digest);
+ ahash_request_set_crypt(hash, &sg, digest, hdrlen);
+ crypto_ahash_digest(hash);
}
EXPORT_SYMBOL_GPL(iscsi_tcp_dgst_header);
@@ -341,7 +345,7 @@ iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn,
*/
static inline void
__iscsi_segment_init(struct iscsi_segment *segment, size_t size,
- iscsi_segment_done_fn_t *done, struct hash_desc *hash)
+ iscsi_segment_done_fn_t *done, struct ahash_request *hash)
{
memset(segment, 0, sizeof(*segment));
segment->total_size = size;
@@ -349,14 +353,14 @@ __iscsi_segment_init(struct iscsi_segment *segment, size_t size,
if (hash) {
segment->hash = hash;
- crypto_hash_init(hash);
+ crypto_ahash_init(hash);
}
}
inline void
iscsi_segment_init_linear(struct iscsi_segment *segment, void *data,
size_t size, iscsi_segment_done_fn_t *done,
- struct hash_desc *hash)
+ struct ahash_request *hash)
{
__iscsi_segment_init(segment, size, done, hash);
segment->data = data;
@@ -368,7 +372,8 @@ inline int
iscsi_segment_seek_sg(struct iscsi_segment *segment,
struct scatterlist *sg_list, unsigned int sg_count,
unsigned int offset, size_t size,
- iscsi_segment_done_fn_t *done, struct hash_desc *hash)
+ iscsi_segment_done_fn_t *done,
+ struct ahash_request *hash)
{
struct scatterlist *sg;
unsigned int i;
@@ -431,7 +436,7 @@ static void
iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
{
struct iscsi_conn *conn = tcp_conn->iscsi_conn;
- struct hash_desc *rx_hash = NULL;
+ struct ahash_request *rx_hash = NULL;
if (conn->datadgst_en &&
!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
@@ -686,7 +691,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
if (tcp_conn->in.datalen) {
struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct hash_desc *rx_hash = NULL;
+ struct ahash_request *rx_hash = NULL;
struct scsi_data_buffer *sdb = scsi_in(task->sc);
/*
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 25aa9b98d53a..a63542bac153 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -1054,11 +1054,11 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
{
struct dentry *dent = file->f_path.dentry;
struct lpfc_hba *phba = file->private_data;
- char dstbuf[32];
+ char dstbuf[33];
uint64_t tmp = 0;
int size;
- memset(dstbuf, 0, 32);
+ memset(dstbuf, 0, 33);
size = (nbytes < 32) ? nbytes : 32;
if (copy_from_user(dstbuf, buf, size))
return 0;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index c37d72effbff..25b5dcd1a5c8 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
+#include <linux/lockdep.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -1314,6 +1315,8 @@ __lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index,
{
struct lpfc_fcf_pri *fcf_pri;
+ lockdep_assert_held(&phba->hbalock);
+
fcf_pri = &phba->fcf.fcf_pri[fcf_index];
fcf_pri->fcf_rec.fcf_index = fcf_index;
/* FCF record priority */
@@ -1398,6 +1401,8 @@ __lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec,
struct fcf_record *new_fcf_record, uint32_t addr_mode,
uint16_t vlan_id, uint32_t flag)
{
+ lockdep_assert_held(&phba->hbalock);
+
/* Copy the fields from the HBA's FCF record */
lpfc_copy_fcf_record(fcf_rec, new_fcf_record);
/* Update other fields of driver FCF record */
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 152b3c8a5428..3bd0be6277b3 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -4139,23 +4139,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
/* The sdev is not guaranteed to be valid post scsi_done upcall. */
cmd->scsi_done(cmd);
- if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
- spin_lock_irqsave(&phba->hbalock, flags);
- lpfc_cmd->pCmd = NULL;
- spin_unlock_irqrestore(&phba->hbalock, flags);
-
- /*
- * If there is a thread waiting for command completion
- * wake up the thread.
- */
- spin_lock_irqsave(shost->host_lock, flags);
- if (lpfc_cmd->waitq)
- wake_up(lpfc_cmd->waitq);
- spin_unlock_irqrestore(shost->host_lock, flags);
- lpfc_release_scsi_buf(phba, lpfc_cmd);
- return;
- }
-
spin_lock_irqsave(&phba->hbalock, flags);
lpfc_cmd->pCmd = NULL;
spin_unlock_irqrestore(&phba->hbalock, flags);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 92dfd6a5178c..2207726b88ee 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/lockdep.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -576,6 +577,8 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_iocbq * iocbq = NULL;
+ lockdep_assert_held(&phba->hbalock);
+
list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
if (iocbq)
phba->iocb_cnt++;
@@ -797,6 +800,7 @@ int
lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
uint16_t xritag)
{
+ lockdep_assert_held(&phba->hbalock);
if (!ndlp)
return 0;
if (!ndlp->active_rrqs_xri_bitmap)
@@ -914,6 +918,8 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
struct lpfc_nodelist *ndlp;
int found = 0;
+ lockdep_assert_held(&phba->hbalock);
+
if (piocbq->iocb_flag & LPFC_IO_FCP) {
lpfc_cmd = (struct lpfc_scsi_buf *) piocbq->context1;
ndlp = lpfc_cmd->rdata->pnode;
@@ -1003,6 +1009,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
unsigned long iflag = 0;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ lockdep_assert_held(&phba->hbalock);
+
if (iocbq->sli4_xritag == NO_XRI)
sglq = NULL;
else
@@ -1058,6 +1066,7 @@ __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
+ lockdep_assert_held(&phba->hbalock);
/*
* Clean all volatile data fields, preserve iotag and node struct.
@@ -1080,6 +1089,8 @@ __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
static void
__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
+ lockdep_assert_held(&phba->hbalock);
+
phba->__lpfc_sli_release_iocbq(phba, iocbq);
phba->iocb_cnt--;
}
@@ -1310,6 +1321,8 @@ static int
lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
+ lockdep_assert_held(&phba->hbalock);
+
list_add_tail(&piocb->list, &pring->txcmplq);
piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ;
@@ -1344,6 +1357,8 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
struct lpfc_iocbq *cmd_iocb;
+ lockdep_assert_held(&phba->hbalock);
+
list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
return cmd_iocb;
}
@@ -1367,6 +1382,9 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
uint32_t max_cmd_idx = pring->sli.sli3.numCiocb;
+
+ lockdep_assert_held(&phba->hbalock);
+
if ((pring->sli.sli3.next_cmdidx == pring->sli.sli3.cmdidx) &&
(++pring->sli.sli3.next_cmdidx >= max_cmd_idx))
pring->sli.sli3.next_cmdidx = 0;
@@ -1497,6 +1515,7 @@ static void
lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
IOCB_t *iocb, struct lpfc_iocbq *nextiocb)
{
+ lockdep_assert_held(&phba->hbalock);
/*
* Set up an iotag
*/
@@ -1606,6 +1625,8 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
IOCB_t *iocb;
struct lpfc_iocbq *nextiocb;
+ lockdep_assert_held(&phba->hbalock);
+
/*
* Check to see if:
* (a) there is anything on the txq to send
@@ -1647,6 +1668,8 @@ lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
{
struct hbq_s *hbqp = &phba->hbqs[hbqno];
+ lockdep_assert_held(&phba->hbalock);
+
if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx &&
++hbqp->next_hbqPutIdx >= hbqp->entry_count)
hbqp->next_hbqPutIdx = 0;
@@ -1747,6 +1770,7 @@ static int
lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
struct hbq_dmabuf *hbq_buf)
{
+ lockdep_assert_held(&phba->hbalock);
return phba->lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf);
}
@@ -1768,6 +1792,7 @@ lpfc_sli_hbq_to_firmware_s3(struct lpfc_hba *phba, uint32_t hbqno,
struct lpfc_hbq_entry *hbqe;
dma_addr_t physaddr = hbq_buf->dbuf.phys;
+ lockdep_assert_held(&phba->hbalock);
/* Get next HBQ entry slot to use */
hbqe = lpfc_sli_next_hbq_slot(phba, hbqno);
if (hbqe) {
@@ -1808,6 +1833,7 @@ lpfc_sli_hbq_to_firmware_s4(struct lpfc_hba *phba, uint32_t hbqno,
struct lpfc_rqe hrqe;
struct lpfc_rqe drqe;
+ lockdep_assert_held(&phba->hbalock);
hrqe.address_lo = putPaddrLow(hbq_buf->hbuf.phys);
hrqe.address_hi = putPaddrHigh(hbq_buf->hbuf.phys);
drqe.address_lo = putPaddrLow(hbq_buf->dbuf.phys);
@@ -1986,6 +2012,8 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
struct hbq_dmabuf *hbq_buf;
uint32_t hbqno;
+ lockdep_assert_held(&phba->hbalock);
+
hbqno = tag >> 16;
if (hbqno >= LPFC_MAX_HBQS)
return NULL;
@@ -2647,6 +2675,7 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
{
struct lpfc_iocbq *cmd_iocb = NULL;
uint16_t iotag;
+ lockdep_assert_held(&phba->hbalock);
iotag = prspiocb->iocb.ulpIoTag;
@@ -2685,6 +2714,7 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
{
struct lpfc_iocbq *cmd_iocb;
+ lockdep_assert_held(&phba->hbalock);
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
@@ -3799,6 +3829,8 @@ void lpfc_reset_barrier(struct lpfc_hba *phba)
int i;
uint8_t hdrtype;
+ lockdep_assert_held(&phba->hbalock);
+
pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);
if (hdrtype != 0x80 ||
(FC_JEDEC_ID(phba->vpd.rev.biuRev) != HELIOS_JEDEC_ID &&
@@ -7861,6 +7893,7 @@ void
__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
+ lockdep_assert_held(&phba->hbalock);
/* Insert the caller's iocb in the txq tail for later processing. */
list_add_tail(&piocb->list, &pring->txq);
}
@@ -7888,6 +7921,8 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
{
struct lpfc_iocbq * nextiocb;
+ lockdep_assert_held(&phba->hbalock);
+
nextiocb = lpfc_sli_ringtx_get(phba, pring);
if (!nextiocb) {
nextiocb = *piocb;
@@ -7927,6 +7962,8 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number,
IOCB_t *iocb;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
+ lockdep_assert_held(&phba->hbalock);
+
if (piocb->iocb_cmpl && (!piocb->vport) &&
(piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
(piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
@@ -8642,6 +8679,8 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_queue *wq;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
+ lockdep_assert_held(&phba->hbalock);
+
if (piocb->sli4_xritag == NO_XRI) {
if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
@@ -9752,6 +9791,8 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
int retval;
unsigned long iflags;
+ lockdep_assert_held(&phba->hbalock);
+
/*
* There are certain command types we don't want to abort. And we
* don't want to abort commands that are already in the process of
@@ -9854,6 +9895,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
int retval = IOCB_ERROR;
IOCB_t *icmd = NULL;
+ lockdep_assert_held(&phba->hbalock);
+
/*
* There are certain command types we don't want to abort. And we
* don't want to abort commands that are already in the process of
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 141226631429..a6682c508c4c 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -18,11 +18,11 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/pci.h>
#include <asm/dbdma.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
-#include <asm/pci-bridge.h>
#include <asm/macio.h>
#include <scsi/scsi.h>
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index c0f7c8ce54aa..4484e63033a5 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -35,8 +35,8 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "06.808.16.00-rc1"
-#define MEGASAS_RELDATE "Oct. 8, 2015"
+#define MEGASAS_VERSION "06.810.09.00-rc1"
+#define MEGASAS_RELDATE "Jan. 28, 2016"
/*
* Device IDs
@@ -152,6 +152,7 @@
#define MFI_RESET_FLAGS MFI_INIT_READY| \
MFI_INIT_MFIMODE| \
MFI_INIT_ABORT
+#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01)
/*
* MFI frame flags
@@ -170,6 +171,7 @@
/* Driver internal */
#define DRV_DCMD_POLLED_MODE 0x1
+#define DRV_DCMD_SKIP_REFIRE 0x2
/*
* Definition for cmd_status
@@ -214,6 +216,7 @@
#define MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS 0x01190100
#define MR_DRIVER_SET_APP_CRASHDUMP_MODE (0xF0010000 | 0x0600)
+#define MR_DCMD_PD_GET_INFO 0x02020000
/*
* Global functions
@@ -390,6 +393,7 @@ enum MR_EVT_ARGS {
#define SGE_BUFFER_SIZE 4096
+#define MEGASAS_CLUSTER_ID_SIZE 16
/*
* define constants for device list query options
*/
@@ -434,6 +438,257 @@ enum MR_PD_STATE {
MR_PD_STATE_SYSTEM = 0x40,
};
+union MR_PD_REF {
+ struct {
+ u16 deviceId;
+ u16 seqNum;
+ } mrPdRef;
+ u32 ref;
+};
+
+/*
+ * define the DDF Type bit structure
+ */
+union MR_PD_DDF_TYPE {
+ struct {
+ union {
+ struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+ u16 forcedPDGUID:1;
+ u16 inVD:1;
+ u16 isGlobalSpare:1;
+ u16 isSpare:1;
+ u16 isForeign:1;
+ u16 reserved:7;
+ u16 intf:4;
+#else
+ u16 intf:4;
+ u16 reserved:7;
+ u16 isForeign:1;
+ u16 isSpare:1;
+ u16 isGlobalSpare:1;
+ u16 inVD:1;
+ u16 forcedPDGUID:1;
+#endif
+ } pdType;
+ u16 type;
+ };
+ u16 reserved;
+ } ddf;
+ struct {
+ u32 reserved;
+ } nonDisk;
+ u32 type;
+} __packed;
+
+/*
+ * defines the progress structure
+ */
+union MR_PROGRESS {
+ struct {
+ u16 progress;
+ union {
+ u16 elapsedSecs;
+ u16 elapsedSecsForLastPercent;
+ };
+ } mrProgress;
+ u32 w;
+} __packed;
+
+/*
+ * defines the physical drive progress structure
+ */
+struct MR_PD_PROGRESS {
+ struct {
+#ifndef MFI_BIG_ENDIAN
+ u32 rbld:1;
+ u32 patrol:1;
+ u32 clear:1;
+ u32 copyBack:1;
+ u32 erase:1;
+ u32 locate:1;
+ u32 reserved:26;
+#else
+ u32 reserved:26;
+ u32 locate:1;
+ u32 erase:1;
+ u32 copyBack:1;
+ u32 clear:1;
+ u32 patrol:1;
+ u32 rbld:1;
+#endif
+ } active;
+ union MR_PROGRESS rbld;
+ union MR_PROGRESS patrol;
+ union {
+ union MR_PROGRESS clear;
+ union MR_PROGRESS erase;
+ };
+
+ struct {
+#ifndef MFI_BIG_ENDIAN
+ u32 rbld:1;
+ u32 patrol:1;
+ u32 clear:1;
+ u32 copyBack:1;
+ u32 erase:1;
+ u32 reserved:27;
+#else
+ u32 reserved:27;
+ u32 erase:1;
+ u32 copyBack:1;
+ u32 clear:1;
+ u32 patrol:1;
+ u32 rbld:1;
+#endif
+ } pause;
+
+ union MR_PROGRESS reserved[3];
+} __packed;
+
+struct MR_PD_INFO {
+ union MR_PD_REF ref;
+ u8 inquiryData[96];
+ u8 vpdPage83[64];
+ u8 notSupported;
+ u8 scsiDevType;
+
+ union {
+ u8 connectedPortBitmap;
+ u8 connectedPortNumbers;
+ };
+
+ u8 deviceSpeed;
+ u32 mediaErrCount;
+ u32 otherErrCount;
+ u32 predFailCount;
+ u32 lastPredFailEventSeqNum;
+
+ u16 fwState;
+ u8 disabledForRemoval;
+ u8 linkSpeed;
+ union MR_PD_DDF_TYPE state;
+
+ struct {
+ u8 count;
+#ifndef __BIG_ENDIAN_BITFIELD
+ u8 isPathBroken:4;
+ u8 reserved3:3;
+ u8 widePortCapable:1;
+#else
+ u8 widePortCapable:1;
+ u8 reserved3:3;
+ u8 isPathBroken:4;
+#endif
+
+ u8 connectorIndex[2];
+ u8 reserved[4];
+ u64 sasAddr[2];
+ u8 reserved2[16];
+ } pathInfo;
+
+ u64 rawSize;
+ u64 nonCoercedSize;
+ u64 coercedSize;
+ u16 enclDeviceId;
+ u8 enclIndex;
+
+ union {
+ u8 slotNumber;
+ u8 enclConnectorIndex;
+ };
+
+ struct MR_PD_PROGRESS progInfo;
+ u8 badBlockTableFull;
+ u8 unusableInCurrentConfig;
+ u8 vpdPage83Ext[64];
+ u8 powerState;
+ u8 enclPosition;
+ u32 allowedOps;
+ u16 copyBackPartnerId;
+ u16 enclPartnerDeviceId;
+ struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+ u16 fdeCapable:1;
+ u16 fdeEnabled:1;
+ u16 secured:1;
+ u16 locked:1;
+ u16 foreign:1;
+ u16 needsEKM:1;
+ u16 reserved:10;
+#else
+ u16 reserved:10;
+ u16 needsEKM:1;
+ u16 foreign:1;
+ u16 locked:1;
+ u16 secured:1;
+ u16 fdeEnabled:1;
+ u16 fdeCapable:1;
+#endif
+ } security;
+ u8 mediaType;
+ u8 notCertified;
+ u8 bridgeVendor[8];
+ u8 bridgeProductIdentification[16];
+ u8 bridgeProductRevisionLevel[4];
+ u8 satBridgeExists;
+
+ u8 interfaceType;
+ u8 temperature;
+ u8 emulatedBlockSize;
+ u16 userDataBlockSize;
+ u16 reserved2;
+
+ struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+ u32 piType:3;
+ u32 piFormatted:1;
+ u32 piEligible:1;
+ u32 NCQ:1;
+ u32 WCE:1;
+ u32 commissionedSpare:1;
+ u32 emergencySpare:1;
+ u32 ineligibleForSSCD:1;
+ u32 ineligibleForLd:1;
+ u32 useSSEraseType:1;
+ u32 wceUnchanged:1;
+ u32 supportScsiUnmap:1;
+ u32 reserved:18;
+#else
+ u32 reserved:18;
+ u32 supportScsiUnmap:1;
+ u32 wceUnchanged:1;
+ u32 useSSEraseType:1;
+ u32 ineligibleForLd:1;
+ u32 ineligibleForSSCD:1;
+ u32 emergencySpare:1;
+ u32 commissionedSpare:1;
+ u32 WCE:1;
+ u32 NCQ:1;
+ u32 piEligible:1;
+ u32 piFormatted:1;
+ u32 piType:3;
+#endif
+ } properties;
+
+ u64 shieldDiagCompletionTime;
+ u8 shieldCounter;
+
+ u8 linkSpeedOther;
+ u8 reserved4[2];
+
+ struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+ u32 bbmErrCountSupported:1;
+ u32 bbmErrCount:31;
+#else
+ u32 bbmErrCount:31;
+ u32 bbmErrCountSupported:1;
+#endif
+ } bbmErr;
+
+ u8 reserved1[512-428];
+} __packed;
/*
* defines the physical drive address structure
@@ -473,6 +728,7 @@ struct megasas_pd_list {
u16 tid;
u8 driveType;
u8 driveState;
+ u8 interface;
} __packed;
/*
@@ -972,7 +1228,8 @@ struct megasas_ctrl_info {
*/
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:26;
+ u32 reserved:25;
+ u32 passive:1;
u32 premiumFeatureMismatch:1;
u32 ctrlPropIncompatible:1;
u32 fwVersionMismatch:1;
@@ -986,11 +1243,12 @@ struct megasas_ctrl_info {
u32 fwVersionMismatch:1;
u32 ctrlPropIncompatible:1;
u32 premiumFeatureMismatch:1;
- u32 reserved:26;
+ u32 passive:1;
+ u32 reserved:25;
#endif
} cluster;
- char clusterId[16]; /*7D4h */
+ char clusterId[MEGASAS_CLUSTER_ID_SIZE]; /*0x7D4 */
struct {
u8 maxVFsSupported; /*0x7E4*/
u8 numVFsEnabled; /*0x7E5*/
@@ -1083,6 +1341,8 @@ struct megasas_ctrl_info {
#define VD_EXT_DEBUG 0
+#define SCAN_PD_CHANNEL 0x1
+#define SCAN_VD_CHANNEL 0x2
enum MR_SCSI_CMD_TYPE {
READ_WRITE_LDIO = 0,
@@ -1091,6 +1351,17 @@ enum MR_SCSI_CMD_TYPE {
NON_READ_WRITE_SYSPDIO = 3,
};
+enum DCMD_TIMEOUT_ACTION {
+ INITIATE_OCR = 0,
+ KILL_ADAPTER = 1,
+ IGNORE_TIMEOUT = 2,
+};
+
+enum FW_BOOT_CONTEXT {
+ PROBE_CONTEXT = 0,
+ OCR_CONTEXT = 1,
+};
+
/* Frame Type */
#define IO_FRAME 0
#define PTHRU_FRAME 1
@@ -1137,6 +1408,7 @@ enum MR_SCSI_CMD_TYPE {
#define MFI_OB_INTR_STATUS_MASK 0x00000002
#define MFI_POLL_TIMEOUT_SECS 60
+#define MFI_IO_TIMEOUT_SECS 180
#define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF (5 * HZ)
#define MEGASAS_OCR_SETTLE_TIME_VF (1000 * 30)
#define MEGASAS_ROUTINE_WAIT_TIME_VF 300
@@ -1154,6 +1426,7 @@ enum MR_SCSI_CMD_TYPE {
#define MR_MAX_REPLY_QUEUES_EXT_OFFSET 0X003FC000
#define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14
#define MR_MAX_MSIX_REG_ARRAY 16
+#define MR_RDPQ_MODE_OFFSET 0X00800000
/*
* register set for both 1068 and 1078 controllers
* structure extended for 1078 registers
@@ -1193,8 +1466,9 @@ struct megasas_register_set {
u32 outbound_scratch_pad ; /*00B0h*/
u32 outbound_scratch_pad_2; /*00B4h*/
+ u32 outbound_scratch_pad_3; /*00B8h*/
- u32 reserved_4[2]; /*00B8h*/
+ u32 reserved_4; /*00BCh*/
u32 inbound_low_queue_port ; /*00C0h*/
@@ -1266,7 +1540,10 @@ union megasas_sgl_frame {
typedef union _MFI_CAPABILITIES {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:23;
+ u32 reserved:20;
+ u32 support_qd_throttling:1;
+ u32 support_fp_rlbypass:1;
+ u32 support_vfid_in_ioframe:1;
u32 support_ext_io_size:1;
u32 support_ext_queue_depth:1;
u32 security_protocol_cmds_fw:1;
@@ -1286,7 +1563,10 @@ typedef union _MFI_CAPABILITIES {
u32 security_protocol_cmds_fw:1;
u32 support_ext_queue_depth:1;
u32 support_ext_io_size:1;
- u32 reserved:23;
+ u32 support_vfid_in_ioframe:1;
+ u32 support_fp_rlbypass:1;
+ u32 support_qd_throttling:1;
+ u32 reserved:20;
#endif
} mfi_capabilities;
__le32 reg;
@@ -1511,6 +1791,15 @@ union megasas_frame {
u8 raw_bytes[64];
};
+/**
+ * struct MR_PRIV_DEVICE - sdev private hostdata
+ * @is_tm_capable: firmware managed tm_capable flag
+ * @tm_busy: TM request is in progress
+ */
+struct MR_PRIV_DEVICE {
+ bool is_tm_capable;
+ bool tm_busy;
+};
struct megasas_cmd;
union megasas_evt_class_locale {
@@ -1700,6 +1989,19 @@ struct MR_DRV_SYSTEM_INFO {
u8 reserved[1980];
};
+enum MR_PD_TYPE {
+ UNKNOWN_DRIVE = 0,
+ PARALLEL_SCSI = 1,
+ SAS_PD = 2,
+ SATA_PD = 3,
+ FC_PD = 4,
+};
+
+/* JBOD Queue depth definitions */
+#define MEGASAS_SATA_QD 32
+#define MEGASAS_SAS_QD 64
+#define MEGASAS_DEFAULT_PD_QD 64
+
struct megasas_instance {
__le32 *producer;
@@ -1714,6 +2016,8 @@ struct megasas_instance {
dma_addr_t vf_affiliation_111_h;
struct MR_CTRL_HB_HOST_MEM *hb_host_mem;
dma_addr_t hb_host_mem_h;
+ struct MR_PD_INFO *pd_info;
+ dma_addr_t pd_info_h;
__le32 *reply_queue;
dma_addr_t reply_queue_h;
@@ -1745,6 +2049,8 @@ struct megasas_instance {
u16 max_fw_cmds;
u16 max_mfi_cmds;
u16 max_scsi_cmds;
+ u16 ldio_threshold;
+ u16 cur_can_queue;
u32 max_sectors_per_req;
struct megasas_aen_event *ev;
@@ -1762,7 +2068,7 @@ struct megasas_instance {
struct megasas_evt_detail *evt_detail;
dma_addr_t evt_detail_h;
struct megasas_cmd *aen_cmd;
- struct mutex aen_mutex;
+ struct mutex hba_mutex;
struct semaphore ioctl_sem;
struct Scsi_Host *host;
@@ -1775,6 +2081,7 @@ struct megasas_instance {
u32 fw_support_ieee;
atomic_t fw_outstanding;
+ atomic_t ldio_outstanding;
atomic_t fw_reset_no_pci_access;
struct megasas_instance_template *instancet;
@@ -1797,7 +2104,7 @@ struct megasas_instance {
u16 drv_supported_vd_count;
u16 drv_supported_pd_count;
- u8 adprecovery;
+ atomic_t adprecovery;
unsigned long last_time;
u32 mfiStatus;
u32 last_seq_num;
@@ -1822,11 +2129,14 @@ struct megasas_instance {
char skip_heartbeat_timer_del;
u8 requestorId;
char PlasmaFW111;
- char mpio;
+ char clusterId[MEGASAS_CLUSTER_ID_SIZE];
+ u8 peerIsPresent;
+ u8 passive;
u16 throttlequeuedepth;
u8 mask_interrupts;
u16 max_chain_frame_sz;
u8 is_imr;
+ u8 is_rdpq;
bool dev_handle;
};
struct MR_LD_VF_MAP {
@@ -1916,7 +2226,7 @@ struct megasas_instance_template {
u32 (*init_adapter)(struct megasas_instance *);
u32 (*build_and_issue_cmd) (struct megasas_instance *,
struct scsi_cmnd *);
- void (*issue_dcmd) (struct megasas_instance *instance,
+ int (*issue_dcmd)(struct megasas_instance *instance,
struct megasas_cmd *cmd);
};
@@ -2014,6 +2324,19 @@ struct megasas_mgmt_info {
int max_index;
};
+enum MEGASAS_OCR_CAUSE {
+ FW_FAULT_OCR = 0,
+ SCSIIO_TIMEOUT_OCR = 1,
+ MFI_IO_TIMEOUT_OCR = 2,
+};
+
+enum DCMD_RETURN_STATUS {
+ DCMD_SUCCESS = 0,
+ DCMD_TIMEOUT = 1,
+ DCMD_FAILED = 2,
+ DCMD_NOT_FIRED = 3,
+};
+
u8
MR_BuildRaidContext(struct megasas_instance *instance,
struct IO_REQUEST_INFO *io_info,
@@ -2051,4 +2374,8 @@ void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance,
int megasas_cmd_type(struct scsi_cmnd *cmd);
void megasas_setup_jbod_map(struct megasas_instance *instance);
+void megasas_update_sdev_properties(struct scsi_device *sdev);
+int megasas_reset_fusion(struct Scsi_Host *shost, int reason);
+int megasas_task_abort_fusion(struct scsi_cmnd *scmd);
+int megasas_reset_target_fusion(struct scsi_cmnd *scmd);
#endif /*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 97a1c1c33b05..5c08568ccfbf 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -83,7 +83,7 @@ module_param(throttlequeuedepth, int, S_IRUGO);
MODULE_PARM_DESC(throttlequeuedepth,
"Adapter queue depth when throttled due to I/O timeout. Default: 16");
-int resetwaittime = MEGASAS_RESET_WAIT_TIME;
+unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
module_param(resetwaittime, int, S_IRUGO);
MODULE_PARM_DESC(resetwaittime, "Wait time in seconds after I/O timeout "
"before resetting adapter. Default: 180");
@@ -92,6 +92,18 @@ int smp_affinity_enable = 1;
module_param(smp_affinity_enable, int, S_IRUGO);
MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
+int rdpq_enable = 1;
+module_param(rdpq_enable, int, S_IRUGO);
+MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disable Default: disable(0)");
+
+unsigned int dual_qdepth_disable;
+module_param(dual_qdepth_disable, int, S_IRUGO);
+MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
+
+unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
+module_param(scmd_timeout, int, S_IRUGO);
+MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
+
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
@@ -104,6 +116,8 @@ static int megasas_ld_list_query(struct megasas_instance *instance,
static int megasas_issue_init_mfi(struct megasas_instance *instance);
static int megasas_register_aen(struct megasas_instance *instance,
u32 seq_num, u32 class_locale_word);
+static int
+megasas_get_pd_info(struct megasas_instance *instance, u16 device_id);
/*
* PCI ID table for all supported controllers
*/
@@ -189,18 +203,18 @@ int
wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
int seconds);
void megasas_reset_reply_desc(struct megasas_instance *instance);
-int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
void megasas_fusion_ocr_wq(struct work_struct *work);
static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
int initial);
int megasas_check_mpio_paths(struct megasas_instance *instance,
struct scsi_cmnd *scmd);
-void
+int
megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
instance->instancet->fire_cmd(instance,
cmd->frame_phys_addr, 0, instance->reg_set);
+ return 0;
}
/**
@@ -473,7 +487,7 @@ static int
megasas_check_reset_xscale(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
- if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+ if ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
(le32_to_cpu(*instance->consumer) ==
MEGASAS_ADPRESET_INPROG_SIGN))
return 1;
@@ -609,7 +623,7 @@ static int
megasas_check_reset_ppc(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
return 1;
return 0;
@@ -735,6 +749,7 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance,
&(regs)->inbound_high_queue_port);
writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1,
&(regs)->inbound_low_queue_port);
+ mmiowb();
spin_unlock_irqrestore(&instance->hba_lock, flags);
}
@@ -746,7 +761,7 @@ static int
megasas_check_reset_skinny(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
return 1;
return 0;
@@ -940,9 +955,8 @@ static int
megasas_check_reset_gen2(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
return 1;
- }
return 0;
}
@@ -983,25 +997,20 @@ extern struct megasas_instance_template megasas_instance_template_fusion;
int
megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
- int seconds;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
- frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE;
+ frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
- /*
- * Issue the frame using inbound queue port
- */
- instance->instancet->issue_dcmd(instance, cmd);
+ if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
+ (instance->instancet->issue_dcmd(instance, cmd))) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return DCMD_NOT_FIRED;
+ }
- /*
- * Wait for cmd_status to change
- */
- if (instance->requestorId)
- seconds = MEGASAS_ROUTINE_WAIT_TIME_VF;
- else
- seconds = MFI_POLL_TIMEOUT_SECS;
- return wait_and_poll(instance, cmd, seconds);
+ return wait_and_poll(instance, cmd, instance->requestorId ?
+ MEGASAS_ROUTINE_WAIT_TIME_VF : MFI_IO_TIMEOUT_SECS);
}
/**
@@ -1019,21 +1028,29 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd, int timeout)
{
int ret = 0;
-
cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
- instance->instancet->issue_dcmd(instance, cmd);
+ if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
+ (instance->instancet->issue_dcmd(instance, cmd))) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return DCMD_NOT_FIRED;
+ }
+
if (timeout) {
ret = wait_event_timeout(instance->int_cmd_wait_q,
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
- if (!ret)
- return 1;
+ if (!ret) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d DCMD Timed out\n",
+ __func__, __LINE__);
+ return DCMD_TIMEOUT;
+ }
} else
wait_event(instance->int_cmd_wait_q,
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS);
return (cmd->cmd_status_drv == MFI_STAT_OK) ?
- 0 : 1;
+ DCMD_SUCCESS : DCMD_FAILED;
}
/**
@@ -1077,15 +1094,20 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
cmd->sync_cmd = 1;
cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
- instance->instancet->issue_dcmd(instance, cmd);
+ if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
+ (instance->instancet->issue_dcmd(instance, cmd))) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return DCMD_NOT_FIRED;
+ }
if (timeout) {
ret = wait_event_timeout(instance->abort_cmd_wait_q,
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
if (!ret) {
- dev_err(&instance->pdev->dev, "Command timedout"
- "from %s\n", __func__);
- return 1;
+ dev_err(&instance->pdev->dev, "Failed from %s %d Abort Timed out\n",
+ __func__, __LINE__);
+ return DCMD_TIMEOUT;
}
} else
wait_event(instance->abort_cmd_wait_q,
@@ -1094,7 +1116,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
cmd->sync_cmd = 0;
megasas_return_cmd(instance, cmd);
- return 0;
+ return (cmd->cmd_status_drv == MFI_STAT_OK) ?
+ DCMD_SUCCESS : DCMD_FAILED;
}
/**
@@ -1621,7 +1644,7 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance,
return 0;
out_return_cmd:
megasas_return_cmd(instance, cmd);
- return 1;
+ return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1634,7 +1657,7 @@ static int
megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
{
struct megasas_instance *instance;
- unsigned long flags;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
instance = (struct megasas_instance *)
scmd->device->host->hostdata;
@@ -1648,35 +1671,38 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
if (instance->issuepend_done == 0)
return SCSI_MLQUEUE_HOST_BUSY;
- spin_lock_irqsave(&instance->hba_lock, flags);
/* Check for an mpio path and adjust behavior */
- if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
if (megasas_check_mpio_paths(instance, scmd) ==
(DID_RESET << 16)) {
- spin_unlock_irqrestore(&instance->hba_lock, flags);
return SCSI_MLQUEUE_HOST_BUSY;
} else {
- spin_unlock_irqrestore(&instance->hba_lock, flags);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return 0;
}
}
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
- spin_unlock_irqrestore(&instance->hba_lock, flags);
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return 0;
}
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
- spin_unlock_irqrestore(&instance->hba_lock, flags);
- return SCSI_MLQUEUE_HOST_BUSY;
+ mr_device_priv_data = scmd->device->hostdata;
+ if (!mr_device_priv_data) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ return 0;
}
- spin_unlock_irqrestore(&instance->hba_lock, flags);
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ if (mr_device_priv_data->tm_busy)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+
scmd->result = 0;
@@ -1699,12 +1725,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
break;
}
- if (instance->instancet->build_and_issue_cmd(instance, scmd)) {
- dev_err(&instance->pdev->dev, "Err returned from build_and_issue_cmd\n");
- return SCSI_MLQUEUE_HOST_BUSY;
- }
-
- return 0;
+ return instance->instancet->build_and_issue_cmd(instance, scmd);
out_done:
scmd->scsi_done(scmd);
@@ -1726,27 +1747,39 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no)
}
/*
-* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD
+* megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities
*
* @sdev: OS provided scsi device
*
* Returns void
*/
-static void megasas_set_dma_alignment(struct scsi_device *sdev)
+void megasas_update_sdev_properties(struct scsi_device *sdev)
{
+ u16 pd_index = 0;
u32 device_id, ld;
struct megasas_instance *instance;
struct fusion_context *fusion;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
struct MR_LD_RAID *raid;
struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
instance = megasas_lookup_instance(sdev->host->host_no);
fusion = instance->ctrl_context;
+ mr_device_priv_data = sdev->hostdata;
if (!fusion)
return;
- if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) {
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
+ instance->use_seqnum_jbod_fp) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ pd_sync = (void *)fusion->pd_seq_sync
+ [(instance->pd_seq_map_id - 1) & 1];
+ mr_device_priv_data->is_tm_capable =
+ pd_sync->seq[pd_index].capability.tmCapable;
+ } else {
device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
+ sdev->id;
local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
@@ -1754,10 +1787,51 @@ static void megasas_set_dma_alignment(struct scsi_device *sdev)
raid = MR_LdRaidGet(ld, local_map_ptr);
if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
- blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+ blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+ mr_device_priv_data->is_tm_capable =
+ raid->capability.tmCapable;
+ }
+}
+
+static void megasas_set_device_queue_depth(struct scsi_device *sdev)
+{
+ u16 pd_index = 0;
+ int ret = DCMD_FAILED;
+ struct megasas_instance *instance;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
+
+ if (instance->pd_info) {
+ mutex_lock(&instance->hba_mutex);
+ ret = megasas_get_pd_info(instance, pd_index);
+ mutex_unlock(&instance->hba_mutex);
+ }
+
+ if (ret != DCMD_SUCCESS)
+ return;
+
+ if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
+
+ switch (instance->pd_list[pd_index].interface) {
+ case SAS_PD:
+ scsi_change_queue_depth(sdev, MEGASAS_SAS_QD);
+ break;
+
+ case SATA_PD:
+ scsi_change_queue_depth(sdev, MEGASAS_SATA_QD);
+ break;
+
+ default:
+ scsi_change_queue_depth(sdev, MEGASAS_DEFAULT_PD_QD);
+ }
+ }
}
}
+
static int megasas_slave_configure(struct scsi_device *sdev)
{
u16 pd_index = 0;
@@ -1774,12 +1848,14 @@ static int megasas_slave_configure(struct scsi_device *sdev)
return -ENXIO;
}
}
- megasas_set_dma_alignment(sdev);
+ megasas_set_device_queue_depth(sdev);
+ megasas_update_sdev_properties(sdev);
+
/*
* The RAID firmware may require extended timeouts.
*/
blk_queue_rq_timeout(sdev->request_queue,
- MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+ scmd_timeout * HZ);
return 0;
}
@@ -1788,6 +1864,7 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
{
u16 pd_index = 0;
struct megasas_instance *instance ;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
instance = megasas_lookup_instance(sdev->host->host_no);
if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
@@ -1799,13 +1876,26 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
sdev->id;
if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState ==
MR_PD_STATE_SYSTEM)) {
- return 0;
+ goto scan_target;
}
return -ENXIO;
}
+
+scan_target:
+ mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data),
+ GFP_KERNEL);
+ if (!mr_device_priv_data)
+ return -ENOMEM;
+ sdev->hostdata = mr_device_priv_data;
return 0;
}
+static void megasas_slave_destroy(struct scsi_device *sdev)
+{
+ kfree(sdev->hostdata);
+ sdev->hostdata = NULL;
+}
+
/*
* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
* kill adapter
@@ -1845,7 +1935,7 @@ static void megasas_complete_outstanding_ioctls(struct megasas_instance *instanc
void megaraid_sas_kill_hba(struct megasas_instance *instance)
{
/* Set critical error to block I/O & ioctls in case caller didn't */
- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+ atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
/* Wait 1 second to ensure IO or ioctls in build have posted */
msleep(1000);
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
@@ -1854,7 +1944,7 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance)
writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
/* Flush */
readl(&instance->reg_set->doorbell);
- if (instance->mpio && instance->requestorId)
+ if (instance->requestorId && instance->peerIsPresent)
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
} else {
writel(MFI_STOP_ADP,
@@ -1883,7 +1973,7 @@ megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
spin_lock_irqsave(instance->host->host_lock, flags);
instance->flag &= ~MEGASAS_FW_BUSY;
- instance->host->can_queue = instance->max_scsi_cmds;
+ instance->host->can_queue = instance->cur_can_queue;
spin_unlock_irqrestore(instance->host->host_lock, flags);
}
}
@@ -1905,7 +1995,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
unsigned long flags;
/* If we have already declared adapter dead, donot complete cmds */
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return;
spin_lock_irqsave(&instance->completion_lock, flags);
@@ -1974,7 +2064,7 @@ void megasas_do_ocr(struct megasas_instance *instance)
*instance->consumer = cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
}
instance->instancet->disable_intr(instance);
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
instance->issuepend_done = 0;
atomic_set(&instance->fw_outstanding, 0);
@@ -2054,9 +2144,7 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance,
dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
"scsi%d\n", instance->host->host_no);
- megasas_issue_blocked_cmd(instance, cmd, 0);
-
- if (dcmd->cmd_status) {
+ if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
" failed with status 0x%x for scsi%d\n",
dcmd->cmd_status, instance->host->host_no);
@@ -2166,9 +2254,8 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance,
dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
"scsi%d\n", instance->host->host_no);
- megasas_issue_blocked_cmd(instance, cmd, 0);
- if (dcmd->cmd_status) {
+ if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
" failed with status 0x%x for scsi%d\n",
dcmd->cmd_status, instance->host->host_no);
@@ -2373,21 +2460,21 @@ void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
*/
static int megasas_wait_for_outstanding(struct megasas_instance *instance)
{
- int i;
+ int i, sl, outstanding;
u32 reset_index;
u32 wait_time = MEGASAS_RESET_WAIT_TIME;
- u8 adprecovery;
unsigned long flags;
struct list_head clist_local;
struct megasas_cmd *reset_cmd;
u32 fw_state;
- u8 kill_adapter_flag;
- spin_lock_irqsave(&instance->hba_lock, flags);
- adprecovery = instance->adprecovery;
- spin_unlock_irqrestore(&instance->hba_lock, flags);
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+ dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n",
+ __func__, __LINE__);
+ return FAILED;
+ }
- if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
INIT_LIST_HEAD(&clist_local);
spin_lock_irqsave(&instance->hba_lock, flags);
@@ -2398,18 +2485,13 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
dev_notice(&instance->pdev->dev, "HBA reset wait ...\n");
for (i = 0; i < wait_time; i++) {
msleep(1000);
- spin_lock_irqsave(&instance->hba_lock, flags);
- adprecovery = instance->adprecovery;
- spin_unlock_irqrestore(&instance->hba_lock, flags);
- if (adprecovery == MEGASAS_HBA_OPERATIONAL)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL)
break;
}
- if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n");
- spin_lock_irqsave(&instance->hba_lock, flags);
- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
- spin_unlock_irqrestore(&instance->hba_lock, flags);
+ atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
return FAILED;
}
@@ -2447,7 +2529,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
}
for (i = 0; i < resetwaittime; i++) {
- int outstanding = atomic_read(&instance->fw_outstanding);
+ outstanding = atomic_read(&instance->fw_outstanding);
if (!outstanding)
break;
@@ -2466,67 +2548,60 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
}
i = 0;
- kill_adapter_flag = 0;
+ outstanding = atomic_read(&instance->fw_outstanding);
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+
+ if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
+ goto no_outstanding;
+
+ if (instance->disableOnlineCtrlReset)
+ goto kill_hba_and_failed;
do {
- fw_state = instance->instancet->read_fw_status_reg(
- instance->reg_set) & MFI_STATE_MASK;
- if ((fw_state == MFI_STATE_FAULT) &&
- (instance->disableOnlineCtrlReset == 0)) {
- if (i == 3) {
- kill_adapter_flag = 2;
- break;
- }
+ if ((fw_state == MFI_STATE_FAULT) || atomic_read(&instance->fw_outstanding)) {
+ dev_info(&instance->pdev->dev,
+ "%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, oustanding 0x%x\n",
+ __func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding));
+ if (i == 3)
+ goto kill_hba_and_failed;
megasas_do_ocr(instance);
- kill_adapter_flag = 1;
- /* wait for 1 secs to let FW finish the pending cmds */
- msleep(1000);
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+ dev_info(&instance->pdev->dev, "%s:%d OCR failed and HBA is killed.\n",
+ __func__, __LINE__);
+ return FAILED;
+ }
+ dev_info(&instance->pdev->dev, "%s:%d waiting_for_outstanding: after issue OCR.\n",
+ __func__, __LINE__);
+
+ for (sl = 0; sl < 10; sl++)
+ msleep(500);
+
+ outstanding = atomic_read(&instance->fw_outstanding);
+
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+ if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
+ goto no_outstanding;
}
i++;
} while (i <= 3);
- if (atomic_read(&instance->fw_outstanding) && !kill_adapter_flag) {
- if (instance->disableOnlineCtrlReset == 0) {
- megasas_do_ocr(instance);
+no_outstanding:
- /* wait for 5 secs to let FW finish the pending cmds */
- for (i = 0; i < wait_time; i++) {
- int outstanding =
- atomic_read(&instance->fw_outstanding);
- if (!outstanding)
- return SUCCESS;
- msleep(1000);
- }
- }
- }
+ dev_info(&instance->pdev->dev, "%s:%d no more pending commands remain after reset handling.\n",
+ __func__, __LINE__);
+ return SUCCESS;
- if (atomic_read(&instance->fw_outstanding) ||
- (kill_adapter_flag == 2)) {
- dev_notice(&instance->pdev->dev, "pending cmds after reset\n");
- /*
- * Send signal to FW to stop processing any pending cmds.
- * The controller will be taken offline by the OS now.
- */
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
- writel(MFI_STOP_ADP,
- &instance->reg_set->doorbell);
- } else {
- writel(MFI_STOP_ADP,
- &instance->reg_set->inbound_doorbell);
- }
- megasas_dump_pending_frames(instance);
- spin_lock_irqsave(&instance->hba_lock, flags);
- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
- spin_unlock_irqrestore(&instance->hba_lock, flags);
- return FAILED;
- }
+kill_hba_and_failed:
- dev_notice(&instance->pdev->dev, "no pending cmds after reset\n");
+ /* Reset not supported, kill adapter */
+ dev_info(&instance->pdev->dev, "%s:%d killing adapter scsi%d"
+ " disableOnlineCtrlReset %d fw_outstanding %d \n",
+ __func__, __LINE__, instance->host->host_no, instance->disableOnlineCtrlReset,
+ atomic_read(&instance->fw_outstanding));
+ megasas_dump_pending_frames(instance);
+ megaraid_sas_kill_hba(instance);
- return SUCCESS;
+ return FAILED;
}
/**
@@ -2547,7 +2622,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n",
scmd->cmnd[0], scmd->retries);
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n");
return FAILED;
}
@@ -2575,7 +2650,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
unsigned long flags;
if (time_after(jiffies, scmd->jiffies_at_alloc +
- (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
+ (scmd_timeout * 2) * HZ)) {
return BLK_EH_NOT_HANDLED;
}
@@ -2851,6 +2926,16 @@ megasas_page_size_show(struct device *cdev,
return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
}
+static ssize_t
+megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->ldio_outstanding));
+}
+
static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO,
@@ -2859,12 +2944,15 @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
megasas_fw_crash_state_show, megasas_fw_crash_state_store);
static DEVICE_ATTR(page_size, S_IRUGO,
megasas_page_size_show, NULL);
+static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
+ megasas_ldio_outstanding_show, NULL);
struct device_attribute *megaraid_host_attrs[] = {
&dev_attr_fw_crash_buffer_size,
&dev_attr_fw_crash_buffer,
&dev_attr_fw_crash_state,
&dev_attr_page_size,
+ &dev_attr_ldio_outstanding,
NULL,
};
@@ -2878,6 +2966,7 @@ static struct scsi_host_template megasas_template = {
.proc_name = "megaraid_sas",
.slave_configure = megasas_slave_configure,
.slave_alloc = megasas_slave_alloc,
+ .slave_destroy = megasas_slave_destroy,
.queuecommand = megasas_queue_command,
.eh_device_reset_handler = megasas_reset_device,
.eh_bus_reset_handler = megasas_reset_bus_host,
@@ -3277,13 +3366,13 @@ process_fw_state_change_wq(struct work_struct *work)
u32 wait;
unsigned long flags;
- if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
dev_notice(&instance->pdev->dev, "error, recovery st %x\n",
- instance->adprecovery);
+ atomic_read(&instance->adprecovery));
return ;
}
- if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
dev_notice(&instance->pdev->dev, "FW detected to be in fault"
"state, restarting it...\n");
@@ -3326,7 +3415,7 @@ process_fw_state_change_wq(struct work_struct *work)
megasas_issue_init_mfi(instance);
spin_lock_irqsave(&instance->hba_lock, flags);
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
spin_unlock_irqrestore(&instance->hba_lock, flags);
instance->instancet->enable_intr(instance);
@@ -3391,14 +3480,14 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
instance->instancet->disable_intr(instance);
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
instance->issuepend_done = 0;
atomic_set(&instance->fw_outstanding, 0);
megasas_internal_reset_defer_cmds(instance);
dev_notice(&instance->pdev->dev, "fwState=%x, stage:%d\n",
- fw_state, instance->adprecovery);
+ fw_state, atomic_read(&instance->adprecovery));
schedule_work(&instance->work_init);
return IRQ_HANDLED;
@@ -3852,6 +3941,92 @@ int megasas_alloc_cmds(struct megasas_instance *instance)
}
/*
+ * dcmd_timeout_ocr_possible - Check if OCR is possible based on Driver/FW state.
+ * @instance: Adapter soft state
+ *
+ * Return 0 for only Fusion adapter, if driver load/unload is not in progress
+ * or FW is not under OCR.
+ */
+inline int
+dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
+
+ if (!instance->ctrl_context)
+ return KILL_ADAPTER;
+ else if (instance->unload ||
+ test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags))
+ return IGNORE_TIMEOUT;
+ else
+ return INITIATE_OCR;
+}
+
+static int
+megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
+{
+ int ret;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__);
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ memset(instance->pd_info, 0, sizeof(*instance->pd_info));
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->mbox.s[0] = cpu_to_le16(device_id);
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO));
+ dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO);
+ dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->pd_info_h);
+ dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_PD_INFO));
+
+ if (instance->ctrl_context && !instance->mask_interrupts)
+ ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
+ else
+ ret = megasas_issue_polled(instance, cmd);
+
+ switch (ret) {
+ case DCMD_SUCCESS:
+ instance->pd_list[device_id].interface =
+ instance->pd_info->state.ddf.pdType.intf;
+ break;
+
+ case DCMD_TIMEOUT:
+
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+
+ break;
+ }
+
+ if (ret != DCMD_TIMEOUT)
+ megasas_return_cmd(instance, cmd);
+
+ return ret;
+}
+/*
* megasas_get_pd_list_info - Returns FW's pd_list structure
* @instance: Adapter soft state
* @pd_list: pd_list structure
@@ -3906,42 +4081,72 @@ megasas_get_pd_list(struct megasas_instance *instance)
if (instance->ctrl_context && !instance->mask_interrupts)
ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
- /*
- * the following function will get the instance PD LIST.
- */
+ switch (ret) {
+ case DCMD_FAILED:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case DCMD_TIMEOUT:
+
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ /*
+ * DCMD failed from AEN path.
+ * AEN path already hold reset_mutex to avoid PCI access
+ * while OCR is in progress.
+ */
+ mutex_unlock(&instance->reset_mutex);
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d \n",
+ __func__, __LINE__);
+ break;
+ }
- pd_addr = ci->addr;
+ break;
+
+ case DCMD_SUCCESS:
+ pd_addr = ci->addr;
- if (ret == 0 &&
- (le32_to_cpu(ci->count) <
- (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
+ if ((le32_to_cpu(ci->count) >
+ (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
+ break;
memset(instance->local_pd_list, 0,
- MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
+ MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
for (pd_index = 0; pd_index < le32_to_cpu(ci->count); pd_index++) {
-
instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].tid =
- le16_to_cpu(pd_addr->deviceId);
+ le16_to_cpu(pd_addr->deviceId);
instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveType =
- pd_addr->scsiDevType;
+ pd_addr->scsiDevType;
instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState =
- MR_PD_STATE_SYSTEM;
+ MR_PD_STATE_SYSTEM;
pd_addr++;
}
+
memcpy(instance->pd_list, instance->local_pd_list,
sizeof(instance->pd_list));
+ break;
+
}
pci_free_consistent(instance->pdev,
MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
ci, ci_h);
- megasas_return_cmd(instance, cmd);
+ if (ret != DCMD_TIMEOUT)
+ megasas_return_cmd(instance, cmd);
return ret;
}
@@ -4002,33 +4207,63 @@ megasas_get_ld_list(struct megasas_instance *instance)
if (instance->ctrl_context && !instance->mask_interrupts)
ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
-
ld_count = le32_to_cpu(ci->ldCount);
- /* the following function will get the instance PD LIST */
+ switch (ret) {
+ case DCMD_FAILED:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case DCMD_TIMEOUT:
+
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ /*
+ * DCMD failed from AEN path.
+ * AEN path already hold reset_mutex to avoid PCI access
+ * while OCR is in progress.
+ */
+ mutex_unlock(&instance->reset_mutex);
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+
+ break;
+
+ case DCMD_SUCCESS:
+ if (ld_count > instance->fw_supported_vd_count)
+ break;
- if ((ret == 0) && (ld_count <= instance->fw_supported_vd_count)) {
memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
for (ld_index = 0; ld_index < ld_count; ld_index++) {
if (ci->ldList[ld_index].state != 0) {
ids = ci->ldList[ld_index].ref.targetId;
- instance->ld_ids[ids] =
- ci->ldList[ld_index].ref.targetId;
+ instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
}
}
+
+ break;
}
- pci_free_consistent(instance->pdev,
- sizeof(struct MR_LD_LIST),
- ci,
- ci_h);
+ pci_free_consistent(instance->pdev, sizeof(struct MR_LD_LIST), ci, ci_h);
+
+ if (ret != DCMD_TIMEOUT)
+ megasas_return_cmd(instance, cmd);
- megasas_return_cmd(instance, cmd);
return ret;
}
@@ -4090,26 +4325,61 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
dcmd->pad_0 = 0;
if (instance->ctrl_context && !instance->mask_interrupts)
- ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
- tgtid_count = le32_to_cpu(ci->count);
+ switch (ret) {
+ case DCMD_FAILED:
+ dev_info(&instance->pdev->dev,
+ "DCMD not supported by firmware - %s %d\n",
+ __func__, __LINE__);
+ ret = megasas_get_ld_list(instance);
+ break;
+ case DCMD_TIMEOUT:
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ /*
+ * DCMD failed from AEN path.
+ * AEN path already hold reset_mutex to avoid PCI access
+ * while OCR is in progress.
+ */
+ mutex_unlock(&instance->reset_mutex);
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+
+ break;
+ case DCMD_SUCCESS:
+ tgtid_count = le32_to_cpu(ci->count);
+
+ if ((tgtid_count > (instance->fw_supported_vd_count)))
+ break;
- if ((ret == 0) && (tgtid_count <= (instance->fw_supported_vd_count))) {
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
ids = ci->targetId[ld_index];
instance->ld_ids[ids] = ci->targetId[ld_index];
}
+ break;
}
pci_free_consistent(instance->pdev, sizeof(struct MR_LD_TARGETID_LIST),
- ci, ci_h);
+ ci, ci_h);
- megasas_return_cmd(instance, cmd);
+ if (ret != DCMD_TIMEOUT)
+ megasas_return_cmd(instance, cmd);
return ret;
}
@@ -4223,38 +4493,73 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
dcmd->mbox.b[0] = 1;
if (instance->ctrl_context && !instance->mask_interrupts)
- ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
- if (!ret) {
+ switch (ret) {
+ case DCMD_SUCCESS:
memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
+ /* Save required controller information in
+ * CPU endianness format.
+ */
le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties);
le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
le32_to_cpus((u32 *)&ctrl_info->adapterOperations3);
+
+ /* Update the latest Ext VD info.
+ * From Init path, store current firmware details.
+ * From OCR path, detect any firmware properties changes.
+ * in case of Firmware upgrade without system reboot.
+ */
megasas_update_ext_vd_details(instance);
instance->use_seqnum_jbod_fp =
ctrl_info->adapterOperations3.useSeqNumJbodFP;
+
+ /*Check whether controller is iMR or MR */
instance->is_imr = (ctrl_info->memory_size ? 0 : 1);
dev_info(&instance->pdev->dev,
- "controller type\t: %s(%dMB)\n",
- instance->is_imr ? "iMR" : "MR",
- le16_to_cpu(ctrl_info->memory_size));
+ "controller type\t: %s(%dMB)\n",
+ instance->is_imr ? "iMR" : "MR",
+ le16_to_cpu(ctrl_info->memory_size));
+
instance->disableOnlineCtrlReset =
ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
- dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
- instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
instance->secure_jbod_support =
ctrl_info->adapterOperations3.supportSecurityonJBOD;
+ dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
+ instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n",
instance->secure_jbod_support ? "Yes" : "No");
+ break;
+
+ case DCMD_TIMEOUT:
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+ case DCMD_FAILED:
+ megaraid_sas_kill_hba(instance);
+ break;
+
}
pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
ci, ci_h);
megasas_return_cmd(instance, cmd);
+
+
return ret;
}
@@ -4304,12 +4609,28 @@ int megasas_set_crash_dump_params(struct megasas_instance *instance,
dcmd->sgl.sge32[0].length = cpu_to_le32(CRASH_DMA_BUF_SIZE);
if (instance->ctrl_context && !instance->mask_interrupts)
- ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
- megasas_return_cmd(instance, cmd);
+ if (ret == DCMD_TIMEOUT) {
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+ } else
+ megasas_return_cmd(instance, cmd);
+
return ret;
}
@@ -4426,6 +4747,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance)
sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS));
}
+ instance->cur_can_queue = instance->max_scsi_cmds;
/*
* Create a pool of commands
*/
@@ -4756,6 +5078,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->msix_vectors = ((scratch_pad_2
& MR_MAX_REPLY_QUEUES_EXT_OFFSET)
>> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
+ if (rdpq_enable)
+ instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ?
+ 1 : 0;
fw_msix_count = instance->msix_vectors;
/* Save 1-15 reply post index address to local memory
* Index 0 is already saved from reg offset
@@ -4792,6 +5117,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
dev_info(&instance->pdev->dev,
"current msix/online cpus\t: (%d/%d)\n",
instance->msix_vectors, (unsigned int)num_online_cpus());
+ dev_info(&instance->pdev->dev,
+ "RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : "disabled");
tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
(unsigned long)instance);
@@ -4856,7 +5183,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2);
- instance->mpio = ctrl_info->adapterOperations2.mpio;
+ instance->peerIsPresent = ctrl_info->cluster.peerIsPresent;
+ instance->passive = ctrl_info->cluster.passive;
+ memcpy(instance->clusterId, ctrl_info->clusterId, sizeof(instance->clusterId));
instance->UnevenSpanSupport =
ctrl_info->adapterOperations2.supportUnevenSpans;
if (instance->UnevenSpanSupport) {
@@ -4932,6 +5261,11 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->throttlequeuedepth =
MEGASAS_THROTTLE_QUEUE_DEPTH;
+ if (resetwaittime > MEGASAS_RESET_WAIT_TIME)
+ resetwaittime = MEGASAS_RESET_WAIT_TIME;
+
+ if ((scmd_timeout < 10) || (scmd_timeout > MEGASAS_DEFAULT_CMD_TIMEOUT))
+ scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
/* Launch SR-IOV heartbeat timer */
if (instance->requestorId) {
@@ -5035,10 +5369,8 @@ megasas_get_seq_num(struct megasas_instance *instance,
dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(el_info_h);
dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_log_info));
- if (megasas_issue_blocked_cmd(instance, cmd, 30))
- dev_err(&instance->pdev->dev, "Command timedout"
- "from %s\n", __func__);
- else {
+ if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS) ==
+ DCMD_SUCCESS) {
/*
* Copy the data back into callers buffer
*/
@@ -5047,7 +5379,9 @@ megasas_get_seq_num(struct megasas_instance *instance,
eli->clear_seq_num = el_info->clear_seq_num;
eli->shutdown_seq_num = el_info->shutdown_seq_num;
eli->boot_seq_num = el_info->boot_seq_num;
- }
+ } else
+ dev_err(&instance->pdev->dev, "DCMD failed "
+ "from %s\n", __func__);
pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
el_info, el_info_h);
@@ -5262,6 +5596,8 @@ static int megasas_io_attach(struct megasas_instance *instance)
if (instance->ctrl_context) {
host->hostt->eh_device_reset_handler = NULL;
host->hostt->eh_bus_reset_handler = NULL;
+ host->hostt->eh_target_reset_handler = megasas_reset_target_fusion;
+ host->hostt->eh_abort_handler = megasas_task_abort_fusion;
}
/*
@@ -5447,7 +5783,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
instance->flag_ieee = 0;
instance->ev = NULL;
instance->issuepend_done = 1;
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
instance->is_imr = 0;
instance->evt_detail = pci_alloc_consistent(pdev,
@@ -5461,6 +5797,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
goto fail_alloc_dma_buf;
}
+ instance->pd_info = pci_alloc_consistent(pdev,
+ sizeof(struct MR_PD_INFO), &instance->pd_info_h);
+
+ if (!instance->pd_info)
+ dev_err(&instance->pdev->dev, "Failed to alloc mem for pd_info\n");
+
/*
* Initialize locks and queues
*/
@@ -5476,8 +5818,8 @@ static int megasas_probe_one(struct pci_dev *pdev,
spin_lock_init(&instance->hba_lock);
spin_lock_init(&instance->completion_lock);
- mutex_init(&instance->aen_mutex);
mutex_init(&instance->reset_mutex);
+ mutex_init(&instance->hba_mutex);
/*
* Initialize PCI related and misc parameters
@@ -5592,6 +5934,10 @@ fail_alloc_dma_buf:
instance->evt_detail,
instance->evt_detail_h);
+ if (instance->pd_info)
+ pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+ instance->pd_info,
+ instance->pd_info_h);
if (instance->producer)
pci_free_consistent(pdev, sizeof(u32), instance->producer,
instance->producer_h);
@@ -5616,7 +5962,7 @@ static void megasas_flush_cache(struct megasas_instance *instance)
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return;
cmd = megasas_get_cmd(instance);
@@ -5638,9 +5984,12 @@ static void megasas_flush_cache(struct megasas_instance *instance)
dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH);
dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
- if (megasas_issue_blocked_cmd(instance, cmd, 30))
- dev_err(&instance->pdev->dev, "Command timedout"
- " from %s\n", __func__);
+ if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
+ != DCMD_SUCCESS) {
+ dev_err(&instance->pdev->dev,
+ "return from %s %d\n", __func__, __LINE__);
+ return;
+ }
megasas_return_cmd(instance, cmd);
}
@@ -5656,7 +6005,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return;
cmd = megasas_get_cmd(instance);
@@ -5666,13 +6015,13 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
if (instance->aen_cmd)
megasas_issue_blocked_abort_cmd(instance,
- instance->aen_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+ instance->aen_cmd, MFI_IO_TIMEOUT_SECS);
if (instance->map_update_cmd)
megasas_issue_blocked_abort_cmd(instance,
- instance->map_update_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+ instance->map_update_cmd, MFI_IO_TIMEOUT_SECS);
if (instance->jbod_seq_cmd)
megasas_issue_blocked_abort_cmd(instance,
- instance->jbod_seq_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+ instance->jbod_seq_cmd, MFI_IO_TIMEOUT_SECS);
dcmd = &cmd->frame->dcmd;
@@ -5687,9 +6036,12 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
dcmd->data_xfer_len = 0;
dcmd->opcode = cpu_to_le32(opcode);
- if (megasas_issue_blocked_cmd(instance, cmd, 30))
- dev_err(&instance->pdev->dev, "Command timedout"
- "from %s\n", __func__);
+ if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
+ != DCMD_SUCCESS) {
+ dev_err(&instance->pdev->dev,
+ "return from %s %d\n", __func__, __LINE__);
+ return;
+ }
megasas_return_cmd(instance, cmd);
}
@@ -5847,6 +6199,10 @@ fail_init_mfi:
instance->evt_detail,
instance->evt_detail_h);
+ if (instance->pd_info)
+ pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+ instance->pd_info,
+ instance->pd_info_h);
if (instance->producer)
pci_free_consistent(pdev, sizeof(u32), instance->producer,
instance->producer_h);
@@ -5941,11 +6297,11 @@ static void megasas_detach_one(struct pci_dev *pdev)
if (fusion->ld_drv_map[i])
free_pages((ulong)fusion->ld_drv_map[i],
fusion->drv_map_pages);
- if (fusion->pd_seq_sync)
- dma_free_coherent(&instance->pdev->dev,
- pd_seq_map_sz,
- fusion->pd_seq_sync[i],
- fusion->pd_seq_phys[i]);
+ if (fusion->pd_seq_sync[i])
+ dma_free_coherent(&instance->pdev->dev,
+ pd_seq_map_sz,
+ fusion->pd_seq_sync[i],
+ fusion->pd_seq_phys[i]);
}
free_pages((ulong)instance->ctrl_context,
instance->ctrl_context_pages);
@@ -5965,6 +6321,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
instance->evt_detail, instance->evt_detail_h);
+ if (instance->pd_info)
+ pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+ instance->pd_info,
+ instance->pd_info_h);
if (instance->vf_affiliation)
pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION),
@@ -6090,7 +6450,7 @@ static int megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd)
for (i = 0; i < megasas_mgmt_info.max_index; i++) {
local_instance = megasas_mgmt_info.instance[i];
if (local_instance && local_instance->crash_dump_drv_support) {
- if ((local_instance->adprecovery ==
+ if ((atomic_read(&local_instance->adprecovery) ==
MEGASAS_HBA_OPERATIONAL) &&
!megasas_set_crash_dump_params(local_instance,
crash_support)) {
@@ -6227,7 +6587,15 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* cmd to the SCSI mid-layer
*/
cmd->sync_cmd = 1;
- megasas_issue_blocked_cmd(instance, cmd, 0);
+ if (megasas_issue_blocked_cmd(instance, cmd, 0) == DCMD_NOT_FIRED) {
+ cmd->sync_cmd = 0;
+ dev_err(&instance->pdev->dev,
+ "return -EBUSY from %s %d opcode 0x%x cmd->cmd_status_drv 0x%x\n",
+ __func__, __LINE__, cmd->frame->dcmd.opcode,
+ cmd->cmd_status_drv);
+ return -EBUSY;
+ }
+
cmd->sync_cmd = 0;
if (instance->unload == 1) {
@@ -6330,7 +6698,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
goto out_kfree_ioc;
}
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_err(&instance->pdev->dev, "Controller in crit error\n");
error = -ENODEV;
goto out_kfree_ioc;
@@ -6349,7 +6717,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
for (i = 0; i < wait_time; i++) {
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
break;
}
@@ -6364,7 +6732,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
}
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
dev_err(&instance->pdev->dev, "timed out while"
@@ -6406,7 +6774,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
if (!instance)
return -ENODEV;
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
return -ENODEV;
}
@@ -6417,7 +6785,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
for (i = 0; i < wait_time; i++) {
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
spin_unlock_irqrestore(&instance->hba_lock,
flags);
break;
@@ -6434,7 +6802,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
}
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
dev_err(&instance->pdev->dev, "timed out while waiting"
"for HBA to recover\n");
@@ -6442,10 +6810,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
}
spin_unlock_irqrestore(&instance->hba_lock, flags);
- mutex_lock(&instance->aen_mutex);
+ mutex_lock(&instance->reset_mutex);
error = megasas_register_aen(instance, aen.seq_num,
aen.class_locale_word);
- mutex_unlock(&instance->aen_mutex);
+ mutex_unlock(&instance->reset_mutex);
return error;
}
@@ -6476,9 +6844,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
int i;
int error = 0;
compat_uptr_t ptr;
- unsigned long local_raw_ptr;
u32 local_sense_off;
u32 local_sense_len;
+ u32 user_sense_off;
if (clear_user(ioc, sizeof(*ioc)))
return -EFAULT;
@@ -6496,17 +6864,16 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
* sense_len is not null, so prepare the 64bit value under
* the same condition.
*/
- if (get_user(local_raw_ptr, ioc->frame.raw) ||
- get_user(local_sense_off, &ioc->sense_off) ||
- get_user(local_sense_len, &ioc->sense_len))
+ if (get_user(local_sense_off, &ioc->sense_off) ||
+ get_user(local_sense_len, &ioc->sense_len) ||
+ get_user(user_sense_off, &cioc->sense_off))
return -EFAULT;
-
if (local_sense_len) {
void __user **sense_ioc_ptr =
- (void __user **)((u8*)local_raw_ptr + local_sense_off);
+ (void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off);
compat_uptr_t *sense_cioc_ptr =
- (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
+ (compat_uptr_t *)(((unsigned long)&cioc->frame.raw) + user_sense_off);
if (get_user(ptr, sense_cioc_ptr) ||
put_user(compat_ptr(ptr), sense_ioc_ptr))
return -EFAULT;
@@ -6647,6 +7014,7 @@ megasas_aen_polling(struct work_struct *work)
int i, j, doscan = 0;
u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
int error;
+ u8 dcmd_ret = DCMD_SUCCESS;
if (!instance) {
printk(KERN_ERR "invalid instance!\n");
@@ -6659,16 +7027,7 @@ megasas_aen_polling(struct work_struct *work)
wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
/* Don't run the event workqueue thread if OCR is running */
- for (i = 0; i < wait_time; i++) {
- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)
- break;
- if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
- dev_notice(&instance->pdev->dev, "%s waiting for "
- "controller reset to finish for scsi%d\n",
- __func__, instance->host->host_no);
- }
- msleep(1000);
- }
+ mutex_lock(&instance->reset_mutex);
instance->ev = NULL;
host = instance->host;
@@ -6676,212 +7035,127 @@ megasas_aen_polling(struct work_struct *work)
megasas_decode_evt(instance);
switch (le32_to_cpu(instance->evt_detail->code)) {
- case MR_EVT_PD_INSERTED:
- if (megasas_get_pd_list(instance) == 0) {
- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
-
- pd_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host, i, j, 0);
-
- if (instance->pd_list[pd_index].driveState
- == MR_PD_STATE_SYSTEM) {
- if (!sdev1)
- scsi_add_device(host, i, j, 0);
-
- if (sdev1)
- scsi_device_put(sdev1);
- }
- }
- }
- }
- doscan = 0;
- break;
+ case MR_EVT_PD_INSERTED:
case MR_EVT_PD_REMOVED:
- if (megasas_get_pd_list(instance) == 0) {
- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
-
- pd_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host, i, j, 0);
-
- if (instance->pd_list[pd_index].driveState
- == MR_PD_STATE_SYSTEM) {
- if (sdev1)
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
- }
- }
- }
- }
- }
- doscan = 0;
+ dcmd_ret = megasas_get_pd_list(instance);
+ if (dcmd_ret == DCMD_SUCCESS)
+ doscan = SCAN_PD_CHANNEL;
break;
case MR_EVT_LD_OFFLINE:
case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
- if (!instance->requestorId ||
- megasas_get_ld_vf_affiliation(instance, 0)) {
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
-
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
- if (instance->ld_ids[ld_index]
- != 0xff) {
- if (sdev1)
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
- }
- }
- }
- }
- doscan = 0;
- }
- break;
case MR_EVT_LD_CREATED:
if (!instance->requestorId ||
- megasas_get_ld_vf_affiliation(instance, 0)) {
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
- if (instance->ld_ids[ld_index]
- != 0xff) {
- if (!sdev1)
- scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
- }
- if (sdev1)
- scsi_device_put(sdev1);
- }
- }
- doscan = 0;
- }
+ (instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+ dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+ if (dcmd_ret == DCMD_SUCCESS)
+ doscan = SCAN_VD_CHANNEL;
+
break;
+
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
case MR_EVT_FOREIGN_CFG_IMPORTED:
case MR_EVT_LD_STATE_CHANGE:
- doscan = 1;
+ dcmd_ret = megasas_get_pd_list(instance);
+
+ if (dcmd_ret != DCMD_SUCCESS)
+ break;
+
+ if (!instance->requestorId ||
+ (instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+ dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+ if (dcmd_ret != DCMD_SUCCESS)
+ break;
+
+ doscan = SCAN_VD_CHANNEL | SCAN_PD_CHANNEL;
+ dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
+ instance->host->host_no);
break;
+
case MR_EVT_CTRL_PROP_CHANGED:
- megasas_get_ctrl_info(instance);
- break;
+ dcmd_ret = megasas_get_ctrl_info(instance);
+ break;
default:
doscan = 0;
break;
}
} else {
dev_err(&instance->pdev->dev, "invalid evt_detail!\n");
+ mutex_unlock(&instance->reset_mutex);
kfree(ev);
return;
}
- if (doscan) {
- dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
- instance->host->host_no);
- if (megasas_get_pd_list(instance) == 0) {
- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
- pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
- sdev1 = scsi_device_lookup(host, i, j, 0);
- if (instance->pd_list[pd_index].driveState ==
- MR_PD_STATE_SYSTEM) {
- if (!sdev1) {
- scsi_add_device(host, i, j, 0);
- }
- if (sdev1)
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
- }
+ mutex_unlock(&instance->reset_mutex);
+
+ if (doscan & SCAN_PD_CHANNEL) {
+ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+ pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+ sdev1 = scsi_device_lookup(host, i, j, 0);
+ if (instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) {
+ if (!sdev1)
+ scsi_add_device(host, i, j, 0);
+ else
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
}
}
}
}
+ }
- if (!instance->requestorId ||
- megasas_get_ld_vf_affiliation(instance, 0)) {
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host,
- MEGASAS_MAX_PD_CHANNELS + i, j, 0);
- if (instance->ld_ids[ld_index]
- != 0xff) {
- if (!sdev1)
- scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
- else
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
- }
+ if (doscan & SCAN_VD_CHANNEL) {
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+ ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+ sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+ if (instance->ld_ids[ld_index] != 0xff) {
+ if (!sdev1)
+ scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+ else
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
}
}
}
}
}
- if (instance->aen_cmd != NULL) {
- kfree(ev);
- return ;
- }
-
- seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+ if (dcmd_ret == DCMD_SUCCESS)
+ seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+ else
+ seq_num = instance->last_seq_num;
/* Register AEN with FW for latest sequence number plus 1 */
class_locale.members.reserved = 0;
class_locale.members.locale = MR_EVT_LOCALE_ALL;
class_locale.members.class = MR_EVT_CLASS_DEBUG;
- mutex_lock(&instance->aen_mutex);
+
+ if (instance->aen_cmd != NULL) {
+ kfree(ev);
+ return;
+ }
+
+ mutex_lock(&instance->reset_mutex);
error = megasas_register_aen(instance, seq_num,
class_locale.word);
- mutex_unlock(&instance->aen_mutex);
-
if (error)
- dev_err(&instance->pdev->dev, "register aen failed error %x\n", error);
+ dev_err(&instance->pdev->dev,
+ "register aen failed error %x\n", error);
+ mutex_unlock(&instance->reset_mutex);
kfree(ev);
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 741509b35617..e413113c86ac 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -1020,6 +1020,8 @@ MR_BuildRaidContext(struct megasas_instance *instance,
/* assume this IO needs the full row - we'll adjust if not true */
regSize = stripSize;
+ io_info->do_fp_rlbypass = raid->capability.fpBypassRegionLock;
+
/* Check if we can send this I/O via FastPath */
if (raid->capability.fpCapable) {
if (isRead)
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 8d630a552b07..98a848bdfdc2 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -91,7 +91,10 @@ void megasas_start_timer(struct megasas_instance *instance,
struct timer_list *timer,
void *fn, unsigned long interval);
extern struct megasas_mgmt_info megasas_mgmt_info;
-extern int resetwaittime;
+extern unsigned int resetwaittime;
+extern unsigned int dual_qdepth_disable;
+static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
+static void megasas_free_reply_fusion(struct megasas_instance *instance);
@@ -201,58 +204,72 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
&instance->reg_set->inbound_low_queue_port);
writel(le32_to_cpu(req_desc->u.high),
&instance->reg_set->inbound_high_queue_port);
+ mmiowb();
spin_unlock_irqrestore(&instance->hba_lock, flags);
#endif
}
-
/**
- * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool
- * @instance: Adapter soft state
+ * megasas_fusion_update_can_queue - Do all Adapter Queue depth related calculations here
+ * @instance: Adapter soft state
+ * fw_boot_context: Whether this function called during probe or after OCR
+ *
+ * This function is only for fusion controllers.
+ * Update host can queue, if firmware downgrade max supported firmware commands.
+ * Firmware upgrade case will be skiped because underlying firmware has
+ * more resource than exposed to the OS.
+ *
*/
-static void megasas_teardown_frame_pool_fusion(
- struct megasas_instance *instance)
+static void
+megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_context)
{
- int i;
- struct fusion_context *fusion = instance->ctrl_context;
-
- u16 max_cmd = instance->max_fw_cmds;
+ u16 cur_max_fw_cmds = 0;
+ u16 ldio_threshold = 0;
+ struct megasas_register_set __iomem *reg_set;
- struct megasas_cmd_fusion *cmd;
+ reg_set = instance->reg_set;
- if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
- dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, "
- "sense pool : %p\n", fusion->sg_dma_pool,
- fusion->sense_dma_pool);
- return;
- }
+ cur_max_fw_cmds = readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF;
- /*
- * Return all frames to pool
- */
- for (i = 0; i < max_cmd; i++) {
+ if (dual_qdepth_disable || !cur_max_fw_cmds)
+ cur_max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+ else
+ ldio_threshold =
+ (instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF) - MEGASAS_FUSION_IOCTL_CMDS;
+
+ dev_info(&instance->pdev->dev,
+ "Current firmware maximum commands: %d\t LDIO threshold: %d\n",
+ cur_max_fw_cmds, ldio_threshold);
+
+ if (fw_boot_context == OCR_CONTEXT) {
+ cur_max_fw_cmds = cur_max_fw_cmds - 1;
+ if (cur_max_fw_cmds <= instance->max_fw_cmds) {
+ instance->cur_can_queue =
+ cur_max_fw_cmds - (MEGASAS_FUSION_INTERNAL_CMDS +
+ MEGASAS_FUSION_IOCTL_CMDS);
+ instance->host->can_queue = instance->cur_can_queue;
+ instance->ldio_threshold = ldio_threshold;
+ }
+ } else {
+ instance->max_fw_cmds = cur_max_fw_cmds;
+ instance->ldio_threshold = ldio_threshold;
- cmd = fusion->cmd_list[i];
+ if (!instance->is_rdpq)
+ instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
- if (cmd->sg_frame)
- pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
- cmd->sg_frame_phys_addr);
+ /*
+ * Reduce the max supported cmds by 1. This is to ensure that the
+ * reply_q_sz (1 more than the max cmd that driver may send)
+ * does not exceed max cmds that the FW can support
+ */
+ instance->max_fw_cmds = instance->max_fw_cmds-1;
- if (cmd->sense)
- pci_pool_free(fusion->sense_dma_pool, cmd->sense,
- cmd->sense_phys_addr);
+ instance->max_scsi_cmds = instance->max_fw_cmds -
+ (MEGASAS_FUSION_INTERNAL_CMDS +
+ MEGASAS_FUSION_IOCTL_CMDS);
+ instance->cur_can_queue = instance->max_scsi_cmds;
}
-
- /*
- * Now destroy the pool itself
- */
- pci_pool_destroy(fusion->sg_dma_pool);
- pci_pool_destroy(fusion->sense_dma_pool);
-
- fusion->sg_dma_pool = NULL;
- fusion->sense_dma_pool = NULL;
}
-
/**
* megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
* @instance: Adapter soft state
@@ -262,55 +279,65 @@ megasas_free_cmds_fusion(struct megasas_instance *instance)
{
int i;
struct fusion_context *fusion = instance->ctrl_context;
+ struct megasas_cmd_fusion *cmd;
- u32 max_cmds, req_sz, reply_sz, io_frames_sz;
+ /* SG, Sense */
+ for (i = 0; i < instance->max_fw_cmds; i++) {
+ cmd = fusion->cmd_list[i];
+ if (cmd) {
+ if (cmd->sg_frame)
+ pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
+ cmd->sg_frame_phys_addr);
+ if (cmd->sense)
+ pci_pool_free(fusion->sense_dma_pool, cmd->sense,
+ cmd->sense_phys_addr);
+ }
+ }
+ if (fusion->sg_dma_pool) {
+ pci_pool_destroy(fusion->sg_dma_pool);
+ fusion->sg_dma_pool = NULL;
+ }
+ if (fusion->sense_dma_pool) {
+ pci_pool_destroy(fusion->sense_dma_pool);
+ fusion->sense_dma_pool = NULL;
+ }
- req_sz = fusion->request_alloc_sz;
- reply_sz = fusion->reply_alloc_sz;
- io_frames_sz = fusion->io_frames_alloc_sz;
- max_cmds = instance->max_fw_cmds;
+ /* Reply Frame, Desc*/
+ if (instance->is_rdpq)
+ megasas_free_rdpq_fusion(instance);
+ else
+ megasas_free_reply_fusion(instance);
- /* Free descriptors and request Frames memory */
+ /* Request Frame, Desc*/
if (fusion->req_frames_desc)
- dma_free_coherent(&instance->pdev->dev, req_sz,
- fusion->req_frames_desc,
- fusion->req_frames_desc_phys);
-
- if (fusion->reply_frames_desc) {
- pci_pool_free(fusion->reply_frames_desc_pool,
- fusion->reply_frames_desc,
- fusion->reply_frames_desc_phys);
- pci_pool_destroy(fusion->reply_frames_desc_pool);
- }
-
- if (fusion->io_request_frames) {
+ dma_free_coherent(&instance->pdev->dev,
+ fusion->request_alloc_sz, fusion->req_frames_desc,
+ fusion->req_frames_desc_phys);
+ if (fusion->io_request_frames)
pci_pool_free(fusion->io_request_frames_pool,
- fusion->io_request_frames,
- fusion->io_request_frames_phys);
+ fusion->io_request_frames,
+ fusion->io_request_frames_phys);
+ if (fusion->io_request_frames_pool) {
pci_pool_destroy(fusion->io_request_frames_pool);
+ fusion->io_request_frames_pool = NULL;
}
- /* Free the Fusion frame pool */
- megasas_teardown_frame_pool_fusion(instance);
- /* Free all the commands in the cmd_list */
- for (i = 0; i < max_cmds; i++)
+ /* cmd_list */
+ for (i = 0; i < instance->max_fw_cmds; i++)
kfree(fusion->cmd_list[i]);
- /* Free the cmd_list buffer itself */
kfree(fusion->cmd_list);
- fusion->cmd_list = NULL;
-
}
/**
- * megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames
+ * megasas_create_sg_sense_fusion - Creates DMA pool for cmd frames
* @instance: Adapter soft state
*
*/
-static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
+static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
{
int i;
u32 max_cmd;
@@ -321,25 +348,17 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
max_cmd = instance->max_fw_cmds;
- /*
- * Use DMA pool facility provided by PCI layer
- */
-
- fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev,
- instance->max_chain_frame_sz,
- 4, 0);
- if (!fusion->sg_dma_pool) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n");
- return -ENOMEM;
- }
- fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
- instance->pdev,
- SCSI_SENSE_BUFFERSIZE, 64, 0);
+ fusion->sg_dma_pool =
+ pci_pool_create("mr_sg", instance->pdev,
+ instance->max_chain_frame_sz, 4, 0);
+ /* SCSI_SENSE_BUFFERSIZE = 96 bytes */
+ fusion->sense_dma_pool =
+ pci_pool_create("mr_sense", instance->pdev,
+ SCSI_SENSE_BUFFERSIZE, 64, 0);
- if (!fusion->sense_dma_pool) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n");
- pci_pool_destroy(fusion->sg_dma_pool);
- fusion->sg_dma_pool = NULL;
+ if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
@@ -347,160 +366,280 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
* Allocate and attach a frame to each of the commands in cmd_list
*/
for (i = 0; i < max_cmd; i++) {
-
cmd = fusion->cmd_list[i];
-
cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
- GFP_KERNEL,
- &cmd->sg_frame_phys_addr);
+ GFP_KERNEL, &cmd->sg_frame_phys_addr);
cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
- GFP_KERNEL, &cmd->sense_phys_addr);
- /*
- * megasas_teardown_frame_pool_fusion() takes care of freeing
- * whatever has been allocated
- */
+ GFP_KERNEL, &cmd->sense_phys_addr);
if (!cmd->sg_frame || !cmd->sense) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n");
- megasas_teardown_frame_pool_fusion(instance);
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
}
return 0;
}
-/**
- * megasas_alloc_cmds_fusion - Allocates the command packets
- * @instance: Adapter soft state
- *
- *
- * Each frame has a 32-bit field called context. This context is used to get
- * back the megasas_cmd_fusion from the frame when a frame gets completed
- * In this driver, the 32 bit values are the indices into an array cmd_list.
- * This array is used only to look up the megasas_cmd_fusion given the context.
- * The free commands themselves are maintained in a linked list called cmd_pool.
- *
- * cmds are formed in the io_request and sg_frame members of the
- * megasas_cmd_fusion. The context field is used to get a request descriptor
- * and is used as SMID of the cmd.
- * SMID value range is from 1 to max_fw_cmds.
- */
int
-megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
{
- int i, j, count;
- u32 max_cmd, io_frames_sz;
+ u32 max_cmd, i;
struct fusion_context *fusion;
- struct megasas_cmd_fusion *cmd;
- union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
- u32 offset;
- dma_addr_t io_req_base_phys;
- u8 *io_req_base;
fusion = instance->ctrl_context;
max_cmd = instance->max_fw_cmds;
+ /*
+ * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
+ * Allocate the dynamic array first and then allocate individual
+ * commands.
+ */
+ fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
+ GFP_KERNEL);
+ if (!fusion->cmd_list) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < max_cmd; i++) {
+ fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion),
+ GFP_KERNEL);
+ if (!fusion->cmd_list[i]) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+int
+megasas_alloc_request_fusion(struct megasas_instance *instance)
+{
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
fusion->req_frames_desc =
dma_alloc_coherent(&instance->pdev->dev,
- fusion->request_alloc_sz,
- &fusion->req_frames_desc_phys, GFP_KERNEL);
-
+ fusion->request_alloc_sz,
+ &fusion->req_frames_desc_phys, GFP_KERNEL);
if (!fusion->req_frames_desc) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "request_frames\n");
- goto fail_req_desc;
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
+ fusion->io_request_frames_pool =
+ pci_pool_create("mr_ioreq", instance->pdev,
+ fusion->io_frames_alloc_sz, 16, 0);
+
+ if (!fusion->io_request_frames_pool) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ fusion->io_request_frames =
+ pci_pool_alloc(fusion->io_request_frames_pool,
+ GFP_KERNEL, &fusion->io_request_frames_phys);
+ if (!fusion->io_request_frames) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int
+megasas_alloc_reply_fusion(struct megasas_instance *instance)
+{
+ int i, count;
+ struct fusion_context *fusion;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+ fusion = instance->ctrl_context;
+
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
fusion->reply_frames_desc_pool =
- pci_pool_create("reply_frames pool", instance->pdev,
+ pci_pool_create("mr_reply", instance->pdev,
fusion->reply_alloc_sz * count, 16, 0);
if (!fusion->reply_frames_desc_pool) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "reply_frame pool\n");
- goto fail_reply_desc;
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
- fusion->reply_frames_desc =
- pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
- &fusion->reply_frames_desc_phys);
- if (!fusion->reply_frames_desc) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "reply_frame pool\n");
- pci_pool_destroy(fusion->reply_frames_desc_pool);
- goto fail_reply_desc;
+ fusion->reply_frames_desc[0] =
+ pci_pool_alloc(fusion->reply_frames_desc_pool,
+ GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
+ if (!fusion->reply_frames_desc[0]) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
-
- reply_desc = fusion->reply_frames_desc;
+ reply_desc = fusion->reply_frames_desc[0];
for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
reply_desc->Words = cpu_to_le64(ULLONG_MAX);
- io_frames_sz = fusion->io_frames_alloc_sz;
+ /* This is not a rdpq mode, but driver still populate
+ * reply_frame_desc array to use same msix index in ISR path.
+ */
+ for (i = 0; i < (count - 1); i++)
+ fusion->reply_frames_desc[i + 1] =
+ fusion->reply_frames_desc[i] +
+ (fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION);
+
+ return 0;
+}
- fusion->io_request_frames_pool =
- pci_pool_create("io_request_frames pool", instance->pdev,
- fusion->io_frames_alloc_sz, 16, 0);
+int
+megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
+{
+ int i, j, count;
+ struct fusion_context *fusion;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
- if (!fusion->io_request_frames_pool) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "io_request_frame pool\n");
- goto fail_io_frames;
+ fusion = instance->ctrl_context;
+
+ fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
+ sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+ &fusion->rdpq_phys);
+ if (!fusion->rdpq_virt) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
- fusion->io_request_frames =
- pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
- &fusion->io_request_frames_phys);
- if (!fusion->io_request_frames) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "io_request_frames frames\n");
- pci_pool_destroy(fusion->io_request_frames_pool);
- goto fail_io_frames;
+ memset(fusion->rdpq_virt, 0,
+ sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION);
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+ fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
+ instance->pdev, fusion->reply_alloc_sz, 16, 0);
+
+ if (!fusion->reply_frames_desc_pool) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
- /*
- * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
- * Allocate the dynamic array first and then allocate individual
- * commands.
- */
- fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *)
- * max_cmd, GFP_KERNEL);
+ for (i = 0; i < count; i++) {
+ fusion->reply_frames_desc[i] =
+ pci_pool_alloc(fusion->reply_frames_desc_pool,
+ GFP_KERNEL, &fusion->reply_frames_desc_phys[i]);
+ if (!fusion->reply_frames_desc[i]) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
- if (!fusion->cmd_list) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc "
- "memory for cmd_list_fusion\n");
- goto fail_cmd_list;
+ fusion->rdpq_virt[i].RDPQBaseAddress =
+ fusion->reply_frames_desc_phys[i];
+
+ reply_desc = fusion->reply_frames_desc[i];
+ for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
+ reply_desc->Words = cpu_to_le64(ULLONG_MAX);
}
+ return 0;
+}
- max_cmd = instance->max_fw_cmds;
- for (i = 0; i < max_cmd; i++) {
- fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
- GFP_KERNEL);
- if (!fusion->cmd_list[i]) {
- dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n");
+static void
+megasas_free_rdpq_fusion(struct megasas_instance *instance) {
- for (j = 0; j < i; j++)
- kfree(fusion->cmd_list[j]);
+ int i;
+ struct fusion_context *fusion;
- kfree(fusion->cmd_list);
- fusion->cmd_list = NULL;
- goto fail_cmd_list;
- }
+ fusion = instance->ctrl_context;
+
+ for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
+ if (fusion->reply_frames_desc[i])
+ pci_pool_free(fusion->reply_frames_desc_pool,
+ fusion->reply_frames_desc[i],
+ fusion->reply_frames_desc_phys[i]);
}
- /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
- io_req_base = fusion->io_request_frames +
- MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
- io_req_base_phys = fusion->io_request_frames_phys +
- MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+ if (fusion->reply_frames_desc_pool)
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+ if (fusion->rdpq_virt)
+ pci_free_consistent(instance->pdev,
+ sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+ fusion->rdpq_virt, fusion->rdpq_phys);
+}
+
+static void
+megasas_free_reply_fusion(struct megasas_instance *instance) {
+
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ if (fusion->reply_frames_desc[0])
+ pci_pool_free(fusion->reply_frames_desc_pool,
+ fusion->reply_frames_desc[0],
+ fusion->reply_frames_desc_phys[0]);
+
+ if (fusion->reply_frames_desc_pool)
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+}
+
+
+/**
+ * megasas_alloc_cmds_fusion - Allocates the command packets
+ * @instance: Adapter soft state
+ *
+ *
+ * Each frame has a 32-bit field called context. This context is used to get
+ * back the megasas_cmd_fusion from the frame when a frame gets completed
+ * In this driver, the 32 bit values are the indices into an array cmd_list.
+ * This array is used only to look up the megasas_cmd_fusion given the context.
+ * The free commands themselves are maintained in a linked list called cmd_pool.
+ *
+ * cmds are formed in the io_request and sg_frame members of the
+ * megasas_cmd_fusion. The context field is used to get a request descriptor
+ * and is used as SMID of the cmd.
+ * SMID value range is from 1 to max_fw_cmds.
+ */
+int
+megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *cmd;
+ u32 offset;
+ dma_addr_t io_req_base_phys;
+ u8 *io_req_base;
+
+
+ fusion = instance->ctrl_context;
+
+ if (megasas_alloc_cmdlist_fusion(instance))
+ goto fail_exit;
+
+ if (megasas_alloc_request_fusion(instance))
+ goto fail_exit;
+
+ if (instance->is_rdpq) {
+ if (megasas_alloc_rdpq_fusion(instance))
+ goto fail_exit;
+ } else
+ if (megasas_alloc_reply_fusion(instance))
+ goto fail_exit;
+
+
+ /* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
+ io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+ io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
/*
* Add all the commands to command pool (fusion->cmd_pool)
*/
/* SMID 0 is reserved. Set SMID/index from 1 */
- for (i = 0; i < max_cmd; i++) {
+ for (i = 0; i < instance->max_fw_cmds; i++) {
cmd = fusion->cmd_list[i];
offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
@@ -518,35 +657,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
cmd->io_request_phys_addr = io_req_base_phys + offset;
}
- /*
- * Create a frame pool and assign one frame to each cmd
- */
- if (megasas_create_frame_pool_fusion(instance)) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
- megasas_free_cmds_fusion(instance);
- goto fail_req_desc;
- }
+ if (megasas_create_sg_sense_fusion(instance))
+ goto fail_exit;
return 0;
-fail_cmd_list:
- pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
- fusion->io_request_frames_phys);
- pci_pool_destroy(fusion->io_request_frames_pool);
-fail_io_frames:
- dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
- fusion->reply_frames_desc,
- fusion->reply_frames_desc_phys);
- pci_pool_free(fusion->reply_frames_desc_pool,
- fusion->reply_frames_desc,
- fusion->reply_frames_desc_phys);
- pci_pool_destroy(fusion->reply_frames_desc_pool);
-
-fail_reply_desc:
- dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
- fusion->req_frames_desc,
- fusion->req_frames_desc_phys);
-fail_req_desc:
+fail_exit:
+ megasas_free_cmds_fusion(instance);
return -ENOMEM;
}
@@ -576,11 +693,12 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
msleep(20);
}
- if (frame_hdr->cmd_status == 0xff)
- return -ETIME;
-
- return (frame_hdr->cmd_status == MFI_STAT_OK) ?
- 0 : 1;
+ if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS)
+ return DCMD_TIMEOUT;
+ else if (frame_hdr->cmd_status == MFI_STAT_OK)
+ return DCMD_SUCCESS;
+ else
+ return DCMD_FAILED;
}
/**
@@ -593,16 +711,17 @@ int
megasas_ioc_init_fusion(struct megasas_instance *instance)
{
struct megasas_init_frame *init_frame;
- struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
+ struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
dma_addr_t ioc_init_handle;
struct megasas_cmd *cmd;
- u8 ret;
+ u8 ret, cur_rdpq_mode;
struct fusion_context *fusion;
union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
int i;
struct megasas_header *frame_hdr;
const char *sys_info;
MFI_CAPABILITIES *drv_ops;
+ u32 scratch_pad_2;
fusion = instance->ctrl_context;
@@ -614,6 +733,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
goto fail_get_cmd;
}
+ scratch_pad_2 = readl
+ (&instance->reg_set->outbound_scratch_pad_2);
+
+ cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
+
+ if (instance->is_rdpq && !cur_rdpq_mode) {
+ dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*"
+ " from RDPQ mode to non RDPQ mode\n");
+ ret = 1;
+ goto fail_fw_init;
+ }
+
IOCInitMessage =
dma_alloc_coherent(&instance->pdev->dev,
sizeof(struct MPI2_IOC_INIT_REQUEST),
@@ -635,7 +766,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
- IOCInitMessage->ReplyDescriptorPostQueueAddress = cpu_to_le64(fusion->reply_frames_desc_phys);
+ IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ?
+ cpu_to_le64(fusion->rdpq_phys) :
+ cpu_to_le64(fusion->reply_frames_desc_phys[0]);
+ IOCInitMessage->MsgFlags = instance->is_rdpq ?
+ MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
init_frame = (struct megasas_init_frame *)cmd->frame;
@@ -665,6 +800,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN)
drv_ops->mfi_capabilities.support_ext_io_size = 1;
+ drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
+ if (!dual_qdepth_disable)
+ drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
+
+ drv_ops->mfi_capabilities.support_qd_throttling = 1;
/* Convert capability to LE32 */
cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
@@ -784,7 +924,8 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
/* Below code is only for non pended DCMD */
if (instance->ctrl_context && !instance->mask_interrupts)
- ret = megasas_issue_blocked_cmd(instance, cmd, 60);
+ ret = megasas_issue_blocked_cmd(instance, cmd,
+ MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
@@ -795,7 +936,10 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
ret = -EINVAL;
}
- if (!ret)
+ if (ret == DCMD_TIMEOUT && instance->ctrl_context)
+ megaraid_sas_kill_hba(instance);
+
+ if (ret == DCMD_SUCCESS)
instance->pd_seq_map_id++;
megasas_return_cmd(instance, cmd);
@@ -875,10 +1019,13 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
if (instance->ctrl_context && !instance->mask_interrupts)
ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
+ if (ret == DCMD_TIMEOUT && instance->ctrl_context)
+ megaraid_sas_kill_hba(instance);
+
megasas_return_cmd(instance, cmd);
return ret;
@@ -1072,12 +1219,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
reg_set = instance->reg_set;
- /*
- * Get various operational parameters from status register
- */
- instance->max_fw_cmds =
- instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
- instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
+ megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
/*
* Reduce the max supported cmds by 1. This is to ensure that the
@@ -1658,7 +1800,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
local_map_ptr, start_lba_lo);
io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
cmd->request_desc->SCSIIO.RequestFlags =
- (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
+ (MPI2_REQ_DESCRIPT_FLAGS_FP_IO
<< MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
if (fusion->adapter_type == INVADER_SERIES) {
if (io_request->RaidContext.regLockFlags ==
@@ -1702,8 +1844,8 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
(MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
<< MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
if (fusion->adapter_type == INVADER_SERIES) {
- if (io_request->RaidContext.regLockFlags ==
- REGION_TYPE_UNUSED)
+ if (io_info.do_fp_rlbypass ||
+ (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED))
cmd->request_desc->SCSIIO.RequestFlags =
(MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
@@ -1791,7 +1933,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
/* build request descriptor */
cmd->request_desc->SCSIIO.RequestFlags =
- (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+ (MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
cmd->request_desc->SCSIIO.DevHandle = devHandle;
@@ -1897,7 +2039,7 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
}
cmd->request_desc->SCSIIO.RequestFlags =
- (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+ (MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
}
}
@@ -2035,13 +2177,21 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
fusion = instance->ctrl_context;
+ if ((megasas_cmd_type(scmd) == READ_WRITE_LDIO) &&
+ instance->ldio_threshold &&
+ (atomic_inc_return(&instance->ldio_outstanding) >
+ instance->ldio_threshold)) {
+ atomic_dec(&instance->ldio_outstanding);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+
cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
index = cmd->index;
req_desc = megasas_get_request_descriptor(instance, index-1);
if (!req_desc)
- return 1;
+ return SCSI_MLQUEUE_HOST_BUSY;
req_desc->Words = 0;
cmd->request_desc = req_desc;
@@ -2050,7 +2200,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
megasas_return_cmd_fusion(instance, cmd);
dev_err(&instance->pdev->dev, "Error building command\n");
cmd->request_desc = NULL;
- return 1;
+ return SCSI_MLQUEUE_HOST_BUSY;
}
req_desc = cmd->request_desc;
@@ -2092,16 +2242,16 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
struct LD_LOAD_BALANCE_INFO *lbinfo;
int threshold_reply_count = 0;
struct scsi_cmnd *scmd_local = NULL;
+ struct MR_TASK_MANAGE_REQUEST *mr_tm_req;
+ struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req;
fusion = instance->ctrl_context;
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return IRQ_HANDLED;
- desc = fusion->reply_frames_desc;
- desc += ((MSIxIndex * fusion->reply_alloc_sz)/
- sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
- fusion->last_reply_idx[MSIxIndex];
+ desc = fusion->reply_frames_desc[MSIxIndex] +
+ fusion->last_reply_idx[MSIxIndex];
reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
@@ -2133,6 +2283,16 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
extStatus = scsi_io_req->RaidContext.exStatus;
switch (scsi_io_req->Function) {
+ case MPI2_FUNCTION_SCSI_TASK_MGMT:
+ mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *)
+ cmd_fusion->io_request;
+ mpi_tm_req = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *)
+ &mr_tm_req->TmRequest;
+ dev_dbg(&instance->pdev->dev, "TM completion:"
+ "type: 0x%x TaskMID: 0x%x\n",
+ mpi_tm_req->TaskType, mpi_tm_req->TaskMID);
+ complete(&cmd_fusion->done);
+ break;
case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/
/* Update load balancing info */
device_id = MEGASAS_DEV_INDEX(scmd_local);
@@ -2155,6 +2315,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
map_cmd_status(cmd_fusion, status, extStatus);
scsi_io_req->RaidContext.status = 0;
scsi_io_req->RaidContext.exStatus = 0;
+ if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+ atomic_dec(&instance->ldio_outstanding);
megasas_return_cmd_fusion(instance, cmd_fusion);
scsi_dma_unmap(scmd_local);
scmd_local->scsi_done(scmd_local);
@@ -2186,9 +2348,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
/* Get the next reply descriptor */
if (!fusion->last_reply_idx[MSIxIndex])
- desc = fusion->reply_frames_desc +
- ((MSIxIndex * fusion->reply_alloc_sz)/
- sizeof(union MPI2_REPLY_DESCRIPTORS_UNION));
+ desc = fusion->reply_frames_desc[MSIxIndex];
else
desc++;
@@ -2254,7 +2414,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
/* If we have already declared adapter dead, donot complete cmds */
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
return;
}
@@ -2411,7 +2571,7 @@ build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
* @cmd: mfi cmd pointer
*
*/
-void
+int
megasas_issue_dcmd_fusion(struct megasas_instance *instance,
struct megasas_cmd *cmd)
{
@@ -2419,10 +2579,13 @@ megasas_issue_dcmd_fusion(struct megasas_instance *instance,
req_desc = build_mpt_cmd(instance, cmd);
if (!req_desc) {
- dev_err(&instance->pdev->dev, "Couldn't issue MFI pass thru cmd\n");
- return;
+ dev_info(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return DCMD_NOT_FIRED;
}
+
megasas_fire_cmd_fusion(instance, req_desc);
+ return DCMD_SUCCESS;
}
/**
@@ -2583,7 +2746,7 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
/* This function waits for outstanding commands on fusion to complete */
int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
- int iotimeout, int *convert)
+ int reason, int *convert)
{
int i, outstanding, retval = 0, hb_seconds_missed = 0;
u32 fw_state;
@@ -2599,14 +2762,22 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
retval = 1;
goto out;
}
+
+ if (reason == MFI_IO_TIMEOUT_OCR) {
+ dev_info(&instance->pdev->dev,
+ "MFI IO is timed out, initiating OCR\n");
+ retval = 1;
+ goto out;
+ }
+
/* If SR-IOV VF mode & heartbeat timeout, don't wait */
- if (instance->requestorId && !iotimeout) {
+ if (instance->requestorId && !reason) {
retval = 1;
goto out;
}
/* If SR-IOV VF mode & I/O timeout, check for HB timeout */
- if (instance->requestorId && iotimeout) {
+ if (instance->requestorId && reason) {
if (instance->hb_host_mem->HB.fwCounter !=
instance->hb_host_mem->HB.driverCounter) {
instance->hb_host_mem->HB.driverCounter =
@@ -2655,17 +2826,18 @@ out:
void megasas_reset_reply_desc(struct megasas_instance *instance)
{
- int i, count;
+ int i, j, count;
struct fusion_context *fusion;
union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
fusion = instance->ctrl_context;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
- for (i = 0 ; i < count ; i++)
+ for (i = 0 ; i < count ; i++) {
fusion->last_reply_idx[i] = 0;
- reply_desc = fusion->reply_frames_desc;
- for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++)
- reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+ reply_desc = fusion->reply_frames_desc[i];
+ for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
+ reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+ }
}
/*
@@ -2680,6 +2852,7 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
struct megasas_cmd *cmd_mfi;
union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
u16 smid;
+ bool refire_cmd = 0;
fusion = instance->ctrl_context;
@@ -2695,42 +2868,500 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
continue;
req_desc = megasas_get_request_descriptor
(instance, smid - 1);
- if (req_desc && ((cmd_mfi->frame->dcmd.opcode !=
+ refire_cmd = req_desc && ((cmd_mfi->frame->dcmd.opcode !=
cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) &&
(cmd_mfi->frame->dcmd.opcode !=
- cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO))))
+ cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO)))
+ && !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE);
+ if (refire_cmd)
megasas_fire_cmd_fusion(instance, req_desc);
else
megasas_return_cmd(instance, cmd_mfi);
}
}
+/*
+ * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
+ * @instance: per adapter struct
+ * @channel: the channel assigned by the OS
+ * @id: the id assigned by the OS
+ *
+ * Returns SUCCESS if no IOs pending to SCSI device, else return FAILED
+ */
+
+static int megasas_track_scsiio(struct megasas_instance *instance,
+ int id, int channel)
+{
+ int i, found = 0;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct fusion_context *fusion;
+ fusion = instance->ctrl_context;
+
+ for (i = 0 ; i < instance->max_scsi_cmds; i++) {
+ cmd_fusion = fusion->cmd_list[i];
+ if (cmd_fusion->scmd &&
+ (cmd_fusion->scmd->device->id == id &&
+ cmd_fusion->scmd->device->channel == channel)) {
+ dev_info(&instance->pdev->dev,
+ "SCSI commands pending to target"
+ "channel %d id %d \tSMID: 0x%x\n",
+ channel, id, cmd_fusion->index);
+ scsi_print_command(cmd_fusion->scmd);
+ found = 1;
+ break;
+ }
+ }
+
+ return found ? FAILED : SUCCESS;
+}
+
+/**
+ * megasas_tm_response_code - translation of device response code
+ * @ioc: per adapter object
+ * @mpi_reply: MPI reply returned by firmware
+ *
+ * Return nothing.
+ */
+static void
+megasas_tm_response_code(struct megasas_instance *instance,
+ struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply)
+{
+ char *desc;
+
+ switch (mpi_reply->ResponseCode) {
+ case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
+ desc = "task management request completed";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
+ desc = "invalid frame";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
+ desc = "task management request not supported";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
+ desc = "task management request failed";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
+ desc = "task management request succeeded";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
+ desc = "invalid lun";
+ break;
+ case 0xA:
+ desc = "overlapped tag attempted";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
+ desc = "task queued, however not sent to target";
+ break;
+ default:
+ desc = "unknown";
+ break;
+ }
+ dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n",
+ mpi_reply->ResponseCode, desc);
+ dev_dbg(&instance->pdev->dev,
+ "TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo"
+ " 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
+ mpi_reply->TerminationCount, mpi_reply->DevHandle,
+ mpi_reply->Function, mpi_reply->TaskType,
+ mpi_reply->IOCStatus, mpi_reply->IOCLogInfo);
+}
+
+/**
+ * megasas_issue_tm - main routine for sending tm requests
+ * @instance: per adapter struct
+ * @device_handle: device handle
+ * @channel: the channel assigned by the OS
+ * @id: the id assigned by the OS
+ * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in megaraid_sas_fusion.c)
+ * @smid_task: smid assigned to the task
+ * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
+ * Context: user
+ *
+ * MegaRaid use MPT interface for Task Magement request.
+ * A generic API for sending task management requests to firmware.
+ *
+ * Return SUCCESS or FAILED.
+ */
+static int
+megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
+ uint channel, uint id, u16 smid_task, u8 type)
+{
+ struct MR_TASK_MANAGE_REQUEST *mr_request;
+ struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request;
+ unsigned long timeleft;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct megasas_cmd *cmd_mfi;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *scsi_lookup;
+ int rc;
+ struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply;
+
+ fusion = instance->ctrl_context;
+
+ cmd_mfi = megasas_get_cmd(instance);
+
+ if (!cmd_mfi) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ cmd_fusion = megasas_get_cmd_fusion(instance,
+ instance->max_scsi_cmds + cmd_mfi->index);
+
+ /* Save the smid. To be used for returning the cmd */
+ cmd_mfi->context.smid = cmd_fusion->index;
+
+ req_desc = megasas_get_request_descriptor(instance,
+ (cmd_fusion->index - 1));
+ if (!req_desc) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ megasas_return_cmd(instance, cmd_mfi);
+ return -ENOMEM;
+ }
+
+ cmd_fusion->request_desc = req_desc;
+ req_desc->Words = 0;
+
+ scsi_lookup = fusion->cmd_list[smid_task - 1];
+
+ mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion->io_request;
+ memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST));
+ mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest;
+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ mpi_request->DevHandle = cpu_to_le16(device_handle);
+ mpi_request->TaskType = type;
+ mpi_request->TaskMID = cpu_to_le16(smid_task);
+ mpi_request->LUN[1] = 0;
+
+
+ req_desc = cmd_fusion->request_desc;
+ req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index);
+ req_desc->HighPriority.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ req_desc->HighPriority.MSIxIndex = 0;
+ req_desc->HighPriority.LMID = 0;
+ req_desc->HighPriority.Reserved1 = 0;
+
+ if (channel < MEGASAS_MAX_PD_CHANNELS)
+ mr_request->tmReqFlags.isTMForPD = 1;
+ else
+ mr_request->tmReqFlags.isTMForLD = 1;
+
+ init_completion(&cmd_fusion->done);
+ megasas_fire_cmd_fusion(instance, req_desc);
+
+ timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ);
+
+ if (!timeleft) {
+ dev_err(&instance->pdev->dev,
+ "task mgmt type 0x%x timed out\n", type);
+ cmd_mfi->flags |= DRV_DCMD_SKIP_REFIRE;
+ mutex_unlock(&instance->reset_mutex);
+ rc = megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
+ return rc;
+ }
+
+ mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->TMReply;
+ megasas_tm_response_code(instance, mpi_reply);
+
+ megasas_return_cmd(instance, cmd_mfi);
+ rc = SUCCESS;
+ switch (type) {
+ case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+ if (scsi_lookup->scmd == NULL)
+ break;
+ else {
+ instance->instancet->disable_intr(instance);
+ msleep(1000);
+ megasas_complete_cmd_dpc_fusion
+ ((unsigned long)instance);
+ instance->instancet->enable_intr(instance);
+ if (scsi_lookup->scmd == NULL)
+ break;
+ }
+ rc = FAILED;
+ break;
+
+ case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+ if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF))
+ break;
+ instance->instancet->disable_intr(instance);
+ msleep(1000);
+ megasas_complete_cmd_dpc_fusion
+ ((unsigned long)instance);
+ rc = megasas_track_scsiio(instance, id, channel);
+ instance->instancet->enable_intr(instance);
+
+ break;
+ case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
+ case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
+ break;
+ default:
+ rc = FAILED;
+ break;
+ }
+
+ return rc;
+
+}
+
+/*
+ * megasas_fusion_smid_lookup : Look for fusion command correpspodning to SCSI
+ * @instance: per adapter struct
+ *
+ * Return Non Zero index, if SMID found in outstanding commands
+ */
+static u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd)
+{
+ int i, ret = 0;
+ struct megasas_instance *instance;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct fusion_context *fusion;
+
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+ fusion = instance->ctrl_context;
+
+ for (i = 0; i < instance->max_scsi_cmds; i++) {
+ cmd_fusion = fusion->cmd_list[i];
+ if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) {
+ scmd_printk(KERN_NOTICE, scmd, "Abort request is for"
+ " SMID: %d\n", cmd_fusion->index);
+ ret = cmd_fusion->index;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/*
+* megasas_get_tm_devhandle - Get devhandle for TM request
+* @sdev- OS provided scsi device
+*
+* Returns- devhandle/targetID of SCSI device
+*/
+static u16 megasas_get_tm_devhandle(struct scsi_device *sdev)
+{
+ u16 pd_index = 0;
+ u32 device_id;
+ struct megasas_instance *instance;
+ struct fusion_context *fusion;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
+ u16 devhandle = (u16)ULONG_MAX;
+
+ instance = (struct megasas_instance *)sdev->host->hostdata;
+ fusion = instance->ctrl_context;
+
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+ if (instance->use_seqnum_jbod_fp) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ pd_sync = (void *)fusion->pd_seq_sync
+ [(instance->pd_seq_map_id - 1) & 1];
+ devhandle = pd_sync->seq[pd_index].devHandle;
+ } else
+ sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable"
+ " without JBOD MAP support from %s %d\n", __func__, __LINE__);
+ } else {
+ device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
+ + sdev->id;
+ devhandle = device_id;
+ }
+
+ return devhandle;
+}
+
+/*
+ * megasas_task_abort_fusion : SCSI task abort function for fusion adapters
+ * @scmd : pointer to scsi command object
+ *
+ * Return SUCCESS, if command aborted else FAILED
+ */
+
+int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
+{
+ struct megasas_instance *instance;
+ u16 smid, devhandle;
+ struct fusion_context *fusion;
+ int ret;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
+ mr_device_priv_data = scmd->device->hostdata;
+
+
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+ fusion = instance->ctrl_context;
+
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
+ dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
+ "SCSI host:%d\n", instance->host->host_no);
+ ret = FAILED;
+ return ret;
+ }
+
+ if (!mr_device_priv_data) {
+ sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+ "scmd(%p)\n", scmd);
+ scmd->result = DID_NO_CONNECT << 16;
+ ret = SUCCESS;
+ goto out;
+ }
+
+
+ if (!mr_device_priv_data->is_tm_capable) {
+ ret = FAILED;
+ goto out;
+ }
+
+ mutex_lock(&instance->reset_mutex);
+
+ smid = megasas_fusion_smid_lookup(scmd);
+
+ if (!smid) {
+ ret = SUCCESS;
+ scmd_printk(KERN_NOTICE, scmd, "Command for which abort is"
+ " issued is not found in oustanding commands\n");
+ mutex_unlock(&instance->reset_mutex);
+ goto out;
+ }
+
+ devhandle = megasas_get_tm_devhandle(scmd->device);
+
+ if (devhandle == (u16)ULONG_MAX) {
+ ret = SUCCESS;
+ sdev_printk(KERN_INFO, scmd->device,
+ "task abort issued for invalid devhandle\n");
+ mutex_unlock(&instance->reset_mutex);
+ goto out;
+ }
+ sdev_printk(KERN_INFO, scmd->device,
+ "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n",
+ scmd, devhandle);
+
+ mr_device_priv_data->tm_busy = 1;
+ ret = megasas_issue_tm(instance, devhandle,
+ scmd->device->channel, scmd->device->id, smid,
+ MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+ mr_device_priv_data->tm_busy = 0;
+
+ mutex_unlock(&instance->reset_mutex);
+out:
+ sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
+ ((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+ return ret;
+}
+
+/*
+ * megasas_reset_target_fusion : target reset function for fusion adapters
+ * scmd: SCSI command pointer
+ *
+ * Returns SUCCESS if all commands associated with target aborted else FAILED
+ */
+
+int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
+{
+
+ struct megasas_instance *instance;
+ int ret = FAILED;
+ u16 devhandle;
+ struct fusion_context *fusion;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
+ mr_device_priv_data = scmd->device->hostdata;
+
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+ fusion = instance->ctrl_context;
+
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
+ dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
+ "SCSI host:%d\n", instance->host->host_no);
+ ret = FAILED;
+ return ret;
+ }
+
+ if (!mr_device_priv_data) {
+ sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+ "scmd(%p)\n", scmd);
+ scmd->result = DID_NO_CONNECT << 16;
+ ret = SUCCESS;
+ goto out;
+ }
+
+
+ if (!mr_device_priv_data->is_tm_capable) {
+ ret = FAILED;
+ goto out;
+ }
+
+ mutex_lock(&instance->reset_mutex);
+ devhandle = megasas_get_tm_devhandle(scmd->device);
+
+ if (devhandle == (u16)ULONG_MAX) {
+ ret = SUCCESS;
+ sdev_printk(KERN_INFO, scmd->device,
+ "target reset issued for invalid devhandle\n");
+ mutex_unlock(&instance->reset_mutex);
+ goto out;
+ }
+
+ sdev_printk(KERN_INFO, scmd->device,
+ "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n",
+ scmd, devhandle);
+ mr_device_priv_data->tm_busy = 1;
+ ret = megasas_issue_tm(instance, devhandle,
+ scmd->device->channel, scmd->device->id, 0,
+ MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
+ mr_device_priv_data->tm_busy = 0;
+ mutex_unlock(&instance->reset_mutex);
+out:
+ scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n",
+ (ret == SUCCESS) ? "SUCCESS" : "FAILED");
+
+ return ret;
+}
+
+/*SRIOV get other instance in cluster if any*/
+struct megasas_instance *megasas_get_peer_instance(struct megasas_instance *instance)
+{
+ int i;
+
+ for (i = 0; i < MAX_MGMT_ADAPTERS; i++) {
+ if (megasas_mgmt_info.instance[i] &&
+ (megasas_mgmt_info.instance[i] != instance) &&
+ megasas_mgmt_info.instance[i]->requestorId &&
+ megasas_mgmt_info.instance[i]->peerIsPresent &&
+ (memcmp((megasas_mgmt_info.instance[i]->clusterId),
+ instance->clusterId, MEGASAS_CLUSTER_ID_SIZE) == 0))
+ return megasas_mgmt_info.instance[i];
+ }
+ return NULL;
+}
+
/* Check for a second path that is currently UP */
int megasas_check_mpio_paths(struct megasas_instance *instance,
struct scsi_cmnd *scmd)
{
- int i, j, retval = (DID_RESET << 16);
-
- if (instance->mpio && instance->requestorId) {
- for (i = 0 ; i < MAX_MGMT_ADAPTERS ; i++)
- for (j = 0 ; j < MAX_LOGICAL_DRIVES; j++)
- if (megasas_mgmt_info.instance[i] &&
- (megasas_mgmt_info.instance[i] != instance) &&
- megasas_mgmt_info.instance[i]->mpio &&
- megasas_mgmt_info.instance[i]->requestorId
- &&
- (megasas_mgmt_info.instance[i]->ld_ids[j]
- == scmd->device->id)) {
- retval = (DID_NO_CONNECT << 16);
- goto out;
- }
+ struct megasas_instance *peer_instance = NULL;
+ int retval = (DID_RESET << 16);
+
+ if (instance->peerIsPresent) {
+ peer_instance = megasas_get_peer_instance(instance);
+ if ((peer_instance) &&
+ (atomic_read(&peer_instance->adprecovery) ==
+ MEGASAS_HBA_OPERATIONAL))
+ retval = (DID_NO_CONNECT << 16);
}
-out:
return retval;
}
/* Core fusion reset function */
-int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
+int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
{
int retval = SUCCESS, i, convert = 0;
struct megasas_instance *instance;
@@ -2739,13 +3370,14 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
u32 abs_state, status_reg, reset_adapter;
u32 io_timeout_in_crash_mode = 0;
struct scsi_cmnd *scmd_local = NULL;
+ struct scsi_device *sdev;
instance = (struct megasas_instance *)shost->hostdata;
fusion = instance->ctrl_context;
mutex_lock(&instance->reset_mutex);
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_warn(&instance->pdev->dev, "Hardware critical error, "
"returning FAILED for scsi%d.\n",
instance->host->host_no);
@@ -2757,10 +3389,10 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
/* IO timeout detected, forcibly put FW in FAULT state */
if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf &&
- instance->crash_dump_app_support && iotimeout) {
- dev_info(&instance->pdev->dev, "IO timeout is detected, "
+ instance->crash_dump_app_support && reason) {
+ dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
"forcibly FAULT Firmware\n");
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
status_reg = readl(&instance->reg_set->doorbell);
writel(status_reg | MFI_STATE_FORCE_OCR,
&instance->reg_set->doorbell);
@@ -2772,10 +3404,10 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
dev_dbg(&instance->pdev->dev, "waiting for [%d] "
"seconds for crash dump collection and OCR "
"to be done\n", (io_timeout_in_crash_mode * 3));
- } while ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+ } while ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
(io_timeout_in_crash_mode < 80));
- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
dev_info(&instance->pdev->dev, "OCR done for IO "
"timeout case\n");
retval = SUCCESS;
@@ -2792,18 +3424,18 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
del_timer_sync(&instance->sriov_heartbeat_timer);
set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
- instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING);
instance->instancet->disable_intr(instance);
msleep(1000);
/* First try waiting for commands to complete */
- if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
+ if (megasas_wait_for_outstanding_fusion(instance, reason,
&convert)) {
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
dev_warn(&instance->pdev->dev, "resetting fusion "
"adapter scsi%d.\n", instance->host->host_no);
if (convert)
- iotimeout = 0;
+ reason = 0;
/* Now return commands back to the OS */
for (i = 0 ; i < instance->max_scsi_cmds; i++) {
@@ -2813,6 +3445,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
scmd_local->result =
megasas_check_mpio_paths(instance,
scmd_local);
+ if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+ atomic_dec(&instance->ldio_outstanding);
megasas_return_cmd_fusion(instance, cmd_fusion);
scsi_dma_unmap(scmd_local);
scmd_local->scsi_done(scmd_local);
@@ -2837,55 +3471,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
}
/* Let SR-IOV VF & PF sync up if there was a HB failure */
- if (instance->requestorId && !iotimeout) {
+ if (instance->requestorId && !reason) {
msleep(MEGASAS_OCR_SETTLE_TIME_VF);
- /* Look for a late HB update after VF settle time */
- if (abs_state == MFI_STATE_OPERATIONAL &&
- (instance->hb_host_mem->HB.fwCounter !=
- instance->hb_host_mem->HB.driverCounter)) {
- instance->hb_host_mem->HB.driverCounter =
- instance->hb_host_mem->HB.fwCounter;
- dev_warn(&instance->pdev->dev, "SR-IOV:"
- "Late FW heartbeat update for "
- "scsi%d.\n",
- instance->host->host_no);
- } else {
- /* In VF mode, first poll for FW ready */
- for (i = 0;
- i < (MEGASAS_RESET_WAIT_TIME * 1000);
- i += 20) {
- status_reg =
- instance->instancet->
- read_fw_status_reg(
- instance->reg_set);
- abs_state = status_reg &
- MFI_STATE_MASK;
- if (abs_state == MFI_STATE_READY) {
- dev_warn(&instance->pdev->dev,
- "SR-IOV: FW was found"
- "to be in ready state "
- "for scsi%d.\n",
- instance->host->host_no);
- break;
- }
- msleep(20);
- }
- if (abs_state != MFI_STATE_READY) {
- dev_warn(&instance->pdev->dev, "SR-IOV: "
- "FW not in ready state after %d"
- " seconds for scsi%d, status_reg = "
- "0x%x.\n",
- MEGASAS_RESET_WAIT_TIME,
- instance->host->host_no,
- status_reg);
- megaraid_sas_kill_hba(instance);
- instance->skip_heartbeat_timer_del = 1;
- instance->adprecovery =
- MEGASAS_HW_CRITICAL_ERROR;
- retval = FAILED;
- goto out;
- }
- }
+ goto transition_to_ready;
}
/* Now try to reset the chip */
@@ -2894,23 +3482,28 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
if (instance->instancet->adp_reset
(instance, instance->reg_set))
continue;
-
+transition_to_ready:
/* Wait for FW to become ready */
if (megasas_transition_to_ready(instance, 1)) {
- dev_warn(&instance->pdev->dev, "Failed to "
- "transition controller to ready "
- "for scsi%d.\n",
- instance->host->host_no);
- continue;
+ dev_warn(&instance->pdev->dev,
+ "Failed to transition controller to ready for "
+ "scsi%d.\n", instance->host->host_no);
+ if (instance->requestorId && !reason)
+ goto fail_kill_adapter;
+ else
+ continue;
}
-
megasas_reset_reply_desc(instance);
+ megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
+
if (megasas_ioc_init_fusion(instance)) {
dev_warn(&instance->pdev->dev,
- "megasas_ioc_init_fusion() failed!"
- " for scsi%d\n",
- instance->host->host_no);
- continue;
+ "megasas_ioc_init_fusion() failed! for "
+ "scsi%d\n", instance->host->host_no);
+ if (instance->requestorId && !reason)
+ goto fail_kill_adapter;
+ else
+ continue;
}
megasas_refire_mgmt_cmd(instance);
@@ -2932,10 +3525,13 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
megasas_setup_jbod_map(instance);
+ shost_for_each_device(sdev, shost)
+ megasas_update_sdev_properties(sdev);
+
clear_bit(MEGASAS_FUSION_IN_RESET,
&instance->reset_flags);
instance->instancet->enable_intr(instance);
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
/* Restart SR-IOV heartbeat */
if (instance->requestorId) {
@@ -2964,6 +3560,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
retval = SUCCESS;
goto out;
}
+fail_kill_adapter:
/* Reset failed, kill the adapter */
dev_warn(&instance->pdev->dev, "Reset failed, killing "
"adapter scsi%d.\n", instance->host->host_no);
@@ -2980,7 +3577,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
}
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
instance->instancet->enable_intr(instance);
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
}
out:
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 473005c99b44..80eaee22f5bc 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -176,7 +176,9 @@ enum REGION_TYPE {
#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100)
#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004)
#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
-#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
+#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01)
+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03)
+#define MPI2_REQ_DESCRIPT_FLAGS_FP_IO (0x06)
#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02)
#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000)
@@ -277,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION {
struct MPI2_SGE_SIMPLE_UNION SGE;
};
+/****************************************************************************
+* SCSI Task Management messages
+****************************************************************************/
+
+/*SCSI Task Management Request Message */
+struct MPI2_SCSI_TASK_MANAGE_REQUEST {
+ u16 DevHandle; /*0x00 */
+ u8 ChainOffset; /*0x02 */
+ u8 Function; /*0x03 */
+ u8 Reserved1; /*0x04 */
+ u8 TaskType; /*0x05 */
+ u8 Reserved2; /*0x06 */
+ u8 MsgFlags; /*0x07 */
+ u8 VP_ID; /*0x08 */
+ u8 VF_ID; /*0x09 */
+ u16 Reserved3; /*0x0A */
+ u8 LUN[8]; /*0x0C */
+ u32 Reserved4[7]; /*0x14 */
+ u16 TaskMID; /*0x30 */
+ u16 Reserved5; /*0x32 */
+};
+
+
+/*SCSI Task Management Reply Message */
+struct MPI2_SCSI_TASK_MANAGE_REPLY {
+ u16 DevHandle; /*0x00 */
+ u8 MsgLength; /*0x02 */
+ u8 Function; /*0x03 */
+ u8 ResponseCode; /*0x04 */
+ u8 TaskType; /*0x05 */
+ u8 Reserved1; /*0x06 */
+ u8 MsgFlags; /*0x07 */
+ u8 VP_ID; /*0x08 */
+ u8 VF_ID; /*0x09 */
+ u16 Reserved2; /*0x0A */
+ u16 Reserved3; /*0x0C */
+ u16 IOCStatus; /*0x0E */
+ u32 IOCLogInfo; /*0x10 */
+ u32 TerminationCount; /*0x14 */
+ u32 ResponseInfo; /*0x18 */
+};
+
+struct MR_TM_REQUEST {
+ char request[128];
+};
+
+struct MR_TM_REPLY {
+ char reply[128];
+};
+
+/* SCSI Task Management Request Message */
+struct MR_TASK_MANAGE_REQUEST {
+ /*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */
+ struct MR_TM_REQUEST TmRequest;
+ union {
+ struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u32 reserved1:30;
+ u32 isTMForPD:1;
+ u32 isTMForLD:1;
+#else
+ u32 isTMForLD:1;
+ u32 isTMForPD:1;
+ u32 reserved1:30;
+#endif
+ u32 reserved2;
+ } tmReqFlags;
+ struct MR_TM_REPLY TMReply;
+ };
+};
+
+/* TaskType values */
+
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01)
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02)
+#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03)
+#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A)
+
+/* ResponseCode values */
+
+#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00)
+#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02)
+#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04)
+#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05)
+#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08)
+#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09)
+#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A)
+#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80)
+
/*
* RAID SCSI IO Request Message
* Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST
@@ -547,7 +643,9 @@ struct MR_SPAN_BLOCK_INFO {
struct MR_LD_RAID {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved4:7;
+ u32 reserved4:5;
+ u32 fpBypassRegionLock:1;
+ u32 tmCapable:1;
u32 fpNonRWCapable:1;
u32 fpReadAcrossStripe:1;
u32 fpWriteAcrossStripe:1;
@@ -569,7 +667,9 @@ struct MR_LD_RAID {
u32 fpWriteAcrossStripe:1;
u32 fpReadAcrossStripe:1;
u32 fpNonRWCapable:1;
- u32 reserved4:7;
+ u32 tmCapable:1;
+ u32 fpBypassRegionLock:1;
+ u32 reserved4:5;
#endif
} capability;
__le32 reserved6;
@@ -639,7 +739,7 @@ struct IO_REQUEST_INFO {
u8 fpOkForIo;
u8 IoforUnevenSpan;
u8 start_span;
- u8 reserved;
+ u8 do_fp_rlbypass;
u64 start_row;
u8 span_arm; /* span[7:5], arm[4:0] */
u8 pd_after_lb;
@@ -694,6 +794,7 @@ struct megasas_cmd_fusion {
u32 sync_cmd_idx;
u32 index;
u8 pd_r1_lb;
+ struct completion done;
};
struct LD_LOAD_BALANCE_INFO {
@@ -807,9 +908,18 @@ struct MR_FW_RAID_MAP_EXT {
* * define MR_PD_CFG_SEQ structure for system PDs
* */
struct MR_PD_CFG_SEQ {
- __le16 seqNum;
- __le16 devHandle;
- u8 reserved[4];
+ u16 seqNum;
+ u16 devHandle;
+ struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u8 reserved:7;
+ u8 tmCapable:1;
+#else
+ u8 tmCapable:1;
+ u8 reserved:7;
+#endif
+ } capability;
+ u8 reserved[3];
} __packed;
struct MR_PD_CFG_SEQ_NUM_SYNC {
@@ -818,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC {
struct MR_PD_CFG_SEQ seq[1];
} __packed;
+struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
+ u64 RDPQBaseAddress;
+ u32 Reserved1;
+ u32 Reserved2;
+};
+
struct fusion_context {
struct megasas_cmd_fusion **cmd_list;
dma_addr_t req_frames_desc_phys;
@@ -830,8 +946,8 @@ struct fusion_context {
struct dma_pool *sg_dma_pool;
struct dma_pool *sense_dma_pool;
- dma_addr_t reply_frames_desc_phys;
- union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
+ dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
struct dma_pool *reply_frames_desc_pool;
u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
@@ -841,6 +957,8 @@ struct fusion_context {
u32 reply_alloc_sz;
u32 io_frames_alloc_sz;
+ struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
+ dma_addr_t rdpq_phys;
u16 max_sge_in_main_msg;
u16 max_sge_in_chain;
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 555367f00228..1753e42826dd 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -29,6 +29,7 @@
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/spinlock.h>
+#include <linux/pci.h>
#include <asm/dbdma.h>
#include <asm/io.h>
#include <asm/pgtable.h>
@@ -38,7 +39,6 @@
#include <asm/processor.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
-#include <asm/pci-bridge.h>
#include <asm/macio.h>
#include <scsi/scsi.h>
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h
index ec27ad2d186f..dfad5b8c1890 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.35
+ * mpi2.h Version: 02.00.39
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -92,6 +92,14 @@
* 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT.
* 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT
* 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-18-14 02.00.36 Updated copyright information.
+ * Bumped MPI2_HEADER_VERSION_UNIT.
+ * 03-16-15 02.00.37 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added Scratchpad registers to
+ * MPI2_SYSTEM_INTERFACE_REGS.
+ * Added MPI2_DIAG_SBR_RELOAD.
+ * 03-19-15 02.00.38 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-25-15 02.00.39 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -124,8 +132,14 @@
MPI25_VERSION_MINOR)
#define MPI2_VERSION_02_05 (0x0205)
+/*minor version for MPI v2.6 compatible products */
+#define MPI26_VERSION_MINOR (0x06)
+#define MPI26_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
+ MPI26_VERSION_MINOR)
+#define MPI2_VERSION_02_06 (0x0206)
+
/*Unit and Dev versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x23)
+#define MPI2_HEADER_VERSION_UNIT (0x27)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -179,10 +193,12 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS {
U32 HCBSize; /*0x74 */
U32 HCBAddressLow; /*0x78 */
U32 HCBAddressHigh; /*0x7C */
- U32 Reserved6[16]; /*0x80 */
+ U32 Reserved6[12]; /*0x80 */
+ U32 Scratchpad[4]; /*0xB0 */
U32 RequestDescriptorPostLow; /*0xC0 */
U32 RequestDescriptorPostHigh; /*0xC4 */
- U32 Reserved7[14]; /*0xC8 */
+ U32 AtomicRequestDescriptorPost;/*0xC8 */
+ U32 Reserved7[13]; /*0xCC */
} MPI2_SYSTEM_INTERFACE_REGS,
*PTR_MPI2_SYSTEM_INTERFACE_REGS,
Mpi2SystemInterfaceRegs_t,
@@ -224,6 +240,8 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS {
*/
#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008)
+#define MPI2_DIAG_SBR_RELOAD (0x00002000)
+
#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800)
#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000)
#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800)
@@ -298,10 +316,19 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS {
#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C)
/*
- *Offsets for the Request Queue
+ *Offsets for the Scratchpad registers
+ */
+#define MPI26_SCRATCHPAD0_OFFSET (0x000000B0)
+#define MPI26_SCRATCHPAD1_OFFSET (0x000000B4)
+#define MPI26_SCRATCHPAD2_OFFSET (0x000000B8)
+#define MPI26_SCRATCHPAD3_OFFSET (0x000000BC)
+
+/*
+ *Offsets for the Request Descriptor Post Queue
*/
#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0)
#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4)
+#define MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET (0x000000C8)
/*Hard Reset delay timings */
#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000)
@@ -329,7 +356,8 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR {
*pMpi2DefaultRequestDescriptor_t;
/*defines for the RequestFlags field */
-#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E)
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x1E)
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_RSHIFT (1)
#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02)
#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
@@ -337,7 +365,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR {
#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A)
#define MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO (0x0C)
-#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
+#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
/*High Priority Request Descriptor */
typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR {
@@ -408,6 +436,33 @@ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION {
Mpi2RequestDescriptorUnion_t,
*pMpi2RequestDescriptorUnion_t;
+/*Atomic Request Descriptors */
+
+/*
+ * All Atomic Request Descriptors have the same format, so the following
+ * structure is used for all Atomic Request Descriptors:
+ * Atomic Default Request Descriptor
+ * Atomic High Priority Request Descriptor
+ * Atomic SCSI IO Request Descriptor
+ * Atomic SCSI Target Request Descriptor
+ * Atomic RAID Accelerator Request Descriptor
+ * Atomic Fast Path SCSI IO Request Descriptor
+ */
+
+/*Atomic Request Descriptor */
+typedef struct _MPI26_ATOMIC_REQUEST_DESCRIPTOR {
+ U8 RequestFlags; /* 0x00 */
+ U8 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+} MPI26_ATOMIC_REQUEST_DESCRIPTOR,
+ *PTR_MPI26_ATOMIC_REQUEST_DESCRIPTOR,
+ Mpi26AtomicRequestDescriptor_t,
+ *pMpi26AtomicRequestDescriptor_t;
+
+/*for the RequestFlags field, use the same
+ *defines as MPI2_DEFAULT_REQUEST_DESCRIPTOR
+ */
+
/*Reply Descriptors */
/*Default Reply Descriptor */
@@ -548,6 +603,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION {
#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18)
#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A)
#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B)
+#define MPI2_FUNCTION_IO_UNIT_CONTROL (0x1B)
#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C)
#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D)
#define MPI2_FUNCTION_DIAG_RELEASE (0x1E)
@@ -587,6 +643,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION {
#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007)
#define MPI2_IOCSTATUS_INVALID_STATE (0x0008)
#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009)
+#define MPI2_IOCSTATUS_INSUFFICIENT_POWER (0x000A)
/****************************************************************************
* Config IOCStatus values
@@ -1045,7 +1102,7 @@ typedef union _MPI2_IEEE_SGE_CHAIN_UNION {
Mpi2IeeeSgeChainUnion_t,
*pMpi2IeeeSgeChainUnion_t;
-/*MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 products only */
+/*MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 and later */
typedef struct _MPI25_IEEE_SGE_CHAIN64 {
U64 Address;
U32 Length;
@@ -1098,6 +1155,11 @@ typedef union _MPI25_SGE_IO_UNION {
#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00)
#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80)
+/*Next Segment Format */
+
+#define MPI26_IEEE_SGE_FLAGS_NSF_MASK (0x1C)
+#define MPI26_IEEE_SGE_FLAGS_NSF_MPI_IEEE (0x00)
+
/*Data Location Address Space */
#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03)
@@ -1108,6 +1170,7 @@ typedef union _MPI25_SGE_IO_UNION {
#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03)
#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \
(MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR)
+#define MPI26_IEEE_SGE_FLAGS_IOCCTL_ADDR (0x02)
/****************************************************************************
* IEEE SGE operation Macros
@@ -1166,6 +1229,7 @@ typedef union _MPI2_SGE_IO_UNION {
#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00)
#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04)
#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08)
+#define MPI26_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08)
#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C)
/*values for SGL Type subfield */
#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03)
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
index 581fdb375db5..9cf09bf7c4a8 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_cnfg.h
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.29
+ * mpi2_cnfg.h Version: 02.00.33
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -178,7 +178,14 @@
* 01-08-14 02.00.28 Added more defines for the BiosOptions field of
* MPI2_CONFIG_PAGE_BIOS_1.
* 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and
- * more defines for the BiosOptions field..
+ * more defines for the BiosOptions field.
+ * 11-18-14 02.00.30 Updated copyright information.
+ * Added MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG.
+ * Added AdapterOrderAux fields to BIOS Page 3.
+ * 03-16-15 02.00.31 Updated for MPI v2.6.
+ * Added new SAS Phy Event codes
+ * 05-25-15 02.00.33 Added more defines for the BiosOptions field of
+ * MPI2_CONFIG_PAGE_BIOS_1.
* --------------------------------------------------------------------------
*/
@@ -355,7 +362,6 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION {
#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF)
-
/****************************************************************************
* Configuration messages
****************************************************************************/
@@ -457,8 +463,17 @@ typedef struct _MPI2_CONFIG_REPLY {
#define MPI25_MFGPAGE_DEVID_SAS3108_5 (0x0094)
#define MPI25_MFGPAGE_DEVID_SAS3108_6 (0x0095)
-
-
+/* MPI v2.6 SAS Products */
+#define MPI26_MFGPAGE_DEVID_SAS3216 (0x00C9)
+#define MPI26_MFGPAGE_DEVID_SAS3224 (0x00C4)
+#define MPI26_MFGPAGE_DEVID_SAS3316_1 (0x00C5)
+#define MPI26_MFGPAGE_DEVID_SAS3316_2 (0x00C6)
+#define MPI26_MFGPAGE_DEVID_SAS3316_3 (0x00C7)
+#define MPI26_MFGPAGE_DEVID_SAS3316_4 (0x00C8)
+#define MPI26_MFGPAGE_DEVID_SAS3324_1 (0x00C0)
+#define MPI26_MFGPAGE_DEVID_SAS3324_2 (0x00C1)
+#define MPI26_MFGPAGE_DEVID_SAS3324_3 (0x00C2)
+#define MPI26_MFGPAGE_DEVID_SAS3324_4 (0x00C3)
/*Manufacturing Page 0 */
@@ -941,8 +956,8 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
U8
BoardTemperatureUnits; /*0x16 */
U8 Reserved3; /*0x17 */
- U32 Reserved4; /* 0x18 */
- U32 Reserved5; /* 0x1C */
+ U32 BoardPowerRequirement; /*0x18 */
+ U32 PCISlotPowerAllocation; /*0x1C */
U32 Reserved6; /* 0x20 */
U32 Reserved7; /* 0x24 */
} MPI2_CONFIG_PAGE_IO_UNIT_7,
@@ -1151,6 +1166,62 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 {
#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01)
+/* IO Unit Page 11 (for MPI v2.6 and later) */
+
+typedef struct _MPI26_IOUNIT11_SPINUP_GROUP {
+ U8 MaxTargetSpinup; /* 0x00 */
+ U8 SpinupDelay; /* 0x01 */
+ U8 SpinupFlags; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+} MPI26_IOUNIT11_SPINUP_GROUP,
+ *PTR_MPI26_IOUNIT11_SPINUP_GROUP,
+ Mpi26IOUnit11SpinupGroup_t,
+ *pMpi26IOUnit11SpinupGroup_t;
+
+/* defines for IO Unit Page 11 SpinupFlags */
+#define MPI26_IOUNITPAGE11_SPINUP_DISABLE_FLAG (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * four and check the value returned for NumPhys at runtime.
+ */
+#ifndef MPI26_IOUNITPAGE11_PHY_MAX
+#define MPI26_IOUNITPAGE11_PHY_MAX (4)
+#endif
+
+typedef struct _MPI26_CONFIG_PAGE_IO_UNIT_11 {
+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */
+ U32 Reserved1; /*0x04 */
+ MPI26_IOUNIT11_SPINUP_GROUP SpinupGroupParameters[4]; /*0x08 */
+ U32 Reserved2; /*0x18 */
+ U32 Reserved3; /*0x1C */
+ U32 Reserved4; /*0x20 */
+ U8 BootDeviceWaitTime; /*0x24 */
+ U8 Reserved5; /*0x25 */
+ U16 Reserved6; /*0x26 */
+ U8 NumPhys; /*0x28 */
+ U8 PEInitialSpinupDelay; /*0x29 */
+ U8 PEReplyDelay; /*0x2A */
+ U8 Flags; /*0x2B */
+ U8 PHY[MPI26_IOUNITPAGE11_PHY_MAX];/*0x2C */
+} MPI26_CONFIG_PAGE_IO_UNIT_11,
+ *PTR_MPI26_CONFIG_PAGE_IO_UNIT_11,
+ Mpi26IOUnitPage11_t,
+ *pMpi26IOUnitPage11_t;
+
+#define MPI26_IOUNITPAGE11_PAGEVERSION (0x00)
+
+/* defines for Flags field */
+#define MPI26_IOUNITPAGE11_FLAGS_AUTO_PORTENABLE (0x01)
+
+/* defines for PHY field */
+#define MPI26_IOUNITPAGE11_PHY_SPINUP_GROUP_MASK (0x03)
+
+
+
+
+
/****************************************************************************
* IOC Config Pages
@@ -1343,6 +1414,10 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 {
#define MPI2_BIOSPAGE1_PAGEVERSION (0x07)
/*values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_BOOT_LIST_ADD_ALT_BOOT_DEVICE (0x00008000)
+#define MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG (0x00004000)
+
+#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800)
#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800)
#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000)
#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800)
@@ -1492,6 +1567,8 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_2 {
/*BIOS Page 3 */
+#define MPI2_BIOSPAGE3_NUM_ADAPTER (4)
+
typedef struct _MPI2_ADAPTER_INFO {
U8 PciBusNumber; /*0x00 */
U8 PciDeviceAndFunctionNumber; /*0x01 */
@@ -1502,17 +1579,26 @@ typedef struct _MPI2_ADAPTER_INFO {
#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001)
#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002)
+typedef struct _MPI2_ADAPTER_ORDER_AUX {
+ U64 WWID; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U32 Reserved2; /* 0x0C */
+} MPI2_ADAPTER_ORDER_AUX, *PTR_MPI2_ADAPTER_ORDER_AUX,
+ Mpi2AdapterOrderAux_t, *pMpi2AdapterOrderAux_t;
+
+
typedef struct _MPI2_CONFIG_PAGE_BIOS_3 {
MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */
U32 GlobalFlags; /*0x04 */
U32 BiosVersion; /*0x08 */
- MPI2_ADAPTER_INFO AdapterOrder[4]; /*0x0C */
+ MPI2_ADAPTER_INFO AdapterOrder[MPI2_BIOSPAGE3_NUM_ADAPTER];
U32 Reserved1; /*0x1C */
+ MPI2_ADAPTER_ORDER_AUX AdapterOrderAux[MPI2_BIOSPAGE3_NUM_ADAPTER];
} MPI2_CONFIG_PAGE_BIOS_3,
*PTR_MPI2_CONFIG_PAGE_BIOS_3,
Mpi2BiosPage3_t, *pMpi2BiosPage3_t;
-#define MPI2_BIOSPAGE3_PAGEVERSION (0x00)
+#define MPI2_BIOSPAGE3_PAGEVERSION (0x01)
/*values for BIOS Page 3 GlobalFlags */
#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002)
@@ -2006,6 +2092,8 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 {
#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01)
/*values for SAS IO Unit Page 0 PhyFlags */
+#define MPI2_SASIOUNIT0_PHYFLAGS_INIT_PERSIST_CONNECT (0x40)
+#define MPI2_SASIOUNIT0_PHYFLAGS_TARG_PERSIST_CONNECT (0x20)
#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10)
#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08)
@@ -2108,6 +2196,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 {
#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001)
/*values for SAS IO Unit Page 1 AdditionalControlFlags */
+#define MPI2_SASIOUNIT1_ACONTROL_DA_PERSIST_CONNECT (0x0100)
#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080)
#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040)
#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020)
@@ -2125,6 +2214,8 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 {
#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01)
/*values for SAS IO Unit Page 1 PhyFlags */
+#define MPI2_SASIOUNIT1_PHYFLAGS_INIT_PERSIST_CONNECT (0x40)
+#define MPI2_SASIOUNIT1_PHYFLAGS_TARG_PERSIST_CONNECT (0x20)
#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10)
#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
@@ -2144,7 +2235,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 {
*SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
-/*SAS IO Unit Page 4 */
+/*SAS IO Unit Page 4 (for MPI v2.5 and earlier) */
typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP {
U8 MaxTargetSpinup; /*0x00 */
@@ -2715,6 +2806,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 {
#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020)
#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010)
#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008)
+#define MPI2_SAS_DEVICE0_FLAGS_PERSIST_CAPABLE (0x0004)
#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002)
#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
@@ -2922,6 +3014,19 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG {
#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1)
#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2)
+/*Following codes are product specific and in MPI v2.6 and later */
+#define MPI2_SASPHY3_EVENT_CODE_LCARB_WAIT_TIME (0xD3)
+#define MPI2_SASPHY3_EVENT_CODE_RCVD_CONN_RESP_WAIT_TIME (0xD4)
+#define MPI2_SASPHY3_EVENT_CODE_LCCONN_TIME (0xD5)
+#define MPI2_SASPHY3_EVENT_CODE_SSP_TX_START_TRANSMIT (0xD6)
+#define MPI2_SASPHY3_EVENT_CODE_SATA_TX_START (0xD7)
+#define MPI2_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMT (0xD8)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_BREAK_CONN (0xD9)
+#define MPI2_SASPHY3_EVENT_CODE_SSP_RX_START_RECEIVE (0xDA)
+#define MPI2_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xDB)
+#define MPI2_SASPHY3_EVENT_CODE_SMP_RX_START_RECEIVE (0xDC)
+
+
/*values for the CounterType field */
#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00)
#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01)
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_init.h b/drivers/scsi/mpt3sas/mpi/mpi2_init.h
index 068c98efd742..c38f624b859d 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_init.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_init.h
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.15
+ * mpi2_init.h Version: 02.00.17
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -46,6 +46,11 @@
* 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION.
* 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY,
* replacing the Reserved4 field.
+ * 11-18-14 02.00.16 Updated copyright information.
+ * 03-16-15 02.00.17 Updated for MPI v2.6.
+ * Added MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH.
+ * Added MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF and
+ * MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF.
* --------------------------------------------------------------------------
*/
@@ -128,6 +133,7 @@ typedef struct _MPI2_SCSI_IO_REQUEST {
#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04)
#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08)
#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C)
+#define MPI26_SCSIIO_MSGFLAGS_IOCCTL_SENSE_ADDR (0x08)
/*SCSI IO SGLFlags bits */
@@ -228,7 +234,7 @@ typedef union _MPI25_SCSI_IO_CDB_UNION {
} MPI25_SCSI_IO_CDB_UNION, *PTR_MPI25_SCSI_IO_CDB_UNION,
Mpi25ScsiIoCdb_t, *pMpi25ScsiIoCdb_t;
-/*MPI v2.5 SCSI IO Request Message */
+/*MPI v2.5/2.6 SCSI IO Request Message */
typedef struct _MPI25_SCSI_IO_REQUEST {
U16 DevHandle; /*0x00 */
U8 ChainOffset; /*0x02 */
@@ -302,12 +308,14 @@ typedef struct _MPI25_SCSI_IO_REQUEST {
#define MPI25_SCSIIO_NUM_SGLOFFSETS (4)
/*defines for the IoFlags field */
-#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK (0xC000)
-#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH (0x0000)
-#define MPI25_SCSIIO_IOFLAGS_FAST_PATH (0x4000)
+#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK (0xC000)
+#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH (0x0000)
+#define MPI25_SCSIIO_IOFLAGS_FAST_PATH (0x4000)
+#define MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH (0x2000)
#define MPI25_SCSIIO_IOFLAGS_LARGE_CDB (0x1000)
#define MPI25_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800)
+#define MPI26_SCSIIO_IOFLAGS_PORT_REQUEST (0x0400)
#define MPI25_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF)
/*MPI v2.5 defines for the EEDPFlags bits */
@@ -512,6 +520,7 @@ typedef struct _MPI2_SEP_REQUEST {
#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01)
/*SlotStatus defines */
+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF (0x00080000)
#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000)
#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
@@ -547,6 +556,7 @@ typedef struct _MPI2_SEP_REPLY {
Mpi2SepReply_t, *pMpi2SepReply_t;
/*SlotStatus defines */
+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF (0x00080000)
#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000)
#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
index d7598cc4bb8e..cf510ed91924 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_ioc.h
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.24
+ * mpi2_ioc.h Version: 02.00.26
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -133,6 +133,10 @@
* Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY.
* Added Encrypted Hash Extended Image.
* 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS.
+ * 11-18-14 02.00.25 Updated copyright information.
+ * 03-16-15 02.00.26 Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and
+ * MPI26_FW_HEADER_PID_FAMILY_3516_SAS.
+ * Added MPI26_CTRL_OP_SHUTDOWN.
* --------------------------------------------------------------------------
*/
@@ -165,7 +169,7 @@ typedef struct _MPI2_IOC_INIT_REQUEST {
U16 HeaderVersion; /*0x0E */
U32 Reserved5; /*0x10 */
U16 Reserved6; /*0x14 */
- U8 Reserved7; /*0x16 */
+ U8 HostPageSize; /*0x16 */
U8 HostMSIxVectors; /*0x17 */
U16 Reserved8; /*0x18 */
U16 SystemRequestFrameSize; /*0x1A */
@@ -289,7 +293,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
U16 MaxDevHandle; /*0x38 */
U16 MaxPersistentEntries; /*0x3A */
U16 MinDevHandle; /*0x3C */
- U16 Reserved4; /*0x3E */
+ U8 CurrentHostPageSize; /* 0x3E */
+ U8 Reserved4; /* 0x3F */
} MPI2_IOC_FACTS_REPLY, *PTR_MPI2_IOC_FACTS_REPLY,
Mpi2IOCFactsReply_t, *pMpi2IOCFactsReply_t;
@@ -326,6 +331,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
/*ProductID field uses MPI2_FW_HEADER_PID_ */
/*IOCCapabilities */
+#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000)
#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000)
#define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE (0x00020000)
#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000)
@@ -343,8 +349,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
/*ProtocolFlags */
-#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001)
#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002)
+#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001)
/****************************************************************************
* PortFacts message
@@ -1247,6 +1253,7 @@ typedef struct _MPI2_FW_UPLOAD_REQUEST {
#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09)
#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
+#define MPI2_FW_UPLOAD_ITYPE_CBB_BACKUP (0x0D)
/*MPI v2.0 FWUpload TransactionContext Element */
typedef struct _MPI2_FW_UPLOAD_TCSGE {
@@ -1328,7 +1335,7 @@ typedef struct _MPI2_FW_IMAGE_HEADER {
U32 Reserved54; /*0x54 */
U32 Reserved58; /*0x58 */
U32 Reserved5C; /*0x5C */
- U32 Reserved60; /*0x60 */
+ U32 BootFlags; /*0x60 */
U32 FirmwareVersionNameWhat; /*0x64 */
U8 FirmwareVersionName[32]; /*0x68 */
U32 VendorNameWhat; /*0x88 */
@@ -1354,18 +1361,22 @@ typedef struct _MPI2_FW_IMAGE_HEADER {
#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00)
#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000)
#define MPI2_FW_HEADER_SIGNATURE (0xEA000000)
+#define MPI26_FW_HEADER_SIGNATURE (0xEB000000)
/*Signature0 field */
#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04)
#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A)
+#define MPI26_FW_HEADER_SIGNATURE0 (0x5AEAA55A)
/*Signature1 field */
#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08)
#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5)
+#define MPI26_FW_HEADER_SIGNATURE1 (0xA55AEAA5)
/*Signature2 field */
#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C)
#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA)
+#define MPI26_FW_HEADER_SIGNATURE2 (0x5AA55AEA)
/*defines for using the ProductID field */
#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000)
@@ -1381,6 +1392,8 @@ typedef struct _MPI2_FW_IMAGE_HEADER {
#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013)
#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014)
#define MPI25_FW_HEADER_PID_FAMILY_3108_SAS (0x0021)
+#define MPI26_FW_HEADER_PID_FAMILY_3324_SAS (0x0028)
+#define MPI26_FW_HEADER_PID_FAMILY_3516_SAS (0x0031)
/*use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
@@ -1388,6 +1401,7 @@ typedef struct _MPI2_FW_IMAGE_HEADER {
#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C)
#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30)
+#define MPI26_FW_HEADER_BOOTFLAGS_OFFSET (0x60)
#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64)
#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840)
@@ -1493,7 +1507,9 @@ typedef struct _MPI2_FLASH_LAYOUT_DATA {
#define MPI2_FLASH_REGION_CONFIG_1 (0x07)
#define MPI2_FLASH_REGION_CONFIG_2 (0x08)
#define MPI2_FLASH_REGION_MEGARAID (0x09)
-#define MPI2_FLASH_REGION_INIT (0x0A)
+#define MPI2_FLASH_REGION_COMMON_BOOT_BLOCK (0x0A)
+#define MPI2_FLASH_REGION_INIT (MPI2_FLASH_REGION_COMMON_BOOT_BLOCK)
+#define MPI2_FLASH_REGION_CBB_BACKUP (0x0D)
/*ImageRevision */
#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00)
@@ -1619,7 +1635,6 @@ typedef struct _MPI25_ENCRYPTED_HASH_DATA {
Mpi25EncryptedHashData_t, *pMpi25EncryptedHashData_t;
-
/****************************************************************************
* PowerManagementControl message
****************************************************************************/
@@ -1726,4 +1741,90 @@ typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY {
} MPI2_PWR_MGMT_CONTROL_REPLY, *PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
Mpi2PwrMgmtControlReply_t, *pMpi2PwrMgmtControlReply_t;
+/****************************************************************************
+* IO Unit Control messages (MPI v2.6 and later only.)
+****************************************************************************/
+
+/* IO Unit Control Request Message */
+typedef struct _MPI26_IOUNIT_CONTROL_REQUEST {
+ U8 Operation; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 DevHandle; /* 0x04 */
+ U8 IOCParameter; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved3; /* 0x0A */
+ U16 Reserved4; /* 0x0C */
+ U8 PhyNum; /* 0x0E */
+ U8 PrimFlags; /* 0x0F */
+ U32 Primitive; /* 0x10 */
+ U8 LookupMethod; /* 0x14 */
+ U8 Reserved5; /* 0x15 */
+ U16 SlotNumber; /* 0x16 */
+ U64 LookupAddress; /* 0x18 */
+ U32 IOCParameterValue; /* 0x20 */
+ U32 Reserved7; /* 0x24 */
+ U32 Reserved8; /* 0x28 */
+} MPI26_IOUNIT_CONTROL_REQUEST,
+ *PTR_MPI26_IOUNIT_CONTROL_REQUEST,
+ Mpi26IoUnitControlRequest_t,
+ *pMpi26IoUnitControlRequest_t;
+
+/* values for the Operation field */
+#define MPI26_CTRL_OP_CLEAR_ALL_PERSISTENT (0x02)
+#define MPI26_CTRL_OP_SAS_PHY_LINK_RESET (0x06)
+#define MPI26_CTRL_OP_SAS_PHY_HARD_RESET (0x07)
+#define MPI26_CTRL_OP_PHY_CLEAR_ERROR_LOG (0x08)
+#define MPI26_CTRL_OP_SAS_SEND_PRIMITIVE (0x0A)
+#define MPI26_CTRL_OP_FORCE_FULL_DISCOVERY (0x0B)
+#define MPI26_CTRL_OP_REMOVE_DEVICE (0x0D)
+#define MPI26_CTRL_OP_LOOKUP_MAPPING (0x0E)
+#define MPI26_CTRL_OP_SET_IOC_PARAMETER (0x0F)
+#define MPI26_CTRL_OP_ENABLE_FP_DEVICE (0x10)
+#define MPI26_CTRL_OP_DISABLE_FP_DEVICE (0x11)
+#define MPI26_CTRL_OP_ENABLE_FP_ALL (0x12)
+#define MPI26_CTRL_OP_DISABLE_FP_ALL (0x13)
+#define MPI26_CTRL_OP_DEV_ENABLE_NCQ (0x14)
+#define MPI26_CTRL_OP_DEV_DISABLE_NCQ (0x15)
+#define MPI26_CTRL_OP_SHUTDOWN (0x16)
+#define MPI26_CTRL_OP_DEV_ENABLE_PERSIST_CONNECTION (0x17)
+#define MPI26_CTRL_OP_DEV_DISABLE_PERSIST_CONNECTION (0x18)
+#define MPI26_CTRL_OP_DEV_CLOSE_PERSIST_CONNECTION (0x19)
+#define MPI26_CTRL_OP_PRODUCT_SPECIFIC_MIN (0x80)
+
+/* values for the PrimFlags field */
+#define MPI26_CTRL_PRIMFLAGS_SINGLE (0x08)
+#define MPI26_CTRL_PRIMFLAGS_TRIPLE (0x02)
+#define MPI26_CTRL_PRIMFLAGS_REDUNDANT (0x01)
+
+/* values for the LookupMethod field */
+#define MPI26_CTRL_LOOKUP_METHOD_WWID_ADDRESS (0x01)
+#define MPI26_CTRL_LOOKUP_METHOD_ENCLOSURE_SLOT (0x02)
+#define MPI26_CTRL_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03)
+
+
+/* IO Unit Control Reply Message */
+typedef struct _MPI26_IOUNIT_CONTROL_REPLY {
+ U8 Operation; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 DevHandle; /* 0x04 */
+ U8 IOCParameter; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved3; /* 0x0A */
+ U16 Reserved4; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+} MPI26_IOUNIT_CONTROL_REPLY,
+ *PTR_MPI26_IOUNIT_CONTROL_REPLY,
+ Mpi26IoUnitControlReply_t,
+ *pMpi26IoUnitControlReply_t;
+
+
#endif
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_raid.h b/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
index 13d93ca029d5..1c0eeeeb5eaf 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2014 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_raid.h
* Title: MPI Integrated RAID messages and structures
* Creation Date: April 26, 2007
*
- * mpi2_raid.h Version: 02.00.10
+ * mpi2_raid.h Version: 02.00.11
*
* Version History
* ---------------
@@ -31,6 +31,7 @@
* 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR.
* Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.
* 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI.
+ * 11-18-14 02.00.11 Updated copyright information.
* --------------------------------------------------------------------------
*/
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_sas.h b/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
index 156e30543a2f..c10c2c02a945 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_sas.h
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: February 9, 2007
*
- * mpi2_sas.h Version: 02.00.08
+ * mpi2_sas.h Version: 02.00.10
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -32,6 +32,9 @@
* Passthrough Request message.
* 08-19-13 02.00.08 Made MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL obsolete
* for anything newer than MPI v2.0.
+ * 11-18-14 02.00.09 Updated copyright information.
+ * 03-16-15 02.00.10 Updated for MPI v2.6.
+ * Added MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA.
* --------------------------------------------------------------------------
*/
@@ -183,6 +186,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST {
/*values for PassthroughFlags field */
#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA (0x0040)
#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020)
#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010)
#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004)
@@ -216,6 +220,8 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REPLY {
/****************************************************************************
* SAS IO Unit Control messages
+* (MPI v2.5 and earlier only.
+* Replaced by IO Unit Control messages in MPI v2.6 and later.)
****************************************************************************/
/*SAS IO Unit Control Request Message */
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
index 1629e5bce7e1..5f9289a1166f 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2014 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_tool.h
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.12
+ * mpi2_tool.h Version: 02.00.13
*
* Version History
* ---------------
@@ -34,6 +34,7 @@
* it uses MPI Chain SGE as well as MPI Simple SGE.
* 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
* 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
+ * 11-18-14 02.00.13 Updated copyright information.
* --------------------------------------------------------------------------
*/
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_type.h b/drivers/scsi/mpt3sas/mpi/mpi2_type.h
index 99ab093602e8..92a81abc2c31 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_type.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_type.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2014 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_type.h
* Title: MPI basic type definitions
* Creation Date: August 16, 2006
*
- * mpi2_type.h Version: 02.00.00
+ * mpi2_type.h Version: 02.00.01
*
* Version History
* ---------------
@@ -14,6 +14,7 @@
* Date Version Description
* -------- -------- ------------------------------------------------------
* 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 11-18-14 02.00.01 Updated copyright information.
* --------------------------------------------------------------------------
*/
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 83658acddd58..e4db5fb3239a 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -83,6 +83,10 @@ static int msix_disable = -1;
module_param(msix_disable, int, 0);
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+static int smp_affinity_enable = 1;
+module_param(smp_affinity_enable, int, S_IRUGO);
+MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
+
static int max_msix_vectors = -1;
module_param(max_msix_vectors, int, 0);
MODULE_PARM_DESC(max_msix_vectors,
@@ -395,6 +399,9 @@ _base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
desc = "insufficient resources";
break;
+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
+ desc = "insufficient power";
+ break;
case MPI2_IOCSTATUS_INVALID_FIELD:
desc = "invalid field";
break;
@@ -772,7 +779,7 @@ mpt3sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
- return 1;
+ return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
if (ioc->base_cmds.status == MPT3_CMD_NOT_USED)
return 1;
@@ -803,6 +810,7 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
Mpi2EventNotificationReply_t *mpi_reply;
Mpi2EventAckRequest_t *ack_request;
u16 smid;
+ struct _event_ack_list *delayed_event_ack;
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
if (!mpi_reply)
@@ -816,8 +824,18 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
goto out;
smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ delayed_event_ack = kzalloc(sizeof(*delayed_event_ack),
+ GFP_ATOMIC);
+ if (!delayed_event_ack)
+ goto out;
+ INIT_LIST_HEAD(&delayed_event_ack->list);
+ delayed_event_ack->Event = mpi_reply->Event;
+ delayed_event_ack->EventContext = mpi_reply->EventContext;
+ list_add_tail(&delayed_event_ack->list,
+ &ioc->delayed_event_ack_list);
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "DELAYED: EVENT ACK: event (0x%04x)\n",
+ ioc->name, le16_to_cpu(mpi_reply->Event)));
goto out;
}
@@ -1348,6 +1366,7 @@ _base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr)
u8 sgl_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
MPI25_IEEE_SGE_FLAGS_END_OF_LIST);
+
_base_add_sg_single_ieee(paddr, sgl_flags, 0, 0, -1);
}
@@ -1797,9 +1816,10 @@ _base_free_irq(struct MPT3SAS_ADAPTER *ioc)
list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
list_del(&reply_q->list);
- irq_set_affinity_hint(reply_q->vector, NULL);
- free_cpumask_var(reply_q->affinity_hint);
- synchronize_irq(reply_q->vector);
+ if (smp_affinity_enable) {
+ irq_set_affinity_hint(reply_q->vector, NULL);
+ free_cpumask_var(reply_q->affinity_hint);
+ }
free_irq(reply_q->vector, reply_q);
kfree(reply_q);
}
@@ -1829,9 +1849,12 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector)
reply_q->msix_index = index;
reply_q->vector = vector;
- if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL))
- return -ENOMEM;
- cpumask_clear(reply_q->affinity_hint);
+ if (smp_affinity_enable) {
+ if (!zalloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL)) {
+ kfree(reply_q);
+ return -ENOMEM;
+ }
+ }
atomic_set(&reply_q->busy, 0);
if (ioc->msix_enable)
@@ -1845,6 +1868,7 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector)
if (r) {
pr_err(MPT3SAS_FMT "unable to allocate interrupt %d!\n",
reply_q->name, vector);
+ free_cpumask_var(reply_q->affinity_hint);
kfree(reply_q);
return -EBUSY;
}
@@ -1894,16 +1918,17 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
for (i = 0 ; i < group ; i++) {
ioc->cpu_msix_table[cpu] = index;
- cpumask_or(reply_q->affinity_hint,
+ if (smp_affinity_enable)
+ cpumask_or(reply_q->affinity_hint,
reply_q->affinity_hint, get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
-
- if (irq_set_affinity_hint(reply_q->vector,
+ if (smp_affinity_enable)
+ if (irq_set_affinity_hint(reply_q->vector,
reply_q->affinity_hint))
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "error setting affinity hint for irq vector %d\n",
- ioc->name, reply_q->vector));
+ dinitprintk(ioc, pr_info(MPT3SAS_FMT
+ "Err setting affinity hint to irq vector %d\n",
+ ioc->name, reply_q->vector));
index++;
}
}
@@ -1961,6 +1986,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
} else if (max_msix_vectors == 0)
goto try_ioapic;
+ if (ioc->msix_vector_count < ioc->cpu_count)
+ smp_affinity_enable = 0;
+
entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
GFP_KERNEL);
if (!entries) {
@@ -2231,6 +2259,12 @@ mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr)
return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
}
+static inline u8
+_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
+{
+ return ioc->cpu_msix_table[raw_smp_processor_id()];
+}
+
/**
* mpt3sas_base_get_smid - obtain a free smid from internal queue
* @ioc: per adapter object
@@ -2291,6 +2325,7 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,
request->scmd = scmd;
request->cb_idx = cb_idx;
smid = request->smid;
+ request->msix_io = _base_get_msix_index(ioc);
list_del(&request->tracker_list);
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
return smid;
@@ -2413,12 +2448,6 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
}
#endif
-static inline u8
-_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
-{
- return ioc->cpu_msix_table[raw_smp_processor_id()];
-}
-
/**
* mpt3sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
* @ioc: per adapter object
@@ -2472,18 +2501,19 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
* mpt3sas_base_put_smid_hi_priority - send Task Managment request to firmware
* @ioc: per adapter object
* @smid: system request message index
- *
+ * @msix_task: msix_task will be same as msix of IO incase of task abort else 0.
* Return nothing.
*/
void
-mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+ u16 msix_task)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.HighPriority.RequestFlags =
MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
- descriptor.HighPriority.MSIxIndex = 0;
+ descriptor.HighPriority.MSIxIndex = msix_task;
descriptor.HighPriority.SMID = cpu_to_le16(smid);
descriptor.HighPriority.LMID = 0;
descriptor.HighPriority.Reserved1 = 0;
@@ -3185,20 +3215,35 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
}
ioc->shost->sg_tablesize = sg_tablesize;
- ioc->hi_priority_depth = facts->HighPriorityCredit;
- ioc->internal_depth = ioc->hi_priority_depth + (5);
+ ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)),
+ (facts->RequestCredit / 4));
+ if (ioc->internal_depth < INTERNAL_CMDS_COUNT) {
+ if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT +
+ INTERNAL_SCSIIO_CMDS_COUNT)) {
+ pr_err(MPT3SAS_FMT "IOC doesn't have enough Request \
+ Credits, it has just %d number of credits\n",
+ ioc->name, facts->RequestCredit);
+ return -ENOMEM;
+ }
+ ioc->internal_depth = 10;
+ }
+
+ ioc->hi_priority_depth = ioc->internal_depth - (5);
/* command line tunables for max controller queue depth */
if (max_queue_depth != -1 && max_queue_depth != 0) {
max_request_credit = min_t(u16, max_queue_depth +
- ioc->hi_priority_depth + ioc->internal_depth,
- facts->RequestCredit);
+ ioc->internal_depth, facts->RequestCredit);
if (max_request_credit > MAX_HBA_QUEUE_DEPTH)
max_request_credit = MAX_HBA_QUEUE_DEPTH;
} else
max_request_credit = min_t(u16, facts->RequestCredit,
MAX_HBA_QUEUE_DEPTH);
- ioc->hba_queue_depth = max_request_credit;
+ /* Firmware maintains additional facts->HighPriorityCredit number of
+ * credits for HiPriprity Request messages, so hba queue depth will be
+ * sum of max_request_credit and high priority queue depth.
+ */
+ ioc->hba_queue_depth = max_request_credit + ioc->hi_priority_depth;
/* request frame size */
ioc->request_sz = facts->IOCRequestFrameSize * 4;
@@ -3206,6 +3251,19 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
/* reply frame size */
ioc->reply_sz = facts->ReplyFrameSize * 4;
+ /* chain segment size */
+ if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
+ if (facts->IOCMaxChainSegmentSize)
+ ioc->chain_segment_sz =
+ facts->IOCMaxChainSegmentSize *
+ MAX_CHAIN_ELEMT_SZ;
+ else
+ /* set to 128 bytes size if IOCMaxChainSegmentSize is zero */
+ ioc->chain_segment_sz = DEFAULT_NUM_FWCHAIN_ELEMTS *
+ MAX_CHAIN_ELEMT_SZ;
+ } else
+ ioc->chain_segment_sz = ioc->request_sz;
+
/* calculate the max scatter element size */
sge_size = max_t(u16, ioc->sge_size, ioc->sge_size_ieee);
@@ -3217,7 +3275,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->max_sges_in_main_message = max_sge_elements/sge_size;
/* now do the same for a chain buffer */
- max_sge_elements = ioc->request_sz - sge_size;
+ max_sge_elements = ioc->chain_segment_sz - sge_size;
ioc->max_sges_in_chain_message = max_sge_elements/sge_size;
/*
@@ -3245,7 +3303,6 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->reply_post_queue_depth += 16 -
(ioc->reply_post_queue_depth % 16);
-
if (ioc->reply_post_queue_depth >
facts->MaxReplyDescriptorPostQueueDepth) {
ioc->reply_post_queue_depth =
@@ -3327,7 +3384,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
/* set the scsi host can_queue depth
* with some internal commands that could be outstanding
*/
- ioc->shost->can_queue = ioc->scsiio_depth;
+ ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT;
dinitprintk(ioc, pr_info(MPT3SAS_FMT
"scsi host: can_queue depth (%d)\n",
ioc->name, ioc->shost->can_queue));
@@ -3354,8 +3411,9 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH)
goto out;
- retry_sz += 64;
- ioc->hba_queue_depth = max_request_credit - retry_sz;
+ retry_sz = 64;
+ ioc->hba_queue_depth -= retry_sz;
+ _base_release_memory_pools(ioc);
goto retry_allocation;
}
@@ -3410,7 +3468,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
goto out;
}
ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
- ioc->request_sz, 16, 0);
+ ioc->chain_segment_sz, 16, 0);
if (!ioc->chain_dma_pool) {
pr_err(MPT3SAS_FMT "chain_dma_pool: pci_pool_create failed\n",
ioc->name);
@@ -3424,13 +3482,13 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->chain_depth = i;
goto chain_done;
}
- total_sz += ioc->request_sz;
+ total_sz += ioc->chain_segment_sz;
}
chain_done:
dinitprintk(ioc, pr_info(MPT3SAS_FMT
"chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n",
- ioc->name, ioc->chain_depth, ioc->request_sz,
- ((ioc->chain_depth * ioc->request_sz))/1024));
+ ioc->name, ioc->chain_depth, ioc->chain_segment_sz,
+ ((ioc->chain_depth * ioc->chain_segment_sz))/1024));
/* initialize hi-priority queue smid's */
ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
@@ -4291,6 +4349,10 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
facts->IOCRequestFrameSize =
le16_to_cpu(mpi_reply.IOCRequestFrameSize);
+ if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
+ facts->IOCMaxChainSegmentSize =
+ le16_to_cpu(mpi_reply.IOCMaxChainSegmentSize);
+ }
facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
ioc->shost->max_id = -1;
@@ -4973,6 +5035,8 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
u32 reply_address;
u16 smid;
struct _tr_list *delayed_tr, *delayed_tr_next;
+ struct _sc_list *delayed_sc, *delayed_sc_next;
+ struct _event_ack_list *delayed_event_ack, *delayed_event_ack_next;
u8 hide_flag;
struct adapter_reply_queue *reply_q;
long reply_post_free;
@@ -4995,6 +5059,18 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
kfree(delayed_tr);
}
+ list_for_each_entry_safe(delayed_sc, delayed_sc_next,
+ &ioc->delayed_sc_list, list) {
+ list_del(&delayed_sc->list);
+ kfree(delayed_sc);
+ }
+
+ list_for_each_entry_safe(delayed_event_ack, delayed_event_ack_next,
+ &ioc->delayed_event_ack_list, list) {
+ list_del(&delayed_event_ack->list);
+ kfree(delayed_event_ack);
+ }
+
/* initialize the scsi lookup free list */
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
INIT_LIST_HEAD(&ioc->free_list);
@@ -5226,6 +5302,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
ioc->build_zero_len_sge = &_base_build_zero_len_sge;
break;
case MPI25_VERSION:
+ case MPI26_VERSION:
/*
* In SAS3.0,
* SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 5ad271efbd45..32580b514b18 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -73,9 +73,9 @@
#define MPT3SAS_DRIVER_NAME "mpt3sas"
#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION "09.102.00.00"
-#define MPT3SAS_MAJOR_VERSION 9
-#define MPT3SAS_MINOR_VERSION 102
+#define MPT3SAS_DRIVER_VERSION "12.100.00.00"
+#define MPT3SAS_MAJOR_VERSION 12
+#define MPT3SAS_MINOR_VERSION 100
#define MPT3SAS_BUILD_VERSION 0
#define MPT3SAS_RELEASE_VERSION 00
@@ -122,11 +122,16 @@
#define NO_SLEEP 0
#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */
+/* reserved for issuing internally framed scsi io cmds */
+#define INTERNAL_SCSIIO_CMDS_COUNT 3
#define MPI3_HIM_MASK 0xFFFFFFFF /* mask every bit*/
#define MPT3SAS_INVALID_DEVICE_HANDLE 0xFFFF
+#define MAX_CHAIN_ELEMT_SZ 16
+#define DEFAULT_NUM_FWCHAIN_ELEMTS 8
+
/*
* reset phases
*/
@@ -398,6 +403,7 @@ struct MPT3SAS_DEVICE {
u8 configured_lun;
u8 block;
u8 tlr_snoop_check;
+ u8 ignore_delay_remove;
};
#define MPT3_CMD_NOT_USED 0x8000 /* free */
@@ -643,6 +649,7 @@ struct chain_tracker {
* @cb_idx: callback index
* @direct_io: To indicate whether I/O is direct (WARPDRIVE)
* @tracker_list: list of free request (ioc->free_list)
+ * @msix_io: IO's msix
*/
struct scsiio_tracker {
u16 smid;
@@ -651,6 +658,7 @@ struct scsiio_tracker {
u8 direct_io;
struct list_head chain_list;
struct list_head tracker_list;
+ u16 msix_io;
};
/**
@@ -676,6 +684,25 @@ struct _tr_list {
u16 state;
};
+/**
+ * struct _sc_list - delayed SAS_IO_UNIT_CONTROL message list
+ * @handle: device handle
+ */
+struct _sc_list {
+ struct list_head list;
+ u16 handle;
+};
+
+/**
+ * struct _event_ack_list - delayed event acknowledgment list
+ * @Event: Event ID
+ * @EventContext: used to track the event uniquely
+ */
+struct _event_ack_list {
+ struct list_head list;
+ u16 Event;
+ u32 EventContext;
+};
/**
* struct adapter_reply_queue - the reply queue struct
@@ -737,7 +764,7 @@ struct mpt3sas_facts {
u32 IOCCapabilities;
union mpi3_version_union FWVersion;
u16 IOCRequestFrameSize;
- u16 Reserved3;
+ u16 IOCMaxChainSegmentSize;
u16 MaxInitiators;
u16 MaxTargets;
u16 MaxSasExpanders;
@@ -884,6 +911,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @max_sges_in_chain_message: number sg elements per chain
* @chains_needed_per_io: max chains per io
* @chain_depth: total chains allocated
+ * @chain_segment_sz: gives the max number of
+ * SGEs accommodate on single chain buffer
* @hi_priority_smid:
* @hi_priority:
* @hi_priority_dma:
@@ -921,6 +950,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @replyPostRegisterIndex: index of next position in Reply Desc Post Queue
* @delayed_tr_list: target reset link list
* @delayed_tr_volume_list: volume target reset link list
+ * @delayed_sc_list:
+ * @delayed_event_ack_list:
* @temp_sensors_count: flag to carry the number of temperature sensors
* @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and
* pci resource handling. PCI resource freeing will lead to free
@@ -1089,6 +1120,7 @@ struct MPT3SAS_ADAPTER {
u16 max_sges_in_chain_message;
u16 chains_needed_per_io;
u32 chain_depth;
+ u16 chain_segment_sz;
/* hi-priority queue */
u16 hi_priority_smid;
@@ -1142,6 +1174,8 @@ struct MPT3SAS_ADAPTER {
struct list_head delayed_tr_list;
struct list_head delayed_tr_volume_list;
+ struct list_head delayed_sc_list;
+ struct list_head delayed_event_ack_list;
u8 temp_sensors_count;
struct mutex pci_access_mutex;
@@ -1213,7 +1247,8 @@ void mpt3sas_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 handle);
void mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 handle);
-void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid);
+void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc,
+ u16 smid, u16 msix_task);
void mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid);
void mpt3sas_base_initialize_callback_handler(void);
u8 mpt3sas_base_register_callback_handler(MPT_CALLBACK cb_func);
@@ -1259,6 +1294,8 @@ void mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle);
void mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
void mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
u64 sas_address);
+u8 mpt3sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc,
+ u16 smid);
struct _sas_node *mpt3sas_scsih_expander_find_by_handle(
struct MPT3SAS_ADAPTER *ioc, u16 handle);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index d8366b056b70..7d00f09666b6 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -401,7 +401,8 @@ mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
Mpi2EventNotificationReply_t *mpi_reply;
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
- mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
+ if (mpi_reply)
+ mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
return 1;
}
@@ -410,7 +411,7 @@ mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
* @ioc: per adapter object
* @iocpp: The ioc pointer is returned in this.
* @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
- * MPI25_VERSION for mpt3ctl ioctl device.
+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device.
*
* Return (-1) means error, else ioc_number.
*/
@@ -419,6 +420,7 @@ _ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp,
int mpi_version)
{
struct MPT3SAS_ADAPTER *ioc;
+ int version = 0;
/* global ioc lock to protect controller on list operations */
spin_lock(&gioc_lock);
list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
@@ -427,8 +429,21 @@ _ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp,
/* Check whether this ioctl command is from right
* ioctl device or not, if not continue the search.
*/
- if (ioc->hba_mpi_version_belonged != mpi_version)
- continue;
+ version = ioc->hba_mpi_version_belonged;
+ /* MPI25_VERSION and MPI26_VERSION uses same ioctl
+ * device.
+ */
+ if (mpi_version == (MPI25_VERSION | MPI26_VERSION)) {
+ if ((version == MPI25_VERSION) ||
+ (version == MPI26_VERSION))
+ goto out;
+ else
+ continue;
+ } else {
+ if (version != mpi_version)
+ continue;
+ }
+out:
spin_unlock(&gioc_lock);
*iocpp = ioc;
return ioc_number;
@@ -817,7 +832,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
tm_request->DevHandle));
ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
data_in_dma, data_in_sz);
- mpt3sas_base_put_smid_hi_priority(ioc, smid);
+ mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
break;
}
case MPI2_FUNCTION_SMP_PASSTHROUGH:
@@ -1053,6 +1068,7 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION);
break;
case MPI25_VERSION:
+ case MPI26_VERSION:
karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3;
strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION);
break;
@@ -2203,7 +2219,7 @@ _ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd,
* @arg - user space data buffer
* @compat - handles 32 bit applications in 64bit os
* @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
- * MPI25_VERSION for mpt3ctl ioctl device.
+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device.
*/
static long
_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
@@ -2341,10 +2357,12 @@ _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
- /* pass MPI25_VERSION value, to indicate that this ioctl cmd
+ /* pass MPI25_VERSION | MPI26_VERSION value,
+ * to indicate that this ioctl cmd
* came from mpt3ctl ioctl device.
*/
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI25_VERSION);
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0,
+ MPI25_VERSION | MPI26_VERSION);
return ret;
}
@@ -2379,7 +2397,8 @@ _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
{
long ret;
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI25_VERSION);
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1,
+ MPI25_VERSION | MPI26_VERSION);
return ret;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 9ab77b06434d..e0e4920d0fa6 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -1589,10 +1589,16 @@ scsih_get_resync(struct device *dev)
percent_complete = 0;
out:
- if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
- if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+ break;
+ case MPI25_VERSION:
+ case MPI26_VERSION:
raid_set_resync(mpt3sas_raid_template, dev, percent_complete);
+ break;
+ }
}
/**
@@ -1650,10 +1656,15 @@ scsih_get_state(struct device *dev)
break;
}
out:
- if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
raid_set_state(mpt2sas_raid_template, dev, state);
- if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+ break;
+ case MPI25_VERSION:
+ case MPI26_VERSION:
raid_set_state(mpt3sas_raid_template, dev, state);
+ break;
+ }
}
/**
@@ -1682,12 +1693,17 @@ _scsih_set_level(struct MPT3SAS_ADAPTER *ioc,
break;
}
- if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
raid_set_level(mpt2sas_raid_template,
- &sdev->sdev_gendev, level);
- if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+ &sdev->sdev_gendev, level);
+ break;
+ case MPI25_VERSION:
+ case MPI26_VERSION:
raid_set_level(mpt3sas_raid_template,
- &sdev->sdev_gendev, level);
+ &sdev->sdev_gendev, level);
+ break;
+ }
}
@@ -1937,7 +1953,15 @@ scsih_slave_configure(struct scsi_device *sdev)
if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
qdepth = MPT3SAS_SAS_QUEUE_DEPTH;
ssp_target = 1;
- ds = "SSP";
+ if (sas_device->device_info &
+ MPI2_SAS_DEVICE_INFO_SEP) {
+ sdev_printk(KERN_WARNING, sdev,
+ "set ignore_delay_remove for handle(0x%04x)\n",
+ sas_device_priv_data->sas_target->handle);
+ sas_device_priv_data->ignore_delay_remove = 1;
+ ds = "SES";
+ } else
+ ds = "SSP";
} else {
qdepth = MPT3SAS_SATA_QUEUE_DEPTH;
if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
@@ -2193,6 +2217,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel,
unsigned long timeleft;
struct scsiio_tracker *scsi_lookup = NULL;
int rc;
+ u16 msix_task = 0;
if (m_type == TM_MUTEX_ON)
mutex_lock(&ioc->tm_cmds.mutex);
@@ -2256,7 +2281,12 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel,
int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
mpt3sas_scsih_set_tm_flag(ioc, handle);
init_completion(&ioc->tm_cmds.done);
- mpt3sas_base_put_smid_hi_priority(ioc, smid);
+ if ((type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) &&
+ (scsi_lookup->msix_io < ioc->reply_queue_count))
+ msix_task = scsi_lookup->msix_io;
+ else
+ msix_task = 0;
+ mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task);
timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -2383,7 +2413,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
(unsigned long long)
sas_device->enclosure_logical_id,
sas_device->slot);
- if (sas_device->connector_name)
+ if (sas_device->connector_name[0] != '\0')
starget_printk(KERN_INFO, starget,
"enclosure level(0x%04x),connector name(%s)\n",
sas_device->enclosure_level,
@@ -2927,6 +2957,12 @@ _scsih_block_io_all_device(struct MPT3SAS_ADAPTER *ioc)
continue;
if (sas_device_priv_data->block)
continue;
+ if (sas_device_priv_data->ignore_delay_remove) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s skip device_block for SES handle(0x%04x)\n",
+ __func__, sas_device_priv_data->sas_target->handle);
+ continue;
+ }
_scsih_internal_device_block(sdev, sas_device_priv_data);
}
}
@@ -2959,6 +2995,12 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
continue;
if (sas_device->pend_sas_rphy_add)
continue;
+ if (sas_device_priv_data->ignore_delay_remove) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s skip device_block for SES handle(0x%04x)\n",
+ __func__, sas_device_priv_data->sas_target->handle);
+ continue;
+ }
_scsih_internal_device_block(sdev, sas_device_priv_data);
}
@@ -3118,7 +3160,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
" slot(%d)\n", ioc->name, (unsigned long long)
sas_device->enclosure_logical_id,
sas_device->slot));
- if (sas_device->connector_name)
+ if (sas_device->connector_name[0] != '\0')
dewtprintk(ioc, pr_info(MPT3SAS_FMT
"setting delete flag: enclosure level(0x%04x),"
" connector name( %s)\n", ioc->name,
@@ -3151,7 +3193,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
mpi_request->DevHandle = cpu_to_le16(handle);
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
- mpt3sas_base_put_smid_hi_priority(ioc, smid);
+ mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
out:
@@ -3186,6 +3228,7 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
Mpi2SasIoUnitControlRequest_t *mpi_request;
u16 smid_sas_ctrl;
u32 ioc_state;
+ struct _sc_list *delayed_sc;
if (ioc->remove_host) {
dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -3228,9 +3271,16 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
smid_sas_ctrl = mpt3sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
if (!smid_sas_ctrl) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- return 1;
+ delayed_sc = kzalloc(sizeof(*delayed_sc), GFP_ATOMIC);
+ if (!delayed_sc)
+ return _scsih_check_for_pending_tm(ioc, smid);
+ INIT_LIST_HEAD(&delayed_sc->list);
+ delayed_sc->handle = mpi_request_tm->DevHandle;
+ list_add_tail(&delayed_sc->list, &ioc->delayed_sc_list);
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "DELAYED:sc:handle(0x%04x), (open)\n",
+ ioc->name, handle));
+ return _scsih_check_for_pending_tm(ioc, smid);
}
dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -3281,7 +3331,7 @@ _scsih_sas_control_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid,
pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
}
- return 1;
+ return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
}
/**
@@ -3332,7 +3382,7 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
mpi_request->DevHandle = cpu_to_le16(handle);
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
- mpt3sas_base_put_smid_hi_priority(ioc, smid);
+ mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
}
/**
@@ -3388,6 +3438,142 @@ _scsih_tm_volume_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid,
return _scsih_check_for_pending_tm(ioc, smid);
}
+/**
+ * _scsih_issue_delayed_event_ack - issue delayed Event ACK messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @event: Event ID
+ * @event_context: used to track events uniquely
+ *
+ * Context - processed in interrupt context.
+ */
+void
+_scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event,
+ u32 event_context)
+{
+ Mpi2EventAckRequest_t *ack_request;
+ int i = smid - ioc->internal_smid;
+ unsigned long flags;
+
+ /* Without releasing the smid just update the
+ * call back index and reuse the same smid for
+ * processing this delayed request
+ */
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ ioc->internal_lookup[i].cb_idx = ioc->base_cb_idx;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n",
+ ioc->name, le16_to_cpu(event), smid,
+ ioc->base_cb_idx));
+ ack_request = mpt3sas_base_get_msg_frame(ioc, smid);
+ memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
+ ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
+ ack_request->Event = event;
+ ack_request->EventContext = event_context;
+ ack_request->VF_ID = 0; /* TODO */
+ ack_request->VP_ID = 0;
+ mpt3sas_base_put_smid_default(ioc, smid);
+}
+
+/**
+ * _scsih_issue_delayed_sas_io_unit_ctrl - issue delayed
+ * sas_io_unit_ctrl messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle
+ *
+ * Context - processed in interrupt context.
+ */
+void
+_scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
+ u16 smid, u16 handle)
+ {
+ Mpi2SasIoUnitControlRequest_t *mpi_request;
+ u32 ioc_state;
+ int i = smid - ioc->internal_smid;
+ unsigned long flags;
+
+ if (ioc->remove_host) {
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: host has been removed\n",
+ __func__, ioc->name));
+ return;
+ } else if (ioc->pci_error_recovery) {
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: host in pci error recovery\n",
+ __func__, ioc->name));
+ return;
+ }
+ ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: host is not operational\n",
+ __func__, ioc->name));
+ return;
+ }
+
+ /* Without releasing the smid just update the
+ * call back index and reuse the same smid for
+ * processing this delayed request
+ */
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ ioc->internal_lookup[i].cb_idx = ioc->tm_sas_control_cb_idx;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
+ ioc->name, le16_to_cpu(handle), smid,
+ ioc->tm_sas_control_cb_idx));
+ mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
+ memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
+ mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
+ mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
+ mpi_request->DevHandle = handle;
+ mpt3sas_base_put_smid_default(ioc, smid);
+}
+
+/**
+ * _scsih_check_for_pending_internal_cmds - check for pending internal messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Context: Executed in interrupt context
+ *
+ * This will check delayed internal messages list, and process the
+ * next request.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+u8
+mpt3sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+ struct _sc_list *delayed_sc;
+ struct _event_ack_list *delayed_event_ack;
+
+ if (!list_empty(&ioc->delayed_event_ack_list)) {
+ delayed_event_ack = list_entry(ioc->delayed_event_ack_list.next,
+ struct _event_ack_list, list);
+ _scsih_issue_delayed_event_ack(ioc, smid,
+ delayed_event_ack->Event, delayed_event_ack->EventContext);
+ list_del(&delayed_event_ack->list);
+ kfree(delayed_event_ack);
+ return 0;
+ }
+
+ if (!list_empty(&ioc->delayed_sc_list)) {
+ delayed_sc = list_entry(ioc->delayed_sc_list.next,
+ struct _sc_list, list);
+ _scsih_issue_delayed_sas_io_unit_ctrl(ioc, smid,
+ delayed_sc->handle);
+ list_del(&delayed_sc->list);
+ kfree(delayed_sc);
+ return 0;
+ }
+ return 1;
+}
/**
* _scsih_check_for_pending_tm - check for pending task management
@@ -4084,6 +4270,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
desc_ioc_state = "eedp app tag error";
break;
+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
+ desc_ioc_state = "insufficient power";
+ break;
default:
desc_ioc_state = "unknown";
break;
@@ -4609,6 +4798,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
case MPI2_IOCSTATUS_INVALID_STATE:
case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
default:
scmd->result = DID_SOFT_ERROR << 16;
break;
@@ -8391,7 +8581,8 @@ static struct raid_function_template mpt3sas_raid_functions = {
* @pdev: PCI device struct
*
* return MPI2_VERSION for SAS 2.0 HBA devices,
- * MPI25_VERSION for SAS 3.0 HBA devices.
+ * MPI25_VERSION for SAS 3.0 HBA devices, and
+ * MPI26 VERSION for Cutlass & Invader SAS 3.0 HBA devices
*/
u16
_scsih_determine_hba_mpi_version(struct pci_dev *pdev)
@@ -8423,6 +8614,17 @@ _scsih_determine_hba_mpi_version(struct pci_dev *pdev)
case MPI25_MFGPAGE_DEVID_SAS3108_5:
case MPI25_MFGPAGE_DEVID_SAS3108_6:
return MPI25_VERSION;
+ case MPI26_MFGPAGE_DEVID_SAS3216:
+ case MPI26_MFGPAGE_DEVID_SAS3224:
+ case MPI26_MFGPAGE_DEVID_SAS3316_1:
+ case MPI26_MFGPAGE_DEVID_SAS3316_2:
+ case MPI26_MFGPAGE_DEVID_SAS3316_3:
+ case MPI26_MFGPAGE_DEVID_SAS3316_4:
+ case MPI26_MFGPAGE_DEVID_SAS3324_1:
+ case MPI26_MFGPAGE_DEVID_SAS3324_2:
+ case MPI26_MFGPAGE_DEVID_SAS3324_3:
+ case MPI26_MFGPAGE_DEVID_SAS3324_4:
+ return MPI26_VERSION;
}
return 0;
}
@@ -8456,7 +8658,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* Enumerate only SAS 3.0 HBA's if hbas_to_enumerate is two,
* for other generation HBA's return with -ENODEV
*/
- if ((hbas_to_enumerate == 2) && (hba_mpi_version != MPI25_VERSION))
+ if ((hbas_to_enumerate == 2) && (!(hba_mpi_version == MPI25_VERSION
+ || hba_mpi_version == MPI26_VERSION)))
return -ENODEV;
switch (hba_mpi_version) {
@@ -8478,6 +8681,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
break;
case MPI25_VERSION:
+ case MPI26_VERSION:
/* Use mpt3sas driver host template for SAS 3.0 HBA's */
shost = scsi_host_alloc(&mpt3sas_driver_template,
sizeof(struct MPT3SAS_ADAPTER));
@@ -8488,7 +8692,9 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->hba_mpi_version_belonged = hba_mpi_version;
ioc->id = mpt3_ids++;
sprintf(ioc->driver_name, "%s", MPT3SAS_DRIVER_NAME);
- if (pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION)
+ if ((ioc->hba_mpi_version_belonged == MPI25_VERSION &&
+ pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION) ||
+ (ioc->hba_mpi_version_belonged == MPI26_VERSION))
ioc->msix96_vector = 1;
break;
default:
@@ -8533,6 +8739,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ioc->raid_device_list);
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
INIT_LIST_HEAD(&ioc->delayed_tr_list);
+ INIT_LIST_HEAD(&ioc->delayed_sc_list);
+ INIT_LIST_HEAD(&ioc->delayed_event_ack_list);
INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
INIT_LIST_HEAD(&ioc->reply_queue_list);
@@ -8866,6 +9074,28 @@ static const struct pci_device_id mpt3sas_pci_table[] = {
PCI_ANY_ID, PCI_ANY_ID },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
PCI_ANY_ID, PCI_ANY_ID },
+ /* Cutlass ~ 3216 and 3224 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3216,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3224,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Intruder ~ 3316 and 3324 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_4,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_4,
+ PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index ca36d7ea0964..6a84b82d71bb 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -1418,7 +1418,6 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
u32 ioc_state;
unsigned long timeleft;
void *psge;
- u32 sgl_flags;
u8 issue_reset = 0;
void *data_out = NULL;
dma_addr_t data_out_dma;
@@ -1507,24 +1506,10 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
cpu_to_le16(sizeof(struct phy_error_log_request));
psge = &mpi_request->SGL;
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_control_request), data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_control_reply), data_out_dma +
- sizeof(struct phy_control_request));
+ ioc->build_sg(ioc, psge, data_out_dma,
+ sizeof(struct phy_control_request),
+ data_out_dma + sizeof(struct phy_control_request),
+ sizeof(struct phy_control_reply));
dtransportprintk(ioc, pr_info(MPT3SAS_FMT
"phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n",
@@ -1615,7 +1600,7 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
SMP_PHY_CONTROL_LINK_RESET);
/* handle hba phys */
- memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
+ memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request.Operation = hard_reset ?
MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index 02360de6b7e0..39285070f3b5 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -2629,7 +2629,7 @@ static void mvumi_shutdown(struct pci_dev *pdev)
mvumi_flush_cache(mhba);
}
-static int mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct mvumi_hba *mhba = NULL;
@@ -2648,7 +2648,7 @@ static int mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}
-static int mvumi_resume(struct pci_dev *pdev)
+static int __maybe_unused mvumi_resume(struct pci_dev *pdev)
{
int ret;
struct mvumi_hba *mhba = NULL;
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index d8a2b5185f56..3b11aad03752 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -2006,9 +2006,8 @@ EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps);
*/
void osd_set_caps(struct osd_cdb *cdb, const void *caps)
{
- bool is_ver1 = true;
/* NOTE: They start at same address */
- memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN);
+ memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN);
}
bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused)
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index ee00e27ba396..f6ad579280d4 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -37,6 +37,7 @@ typedef struct {
unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */
unsigned int failed:1; /* Failure flag */
unsigned wanted:1; /* Parport sharing busy flag */
+ unsigned int dev_no; /* Device number */
wait_queue_head_t *waiting;
struct Scsi_Host *host;
struct list_head list;
@@ -985,15 +986,40 @@ static struct scsi_host_template ppa_template = {
static LIST_HEAD(ppa_hosts);
+/*
+ * Finds the first available device number that can be alloted to the
+ * new ppa device and returns the address of the previous node so that
+ * we can add to the tail and have a list in the ascending order.
+ */
+
+static inline ppa_struct *find_parent(void)
+{
+ ppa_struct *dev, *par = NULL;
+ unsigned int cnt = 0;
+
+ if (list_empty(&ppa_hosts))
+ return NULL;
+
+ list_for_each_entry(dev, &ppa_hosts, list) {
+ if (dev->dev_no != cnt)
+ return par;
+ cnt++;
+ par = dev;
+ }
+
+ return par;
+}
+
static int __ppa_attach(struct parport *pb)
{
struct Scsi_Host *host;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
DEFINE_WAIT(wait);
- ppa_struct *dev;
+ ppa_struct *dev, *temp;
int ports;
int modes, ppb, ppb_hi;
int err = -ENOMEM;
+ struct pardev_cb ppa_cb;
dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL);
if (!dev)
@@ -1002,8 +1028,15 @@ static int __ppa_attach(struct parport *pb)
dev->mode = PPA_AUTODETECT;
dev->recon_tmo = PPA_RECON_TMO;
init_waitqueue_head(&waiting);
- dev->dev = parport_register_device(pb, "ppa", NULL, ppa_wakeup,
- NULL, 0, dev);
+ temp = find_parent();
+ if (temp)
+ dev->dev_no = temp->dev_no + 1;
+
+ memset(&ppa_cb, 0, sizeof(ppa_cb));
+ ppa_cb.private = dev;
+ ppa_cb.wakeup = ppa_wakeup;
+
+ dev->dev = parport_register_dev_model(pb, "ppa", &ppa_cb, dev->dev_no);
if (!dev->dev)
goto out;
@@ -1110,9 +1143,10 @@ static void ppa_detach(struct parport *pb)
}
static struct parport_driver ppa_driver = {
- .name = "ppa",
- .attach = ppa_attach,
- .detach = ppa_detach,
+ .name = "ppa",
+ .match_port = ppa_attach,
+ .detach = ppa_detach,
+ .devmodel = true,
};
static int __init ppa_driver_init(void)
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 6992ebc50c87..4dc06a13cab8 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -272,8 +272,8 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
iter = (uint32_t *)buf;
chksum = 0;
- for (cnt = 0; cnt < ((count >> 2) - 1); cnt++)
- chksum += le32_to_cpu(*iter++);
+ for (cnt = 0; cnt < ((count >> 2) - 1); cnt++, iter++)
+ chksum += le32_to_cpu(*iter);
chksum = ~chksum + 1;
*iter = cpu_to_le32(chksum);
} else {
@@ -562,6 +562,7 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
+ uint32_t faddr;
if (unlikely(pci_channel_offline(ha->pdev)))
return -EAGAIN;
@@ -569,9 +570,16 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EINVAL;
- if (IS_NOCACHE_VPD_TYPE(ha))
- ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2,
+ if (IS_NOCACHE_VPD_TYPE(ha)) {
+ faddr = ha->flt_region_vpd << 2;
+
+ if (IS_QLA27XX(ha) &&
+ qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_vpd_sec << 2;
+
+ ha->isp_ops->read_optrom(vha, ha->vpd, faddr,
ha->vpd_size);
+ }
return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
}
@@ -1909,7 +1917,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
if (qla2x00_reset_active(vha))
goto done;
- stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
+ stats = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct link_statistics), &stats_dma, GFP_KERNEL);
if (stats == NULL) {
ql_log(ql_log_warn, vha, 0x707d,
"Failed to allocate memory for stats.\n");
@@ -1957,7 +1966,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
do_div(pfc_host_stat->seconds_since_last_reset, HZ);
done_free:
- dma_pool_free(ha->s_dma_pool, stats, stats_dma);
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics),
+ stats, stats_dma);
done:
return pfc_host_stat;
}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index c26acde797f0..392c147d5793 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -2107,6 +2107,195 @@ qla8044_serdes_op(struct fc_bsg_job *bsg_job)
}
static int
+qla27xx_get_flash_upd_cap(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ struct qla_flash_update_caps cap;
+
+ if (!(IS_QLA27XX(ha)))
+ return -EPERM;
+
+ memset(&cap, 0, sizeof(cap));
+ cap.capabilities = (uint64_t)ha->fw_attributes_ext[1] << 48 |
+ (uint64_t)ha->fw_attributes_ext[0] << 32 |
+ (uint64_t)ha->fw_attributes_h << 16 |
+ (uint64_t)ha->fw_attributes;
+
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, &cap, sizeof(cap));
+ bsg_job->reply->reply_payload_rcv_len = sizeof(cap);
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+ return 0;
+}
+
+static int
+qla27xx_set_flash_upd_cap(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ uint64_t online_fw_attr = 0;
+ struct qla_flash_update_caps cap;
+
+ if (!(IS_QLA27XX(ha)))
+ return -EPERM;
+
+ memset(&cap, 0, sizeof(cap));
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, &cap, sizeof(cap));
+
+ online_fw_attr = (uint64_t)ha->fw_attributes_ext[1] << 48 |
+ (uint64_t)ha->fw_attributes_ext[0] << 32 |
+ (uint64_t)ha->fw_attributes_h << 16 |
+ (uint64_t)ha->fw_attributes;
+
+ if (online_fw_attr != cap.capabilities) {
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_INVALID_PARAM;
+ return -EINVAL;
+ }
+
+ if (cap.outage_duration < MAX_LOOP_TIMEOUT) {
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_INVALID_PARAM;
+ return -EINVAL;
+ }
+
+ bsg_job->reply->reply_payload_rcv_len = 0;
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+ return 0;
+}
+
+static int
+qla27xx_get_bbcr_data(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ struct qla_bbcr_data bbcr;
+ uint16_t loop_id, topo, sw_cap;
+ uint8_t domain, area, al_pa, state;
+ int rval;
+
+ if (!(IS_QLA27XX(ha)))
+ return -EPERM;
+
+ memset(&bbcr, 0, sizeof(bbcr));
+
+ if (vha->flags.bbcr_enable)
+ bbcr.status = QLA_BBCR_STATUS_ENABLED;
+ else
+ bbcr.status = QLA_BBCR_STATUS_DISABLED;
+
+ if (bbcr.status == QLA_BBCR_STATUS_ENABLED) {
+ rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,
+ &area, &domain, &topo, &sw_cap);
+ if (rval != QLA_SUCCESS) {
+ bbcr.status = QLA_BBCR_STATUS_UNKNOWN;
+ bbcr.state = QLA_BBCR_STATE_OFFLINE;
+ bbcr.mbx1 = loop_id;
+ goto done;
+ }
+
+ state = (vha->bbcr >> 12) & 0x1;
+
+ if (state) {
+ bbcr.state = QLA_BBCR_STATE_OFFLINE;
+ bbcr.offline_reason_code = QLA_BBCR_REASON_LOGIN_REJECT;
+ } else {
+ bbcr.state = QLA_BBCR_STATE_ONLINE;
+ bbcr.negotiated_bbscn = (vha->bbcr >> 8) & 0xf;
+ }
+
+ bbcr.configured_bbscn = vha->bbcr & 0xf;
+ }
+
+done:
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, &bbcr, sizeof(bbcr));
+ bsg_job->reply->reply_payload_rcv_len = sizeof(bbcr);
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+ return 0;
+}
+
+static int
+qla2x00_get_priv_stats(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
+ struct link_statistics *stats = NULL;
+ dma_addr_t stats_dma;
+ int rval = QLA_FUNCTION_FAILED;
+
+ if (test_bit(UNLOADING, &vha->dpc_flags))
+ goto done;
+
+ if (unlikely(pci_channel_offline(ha->pdev)))
+ goto done;
+
+ if (qla2x00_reset_active(vha))
+ goto done;
+
+ if (!IS_FWI2_CAPABLE(ha))
+ goto done;
+
+ stats = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct link_statistics), &stats_dma, GFP_KERNEL);
+ if (!stats) {
+ ql_log(ql_log_warn, vha, 0x70e2,
+ "Failed to allocate memory for stats.\n");
+ goto done;
+ }
+
+ memset(stats, 0, sizeof(struct link_statistics));
+
+ rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma);
+
+ if (rval != QLA_SUCCESS)
+ goto done_free;
+
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3,
+ (uint8_t *)stats, sizeof(struct link_statistics));
+
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, stats, sizeof(struct link_statistics));
+ bsg_job->reply->reply_payload_rcv_len = sizeof(struct link_statistics);
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+
+done_free:
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics),
+ stats, stats_dma);
+done:
+ return rval;
+}
+
+static int
qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
{
switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
@@ -2161,6 +2350,18 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
case QL_VND_SERDES_OP_EX:
return qla8044_serdes_op(bsg_job);
+ case QL_VND_GET_FLASH_UPDATE_CAPS:
+ return qla27xx_get_flash_upd_cap(bsg_job);
+
+ case QL_VND_SET_FLASH_UPDATE_CAPS:
+ return qla27xx_set_flash_upd_cap(bsg_job);
+
+ case QL_VND_GET_BBCR_DATA:
+ return qla27xx_get_bbcr_data(bsg_job);
+
+ case QL_VND_GET_PRIV_STATS:
+ return qla2x00_get_priv_stats(bsg_job);
+
default:
return -ENOSYS;
}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index d38f9efa56fa..c80192d45536 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -25,6 +25,10 @@
#define QL_VND_FX00_MGMT_CMD 0x12
#define QL_VND_SERDES_OP 0x13
#define QL_VND_SERDES_OP_EX 0x14
+#define QL_VND_GET_FLASH_UPDATE_CAPS 0x15
+#define QL_VND_SET_FLASH_UPDATE_CAPS 0x16
+#define QL_VND_GET_BBCR_DATA 0x17
+#define QL_VND_GET_PRIV_STATS 0x18
/* BSG Vendor specific subcode returns */
#define EXT_STATUS_OK 0
@@ -232,4 +236,34 @@ struct qla_serdes_reg_ex {
uint32_t val;
} __packed;
+struct qla_flash_update_caps {
+ uint64_t capabilities;
+ uint32_t outage_duration;
+ uint8_t reserved[20];
+} __packed;
+
+/* BB_CR Status */
+#define QLA_BBCR_STATUS_DISABLED 0
+#define QLA_BBCR_STATUS_ENABLED 1
+#define QLA_BBCR_STATUS_UNKNOWN 2
+
+/* BB_CR State */
+#define QLA_BBCR_STATE_OFFLINE 0
+#define QLA_BBCR_STATE_ONLINE 1
+
+/* BB_CR Offline Reason Code */
+#define QLA_BBCR_REASON_PORT_SPEED 1
+#define QLA_BBCR_REASON_PEER_PORT 2
+#define QLA_BBCR_REASON_SWITCH 3
+#define QLA_BBCR_REASON_LOGIN_REJECT 4
+
+struct qla_bbcr_data {
+ uint8_t status; /* 1 - enabled, 0 - Disabled */
+ uint8_t state; /* 1 - online, 0 - offline */
+ uint8_t configured_bbscn; /* 0-15 */
+ uint8_t negotiated_bbscn; /* 0-15 */
+ uint8_t offline_reason_code;
+ uint16_t mbx1; /* Port state */
+ uint8_t reserved[9];
+} __packed;
#endif
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index cd0d94ea7f74..b64c504ff12f 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,7 +11,7 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
- * | Module Init and Probe | 0x017f | 0x0146 |
+ * | Module Init and Probe | 0x018f | 0x0146 |
* | | | 0x015b-0x0160 |
* | | | 0x016e-0x0170 |
* | Mailbox commands | 0x1192 | |
@@ -27,11 +27,12 @@
* | | | 0x303a |
* | DPC Thread | 0x4023 | 0x4002,0x4013 |
* | Async Events | 0x5089 | 0x502b-0x502f |
+ * | | | 0x505e |
* | | | 0x5084,0x5075 |
* | | | 0x503d,0x5044 |
* | | | 0x507b,0x505f |
* | Timer Routines | 0x6012 | |
- * | User Space Interactions | 0x70e65 | 0x7018,0x702e |
+ * | User Space Interactions | 0x70e3 | 0x7018,0x702e |
* | | | 0x7020,0x7024 |
* | | | 0x7039,0x7045 |
* | | | 0x7073-0x7075 |
@@ -293,8 +294,8 @@ qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
WRT_REG_DWORD(&reg->iobase_addr, iobase);
dmp_reg = &reg->iobase_window;
- while (count--)
- *buf++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for ( ; count--; dmp_reg++)
+ *buf++ = htonl(RD_REG_DWORD(dmp_reg));
return buf;
}
@@ -456,8 +457,8 @@ qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count,
{
uint16_t __iomem *dmp_reg = &reg->u.isp2300.fb_cmd;
- while (count--)
- *buf++ = htons(RD_REG_WORD(dmp_reg++));
+ for ( ; count--; dmp_reg++)
+ *buf++ = htons(RD_REG_WORD(dmp_reg));
}
static inline void *
@@ -732,16 +733,18 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
if (rval == QLA_SUCCESS) {
dmp_reg = &reg->flash_address;
- for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
- fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++, dmp_reg++)
+ fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
dmp_reg = &reg->u.isp2300.req_q_in;
- for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++)
- fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2;
+ cnt++, dmp_reg++)
+ fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
dmp_reg = &reg->u.isp2300.mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2;
+ cnt++, dmp_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
WRT_REG_WORD(&reg->ctrl_status, 0x40);
qla2xxx_read_window(reg, 32, fw->resp_dma_reg);
@@ -751,8 +754,9 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
WRT_REG_WORD(&reg->ctrl_status, 0x00);
dmp_reg = &reg->risc_hw;
- for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
- fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2;
+ cnt++, dmp_reg++)
+ fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
WRT_REG_WORD(&reg->pcr, 0x2000);
qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
@@ -895,25 +899,25 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
}
if (rval == QLA_SUCCESS) {
dmp_reg = &reg->flash_address;
- for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
- fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++, dmp_reg++)
+ fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
dmp_reg = &reg->u.isp2100.mailbox0;
- for (cnt = 0; cnt < ha->mbx_count; cnt++) {
+ for (cnt = 0; cnt < ha->mbx_count; cnt++, dmp_reg++) {
if (cnt == 8)
dmp_reg = &reg->u_end.isp2200.mailbox8;
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
}
dmp_reg = &reg->u.isp2100.unused_2[0];
- for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
- fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++, dmp_reg++)
+ fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
WRT_REG_WORD(&reg->ctrl_status, 0x00);
dmp_reg = &reg->risc_hw;
- for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
- fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++, dmp_reg++)
+ fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
WRT_REG_WORD(&reg->pcr, 0x2000);
qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
@@ -1095,8 +1099,8 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Host interface registers. */
dmp_reg = &reg->flash_addr;
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++, dmp_reg++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -1128,8 +1132,8 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Mailbox registers. */
mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, dmp_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
@@ -1167,20 +1171,20 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
iter_reg = fw->req0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->resp0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->req1_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
@@ -1358,8 +1362,10 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
RD_REG_DWORD(&reg->iobase_addr);
WRT_REG_DWORD(&reg->iobase_window, 0x01);
dmp_reg = &reg->iobase_c4;
- fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
- fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
+ fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
@@ -1368,8 +1374,8 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Host interface registers. */
dmp_reg = &reg->flash_addr;
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++, dmp_reg++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -1417,8 +1423,8 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Mailbox registers. */
mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, mbx_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
@@ -1481,20 +1487,20 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
iter_reg = fw->req0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->resp0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->req1_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
@@ -1679,8 +1685,10 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
RD_REG_DWORD(&reg->iobase_addr);
WRT_REG_DWORD(&reg->iobase_window, 0x01);
dmp_reg = &reg->iobase_c4;
- fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
- fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
+ fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
@@ -1689,8 +1697,8 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Host interface registers. */
dmp_reg = &reg->flash_addr;
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++, dmp_reg++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -1738,8 +1746,8 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Mailbox registers. */
mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, mbx_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
@@ -1802,20 +1810,20 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
iter_reg = fw->req0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->resp0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->req1_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
@@ -2022,8 +2030,10 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
RD_REG_DWORD(&reg->iobase_addr);
WRT_REG_DWORD(&reg->iobase_window, 0x01);
dmp_reg = &reg->iobase_c4;
- fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
- fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
+ fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
@@ -2032,8 +2042,8 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Host interface registers. */
dmp_reg = &reg->flash_addr;
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++, dmp_reg++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -2081,8 +2091,8 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Mailbox registers. */
mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, dmp_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
@@ -2177,20 +2187,20 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
iter_reg = fw->req0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->resp0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->req1_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 9872f3429e53..ceb452dd143c 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1060,6 +1060,12 @@ struct mbx_cmd_32 {
#define FSTATE_FATAL_ERROR 4
#define FSTATE_LOOP_BACK_CONN 5
+#define QLA27XX_IMG_STATUS_VER_MAJOR 0x01
+#define QLA27XX_IMG_STATUS_VER_MINOR 0x00
+#define QLA27XX_IMG_STATUS_SIGN 0xFACEFADE
+#define QLA27XX_PRIMARY_IMAGE 1
+#define QLA27XX_SECONDARY_IMAGE 2
+
/*
* Port Database structure definition
* Little endian except where noted.
@@ -1248,13 +1254,41 @@ struct link_statistics {
uint32_t inval_xmit_word_cnt;
uint32_t inval_crc_cnt;
uint32_t lip_cnt;
- uint32_t unused1[0x1a];
+ uint32_t link_up_cnt;
+ uint32_t link_down_loop_init_tmo;
+ uint32_t link_down_los;
+ uint32_t link_down_loss_rcv_clk;
+ uint32_t reserved0[5];
+ uint32_t port_cfg_chg;
+ uint32_t reserved1[11];
+ uint32_t rsp_q_full;
+ uint32_t atio_q_full;
+ uint32_t drop_ae;
+ uint32_t els_proto_err;
+ uint32_t reserved2;
uint32_t tx_frames;
uint32_t rx_frames;
uint32_t discarded_frames;
uint32_t dropped_frames;
- uint32_t unused2[1];
+ uint32_t reserved3;
uint32_t nos_rcvd;
+ uint32_t reserved4[4];
+ uint32_t tx_prjt;
+ uint32_t rcv_exfail;
+ uint32_t rcv_abts;
+ uint32_t seq_frm_miss;
+ uint32_t corr_err;
+ uint32_t mb_rqst;
+ uint32_t nport_full;
+ uint32_t eofa;
+ uint32_t reserved5;
+ uint32_t fpm_recv_word_cnt_lo;
+ uint32_t fpm_recv_word_cnt_hi;
+ uint32_t fpm_disc_word_cnt_lo;
+ uint32_t fpm_disc_word_cnt_hi;
+ uint32_t fpm_xmit_word_cnt_lo;
+ uint32_t fpm_xmit_word_cnt_hi;
+ uint32_t reserved6[70];
};
/*
@@ -3433,14 +3467,20 @@ struct qla_hw_data {
uint32_t flt_region_flt;
uint32_t flt_region_fdt;
uint32_t flt_region_boot;
+ uint32_t flt_region_boot_sec;
uint32_t flt_region_fw;
+ uint32_t flt_region_fw_sec;
uint32_t flt_region_vpd_nvram;
uint32_t flt_region_vpd;
+ uint32_t flt_region_vpd_sec;
uint32_t flt_region_nvram;
uint32_t flt_region_npiv_conf;
uint32_t flt_region_gold_fw;
uint32_t flt_region_fcp_prio;
uint32_t flt_region_bootload;
+ uint32_t flt_region_img_status_pri;
+ uint32_t flt_region_img_status_sec;
+ uint8_t active_image;
/* Needed for BEACON */
uint16_t beacon_blink_led;
@@ -3571,6 +3611,7 @@ typedef struct scsi_qla_host {
uint32_t delete_progress:1;
uint32_t fw_tgt_reported:1;
+ uint32_t bbcr_enable:1;
} flags;
atomic_t loop_state;
@@ -3703,8 +3744,19 @@ typedef struct scsi_qla_host {
atomic_t vref_count;
struct qla8044_reset_template reset_tmplt;
struct qla_tgt_counters tgt_counters;
+ uint16_t bbcr;
} scsi_qla_host_t;
+struct qla27xx_image_status {
+ uint8_t image_status_mask;
+ uint16_t generation_number;
+ uint8_t reserved[3];
+ uint8_t ver_minor;
+ uint8_t ver_major;
+ uint32_t checksum;
+ uint32_t signature;
+} __packed;
+
#define SET_VP_IDX 1
#define SET_AL_PA 2
#define RESET_VP_IDX 3
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 42bb357bf56b..4c0f3a774799 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1288,7 +1288,9 @@ struct vp_rpt_id_entry_24xx {
uint8_t vp_idx_map[16];
- uint8_t reserved_4[32];
+ uint8_t reserved_4[28];
+ uint16_t bbcr;
+ uint8_t reserved_5[6];
};
#define VF_EVFP_IOCB_TYPE 0x26 /* Exchange Virtual Fabric Parameters entry. */
@@ -1393,6 +1395,16 @@ struct qla_flt_header {
#define FLT_REG_FCOE_NVRAM_0 0xAA
#define FLT_REG_FCOE_NVRAM_1 0xAC
+/* 27xx */
+#define FLT_REG_IMG_PRI_27XX 0x95
+#define FLT_REG_IMG_SEC_27XX 0x96
+#define FLT_REG_FW_SEC_27XX 0x02
+#define FLT_REG_BOOTLOAD_SEC_27XX 0x9
+#define FLT_REG_VPD_SEC_27XX_0 0x50
+#define FLT_REG_VPD_SEC_27XX_1 0x52
+#define FLT_REG_VPD_SEC_27XX_2 0xD8
+#define FLT_REG_VPD_SEC_27XX_3 0xDA
+
struct qla_flt_region {
uint32_t code;
uint32_t size;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 0103e468e357..fe943772fe7b 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -90,6 +90,7 @@ extern int qla2xxx_mctp_dump(scsi_qla_host_t *);
extern int
qla2x00_alloc_outstanding_cmds(struct qla_hw_data *, struct req_que *);
extern int qla2x00_init_rings(scsi_qla_host_t *);
+extern uint8_t qla27xx_find_valid_image(struct scsi_qla_host *);
/*
* Global Data in qla_os.c source file.
@@ -121,6 +122,7 @@ extern int ql2xmdcapmask;
extern int ql2xmdenable;
extern int ql2xexlogins;
extern int ql2xexchoffld;
+extern int ql2xfwholdabts;
extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 692a7570b5e1..c56cdb35f3ed 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -157,8 +157,12 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
lio->u.logio.flags |= SRB_LOGIN_RETRIED;
rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
+ if (rval != QLA_SUCCESS) {
+ fcport->flags &= ~FCF_ASYNC_SENT;
+ fcport->flags |= FCF_LOGIN_NEEDED;
+ set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
goto done_free_sp;
+ }
ql_dbg(ql_dbg_disc, vha, 0x2072,
"Async-login - hdl=%x, loopid=%x portid=%02x%02x%02x "
@@ -2062,6 +2066,10 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
if (IS_P3P_TYPE(ha))
return;
+ /* Hold status IOCBs until ABTS response received. */
+ if (ql2xfwholdabts)
+ ha->fw_options[3] |= BIT_12;
+
/* Update Serial Link options. */
if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
return;
@@ -2844,7 +2852,6 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
if (nv->login_timeout < 4)
nv->login_timeout = 4;
ha->login_timeout = nv->login_timeout;
- icb->login_timeout = nv->login_timeout;
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
@@ -5122,8 +5129,8 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
dptr = (uint32_t *)nv;
ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
ha->nvram_size);
- for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
- chksum += le32_to_cpu(*dptr++);
+ for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++)
+ chksum += le32_to_cpu(*dptr);
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x006a,
"Contents of NVRAM\n");
@@ -5274,7 +5281,6 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
if (le16_to_cpu(nv->login_timeout) < 4)
nv->login_timeout = cpu_to_le16(4);
ha->login_timeout = le16_to_cpu(nv->login_timeout);
- icb->login_timeout = nv->login_timeout;
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
@@ -5346,6 +5352,93 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
return (rval);
}
+uint8_t qla27xx_find_valid_image(struct scsi_qla_host *vha)
+{
+ struct qla27xx_image_status pri_image_status, sec_image_status;
+ uint8_t valid_pri_image, valid_sec_image;
+ uint32_t *wptr;
+ uint32_t cnt, chksum, size;
+ struct qla_hw_data *ha = vha->hw;
+
+ valid_pri_image = valid_sec_image = 1;
+ ha->active_image = 0;
+ size = sizeof(struct qla27xx_image_status) / sizeof(uint32_t);
+
+ if (!ha->flt_region_img_status_pri) {
+ valid_pri_image = 0;
+ goto check_sec_image;
+ }
+
+ qla24xx_read_flash_data(vha, (uint32_t *)(&pri_image_status),
+ ha->flt_region_img_status_pri, size);
+
+ if (pri_image_status.signature != QLA27XX_IMG_STATUS_SIGN) {
+ ql_dbg(ql_dbg_init, vha, 0x018b,
+ "Primary image signature (0x%x) not valid\n",
+ pri_image_status.signature);
+ valid_pri_image = 0;
+ goto check_sec_image;
+ }
+
+ wptr = (uint32_t *)(&pri_image_status);
+ cnt = size;
+
+ for (chksum = 0; cnt--; wptr++)
+ chksum += le32_to_cpu(*wptr);
+ if (chksum) {
+ ql_dbg(ql_dbg_init, vha, 0x018c,
+ "Checksum validation failed for primary image (0x%x)\n",
+ chksum);
+ valid_pri_image = 0;
+ }
+
+check_sec_image:
+ if (!ha->flt_region_img_status_sec) {
+ valid_sec_image = 0;
+ goto check_valid_image;
+ }
+
+ qla24xx_read_flash_data(vha, (uint32_t *)(&sec_image_status),
+ ha->flt_region_img_status_sec, size);
+
+ if (sec_image_status.signature != QLA27XX_IMG_STATUS_SIGN) {
+ ql_dbg(ql_dbg_init, vha, 0x018d,
+ "Secondary image signature(0x%x) not valid\n",
+ sec_image_status.signature);
+ valid_sec_image = 0;
+ goto check_valid_image;
+ }
+
+ wptr = (uint32_t *)(&sec_image_status);
+ cnt = size;
+ for (chksum = 0; cnt--; wptr++)
+ chksum += le32_to_cpu(*wptr);
+ if (chksum) {
+ ql_dbg(ql_dbg_init, vha, 0x018e,
+ "Checksum validation failed for secondary image (0x%x)\n",
+ chksum);
+ valid_sec_image = 0;
+ }
+
+check_valid_image:
+ if (valid_pri_image && (pri_image_status.image_status_mask & 0x1))
+ ha->active_image = QLA27XX_PRIMARY_IMAGE;
+ if (valid_sec_image && (sec_image_status.image_status_mask & 0x1)) {
+ if (!ha->active_image ||
+ pri_image_status.generation_number <
+ sec_image_status.generation_number)
+ ha->active_image = QLA27XX_SECONDARY_IMAGE;
+ }
+
+ ql_dbg(ql_dbg_init, vha, 0x018f, "%s image\n",
+ ha->active_image == 0 ? "default bootld and fw" :
+ ha->active_image == 1 ? "primary" :
+ ha->active_image == 2 ? "secondary" :
+ "Invalid");
+
+ return ha->active_image;
+}
+
static int
qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
uint32_t faddr)
@@ -5368,6 +5461,10 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
dcode = (uint32_t *)req->ring;
*srisc_addr = 0;
+ if (IS_QLA27XX(ha) &&
+ qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_fw_sec;
+
/* Validate firmware image by checking version. */
qla24xx_read_flash_data(vha, dcode, faddr + 4, 4);
for (i = 0; i < 4; i++)
@@ -6068,8 +6165,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
ha->nvram_size);
dptr = (uint32_t *)nv;
- for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
- chksum += le32_to_cpu(*dptr++);
+ for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++)
+ chksum += le32_to_cpu(*dptr);
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
"Contents of NVRAM:\n");
@@ -6231,7 +6328,6 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
if (le16_to_cpu(nv->login_timeout) < 4)
nv->login_timeout = cpu_to_le16(4);
ha->login_timeout = le16_to_cpu(nv->login_timeout);
- icb->login_timeout = nv->login_timeout;
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
@@ -6413,12 +6509,17 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
+ /* Hold status IOCBs until ABTS response received. */
+ if (ql2xfwholdabts)
+ ha->fw_options[3] |= BIT_12;
+
if (!ql2xetsenable)
- return;
+ goto out;
/* Enable ETS Burst. */
memset(ha->fw_options, 0, sizeof(ha->fw_options));
ha->fw_options[2] |= BIT_9;
+out:
qla2x00_set_fw_options(vha, ha->fw_options);
}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index a6b7f1588aa4..edc48f3b8230 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -87,8 +87,8 @@ host_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize)
__le32 *odest = (__le32 *) dst;
uint32_t iter = bsize >> 2;
- for (; iter ; iter--)
- *odest++ = cpu_to_le32(*isrc++);
+ for ( ; iter--; isrc++)
+ *odest++ = cpu_to_le32(*isrc);
}
static inline void
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 4af95479a9db..5649c200d37c 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -934,10 +934,6 @@ skip_rio:
break;
global_port_update:
- /* Port unavailable. */
- ql_log(ql_log_warn, vha, 0x505e,
- "Link is offline.\n");
-
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer,
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 87e6758302f6..968b84613096 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1349,6 +1349,8 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
if (IS_FWI2_CAPABLE(vha->hw))
mcp->in_mb |= MBX_19|MBX_18|MBX_17|MBX_16;
+ if (IS_QLA27XX(vha->hw))
+ mcp->in_mb |= MBX_15;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
rval = qla2x00_mailbox_command(vha, mcp);
@@ -1400,6 +1402,9 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
wwn_to_u64(vha->port_name));
}
}
+
+ if (IS_QLA27XX(vha->hw))
+ vha->bbcr = mcp->mb[15];
}
return rval;
@@ -2754,7 +2759,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- uint32_t *siter, *diter, dwords;
+ uint32_t *iter, dwords;
struct qla_hw_data *ha = vha->hw;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1084,
@@ -2794,10 +2799,11 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
/* Copy over data -- firmware data is LE. */
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1086,
"Done %s.\n", __func__);
- dwords = offsetof(struct link_statistics, unused1) / 4;
- siter = diter = &stats->link_fail_cnt;
- while (dwords--)
- *diter++ = le32_to_cpu(*siter++);
+ dwords = offsetof(struct link_statistics,
+ link_up_cnt) / 4;
+ iter = &stats->link_fail_cnt;
+ for ( ; dwords--; iter++)
+ le32_to_cpus(iter);
}
} else {
/* Failed. */
@@ -2814,7 +2820,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- uint32_t *siter, *diter, dwords;
+ uint32_t *iter, dwords;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1088,
"Entered %s.\n", __func__);
@@ -2843,9 +2849,9 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
"Done %s.\n", __func__);
/* Copy over data -- firmware data is LE. */
dwords = sizeof(struct link_statistics) / 4;
- siter = diter = &stats->link_fail_cnt;
- while (dwords--)
- *diter++ = le32_to_cpu(*siter++);
+ iter = &stats->link_fail_cnt;
+ for ( ; dwords--; iter++)
+ le32_to_cpus(iter);
}
} else {
/* Failed. */
@@ -3612,6 +3618,9 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]);
+ /* buffer to buffer credit flag */
+ vha->flags.bbcr_enable = (rptid_entry->bbcr & 0xf) != 0;
+
/* FA-WWN is only for physical port */
if (!vp_idx) {
void *wwpn = ha->init_cb->port_name;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index f6c7ce35b542..7c0b60ca158f 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -233,6 +233,13 @@ MODULE_PARM_DESC(ql2xexchoffld,
"Number of exchanges to offload. "
"0 (Default)- Disabled.");
+int ql2xfwholdabts = 0;
+module_param(ql2xfwholdabts, int, S_IRUGO);
+MODULE_PARM_DESC(ql2xfwholdabts,
+ "Allow FW to hold status IOCB until ABTS rsp received. "
+ "0 (Default) Do not set fw option. "
+ "1 - Set fw option to hold ABTS.");
+
/*
* SCSI host template entry points
*/
@@ -2216,6 +2223,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_ZIO_SUPPORTED;
ha->device_type |= DT_FWI2;
ha->device_type |= DT_IIDMA;
+ ha->device_type |= DT_T10_PI;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP2271:
@@ -2223,6 +2231,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_ZIO_SUPPORTED;
ha->device_type |= DT_FWI2;
ha->device_type |= DT_IIDMA;
+ ha->device_type |= DT_T10_PI;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP2261:
@@ -2230,6 +2239,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_ZIO_SUPPORTED;
ha->device_type |= DT_FWI2;
ha->device_type |= DT_IIDMA;
+ ha->device_type |= DT_T10_PI;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
}
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 3272ed5bbcc7..5e9392316425 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -610,8 +610,8 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
wptr = (uint16_t *)req->ring;
cnt = sizeof(struct qla_flt_location) >> 1;
- for (chksum = 0; cnt; cnt--)
- chksum += le16_to_cpu(*wptr++);
+ for (chksum = 0; cnt--; wptr++)
+ chksum += le16_to_cpu(*wptr);
if (chksum) {
ql_log(ql_log_fatal, vha, 0x0045,
"Inconsistent FLTL detected: checksum=0x%x.\n", chksum);
@@ -702,8 +702,8 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
}
cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
- for (chksum = 0; cnt; cnt--)
- chksum += le16_to_cpu(*wptr++);
+ for (chksum = 0; cnt--; wptr++)
+ chksum += le16_to_cpu(*wptr);
if (chksum) {
ql_log(ql_log_fatal, vha, 0x0048,
"Inconsistent FLT detected: version=0x%x length=0x%x checksum=0x%x.\n",
@@ -846,6 +846,38 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
if (ha->port_no == 1)
ha->flt_region_nvram = start;
break;
+ case FLT_REG_IMG_PRI_27XX:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_img_status_pri = start;
+ break;
+ case FLT_REG_IMG_SEC_27XX:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_img_status_sec = start;
+ break;
+ case FLT_REG_FW_SEC_27XX:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_fw_sec = start;
+ break;
+ case FLT_REG_BOOTLOAD_SEC_27XX:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_boot_sec = start;
+ break;
+ case FLT_REG_VPD_SEC_27XX_0:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_vpd_sec = start;
+ break;
+ case FLT_REG_VPD_SEC_27XX_1:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_vpd_sec = start;
+ break;
+ case FLT_REG_VPD_SEC_27XX_2:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_vpd_sec = start;
+ break;
+ case FLT_REG_VPD_SEC_27XX_3:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_vpd_sec = start;
+ break;
}
}
goto done;
@@ -898,9 +930,8 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
fdt->sig[3] != 'D')
goto no_flash_data;
- for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1;
- cnt++)
- chksum += le16_to_cpu(*wptr++);
+ for (cnt = 0, chksum = 0; cnt < sizeof(*fdt) >> 1; cnt++, wptr++)
+ chksum += le16_to_cpu(*wptr);
if (chksum) {
ql_dbg(ql_dbg_init, vha, 0x004c,
"Inconsistent FDT detected:"
@@ -995,7 +1026,8 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha)
ha->fcoe_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT;
ha->fcoe_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT;
} else {
- ha->fcoe_dev_init_timeout = le32_to_cpu(*wptr++);
+ ha->fcoe_dev_init_timeout = le32_to_cpu(*wptr);
+ wptr++;
ha->fcoe_reset_timeout = le32_to_cpu(*wptr);
}
ql_dbg(ql_dbg_init, vha, 0x004e,
@@ -1072,10 +1104,9 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
ha->isp_ops->read_optrom(vha, (uint8_t *)data,
ha->flt_region_npiv_conf << 2, NPIV_CONFIG_SIZE);
- cnt = (sizeof(struct qla_npiv_header) + le16_to_cpu(hdr.entries) *
- sizeof(struct qla_npiv_entry)) >> 1;
- for (wptr = data, chksum = 0; cnt; cnt--)
- chksum += le16_to_cpu(*wptr++);
+ cnt = (sizeof(hdr) + le16_to_cpu(hdr.entries) * sizeof(*entry)) >> 1;
+ for (wptr = data, chksum = 0; cnt--; wptr++)
+ chksum += le16_to_cpu(*wptr);
if (chksum) {
ql_dbg(ql_dbg_user, vha, 0x7092,
"Inconsistent NPIV-Config "
@@ -2989,6 +3020,9 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
uint8_t code_type, last_image;
int i;
struct qla_hw_data *ha = vha->hw;
+ uint32_t faddr = 0;
+
+ pcihdr = pcids = 0;
if (IS_P3P_TYPE(ha))
return ret;
@@ -3002,9 +3036,11 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
dcode = mbuf;
-
- /* Begin with first PCI expansion ROM header. */
pcihdr = ha->flt_region_boot << 2;
+ if (IS_QLA27XX(ha) &&
+ qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
+ pcihdr = ha->flt_region_boot_sec << 2;
+
last_image = 1;
do {
/* Verify PCI expansion ROM header. */
@@ -3077,8 +3113,12 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
/* Read firmware image information. */
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
dcode = mbuf;
+ faddr = ha->flt_region_fw;
+ if (IS_QLA27XX(ha) &&
+ qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_fw_sec;
- qla24xx_read_flash_data(vha, dcode, ha->flt_region_fw + 4, 4);
+ qla24xx_read_flash_data(vha, dcode, faddr + 4, 4);
for (i = 0; i < 4; i++)
dcode[i] = be32_to_cpu(dcode[i]);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 6d31faa8c57b..0bc93fa46dae 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.07.00.26-k"
+#define QLA2XXX_VERSION "8.07.00.33-k"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 7
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
index 5d4f8e67fb25..638f72c5ab05 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.c
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -46,11 +46,13 @@ int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
ret_val = qla4_83xx_set_win_base(ha, addr);
- if (ret_val == QLA_SUCCESS)
+ if (ret_val == QLA_SUCCESS) {
*data = qla4_83xx_rd_reg(ha, QLA83XX_WILDCARD);
- else
+ } else {
+ *data = 0xffffffff;
ql4_printk(KERN_ERR, ha, "%s: failed read of addr 0x%x!\n",
__func__, addr);
+ }
return ret_val;
}
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 676385ff28ef..69bfc0a1aea3 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -710,7 +710,7 @@ static int qpti_map_regs(struct qlogicpti *qpti)
"PTI Qlogic/ISP");
if (!qpti->qregs) {
printk("PTI: Qlogic/ISP registers are unmappable\n");
- return -1;
+ return -ENODEV;
}
if (qpti->is_pti) {
qpti->sreg = of_ioremap(&op->resource[0], (16 * 4096),
@@ -718,7 +718,7 @@ static int qpti_map_regs(struct qlogicpti *qpti)
"PTI Qlogic/ISP statreg");
if (!qpti->sreg) {
printk("PTI: Qlogic/ISP status register is unmappable\n");
- return -1;
+ return -ENODEV;
}
}
return 0;
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index da2e068ee47d..3408578b08d6 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -206,6 +206,7 @@ static struct {
{"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
{"Marvell", "Console", NULL, BLIST_SKIP_VPD_PAGES},
+ {"Marvell", "91xx Config", "1.01", BLIST_SKIP_VPD_PAGES},
{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"MATSHITA", "DMC-LC5", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
{"MATSHITA", "DMC-LC40", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
@@ -219,6 +220,8 @@ static struct {
{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NEC", "iStorage", NULL, BLIST_REPORTLUN2},
+ {"NETAPP", "LUN C-Mode", NULL, BLIST_SYNC_ALUA},
+ {"NETAPP", "INF-01-00", NULL, BLIST_SYNC_ALUA},
{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index fa6b2c4eb7a2..8106515d1df8 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1344,6 +1344,7 @@ scsi_prep_return(struct request_queue *q, struct request *req, int ret)
switch (ret) {
case BLKPREP_KILL:
+ case BLKPREP_INVALID:
req->errors = DID_NO_CONNECT << 16;
/* release the command and kill it */
if (req->special) {
@@ -2699,6 +2700,7 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
envp[idx++] = "SDEV_MEDIA_CHANGE=1";
break;
case SDEV_EVT_INQUIRY_CHANGE_REPORTED:
+ scsi_rescan_device(&sdev->sdev_gendev);
envp[idx++] = "SDEV_UA=INQUIRY_DATA_HAS_CHANGED";
break;
case SDEV_EVT_CAPACITY_CHANGE_REPORTED:
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 6a820668d442..97074c91e328 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -43,6 +43,7 @@
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
+#include <scsi/scsi_dh.h>
#include <scsi/scsi_eh.h>
#include "scsi_priv.h"
@@ -518,7 +519,8 @@ void scsi_target_reap(struct scsi_target *starget)
}
/**
- * sanitize_inquiry_string - remove non-graphical chars from an INQUIRY result string
+ * scsi_sanitize_inquiry_string - remove non-graphical chars from an
+ * INQUIRY result string
* @s: INQUIRY result string to sanitize
* @len: length of the string
*
@@ -531,7 +533,7 @@ void scsi_target_reap(struct scsi_target *starget)
* string terminator, so all the following characters are set to
* spaces.
**/
-static void sanitize_inquiry_string(unsigned char *s, int len)
+void scsi_sanitize_inquiry_string(unsigned char *s, int len)
{
int terminated = 0;
@@ -542,6 +544,7 @@ static void sanitize_inquiry_string(unsigned char *s, int len)
*s = ' ';
}
}
+EXPORT_SYMBOL(scsi_sanitize_inquiry_string);
/**
* scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
@@ -627,9 +630,9 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
}
if (result == 0) {
- sanitize_inquiry_string(&inq_result[8], 8);
- sanitize_inquiry_string(&inq_result[16], 16);
- sanitize_inquiry_string(&inq_result[32], 4);
+ scsi_sanitize_inquiry_string(&inq_result[8], 8);
+ scsi_sanitize_inquiry_string(&inq_result[16], 16);
+ scsi_sanitize_inquiry_string(&inq_result[32], 4);
response_len = inq_result[4] + 5;
if (response_len > 255)
@@ -962,6 +965,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
if (*bflags & BLIST_NO_DIF)
sdev->no_dif = 1;
+ if (*bflags & BLIST_SYNC_ALUA)
+ sdev->synchronous_alua = 1;
+
sdev->eh_timeout = SCSI_DEFAULT_EH_TIMEOUT;
if (*bflags & BLIST_TRY_VPD_PAGES)
@@ -1519,9 +1525,14 @@ EXPORT_SYMBOL(scsi_add_device);
void scsi_rescan_device(struct device *dev)
{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
device_lock(dev);
- scsi_attach_vpd(to_scsi_device(dev));
+ scsi_attach_vpd(sdev);
+
+ if (sdev->handler && sdev->handler->rescan)
+ sdev->handler->rescan(sdev);
if (dev->driver && try_module_get(dev->driver->owner)) {
struct scsi_driver *drv = to_scsi_driver(dev->driver);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 4f18a851e2c7..d16441961f3a 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -81,6 +81,33 @@ const char *scsi_host_state_name(enum scsi_host_state state)
return name;
}
+static const struct {
+ unsigned char value;
+ char *name;
+} sdev_access_states[] = {
+ { SCSI_ACCESS_STATE_OPTIMAL, "active/optimized" },
+ { SCSI_ACCESS_STATE_ACTIVE, "active/non-optimized" },
+ { SCSI_ACCESS_STATE_STANDBY, "standby" },
+ { SCSI_ACCESS_STATE_UNAVAILABLE, "unavailable" },
+ { SCSI_ACCESS_STATE_LBA, "lba-dependent" },
+ { SCSI_ACCESS_STATE_OFFLINE, "offline" },
+ { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" },
+};
+
+const char *scsi_access_state_name(unsigned char state)
+{
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(sdev_access_states); i++) {
+ if (sdev_access_states[i].value == state) {
+ name = sdev_access_states[i].name;
+ break;
+ }
+ }
+ return name;
+}
+
static int check_set(unsigned long long *val, char *src)
{
char *last;
@@ -973,6 +1000,43 @@ sdev_store_dh_state(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state,
sdev_store_dh_state);
+
+static ssize_t
+sdev_show_access_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ unsigned char access_state;
+ const char *access_state_name;
+
+ if (!sdev->handler)
+ return -EINVAL;
+
+ access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK);
+ access_state_name = scsi_access_state_name(access_state);
+
+ return sprintf(buf, "%s\n",
+ access_state_name ? access_state_name : "unknown");
+}
+static DEVICE_ATTR(access_state, S_IRUGO, sdev_show_access_state, NULL);
+
+static ssize_t
+sdev_show_preferred_path(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!sdev->handler)
+ return -EINVAL;
+
+ if (sdev->access_state & SCSI_ACCESS_STATE_PREFERRED)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+static DEVICE_ATTR(preferred_path, S_IRUGO, sdev_show_preferred_path, NULL);
#endif
static ssize_t
@@ -1020,9 +1084,33 @@ static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj,
!sdev->host->hostt->change_queue_depth)
return 0;
+#ifdef CONFIG_SCSI_DH
+ if (attr == &dev_attr_access_state.attr &&
+ !sdev->handler)
+ return 0;
+ if (attr == &dev_attr_preferred_path.attr &&
+ !sdev->handler)
+ return 0;
+#endif
return attr->mode;
}
+static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj,
+ struct bin_attribute *attr, int i)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+
+ if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80)
+ return 0;
+
+ if (attr == &dev_attr_vpd_pg83 && sdev->vpd_pg83)
+ return 0;
+
+ return S_IRUGO;
+}
+
/* Default template for device attributes. May NOT be modified */
static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_device_blocked.attr,
@@ -1047,6 +1135,8 @@ static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_wwid.attr,
#ifdef CONFIG_SCSI_DH
&dev_attr_dh_state.attr,
+ &dev_attr_access_state.attr,
+ &dev_attr_preferred_path.attr,
#endif
&dev_attr_queue_ramp_up_period.attr,
REF_EVT(media_change),
@@ -1068,6 +1158,7 @@ static struct attribute_group scsi_sdev_attr_group = {
.attrs = scsi_sdev_attrs,
.bin_attrs = scsi_sdev_bin_attrs,
.is_visible = scsi_sdev_attr_is_visible,
+ .is_bin_visible = scsi_sdev_bin_attr_is_visible,
};
static const struct attribute_group *scsi_sdev_attr_groups[] = {
@@ -1129,13 +1220,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
scsi_autopm_get_device(sdev);
- error = device_add(&sdev->sdev_gendev);
- if (error) {
- sdev_printk(KERN_INFO, sdev,
- "failed to add device: %d\n", error);
- return error;
- }
-
error = scsi_dh_add_device(sdev);
if (error)
/*
@@ -1144,6 +1228,14 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
sdev_printk(KERN_INFO, sdev,
"failed to add device handler: %d\n", error);
+ error = device_add(&sdev->sdev_gendev);
+ if (error) {
+ sdev_printk(KERN_INFO, sdev,
+ "failed to add device: %d\n", error);
+ scsi_dh_remove_device(sdev);
+ return error;
+ }
+
device_enable_async_suspend(&sdev->sdev_dev);
error = device_add(&sdev->sdev_dev);
if (error) {
@@ -1272,16 +1364,18 @@ static void __scsi_remove_target(struct scsi_target *starget)
void scsi_remove_target(struct device *dev)
{
struct Scsi_Host *shost = dev_to_shost(dev->parent);
- struct scsi_target *starget;
+ struct scsi_target *starget, *last_target = NULL;
unsigned long flags;
restart:
spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry(starget, &shost->__targets, siblings) {
- if (starget->state == STARGET_DEL)
+ if (starget->state == STARGET_DEL ||
+ starget == last_target)
continue;
if (starget->dev.parent == dev || &starget->dev == dev) {
kref_get(&starget->reap_ref);
+ last_target = starget;
spin_unlock_irqrestore(shost->host_lock, flags);
__scsi_remove_target(starget);
scsi_target_reap(starget);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index e4b3d8f4fd85..441481623fb9 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -4308,6 +4308,8 @@ static const struct {
{ISCSI_PORT_SPEED_100MBPS, "100 Mbps" },
{ISCSI_PORT_SPEED_1GBPS, "1 Gbps" },
{ISCSI_PORT_SPEED_10GBPS, "10 Gbps" },
+ {ISCSI_PORT_SPEED_25GBPS, "25 Gbps" },
+ {ISCSI_PORT_SPEED_40GBPS, "40 Gbps" },
};
char *iscsi_get_port_speed_name(struct Scsi_Host *shost)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index d749da765df1..5a5457ac9cdb 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -648,7 +648,7 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
*/
if (sdkp->lbprz) {
q->limits.discard_alignment = 0;
- q->limits.discard_granularity = 1;
+ q->limits.discard_granularity = logical_block_size;
} else {
q->limits.discard_alignment = sdkp->unmap_alignment *
logical_block_size;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 5e820674432c..ae7d9bdf409c 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -652,7 +652,8 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
else
hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
hp->dxfer_len = mxsize;
- if (hp->dxfer_direction == SG_DXFER_TO_DEV)
+ if ((hp->dxfer_direction == SG_DXFER_TO_DEV) ||
+ (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV))
hp->dxferp = (char __user *)buf + cmd_size;
else
hp->dxferp = NULL;
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 3b3b56f4a830..82ed99848378 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -176,8 +176,7 @@ static struct eisa_device_id sim710_eisa_ids[] = {
};
MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
-static __init int
-sim710_eisa_probe(struct device *dev)
+static int sim710_eisa_probe(struct device *dev)
{
struct eisa_device *edev = to_eisa_device(dev);
unsigned long io_addr = edev->base_addr;
diff --git a/drivers/scsi/snic/snic_ctl.c b/drivers/scsi/snic/snic_ctl.c
index aebe75320ed3..ab0e06b0b4ff 100644
--- a/drivers/scsi/snic/snic_ctl.c
+++ b/drivers/scsi/snic/snic_ctl.c
@@ -75,7 +75,7 @@ snic_ver_enc(const char *s)
continue;
}
- if (i > 4 || !isdigit(c))
+ if (i > 3 || !isdigit(c))
goto end;
v[i] = v[i] * 10 + (c - '0');
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 2e522951b619..607b0a505844 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -9,7 +9,7 @@
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
- Copyright 1992 - 2010 Kai Makisara
+ Copyright 1992 - 2016 Kai Makisara
email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809
@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20101219";
+static const char *verstr = "20160209";
#include <linux/module.h>
@@ -3296,7 +3296,10 @@ static int switch_partition(struct scsi_tape *STp)
#define PP_OFF_RESERVED 7
#define PP_BIT_IDP 0x20
+#define PP_BIT_FDP 0x80
#define PP_MSK_PSUM_MB 0x10
+#define PP_MSK_PSUM_UNITS 0x18
+#define PP_MSK_POFM 0x04
/* Get the number of partitions on the tape. As a side effect reads the
mode page into the tape buffer. */
@@ -3322,6 +3325,29 @@ static int nbr_partitions(struct scsi_tape *STp)
}
+static int format_medium(struct scsi_tape *STp, int format)
+{
+ int result = 0;
+ int timeout = STp->long_timeout;
+ unsigned char scmd[MAX_COMMAND_SIZE];
+ struct st_request *SRpnt;
+
+ memset(scmd, 0, MAX_COMMAND_SIZE);
+ scmd[0] = FORMAT_UNIT;
+ scmd[2] = format;
+ if (STp->immediate) {
+ scmd[1] |= 1; /* Don't wait for completion */
+ timeout = STp->device->request_queue->rq_timeout;
+ }
+ DEBC_printk(STp, "Sending FORMAT MEDIUM\n");
+ SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
+ timeout, MAX_RETRIES, 1);
+ if (!SRpnt)
+ result = STp->buffer->syscall_result;
+ return result;
+}
+
+
/* Partition the tape into two partitions if size > 0 or one partition if
size == 0.
@@ -3340,11 +3366,16 @@ static int nbr_partitions(struct scsi_tape *STp)
and 10 when 1 partition is defined (information from Eric Lee Green). This is
is acceptable also to some other old drives and enforced if the first partition
size field is used for the first additional partition size.
+
+ For drives that advertize SCSI-3 or newer, use the SSC-3 methods.
*/
static int partition_tape(struct scsi_tape *STp, int size)
{
int result;
+ int target_partition;
+ bool scsi3 = STp->device->scsi_level >= SCSI_3, needs_format = false;
int pgo, psd_cnt, psdo;
+ int psum = PP_MSK_PSUM_MB, units = 0;
unsigned char *bp;
result = read_mode_page(STp, PART_PAGE, 0);
@@ -3352,6 +3383,12 @@ static int partition_tape(struct scsi_tape *STp, int size)
DEBC_printk(STp, "Can't read partition mode page.\n");
return result;
}
+ target_partition = 1;
+ if (size < 0) {
+ target_partition = 0;
+ size = -size;
+ }
+
/* The mode page is in the buffer. Let's modify it and write it. */
bp = (STp->buffer)->b_data;
pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH];
@@ -3359,9 +3396,52 @@ static int partition_tape(struct scsi_tape *STp, int size)
bp[pgo + MP_OFF_PAGE_LENGTH] + 2);
psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2;
+
+ if (scsi3) {
+ needs_format = (bp[pgo + PP_OFF_FLAGS] & PP_MSK_POFM) != 0;
+ if (needs_format && size == 0) {
+ /* No need to write the mode page when clearing
+ * partitioning
+ */
+ DEBC_printk(STp, "Formatting tape with one partition.\n");
+ result = format_medium(STp, 0);
+ goto out;
+ }
+ if (needs_format) /* Leave the old value for HP DATs claiming SCSI_3 */
+ psd_cnt = 2;
+ if ((bp[pgo + PP_OFF_FLAGS] & PP_MSK_PSUM_UNITS) == PP_MSK_PSUM_UNITS) {
+ /* Use units scaling for large partitions if the device
+ * suggests it and no precision lost. Required for IBM
+ * TS1140/50 drives that don't support MB units.
+ */
+ if (size >= 1000 && (size % 1000) == 0) {
+ size /= 1000;
+ psum = PP_MSK_PSUM_UNITS;
+ units = 9; /* GB */
+ }
+ }
+ /* Try it anyway if too large to specify in MB */
+ if (psum == PP_MSK_PSUM_MB && size >= 65534) {
+ size /= 1000;
+ psum = PP_MSK_PSUM_UNITS;
+ units = 9; /* GB */
+ }
+ }
+
+ if (size >= 65535 || /* Does not fit into two bytes */
+ (target_partition == 0 && psd_cnt < 2)) {
+ result = -EINVAL;
+ goto out;
+ }
+
psdo = pgo + PART_PAGE_FIXED_LENGTH;
- if (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS]) {
- bp[psdo] = bp[psdo + 1] = 0xff; /* Rest of the tape */
+ /* The second condition is for HP DDS which use only one partition size
+ * descriptor
+ */
+ if (target_partition > 0 &&
+ (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS] ||
+ bp[pgo + PP_OFF_MAX_ADD_PARTS] != 1)) {
+ bp[psdo] = bp[psdo + 1] = 0xff; /* Rest to partition 0 */
psdo += 2;
}
memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2);
@@ -3370,7 +3450,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS],
bp[pgo + PP_OFF_NBR_ADD_PARTS]);
- if (size <= 0) {
+ if (size == 0) {
bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS])
bp[pgo + MP_OFF_PAGE_LENGTH] = 6;
@@ -3378,22 +3458,37 @@ static int partition_tape(struct scsi_tape *STp, int size)
} else {
bp[psdo] = (size >> 8) & 0xff;
bp[psdo + 1] = size & 0xff;
+ if (target_partition == 0)
+ bp[psdo + 2] = bp[psdo + 3] = 0xff;
bp[pgo + 3] = 1;
if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8)
bp[pgo + MP_OFF_PAGE_LENGTH] = 8;
- DEBC_printk(STp, "Formatting tape with two partitions "
- "(1 = %d MB).\n", size);
+ DEBC_printk(STp,
+ "Formatting tape with two partitions (%i = %d MB).\n",
+ target_partition, units > 0 ? size * 1000 : size);
}
bp[pgo + PP_OFF_PART_UNITS] = 0;
bp[pgo + PP_OFF_RESERVED] = 0;
- bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | PP_MSK_PSUM_MB;
+ if (size != 1 || units != 0) {
+ bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | psum |
+ (bp[pgo + PP_OFF_FLAGS] & 0x07);
+ bp[pgo + PP_OFF_PART_UNITS] = units;
+ } else
+ bp[pgo + PP_OFF_FLAGS] = PP_BIT_FDP |
+ (bp[pgo + PP_OFF_FLAGS] & 0x1f);
+ bp[pgo + MP_OFF_PAGE_LENGTH] = 6 + psd_cnt * 2;
result = write_mode_page(STp, PART_PAGE, 1);
+
+ if (!result && needs_format)
+ result = format_medium(STp, 1);
+
if (result) {
st_printk(KERN_INFO, STp, "Partitioning of tape failed.\n");
result = (-EIO);
}
+out:
return result;
}
@@ -3570,8 +3665,13 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
retval = (-EINVAL);
goto out;
}
- if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 ||
- (i = partition_tape(STp, mtc.mt_count)) < 0) {
+ i = do_load_unload(STp, file, 1);
+ if (i < 0) {
+ retval = i;
+ goto out;
+ }
+ i = partition_tape(STp, mtc.mt_count);
+ if (i < 0) {
retval = i;
goto out;
}
@@ -3581,7 +3681,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
STp->ps[i].last_block_valid = 0;
}
STp->partition = STp->new_partition = 0;
- STp->nbr_partitions = 1; /* Bad guess ?-) */
+ STp->nbr_partitions = mtc.mt_count != 0 ? 2 : 1;
STps->drv_block = STps->drv_file = 0;
retval = 0;
goto out;
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 2de28d7a0b04..5b23175a584c 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -1,7 +1,7 @@
/*
* SuperTrak EX Series Storage Controller driver for Linux
*
- * Copyright (C) 2005-2009 Promise Technology Inc.
+ * Copyright (C) 2005-2015 Promise Technology Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -38,11 +38,11 @@
#include <scsi/scsi_eh.h>
#define DRV_NAME "stex"
-#define ST_DRIVER_VERSION "4.6.0000.4"
-#define ST_VER_MAJOR 4
-#define ST_VER_MINOR 6
-#define ST_OEM 0
-#define ST_BUILD_VER 4
+#define ST_DRIVER_VERSION "5.00.0000.01"
+#define ST_VER_MAJOR 5
+#define ST_VER_MINOR 00
+#define ST_OEM 0000
+#define ST_BUILD_VER 01
enum {
/* MU register offset */
@@ -84,6 +84,8 @@ enum {
MU_STATE_STARTED = 2,
MU_STATE_RESETTING = 3,
MU_STATE_FAILED = 4,
+ MU_STATE_STOP = 5,
+ MU_STATE_NOCONNECT = 6,
MU_MAX_DELAY = 120,
MU_HANDSHAKE_SIGNATURE = 0x55aaaa55,
@@ -165,6 +167,14 @@ enum {
ST_ADDITIONAL_MEM = 0x200000,
ST_ADDITIONAL_MEM_MIN = 0x80000,
+ PMIC_SHUTDOWN = 0x0D,
+ PMIC_REUMSE = 0x10,
+ ST_IGNORED = -1,
+ ST_NOTHANDLED = 7,
+ ST_S3 = 3,
+ ST_S4 = 4,
+ ST_S5 = 5,
+ ST_S6 = 6,
};
struct st_sgitem {
@@ -328,6 +338,7 @@ struct st_hba {
u16 rq_count;
u16 rq_size;
u16 sts_count;
+ u8 supports_pm;
};
struct st_card_info {
@@ -536,6 +547,27 @@ stex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
readl(hba->mmio_base + YH2I_REQ); /* flush */
}
+static void return_abnormal_state(struct st_hba *hba, int status)
+{
+ struct st_ccb *ccb;
+ unsigned long flags;
+ u16 tag;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ for (tag = 0; tag < hba->host->can_queue; tag++) {
+ ccb = &hba->ccb[tag];
+ if (ccb->req == NULL)
+ continue;
+ ccb->req = NULL;
+ if (ccb->cmd) {
+ scsi_dma_unmap(ccb->cmd);
+ ccb->cmd->result = status << 16;
+ ccb->cmd->scsi_done(ccb->cmd);
+ ccb->cmd = NULL;
+ }
+ }
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
static int
stex_slave_config(struct scsi_device *sdev)
{
@@ -559,8 +591,12 @@ stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
id = cmd->device->id;
lun = cmd->device->lun;
hba = (struct st_hba *) &host->hostdata[0];
-
- if (unlikely(hba->mu_status == MU_STATE_RESETTING))
+ if (hba->mu_status == MU_STATE_NOCONNECT) {
+ cmd->result = DID_NO_CONNECT;
+ done(cmd);
+ return 0;
+ }
+ if (unlikely(hba->mu_status != MU_STATE_STARTED))
return SCSI_MLQUEUE_HOST_BUSY;
switch (cmd->cmnd[0]) {
@@ -1259,10 +1295,8 @@ static void stex_ss_reset(struct st_hba *hba)
static int stex_do_reset(struct st_hba *hba)
{
- struct st_ccb *ccb;
unsigned long flags;
unsigned int mu_status = MU_STATE_RESETTING;
- u16 tag;
spin_lock_irqsave(hba->host->host_lock, flags);
if (hba->mu_status == MU_STATE_STARTING) {
@@ -1296,20 +1330,8 @@ static int stex_do_reset(struct st_hba *hba)
else if (hba->cardtype == st_yel)
stex_ss_reset(hba);
- spin_lock_irqsave(hba->host->host_lock, flags);
- for (tag = 0; tag < hba->host->can_queue; tag++) {
- ccb = &hba->ccb[tag];
- if (ccb->req == NULL)
- continue;
- ccb->req = NULL;
- if (ccb->cmd) {
- scsi_dma_unmap(ccb->cmd);
- ccb->cmd->result = DID_RESET << 16;
- ccb->cmd->scsi_done(ccb->cmd);
- ccb->cmd = NULL;
- }
- }
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return_abnormal_state(hba, DID_RESET);
if (stex_handshake(hba) == 0)
return 0;
@@ -1560,6 +1582,25 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hba->cardtype = (unsigned int) id->driver_data;
ci = &stex_card_info[hba->cardtype];
+ switch (id->subdevice) {
+ case 0x4221:
+ case 0x4222:
+ case 0x4223:
+ case 0x4224:
+ case 0x4225:
+ case 0x4226:
+ case 0x4227:
+ case 0x4261:
+ case 0x4262:
+ case 0x4263:
+ case 0x4264:
+ case 0x4265:
+ break;
+ default:
+ if (hba->cardtype == st_yel)
+ hba->supports_pm = 1;
+ }
+
sts_offset = scratch_offset = (ci->rq_count+1) * ci->rq_size;
if (hba->cardtype == st_yel)
sts_offset += (ci->sts_count+1) * sizeof(u32);
@@ -1685,7 +1726,7 @@ out_disable:
return err;
}
-static void stex_hba_stop(struct st_hba *hba)
+static void stex_hba_stop(struct st_hba *hba, int st_sleep_mic)
{
struct req_msg *req;
struct st_msg_header *msg_h;
@@ -1694,6 +1735,15 @@ static void stex_hba_stop(struct st_hba *hba)
u16 tag = 0;
spin_lock_irqsave(hba->host->host_lock, flags);
+
+ if (hba->cardtype == st_yel && hba->supports_pm == 1)
+ {
+ if(st_sleep_mic == ST_NOTHANDLED)
+ {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return;
+ }
+ }
req = hba->alloc_rq(hba);
if (hba->cardtype == st_yel) {
msg_h = (struct st_msg_header *)req - 1;
@@ -1701,11 +1751,18 @@ static void stex_hba_stop(struct st_hba *hba)
} else
memset(req, 0, hba->rq_size);
- if (hba->cardtype == st_yosemite || hba->cardtype == st_yel) {
+ if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel)
+ && st_sleep_mic == ST_IGNORED) {
req->cdb[0] = MGT_CMD;
req->cdb[1] = MGT_CMD_SIGNATURE;
req->cdb[2] = CTLR_CONFIG_CMD;
req->cdb[3] = CTLR_SHUTDOWN;
+ } else if (hba->cardtype == st_yel && st_sleep_mic != ST_IGNORED) {
+ req->cdb[0] = MGT_CMD;
+ req->cdb[1] = MGT_CMD_SIGNATURE;
+ req->cdb[2] = CTLR_CONFIG_CMD;
+ req->cdb[3] = PMIC_SHUTDOWN;
+ req->cdb[4] = st_sleep_mic;
} else {
req->cdb[0] = CONTROLLER_CMD;
req->cdb[1] = CTLR_POWER_STATE_CHANGE;
@@ -1725,10 +1782,12 @@ static void stex_hba_stop(struct st_hba *hba)
while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {
if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
hba->ccb[tag].req_type = 0;
+ hba->mu_status = MU_STATE_STOP;
return;
}
msleep(1);
}
+ hba->mu_status = MU_STATE_STOP;
}
static void stex_hba_free(struct st_hba *hba)
@@ -1751,9 +1810,11 @@ static void stex_remove(struct pci_dev *pdev)
{
struct st_hba *hba = pci_get_drvdata(pdev);
+ hba->mu_status = MU_STATE_NOCONNECT;
+ return_abnormal_state(hba, DID_NO_CONNECT);
scsi_remove_host(hba->host);
- stex_hba_stop(hba);
+ scsi_block_requests(hba->host);
stex_hba_free(hba);
@@ -1766,9 +1827,43 @@ static void stex_shutdown(struct pci_dev *pdev)
{
struct st_hba *hba = pci_get_drvdata(pdev);
- stex_hba_stop(hba);
+ if (hba->supports_pm == 0)
+ stex_hba_stop(hba, ST_IGNORED);
+ else
+ stex_hba_stop(hba, ST_S5);
+}
+
+static int stex_choice_sleep_mic(pm_message_t state)
+{
+ switch (state.event) {
+ case PM_EVENT_SUSPEND:
+ return ST_S3;
+ case PM_EVENT_HIBERNATE:
+ return ST_S4;
+ default:
+ return ST_NOTHANDLED;
+ }
+}
+
+static int stex_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct st_hba *hba = pci_get_drvdata(pdev);
+
+ if (hba->cardtype == st_yel && hba->supports_pm == 1)
+ stex_hba_stop(hba, stex_choice_sleep_mic(state));
+ else
+ stex_hba_stop(hba, ST_IGNORED);
+ return 0;
}
+static int stex_resume(struct pci_dev *pdev)
+{
+ struct st_hba *hba = pci_get_drvdata(pdev);
+
+ hba->mu_status = MU_STATE_STARTING;
+ stex_handshake(hba);
+ return 0;
+}
MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
static struct pci_driver stex_pci_driver = {
@@ -1777,6 +1872,8 @@ static struct pci_driver stex_pci_driver = {
.probe = stex_probe,
.remove = stex_remove,
.shutdown = stex_shutdown,
+ .suspend = stex_suspend,
+ .resume = stex_resume,
};
static int __init stex_init(void)
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 292c04eec9ad..3ddcabb790a8 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -914,8 +914,9 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
do_work = true;
process_err_fn = storvsc_remove_lun;
break;
- case (SRB_STATUS_ABORTED | SRB_STATUS_AUTOSENSE_VALID):
- if ((asc == 0x2a) && (ascq == 0x9)) {
+ case SRB_STATUS_ABORTED:
+ if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
+ (asc == 0x2a) && (ascq == 0x9)) {
do_work = true;
process_err_fn = storvsc_device_scan;
/*
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 42c459a9d3fe..54a16cef0367 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -170,7 +170,7 @@ enum ufs_desc_max_size {
* of descriptor header.
*/
QUERY_DESC_STRING_MAX_SIZE = 0xFE,
- QUERY_DESC_GEOMETRY_MAZ_SIZE = 0x44,
+ QUERY_DESC_GEOMETRY_MAX_SIZE = 0x44,
QUERY_DESC_POWER_MAX_SIZE = 0x62,
QUERY_DESC_RFU_MAX_SIZE = 0x00,
};
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 85cd2564c157..9c1b94bef8f3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,7 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.c
* Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -58,13 +58,25 @@
#define QUERY_REQ_RETRIES 10
/* Query request timeout */
#define QUERY_REQ_TIMEOUT 30 /* msec */
+/*
+ * Query request timeout for fDeviceInit flag
+ * fDeviceInit query response time for some devices is too large that default
+ * QUERY_REQ_TIMEOUT may not be enough for such devices.
+ */
+#define QUERY_FDEVICEINIT_REQ_TIMEOUT 600 /* msec */
/* Task management command timeout */
#define TM_CMD_TIMEOUT 100 /* msecs */
+/* maximum number of retries for a general UIC command */
+#define UFS_UIC_COMMAND_RETRIES 3
+
/* maximum number of link-startup retries */
#define DME_LINKSTARTUP_RETRIES 3
+/* Maximum retries for Hibern8 enter */
+#define UIC_HIBERN8_ENTER_RETRIES 3
+
/* maximum number of reset retries before giving up */
#define MAX_HOST_RESET_RETRIES 5
@@ -92,7 +104,7 @@ static u32 ufs_query_desc_max_size[] = {
QUERY_DESC_INTERCONNECT_MAX_SIZE,
QUERY_DESC_STRING_MAX_SIZE,
QUERY_DESC_RFU_MAX_SIZE,
- QUERY_DESC_GEOMETRY_MAZ_SIZE,
+ QUERY_DESC_GEOMETRY_MAX_SIZE,
QUERY_DESC_POWER_MAX_SIZE,
QUERY_DESC_RFU_MAX_SIZE,
};
@@ -190,6 +202,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode);
static int ufshcd_change_power_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *pwr_mode);
+static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
+{
+ return tag >= 0 && tag < hba->nutrs;
+}
static inline int ufshcd_enable_irq(struct ufs_hba *hba)
{
@@ -360,6 +376,16 @@ static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
}
/**
+ * ufshcd_outstanding_req_clear - Clear a bit in outstanding request field
+ * @hba: per adapter instance
+ * @tag: position of the bit to be cleared
+ */
+static inline void ufshcd_outstanding_req_clear(struct ufs_hba *hba, int tag)
+{
+ __clear_bit(tag, &hba->outstanding_reqs);
+}
+
+/**
* ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
* @reg: Register value of host controller status
*
@@ -374,11 +400,9 @@ static inline int ufshcd_get_lists_status(u32 reg)
* 1 UTRLRDY
* 2 UTMRLRDY
* 3 UCRDY
- * 4 HEI
- * 5 DEI
- * 6-7 reserved
+ * 4-7 reserved
*/
- return (((reg) & (0xFF)) >> 1) ^ (0x07);
+ return ((reg & 0xFF) >> 1) ^ 0x07;
}
/**
@@ -582,6 +606,11 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
spin_lock_irqsave(hba->host->host_lock, flags);
hba->clk_gating.active_reqs++;
+ if (ufshcd_eh_in_progress(hba)) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return 0;
+ }
+
start:
switch (hba->clk_gating.state) {
case CLKS_ON:
@@ -697,7 +726,8 @@ static void __ufshcd_release(struct ufs_hba *hba)
if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended
|| hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL
|| hba->lrb_in_use || hba->outstanding_tasks
- || hba->active_uic_cmd || hba->uic_async_done)
+ || hba->active_uic_cmd || hba->uic_async_done
+ || ufshcd_eh_in_progress(hba))
return;
hba->clk_gating.state = REQ_CLKS_OFF;
@@ -953,13 +983,15 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
* __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
* @hba: per adapter instance
* @uic_cmd: UIC command
+ * @completion: initialize the completion only if this is set to true
*
* Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
* with mutex held and host_lock locked.
* Returns 0 only if success.
*/
static int
-__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd,
+ bool completion)
{
if (!ufshcd_ready_for_uic_cmd(hba)) {
dev_err(hba->dev,
@@ -967,7 +999,8 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
return -EIO;
}
- init_completion(&uic_cmd->done);
+ if (completion)
+ init_completion(&uic_cmd->done);
ufshcd_dispatch_uic_cmd(hba, uic_cmd);
@@ -992,7 +1025,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
ufshcd_add_delay_before_dme_cmd(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
- ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
+ ret = __ufshcd_send_uic_cmd(hba, uic_cmd, true);
spin_unlock_irqrestore(hba->host->host_lock, flags);
if (!ret)
ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
@@ -1035,6 +1068,7 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
cpu_to_le32(lower_32_bits(sg->dma_address));
prd_table[i].upper_addr =
cpu_to_le32(upper_32_bits(sg->dma_address));
+ prd_table[i].reserved = 0;
}
} else {
lrbp->utr_descriptor_ptr->prd_table_length = 0;
@@ -1117,7 +1151,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
/* Transfer request descriptor header fields */
req_desc->header.dword_0 = cpu_to_le32(dword_0);
-
+ /* dword_1 is reserved, hence it is set to 0 */
+ req_desc->header.dword_1 = 0;
/*
* assigning invalid value for command status. Controller
* updates OCS on command completion, with the command
@@ -1125,6 +1160,10 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
*/
req_desc->header.dword_2 =
cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+ /* dword_3 is reserved, hence it is set to 0 */
+ req_desc->header.dword_3 = 0;
+
+ req_desc->prd_table_length = 0;
}
/**
@@ -1137,6 +1176,7 @@ static
void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
{
struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+ unsigned short cdb_len;
/* command descriptor fields */
ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
@@ -1151,8 +1191,11 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
ucd_req_ptr->sc.exp_data_transfer_len =
cpu_to_be32(lrbp->cmd->sdb.length);
- memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
- (min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
+ cdb_len = min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE);
+ memset(ucd_req_ptr->sc.cdb, 0, MAX_CDB_SIZE);
+ memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd, cdb_len);
+
+ memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
}
/**
@@ -1189,6 +1232,7 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC)
memcpy(descp, query->descriptor, len);
+ memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
}
static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
@@ -1201,6 +1245,11 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
ucd_req_ptr->header.dword_0 =
UPIU_HEADER_DWORD(
UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag);
+ /* clear rest of the fields of basic header */
+ ucd_req_ptr->header.dword_1 = 0;
+ ucd_req_ptr->header.dword_2 = 0;
+
+ memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
}
/**
@@ -1293,6 +1342,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
hba = shost_priv(host);
tag = cmd->request->tag;
+ if (!ufshcd_valid_tag(hba, tag)) {
+ dev_err(hba->dev,
+ "%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
+ __func__, tag, cmd, cmd->request);
+ BUG();
+ }
spin_lock_irqsave(hba->host->host_lock, flags);
switch (hba->ufshcd_state) {
@@ -1312,6 +1367,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
cmd->scsi_done(cmd);
goto out_unlock;
}
+
+ /* if error handling is in progress, don't issue commands */
+ if (ufshcd_eh_in_progress(hba)) {
+ set_host_byte(cmd, DID_ERROR);
+ cmd->scsi_done(cmd);
+ goto out_unlock;
+ }
spin_unlock_irqrestore(hba->host->host_lock, flags);
/* acquire the tag to make sure device cmds don't use it */
@@ -1475,9 +1537,17 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
if (!time_left) {
err = -ETIMEDOUT;
+ dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n",
+ __func__, lrbp->task_tag);
if (!ufshcd_clear_cmd(hba, lrbp->task_tag))
- /* sucessfully cleared the command, retry if needed */
+ /* successfully cleared the command, retry if needed */
err = -EAGAIN;
+ /*
+ * in case of an error, after clearing the doorbell,
+ * we also need to clear the outstanding_request
+ * field in hba
+ */
+ ufshcd_outstanding_req_clear(hba, lrbp->task_tag);
}
return err;
@@ -1555,6 +1625,8 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
hba->dev_cmd.complete = &wait;
+ /* Make sure descriptors are ready before ringing the doorbell */
+ wmb();
spin_lock_irqsave(hba->host->host_lock, flags);
ufshcd_send_command(hba, tag);
spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -1591,6 +1663,29 @@ static inline void ufshcd_init_query(struct ufs_hba *hba,
(*request)->upiu_req.selector = selector;
}
+static int ufshcd_query_flag_retry(struct ufs_hba *hba,
+ enum query_opcode opcode, enum flag_idn idn, bool *flag_res)
+{
+ int ret;
+ int retries;
+
+ for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) {
+ ret = ufshcd_query_flag(hba, opcode, idn, flag_res);
+ if (ret)
+ dev_dbg(hba->dev,
+ "%s: failed with error %d, retries %d\n",
+ __func__, ret, retries);
+ else
+ break;
+ }
+
+ if (ret)
+ dev_err(hba->dev,
+ "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n",
+ __func__, opcode, idn, ret, retries);
+ return ret;
+}
+
/**
* ufshcd_query_flag() - API function for sending flag query requests
* hba: per-adapter instance
@@ -1600,12 +1695,13 @@ static inline void ufshcd_init_query(struct ufs_hba *hba,
*
* Returns 0 for success, non-zero in case of failure
*/
-static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
enum flag_idn idn, bool *flag_res)
{
struct ufs_query_req *request = NULL;
struct ufs_query_res *response = NULL;
int err, index = 0, selector = 0;
+ int timeout = QUERY_REQ_TIMEOUT;
BUG_ON(!hba);
@@ -1638,7 +1734,10 @@ static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
goto out_unlock;
}
- err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+ if (idn == QUERY_FLAG_IDN_FDEVICEINIT)
+ timeout = QUERY_FDEVICEINIT_REQ_TIMEOUT;
+
+ err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout);
if (err) {
dev_err(hba->dev,
@@ -1722,6 +1821,43 @@ out:
}
/**
+ * ufshcd_query_attr_retry() - API function for sending query
+ * attribute with retries
+ * @hba: per-adapter instance
+ * @opcode: attribute opcode
+ * @idn: attribute idn to access
+ * @index: index field
+ * @selector: selector field
+ * @attr_val: the attribute value after the query request
+ * completes
+ *
+ * Returns 0 for success, non-zero in case of failure
+*/
+static int ufshcd_query_attr_retry(struct ufs_hba *hba,
+ enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector,
+ u32 *attr_val)
+{
+ int ret = 0;
+ u32 retries;
+
+ for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+ ret = ufshcd_query_attr(hba, opcode, idn, index,
+ selector, attr_val);
+ if (ret)
+ dev_dbg(hba->dev, "%s: failed with error %d, retries %d\n",
+ __func__, ret, retries);
+ else
+ break;
+ }
+
+ if (ret)
+ dev_err(hba->dev,
+ "%s: query attribute, idn %d, failed with error %d after %d retires\n",
+ __func__, idn, ret, QUERY_REQ_RETRIES);
+ return ret;
+}
+
+/**
* ufshcd_query_descriptor - API function for sending descriptor requests
* hba: per-adapter instance
* opcode: attribute opcode
@@ -2128,6 +2264,7 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
};
const char *set = action[!!peer];
int ret;
+ int retries = UFS_UIC_COMMAND_RETRIES;
uic_cmd.command = peer ?
UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
@@ -2135,10 +2272,18 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
uic_cmd.argument3 = mib_val;
- ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
- if (ret)
- dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
- set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
+ do {
+ /* for peer attributes we retry upon failure */
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
+ set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
+ } while (ret && peer && --retries);
+
+ if (!retries)
+ dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n",
+ set, UIC_GET_ATTR_ID(attr_sel), mib_val,
+ retries);
return ret;
}
@@ -2163,6 +2308,7 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
};
const char *get = action[!!peer];
int ret;
+ int retries = UFS_UIC_COMMAND_RETRIES;
struct ufs_pa_layer_attr orig_pwr_info;
struct ufs_pa_layer_attr temp_pwr_info;
bool pwr_mode_change = false;
@@ -2193,14 +2339,19 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
uic_cmd.argument1 = attr_sel;
- ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
- if (ret) {
- dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
- get, UIC_GET_ATTR_ID(attr_sel), ret);
- goto out;
- }
+ do {
+ /* for peer attributes we retry upon failure */
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n",
+ get, UIC_GET_ATTR_ID(attr_sel), ret);
+ } while (ret && peer && --retries);
- if (mib_val)
+ if (!retries)
+ dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n",
+ get, UIC_GET_ATTR_ID(attr_sel), retries);
+
+ if (mib_val && !ret)
*mib_val = uic_cmd.argument3;
if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE)
@@ -2233,6 +2384,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
unsigned long flags;
u8 status;
int ret;
+ bool reenable_intr = false;
mutex_lock(&hba->uic_cmd_mutex);
init_completion(&uic_async_done);
@@ -2240,15 +2392,17 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
spin_lock_irqsave(hba->host->host_lock, flags);
hba->uic_async_done = &uic_async_done;
- ret = __ufshcd_send_uic_cmd(hba, cmd);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- if (ret) {
- dev_err(hba->dev,
- "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n",
- cmd->command, cmd->argument3, ret);
- goto out;
+ if (ufshcd_readl(hba, REG_INTERRUPT_ENABLE) & UIC_COMMAND_COMPL) {
+ ufshcd_disable_intr(hba, UIC_COMMAND_COMPL);
+ /*
+ * Make sure UIC command completion interrupt is disabled before
+ * issuing UIC command.
+ */
+ wmb();
+ reenable_intr = true;
}
- ret = ufshcd_wait_for_uic_cmd(hba, cmd);
+ ret = __ufshcd_send_uic_cmd(hba, cmd, false);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
if (ret) {
dev_err(hba->dev,
"pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n",
@@ -2274,7 +2428,10 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
}
out:
spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->active_uic_cmd = NULL;
hba->uic_async_done = NULL;
+ if (reenable_intr)
+ ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
spin_unlock_irqrestore(hba->host->host_lock, flags);
mutex_unlock(&hba->uic_cmd_mutex);
@@ -2315,13 +2472,65 @@ out:
return ret;
}
-static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
+static int ufshcd_link_recovery(struct ufs_hba *hba)
{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->ufshcd_state = UFSHCD_STATE_RESET;
+ ufshcd_set_eh_in_progress(hba);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ ret = ufshcd_host_reset_and_restore(hba);
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (ret)
+ hba->ufshcd_state = UFSHCD_STATE_ERROR;
+ ufshcd_clear_eh_in_progress(hba);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ if (ret)
+ dev_err(hba->dev, "%s: link recovery failed, err %d",
+ __func__, ret);
+
+ return ret;
+}
+
+static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
+{
+ int ret;
struct uic_command uic_cmd = {0};
uic_cmd.command = UIC_CMD_DME_HIBER_ENTER;
+ ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
+
+ if (ret) {
+ dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d\n",
+ __func__, ret);
+
+ /*
+ * If link recovery fails then return error so that caller
+ * don't retry the hibern8 enter again.
+ */
+ if (ufshcd_link_recovery(hba))
+ ret = -ENOLINK;
+ }
- return ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
+ return ret;
+}
+
+static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
+{
+ int ret = 0, retries;
+
+ for (retries = UIC_HIBERN8_ENTER_RETRIES; retries > 0; retries--) {
+ ret = __ufshcd_uic_hibern8_enter(hba);
+ if (!ret || ret == -ENOLINK)
+ goto out;
+ }
+out:
+ return ret;
}
static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
@@ -2332,8 +2541,9 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
uic_cmd.command = UIC_CMD_DME_HIBER_EXIT;
ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
if (ret) {
- ufshcd_set_link_off(hba);
- ret = ufshcd_host_reset_and_restore(hba);
+ dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d\n",
+ __func__, ret);
+ ret = ufshcd_link_recovery(hba);
}
return ret;
@@ -2513,17 +2723,12 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
*/
static int ufshcd_complete_dev_init(struct ufs_hba *hba)
{
- int i, retries, err = 0;
+ int i;
+ int err;
bool flag_res = 1;
- for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
- /* Set the fDeviceInit flag */
- err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
- QUERY_FLAG_IDN_FDEVICEINIT, NULL);
- if (!err || err == -ETIMEDOUT)
- break;
- dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
- }
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+ QUERY_FLAG_IDN_FDEVICEINIT, NULL);
if (err) {
dev_err(hba->dev,
"%s setting fDeviceInit flag failed with error %d\n",
@@ -2531,18 +2736,11 @@ static int ufshcd_complete_dev_init(struct ufs_hba *hba)
goto out;
}
- /* poll for max. 100 iterations for fDeviceInit flag to clear */
- for (i = 0; i < 100 && !err && flag_res; i++) {
- for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
- err = ufshcd_query_flag(hba,
- UPIU_QUERY_OPCODE_READ_FLAG,
- QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
- if (!err || err == -ETIMEDOUT)
- break;
- dev_dbg(hba->dev, "%s: error %d retrying\n", __func__,
- err);
- }
- }
+ /* poll for max. 1000 iterations for fDeviceInit flag to clear */
+ for (i = 0; i < 1000 && !err && flag_res; i++)
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
+ QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+
if (err)
dev_err(hba->dev,
"%s reading fDeviceInit flag failed with error %d\n",
@@ -2563,7 +2761,7 @@ out:
* To bring UFS host controller to operational state,
* 1. Enable required interrupts
* 2. Configure interrupt aggregation
- * 3. Program UTRL and UTMRL base addres
+ * 3. Program UTRL and UTMRL base address
* 4. Configure run-stop-registers
*
* Returns 0 on success, non-zero value on failure
@@ -2593,8 +2791,13 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
REG_UTP_TASK_REQ_LIST_BASE_H);
/*
+ * Make sure base address and interrupt setup are updated before
+ * enabling the run/stop registers below.
+ */
+ wmb();
+
+ /*
* UCRDY, UTMRLDY and UTRLRDY bits must be 1
- * DEI, HEI bits must be 0
*/
reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
if (!(ufshcd_get_lists_status(reg))) {
@@ -3090,7 +3293,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
scsi_status = result & MASK_SCSI_STATUS;
result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
- if (ufshcd_is_exception_event(lrbp->ucd_rsp_ptr))
+ /*
+ * Currently we are only supporting BKOPs exception
+ * events hence we can ignore BKOPs exception event
+ * during power management callbacks. BKOPs exception
+ * event is not expected to be raised in runtime suspend
+ * callback as it allows the urgent bkops.
+ * During system suspend, we are anyway forcefully
+ * disabling the bkops and if urgent bkops is needed
+ * it will be enabled on system resume. Long term
+ * solution could be to abort the system suspend if
+ * UFS device needs urgent BKOPs.
+ */
+ if (!hba->pm_op_in_progress &&
+ ufshcd_is_exception_event(lrbp->ucd_rsp_ptr))
schedule_work(&hba->eeh_work);
break;
case UPIU_TRANSACTION_REJECT_UPIU:
@@ -3222,7 +3438,7 @@ static int ufshcd_disable_ee(struct ufs_hba *hba, u16 mask)
val = hba->ee_ctrl_mask & ~mask;
val &= 0xFFFF; /* 2 bytes */
- err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val);
if (!err)
hba->ee_ctrl_mask &= ~mask;
@@ -3250,7 +3466,7 @@ static int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask)
val = hba->ee_ctrl_mask | mask;
val &= 0xFFFF; /* 2 bytes */
- err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val);
if (!err)
hba->ee_ctrl_mask |= mask;
@@ -3276,7 +3492,7 @@ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba)
if (hba->auto_bkops_enabled)
goto out;
- err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
QUERY_FLAG_IDN_BKOPS_EN, NULL);
if (err) {
dev_err(hba->dev, "%s: failed to enable bkops %d\n",
@@ -3325,7 +3541,7 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba)
goto out;
}
- err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
QUERY_FLAG_IDN_BKOPS_EN, NULL);
if (err) {
dev_err(hba->dev, "%s: failed to disable bkops %d\n",
@@ -3356,7 +3572,7 @@ static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba)
static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status)
{
- return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+ return ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, status);
}
@@ -3419,7 +3635,7 @@ static int ufshcd_urgent_bkops(struct ufs_hba *hba)
static inline int ufshcd_get_ee_status(struct ufs_hba *hba, u32 *status)
{
- return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+ return ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
QUERY_ATTR_IDN_EE_STATUS, 0, 0, status);
}
@@ -3645,16 +3861,20 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
*/
static irqreturn_t ufshcd_intr(int irq, void *__hba)
{
- u32 intr_status;
+ u32 intr_status, enabled_intr_status;
irqreturn_t retval = IRQ_NONE;
struct ufs_hba *hba = __hba;
spin_lock(hba->host->host_lock);
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+ enabled_intr_status =
+ intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
- if (intr_status) {
+ if (intr_status)
ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
- ufshcd_sl_intr(hba, intr_status);
+
+ if (enabled_intr_status) {
+ ufshcd_sl_intr(hba, enabled_intr_status);
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
@@ -3740,6 +3960,10 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
/* send command to the controller */
__set_bit(free_slot, &hba->outstanding_tasks);
+
+ /* Make sure descriptors are ready before ringing the task doorbell */
+ wmb();
+
ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
spin_unlock_irqrestore(host->host_lock, flags);
@@ -3845,13 +4069,23 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
host = cmd->device->host;
hba = shost_priv(host);
tag = cmd->request->tag;
+ if (!ufshcd_valid_tag(hba, tag)) {
+ dev_err(hba->dev,
+ "%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
+ __func__, tag, cmd, cmd->request);
+ BUG();
+ }
ufshcd_hold(hba, false);
+ reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
/* If command is already aborted/completed, return SUCCESS */
- if (!(test_bit(tag, &hba->outstanding_reqs)))
+ if (!(test_bit(tag, &hba->outstanding_reqs))) {
+ dev_err(hba->dev,
+ "%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n",
+ __func__, tag, hba->outstanding_reqs, reg);
goto out;
+ }
- reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
if (!(reg & (1 << tag))) {
dev_err(hba->dev,
"%s: cmd was completed, but without a notifying intr, tag = %d",
@@ -3905,7 +4139,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
scsi_dma_unmap(cmd);
spin_lock_irqsave(host->host_lock, flags);
- __clear_bit(tag, &hba->outstanding_reqs);
+ ufshcd_outstanding_req_clear(hba, tag);
hba->lrb[tag].cmd = NULL;
spin_unlock_irqrestore(host->host_lock, flags);
@@ -4155,9 +4389,9 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
dev_dbg(hba->dev, "%s: setting icc_level 0x%x",
__func__, hba->init_prefetch_data.icc_level);
- ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
- QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0,
- &hba->init_prefetch_data.icc_level);
+ ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0,
+ &hba->init_prefetch_data.icc_level);
if (ret)
dev_err(hba->dev,
@@ -4262,7 +4496,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
/* UFS device is also active now */
ufshcd_set_ufs_dev_active(hba);
ufshcd_force_reset_auto_bkops(hba);
- hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
hba->wlun_dev_clr_ua = true;
if (ufshcd_get_max_pwr_mode(hba)) {
@@ -4276,6 +4509,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
__func__, ret);
}
+ /* set the state as operational after switching to desired gear */
+ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
/*
* If we are in error handling context or in power management callbacks
* context, no need to scan the host
@@ -4285,8 +4520,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
/* clear any previous UFS device information */
memset(&hba->dev_info, 0, sizeof(hba->dev_info));
- if (!ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,
- QUERY_FLAG_IDN_PWR_ON_WPE, &flag))
+ if (!ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
+ QUERY_FLAG_IDN_PWR_ON_WPE, &flag))
hba->dev_info.f_power_on_wp_en = flag;
if (!hba->is_init_prefetch)
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 2570d9477b37..e3931d0c94eb 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -3,6 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.h
* Copyright (C) 2011-2013 Samsung India Software Operations
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -177,7 +178,7 @@ struct ufshcd_lrb {
};
/**
- * struct ufs_query - holds relevent data structures for query request
+ * struct ufs_query - holds relevant data structures for query request
* @request: request upiu and function
* @descriptor: buffer for sending/receiving descriptor
* @response: response upiu and response
@@ -681,6 +682,9 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER);
}
+/* Expose Query-Request API */
+int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+ enum flag_idn idn, bool *flag_res);
int ufshcd_hold(struct ufs_hba *hba, bool async);
void ufshcd_release(struct ufs_hba *hba);
diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c
index 91a003011acf..a9bac3bf20de 100644
--- a/drivers/sh/pm_runtime.c
+++ b/drivers/sh/pm_runtime.c
@@ -34,7 +34,7 @@ static struct pm_clk_notifier_block platform_bus_notifier = {
static int __init sh_pm_runtime_init(void)
{
- if (IS_ENABLED(CONFIG_ARCH_SHMOBILE)) {
+ if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_ARCH_SHMOBILE)) {
if (!of_find_compatible_node(NULL, NULL,
"renesas,cpg-mstp-clocks"))
return 0;
diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c
index 2d9e7f3d5611..bb1fb7712134 100644
--- a/drivers/sh/superhyway/superhyway.c
+++ b/drivers/sh/superhyway/superhyway.c
@@ -66,7 +66,7 @@ int superhyway_add_device(unsigned long base, struct superhyway_device *sdev,
superhyway_read_vcr(dev, base, &dev->vcr);
if (!dev->resource) {
- dev->resource = kmalloc(sizeof(struct resource), GFP_KERNEL);
+ dev->resource = kzalloc(sizeof(struct resource), GFP_KERNEL);
if (!dev->resource) {
kfree(dev);
return -ENOMEM;
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 77064160dd76..9d8c84bb1544 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -75,11 +75,26 @@ config SPI_ATMEL
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
+config SPI_AU1550
+ tristate "Au1550/Au1200/Au1300 SPI Controller"
+ depends on MIPS_ALCHEMY
+ select SPI_BITBANG
+ help
+ If you say yes to this option, support will be included for the
+ PSC SPI controller found on Au1550, Au1200 and Au1300 series.
+
+config SPI_AXI_SPI_ENGINE
+ tristate "Analog Devices AXI SPI Engine controller"
+ depends on HAS_IOMEM
+ help
+ This enables support for the Analog Devices AXI SPI Engine SPI controller.
+ It is part of the SPI Engine framework that is used in some Analog Devices
+ reference designs for FPGAs.
+
config SPI_BCM2835
tristate "BCM2835 SPI controller"
depends on GPIOLIB
depends on ARCH_BCM2835 || COMPILE_TEST
- depends on GPIOLIB
help
This selects a driver for the Broadcom BCM2835 SPI master.
@@ -90,8 +105,7 @@ config SPI_BCM2835
config SPI_BCM2835AUX
tristate "BCM2835 SPI auxiliary controller"
- depends on ARCH_BCM2835 || COMPILE_TEST
- depends on GPIOLIB
+ depends on (ARCH_BCM2835 && GPIOLIB) || COMPILE_TEST
help
This selects a driver for the Broadcom BCM2835 SPI aux master.
@@ -118,14 +132,6 @@ config SPI_BFIN_SPORT
help
Enable support for a SPI bus via the Blackfin SPORT peripheral.
-config SPI_AU1550
- tristate "Au1550/Au1200/Au1300 SPI Controller"
- depends on MIPS_ALCHEMY
- select SPI_BITBANG
- help
- If you say yes to this option, support will be included for the
- PSC SPI controller found on Au1550, Au1200 and Au1300 series.
-
config SPI_BCM53XX
tristate "Broadcom BCM53xx SPI controller"
depends on ARCH_BCM_5301X
@@ -197,6 +203,23 @@ config SPI_DAVINCI
help
SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
+config SPI_DESIGNWARE
+ tristate "DesignWare SPI controller core support"
+ help
+ general driver for SPI controller core from DesignWare
+
+config SPI_DW_PCI
+ tristate "PCI interface driver for DW SPI core"
+ depends on SPI_DESIGNWARE && PCI
+
+config SPI_DW_MID_DMA
+ bool "DMA support for DW SPI controller on Intel MID platform"
+ depends on SPI_DW_PCI && DW_DMAC_PCI
+
+config SPI_DW_MMIO
+ tristate "Memory-mapped io interface driver for DW SPI core"
+ depends on SPI_DESIGNWARE
+
config SPI_DLN2
tristate "Diolan DLN-2 USB SPI adapter"
depends on MFD_DLN2
@@ -271,6 +294,16 @@ config SPI_LM70_LLP
which interfaces to an LM70 temperature sensor using
a parallel port.
+config SPI_LP8841_RTC
+ tristate "ICP DAS LP-8841 SPI Controller for RTC"
+ depends on MACH_PXA27X_DT || COMPILE_TEST
+ help
+ This driver provides an SPI master device to drive Maxim
+ DS-1302 real time clock.
+
+ Say N here unless you plan to run the kernel on an ICP DAS
+ LP-8x4x industrial computer.
+
config SPI_MPC52xx
tristate "Freescale MPC52xx SPI (non-PSC) controller support"
depends on PPC_MPC52xx
@@ -346,6 +379,13 @@ config SPI_MT65XX
say Y or M here.If you are not sure, say N.
SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs.
+config SPI_NUC900
+ tristate "Nuvoton NUC900 series SPI"
+ depends on ARCH_W90X900
+ select SPI_BITBANG
+ help
+ SPI driver for Nuvoton NUC900 series ARM SoCs
+
config SPI_OC_TINY
tristate "OpenCores tiny SPI"
depends on GPIOLIB || COMPILE_TEST
@@ -415,10 +455,6 @@ config SPI_PPC4xx
help
This selects a driver for the PPC4xx SPI Controller.
-config SPI_PXA2XX_DMA
- def_bool y
- depends on SPI_PXA2XX
-
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on (ARCH_PXA || PCI || ACPI)
@@ -451,7 +487,7 @@ config SPI_RB4XX
config SPI_RSPI
tristate "Renesas RSPI/QSPI controller"
- depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
+ depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
help
SPI driver for Renesas RSPI and QSPI blocks.
@@ -501,7 +537,7 @@ config SPI_SC18IS602
config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on HAVE_CLK && HAS_DMA
- depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
+ depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
help
SPI driver for SuperH and SH Mobile MSIOF blocks.
@@ -520,7 +556,7 @@ config SPI_SH_SCI
config SPI_SH_HSPI
tristate "SuperH HSPI controller"
- depends on ARCH_SHMOBILE || COMPILE_TEST
+ depends on ARCH_RENESAS || COMPILE_TEST
help
SPI driver for SuperH HSPI blocks.
@@ -647,34 +683,10 @@ config SPI_ZYNQMP_GQSPI
help
Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
-config SPI_NUC900
- tristate "Nuvoton NUC900 series SPI"
- depends on ARCH_W90X900
- select SPI_BITBANG
- help
- SPI driver for Nuvoton NUC900 series ARM SoCs
-
#
# Add new SPI master controllers in alphabetical order above this line
#
-config SPI_DESIGNWARE
- tristate "DesignWare SPI controller core support"
- help
- general driver for SPI controller core from DesignWare
-
-config SPI_DW_PCI
- tristate "PCI interface driver for DW SPI core"
- depends on SPI_DESIGNWARE && PCI
-
-config SPI_DW_MID_DMA
- bool "DMA support for DW SPI controller on Intel MID platform"
- depends on SPI_DW_PCI && DW_DMAC_PCI
-
-config SPI_DW_MMIO
- tristate "Memory-mapped io interface driver for DW SPI core"
- depends on SPI_DESIGNWARE
-
#
# There are lots of SPI device types, with sensors and memory
# being probably the most widely used ones.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 8991ffce6e12..fbb255c5a608 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera.o
obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
+obj-$(CONFIG_SPI_AXI_SPI_ENGINE) += spi-axi-spi-engine.o
obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm2835aux.o
obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_SPI_GPIO) += spi-gpio.o
obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o
obj-$(CONFIG_SPI_IMX) += spi-imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
+obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o
obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
@@ -62,8 +64,7 @@ obj-$(CONFIG_SPI_TI_QSPI) += spi-ti-qspi.o
obj-$(CONFIG_SPI_ORION) += spi-orion.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
-spi-pxa2xx-platform-objs := spi-pxa2xx.o
-spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
+spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index aebad36391c9..8feac599e9ab 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1571,6 +1571,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
as->use_cs_gpios = true;
if (atmel_spi_is_v2(as) &&
+ pdev->dev.of_node &&
!of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) {
as->use_cs_gpios = false;
master->num_chipselect = 4;
diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
new file mode 100644
index 000000000000..c968ab210a51
--- /dev/null
+++ b/drivers/spi/spi-axi-spi-engine.c
@@ -0,0 +1,591 @@
+/*
+ * SPI-Engine SPI controller driver
+ * Copyright 2015 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#define SPI_ENGINE_VERSION_MAJOR(x) ((x >> 16) & 0xff)
+#define SPI_ENGINE_VERSION_MINOR(x) ((x >> 8) & 0xff)
+#define SPI_ENGINE_VERSION_PATCH(x) (x & 0xff)
+
+#define SPI_ENGINE_REG_VERSION 0x00
+
+#define SPI_ENGINE_REG_RESET 0x40
+
+#define SPI_ENGINE_REG_INT_ENABLE 0x80
+#define SPI_ENGINE_REG_INT_PENDING 0x84
+#define SPI_ENGINE_REG_INT_SOURCE 0x88
+
+#define SPI_ENGINE_REG_SYNC_ID 0xc0
+
+#define SPI_ENGINE_REG_CMD_FIFO_ROOM 0xd0
+#define SPI_ENGINE_REG_SDO_FIFO_ROOM 0xd4
+#define SPI_ENGINE_REG_SDI_FIFO_LEVEL 0xd8
+
+#define SPI_ENGINE_REG_CMD_FIFO 0xe0
+#define SPI_ENGINE_REG_SDO_DATA_FIFO 0xe4
+#define SPI_ENGINE_REG_SDI_DATA_FIFO 0xe8
+#define SPI_ENGINE_REG_SDI_DATA_FIFO_PEEK 0xec
+
+#define SPI_ENGINE_INT_CMD_ALMOST_EMPTY BIT(0)
+#define SPI_ENGINE_INT_SDO_ALMOST_EMPTY BIT(1)
+#define SPI_ENGINE_INT_SDI_ALMOST_FULL BIT(2)
+#define SPI_ENGINE_INT_SYNC BIT(3)
+
+#define SPI_ENGINE_CONFIG_CPHA BIT(0)
+#define SPI_ENGINE_CONFIG_CPOL BIT(1)
+#define SPI_ENGINE_CONFIG_3WIRE BIT(2)
+
+#define SPI_ENGINE_INST_TRANSFER 0x0
+#define SPI_ENGINE_INST_ASSERT 0x1
+#define SPI_ENGINE_INST_WRITE 0x2
+#define SPI_ENGINE_INST_MISC 0x3
+
+#define SPI_ENGINE_CMD_REG_CLK_DIV 0x0
+#define SPI_ENGINE_CMD_REG_CONFIG 0x1
+
+#define SPI_ENGINE_MISC_SYNC 0x0
+#define SPI_ENGINE_MISC_SLEEP 0x1
+
+#define SPI_ENGINE_TRANSFER_WRITE 0x1
+#define SPI_ENGINE_TRANSFER_READ 0x2
+
+#define SPI_ENGINE_CMD(inst, arg1, arg2) \
+ (((inst) << 12) | ((arg1) << 8) | (arg2))
+
+#define SPI_ENGINE_CMD_TRANSFER(flags, n) \
+ SPI_ENGINE_CMD(SPI_ENGINE_INST_TRANSFER, (flags), (n))
+#define SPI_ENGINE_CMD_ASSERT(delay, cs) \
+ SPI_ENGINE_CMD(SPI_ENGINE_INST_ASSERT, (delay), (cs))
+#define SPI_ENGINE_CMD_WRITE(reg, val) \
+ SPI_ENGINE_CMD(SPI_ENGINE_INST_WRITE, (reg), (val))
+#define SPI_ENGINE_CMD_SLEEP(delay) \
+ SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SLEEP, (delay))
+#define SPI_ENGINE_CMD_SYNC(id) \
+ SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SYNC, (id))
+
+struct spi_engine_program {
+ unsigned int length;
+ uint16_t instructions[];
+};
+
+struct spi_engine {
+ struct clk *clk;
+ struct clk *ref_clk;
+
+ spinlock_t lock;
+
+ void __iomem *base;
+
+ struct spi_message *msg;
+ struct spi_engine_program *p;
+ unsigned cmd_length;
+ const uint16_t *cmd_buf;
+
+ struct spi_transfer *tx_xfer;
+ unsigned int tx_length;
+ const uint8_t *tx_buf;
+
+ struct spi_transfer *rx_xfer;
+ unsigned int rx_length;
+ uint8_t *rx_buf;
+
+ unsigned int sync_id;
+ unsigned int completed_id;
+
+ unsigned int int_enable;
+};
+
+static void spi_engine_program_add_cmd(struct spi_engine_program *p,
+ bool dry, uint16_t cmd)
+{
+ if (!dry)
+ p->instructions[p->length] = cmd;
+ p->length++;
+}
+
+static unsigned int spi_engine_get_config(struct spi_device *spi)
+{
+ unsigned int config = 0;
+
+ if (spi->mode & SPI_CPOL)
+ config |= SPI_ENGINE_CONFIG_CPOL;
+ if (spi->mode & SPI_CPHA)
+ config |= SPI_ENGINE_CONFIG_CPHA;
+ if (spi->mode & SPI_3WIRE)
+ config |= SPI_ENGINE_CONFIG_3WIRE;
+
+ return config;
+}
+
+static unsigned int spi_engine_get_clk_div(struct spi_engine *spi_engine,
+ struct spi_device *spi, struct spi_transfer *xfer)
+{
+ unsigned int clk_div;
+
+ clk_div = DIV_ROUND_UP(clk_get_rate(spi_engine->ref_clk),
+ xfer->speed_hz * 2);
+ if (clk_div > 255)
+ clk_div = 255;
+ else if (clk_div > 0)
+ clk_div -= 1;
+
+ return clk_div;
+}
+
+static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
+ struct spi_transfer *xfer)
+{
+ unsigned int len = xfer->len;
+
+ while (len) {
+ unsigned int n = min(len, 256U);
+ unsigned int flags = 0;
+
+ if (xfer->tx_buf)
+ flags |= SPI_ENGINE_TRANSFER_WRITE;
+ if (xfer->rx_buf)
+ flags |= SPI_ENGINE_TRANSFER_READ;
+
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_TRANSFER(flags, n - 1));
+ len -= n;
+ }
+}
+
+static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
+ struct spi_engine *spi_engine, unsigned int clk_div, unsigned int delay)
+{
+ unsigned int spi_clk = clk_get_rate(spi_engine->ref_clk);
+ unsigned int t;
+
+ if (delay == 0)
+ return;
+
+ t = DIV_ROUND_UP(delay * spi_clk, (clk_div + 1) * 2);
+ while (t) {
+ unsigned int n = min(t, 256U);
+
+ spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_SLEEP(n - 1));
+ t -= n;
+ }
+}
+
+static void spi_engine_gen_cs(struct spi_engine_program *p, bool dry,
+ struct spi_device *spi, bool assert)
+{
+ unsigned int mask = 0xff;
+
+ if (assert)
+ mask ^= BIT(spi->chip_select);
+
+ spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_ASSERT(1, mask));
+}
+
+static int spi_engine_compile_message(struct spi_engine *spi_engine,
+ struct spi_message *msg, bool dry, struct spi_engine_program *p)
+{
+ struct spi_device *spi = msg->spi;
+ struct spi_transfer *xfer;
+ int clk_div, new_clk_div;
+ bool cs_change = true;
+
+ clk_div = -1;
+
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CONFIG,
+ spi_engine_get_config(spi)));
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ new_clk_div = spi_engine_get_clk_div(spi_engine, spi, xfer);
+ if (new_clk_div != clk_div) {
+ clk_div = new_clk_div;
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CLK_DIV,
+ clk_div));
+ }
+
+ if (cs_change)
+ spi_engine_gen_cs(p, dry, spi, true);
+
+ spi_engine_gen_xfer(p, dry, xfer);
+ spi_engine_gen_sleep(p, dry, spi_engine, clk_div,
+ xfer->delay_usecs);
+
+ cs_change = xfer->cs_change;
+ if (list_is_last(&xfer->transfer_list, &msg->transfers))
+ cs_change = !cs_change;
+
+ if (cs_change)
+ spi_engine_gen_cs(p, dry, spi, false);
+ }
+
+ return 0;
+}
+
+static void spi_engine_xfer_next(struct spi_engine *spi_engine,
+ struct spi_transfer **_xfer)
+{
+ struct spi_message *msg = spi_engine->msg;
+ struct spi_transfer *xfer = *_xfer;
+
+ if (!xfer) {
+ xfer = list_first_entry(&msg->transfers,
+ struct spi_transfer, transfer_list);
+ } else if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
+ xfer = NULL;
+ } else {
+ xfer = list_next_entry(xfer, transfer_list);
+ }
+
+ *_xfer = xfer;
+}
+
+static void spi_engine_tx_next(struct spi_engine *spi_engine)
+{
+ struct spi_transfer *xfer = spi_engine->tx_xfer;
+
+ do {
+ spi_engine_xfer_next(spi_engine, &xfer);
+ } while (xfer && !xfer->tx_buf);
+
+ spi_engine->tx_xfer = xfer;
+ if (xfer) {
+ spi_engine->tx_length = xfer->len;
+ spi_engine->tx_buf = xfer->tx_buf;
+ } else {
+ spi_engine->tx_buf = NULL;
+ }
+}
+
+static void spi_engine_rx_next(struct spi_engine *spi_engine)
+{
+ struct spi_transfer *xfer = spi_engine->rx_xfer;
+
+ do {
+ spi_engine_xfer_next(spi_engine, &xfer);
+ } while (xfer && !xfer->rx_buf);
+
+ spi_engine->rx_xfer = xfer;
+ if (xfer) {
+ spi_engine->rx_length = xfer->len;
+ spi_engine->rx_buf = xfer->rx_buf;
+ } else {
+ spi_engine->rx_buf = NULL;
+ }
+}
+
+static bool spi_engine_write_cmd_fifo(struct spi_engine *spi_engine)
+{
+ void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_CMD_FIFO;
+ unsigned int n, m, i;
+ const uint16_t *buf;
+
+ n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_CMD_FIFO_ROOM);
+ while (n && spi_engine->cmd_length) {
+ m = min(n, spi_engine->cmd_length);
+ buf = spi_engine->cmd_buf;
+ for (i = 0; i < m; i++)
+ writel_relaxed(buf[i], addr);
+ spi_engine->cmd_buf += m;
+ spi_engine->cmd_length -= m;
+ n -= m;
+ }
+
+ return spi_engine->cmd_length != 0;
+}
+
+static bool spi_engine_write_tx_fifo(struct spi_engine *spi_engine)
+{
+ void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDO_DATA_FIFO;
+ unsigned int n, m, i;
+ const uint8_t *buf;
+
+ n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDO_FIFO_ROOM);
+ while (n && spi_engine->tx_length) {
+ m = min(n, spi_engine->tx_length);
+ buf = spi_engine->tx_buf;
+ for (i = 0; i < m; i++)
+ writel_relaxed(buf[i], addr);
+ spi_engine->tx_buf += m;
+ spi_engine->tx_length -= m;
+ n -= m;
+ if (spi_engine->tx_length == 0)
+ spi_engine_tx_next(spi_engine);
+ }
+
+ return spi_engine->tx_length != 0;
+}
+
+static bool spi_engine_read_rx_fifo(struct spi_engine *spi_engine)
+{
+ void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDI_DATA_FIFO;
+ unsigned int n, m, i;
+ uint8_t *buf;
+
+ n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDI_FIFO_LEVEL);
+ while (n && spi_engine->rx_length) {
+ m = min(n, spi_engine->rx_length);
+ buf = spi_engine->rx_buf;
+ for (i = 0; i < m; i++)
+ buf[i] = readl_relaxed(addr);
+ spi_engine->rx_buf += m;
+ spi_engine->rx_length -= m;
+ n -= m;
+ if (spi_engine->rx_length == 0)
+ spi_engine_rx_next(spi_engine);
+ }
+
+ return spi_engine->rx_length != 0;
+}
+
+static irqreturn_t spi_engine_irq(int irq, void *devid)
+{
+ struct spi_master *master = devid;
+ struct spi_engine *spi_engine = spi_master_get_devdata(master);
+ unsigned int disable_int = 0;
+ unsigned int pending;
+
+ pending = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
+
+ if (pending & SPI_ENGINE_INT_SYNC) {
+ writel_relaxed(SPI_ENGINE_INT_SYNC,
+ spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
+ spi_engine->completed_id = readl_relaxed(
+ spi_engine->base + SPI_ENGINE_REG_SYNC_ID);
+ }
+
+ spin_lock(&spi_engine->lock);
+
+ if (pending & SPI_ENGINE_INT_CMD_ALMOST_EMPTY) {
+ if (!spi_engine_write_cmd_fifo(spi_engine))
+ disable_int |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
+ }
+
+ if (pending & SPI_ENGINE_INT_SDO_ALMOST_EMPTY) {
+ if (!spi_engine_write_tx_fifo(spi_engine))
+ disable_int |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
+ }
+
+ if (pending & (SPI_ENGINE_INT_SDI_ALMOST_FULL | SPI_ENGINE_INT_SYNC)) {
+ if (!spi_engine_read_rx_fifo(spi_engine))
+ disable_int |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
+ }
+
+ if (pending & SPI_ENGINE_INT_SYNC) {
+ if (spi_engine->msg &&
+ spi_engine->completed_id == spi_engine->sync_id) {
+ struct spi_message *msg = spi_engine->msg;
+
+ kfree(spi_engine->p);
+ msg->status = 0;
+ msg->actual_length = msg->frame_length;
+ spi_engine->msg = NULL;
+ spi_finalize_current_message(master);
+ disable_int |= SPI_ENGINE_INT_SYNC;
+ }
+ }
+
+ if (disable_int) {
+ spi_engine->int_enable &= ~disable_int;
+ writel_relaxed(spi_engine->int_enable,
+ spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
+ }
+
+ spin_unlock(&spi_engine->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int spi_engine_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct spi_engine_program p_dry, *p;
+ struct spi_engine *spi_engine = spi_master_get_devdata(master);
+ unsigned int int_enable = 0;
+ unsigned long flags;
+ size_t size;
+
+ p_dry.length = 0;
+ spi_engine_compile_message(spi_engine, msg, true, &p_dry);
+
+ size = sizeof(*p->instructions) * (p_dry.length + 1);
+ p = kzalloc(sizeof(*p) + size, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+ spi_engine_compile_message(spi_engine, msg, false, p);
+
+ spin_lock_irqsave(&spi_engine->lock, flags);
+ spi_engine->sync_id = (spi_engine->sync_id + 1) & 0xff;
+ spi_engine_program_add_cmd(p, false,
+ SPI_ENGINE_CMD_SYNC(spi_engine->sync_id));
+
+ spi_engine->msg = msg;
+ spi_engine->p = p;
+
+ spi_engine->cmd_buf = p->instructions;
+ spi_engine->cmd_length = p->length;
+ if (spi_engine_write_cmd_fifo(spi_engine))
+ int_enable |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
+
+ spi_engine_tx_next(spi_engine);
+ if (spi_engine_write_tx_fifo(spi_engine))
+ int_enable |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
+
+ spi_engine_rx_next(spi_engine);
+ if (spi_engine->rx_length != 0)
+ int_enable |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
+
+ int_enable |= SPI_ENGINE_INT_SYNC;
+
+ writel_relaxed(int_enable,
+ spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
+ spi_engine->int_enable = int_enable;
+ spin_unlock_irqrestore(&spi_engine->lock, flags);
+
+ return 0;
+}
+
+static int spi_engine_probe(struct platform_device *pdev)
+{
+ struct spi_engine *spi_engine;
+ struct spi_master *master;
+ unsigned int version;
+ struct resource *res;
+ int irq;
+ int ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0)
+ return -ENXIO;
+
+ spi_engine = devm_kzalloc(&pdev->dev, sizeof(*spi_engine), GFP_KERNEL);
+ if (!spi_engine)
+ return -ENOMEM;
+
+ master = spi_alloc_master(&pdev->dev, 0);
+ if (!master)
+ return -ENOMEM;
+
+ spi_master_set_devdata(master, spi_engine);
+
+ spin_lock_init(&spi_engine->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ spi_engine->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(spi_engine->base)) {
+ ret = PTR_ERR(spi_engine->base);
+ goto err_put_master;
+ }
+
+ version = readl(spi_engine->base + SPI_ENGINE_REG_VERSION);
+ if (SPI_ENGINE_VERSION_MAJOR(version) != 1) {
+ dev_err(&pdev->dev, "Unsupported peripheral version %u.%u.%c\n",
+ SPI_ENGINE_VERSION_MAJOR(version),
+ SPI_ENGINE_VERSION_MINOR(version),
+ SPI_ENGINE_VERSION_PATCH(version));
+ return -ENODEV;
+ }
+
+ spi_engine->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
+ if (IS_ERR(spi_engine->clk)) {
+ ret = PTR_ERR(spi_engine->clk);
+ goto err_put_master;
+ }
+
+ spi_engine->ref_clk = devm_clk_get(&pdev->dev, "spi_clk");
+ if (IS_ERR(spi_engine->ref_clk)) {
+ ret = PTR_ERR(spi_engine->ref_clk);
+ goto err_put_master;
+ }
+
+ ret = clk_prepare_enable(spi_engine->clk);
+ if (ret)
+ goto err_put_master;
+
+ ret = clk_prepare_enable(spi_engine->ref_clk);
+ if (ret)
+ goto err_clk_disable;
+
+ writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_RESET);
+ writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
+ writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
+
+ ret = request_irq(irq, spi_engine_irq, 0, pdev->name, master);
+ if (ret)
+ goto err_ref_clk_disable;
+
+ master->dev.parent = &pdev->dev;
+ master->dev.of_node = pdev->dev.of_node;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->max_speed_hz = clk_get_rate(spi_engine->ref_clk) / 2;
+ master->transfer_one_message = spi_engine_transfer_one_message;
+ master->num_chipselect = 8;
+
+ ret = spi_register_master(master);
+ if (ret)
+ goto err_free_irq;
+
+ platform_set_drvdata(pdev, master);
+
+ return 0;
+err_free_irq:
+ free_irq(irq, master);
+err_ref_clk_disable:
+ clk_disable_unprepare(spi_engine->ref_clk);
+err_clk_disable:
+ clk_disable_unprepare(spi_engine->clk);
+err_put_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int spi_engine_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_engine *spi_engine = spi_master_get_devdata(master);
+ int irq = platform_get_irq(pdev, 0);
+
+ spi_unregister_master(master);
+
+ free_irq(irq, master);
+
+ writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
+ writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
+ writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET);
+
+ clk_disable_unprepare(spi_engine->ref_clk);
+ clk_disable_unprepare(spi_engine->clk);
+
+ return 0;
+}
+
+static const struct of_device_id spi_engine_match_table[] = {
+ { .compatible = "adi,axi-spi-engine-1.00.a" },
+ { },
+};
+
+static struct platform_driver spi_engine_driver = {
+ .probe = spi_engine_probe,
+ .remove = spi_engine_remove,
+ .driver = {
+ .name = "spi-engine",
+ .of_match_table = spi_engine_match_table,
+ },
+};
+module_platform_driver(spi_engine_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices SPI engine peripheral driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index cf04960cc3e6..f35cc10772f6 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -727,11 +727,6 @@ static int bcm2835_spi_setup(struct spi_device *spi)
spi->chip_select, spi->cs_gpio, err);
return err;
}
- /* the implementation of pinctrl-bcm2835 currently does not
- * set the GPIO value when using gpio_direction_output
- * so we are setting it here explicitly
- */
- gpio_set_value(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ? 0 : 1);
return 0;
}
diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index 7de6f8472a81..7428091d3f5b 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -64,17 +64,17 @@
#define BCM2835_AUX_SPI_CNTL0_VAR_WIDTH 0x00004000
#define BCM2835_AUX_SPI_CNTL0_DOUTHOLD 0x00003000
#define BCM2835_AUX_SPI_CNTL0_ENABLE 0x00000800
-#define BCM2835_AUX_SPI_CNTL0_CPHA_IN 0x00000400
+#define BCM2835_AUX_SPI_CNTL0_IN_RISING 0x00000400
#define BCM2835_AUX_SPI_CNTL0_CLEARFIFO 0x00000200
-#define BCM2835_AUX_SPI_CNTL0_CPHA_OUT 0x00000100
+#define BCM2835_AUX_SPI_CNTL0_OUT_RISING 0x00000100
#define BCM2835_AUX_SPI_CNTL0_CPOL 0x00000080
#define BCM2835_AUX_SPI_CNTL0_MSBF_OUT 0x00000040
#define BCM2835_AUX_SPI_CNTL0_SHIFTLEN 0x0000003F
/* Bitfields in CNTL1 */
#define BCM2835_AUX_SPI_CNTL1_CSHIGH 0x00000700
-#define BCM2835_AUX_SPI_CNTL1_IDLE 0x00000080
-#define BCM2835_AUX_SPI_CNTL1_TXEMPTY 0x00000040
+#define BCM2835_AUX_SPI_CNTL1_TXEMPTY 0x00000080
+#define BCM2835_AUX_SPI_CNTL1_IDLE 0x00000040
#define BCM2835_AUX_SPI_CNTL1_MSBF_IN 0x00000002
#define BCM2835_AUX_SPI_CNTL1_KEEP_IN 0x00000001
@@ -92,9 +92,6 @@
#define BCM2835_AUX_SPI_POLLING_LIMIT_US 30
#define BCM2835_AUX_SPI_POLLING_JIFFIES 2
-#define BCM2835_AUX_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
- | SPI_NO_CS)
-
struct bcm2835aux_spi {
void __iomem *regs;
struct clk *clk;
@@ -212,9 +209,15 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
ret = IRQ_HANDLED;
}
- /* and if rx_len is 0 then wake up completion and disable spi */
+ if (!bs->tx_len) {
+ /* disable tx fifo empty interrupt */
+ bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1] |
+ BCM2835_AUX_SPI_CNTL1_IDLE);
+ }
+
+ /* and if rx_len is 0 then disable interrupts and wake up completion */
if (!bs->rx_len) {
- bcm2835aux_spi_reset_hw(bs);
+ bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
complete(&master->xfer_completion);
}
@@ -307,9 +310,6 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
}
}
- /* Transfer complete - reset SPI HW */
- bcm2835aux_spi_reset_hw(bs);
-
/* and return without waiting for completion */
return 0;
}
@@ -330,10 +330,6 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
* resulting (potentially) in more interrupts when transferring
* more than 12 bytes
*/
- bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE |
- BCM2835_AUX_SPI_CNTL0_VAR_WIDTH |
- BCM2835_AUX_SPI_CNTL0_MSBF_OUT;
- bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
/* set clock */
spi_hz = tfr->speed_hz;
@@ -348,17 +344,13 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
} else { /* the slowest we can go */
speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX;
}
+ /* mask out old speed from previous spi_transfer */
+ bs->cntl[0] &= ~(BCM2835_AUX_SPI_CNTL0_SPEED);
+ /* set the new speed */
bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT;
spi_used_hz = clk_hz / (2 * (speed + 1));
- /* handle all the modes */
- if (spi->mode & SPI_CPOL)
- bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
- if (spi->mode & SPI_CPHA)
- bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
- BCM2835_AUX_SPI_CNTL0_CPHA_IN;
-
/* set transmit buffers and length */
bs->tx_buf = tfr->tx_buf;
bs->rx_buf = tfr->rx_buf;
@@ -382,6 +374,40 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
}
+static int bcm2835aux_spi_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct spi_device *spi = msg->spi;
+ struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+
+ bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE |
+ BCM2835_AUX_SPI_CNTL0_VAR_WIDTH |
+ BCM2835_AUX_SPI_CNTL0_MSBF_OUT;
+ bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
+
+ /* handle all the modes */
+ if (spi->mode & SPI_CPOL) {
+ bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
+ bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_OUT_RISING;
+ } else {
+ bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_IN_RISING;
+ }
+ bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
+ bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);
+
+ return 0;
+}
+
+static int bcm2835aux_spi_unprepare_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+
+ bcm2835aux_spi_reset_hw(bs);
+
+ return 0;
+}
+
static void bcm2835aux_spi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
@@ -405,11 +431,13 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, master);
- master->mode_bits = BCM2835_AUX_SPI_MODE_BITS;
+ master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS);
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->num_chipselect = -1;
master->transfer_one = bcm2835aux_spi_transfer_one;
master->handle_err = bcm2835aux_spi_handle_err;
+ master->prepare_message = bcm2835aux_spi_prepare_message;
+ master->unprepare_message = bcm2835aux_spi_unprepare_message;
master->dev.of_node = pdev->dev.of_node;
bs = spi_master_get_devdata(master);
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 9185f6c08459..e31971f91475 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -89,10 +89,10 @@ static void mid_spi_dma_exit(struct dw_spi *dws)
if (!dws->dma_inited)
return;
- dmaengine_terminate_all(dws->txchan);
+ dmaengine_terminate_sync(dws->txchan);
dma_release_channel(dws->txchan);
- dmaengine_terminate_all(dws->rxchan);
+ dmaengine_terminate_sync(dws->rxchan);
dma_release_channel(dws->rxchan);
}
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index a6d7029a85ac..447497e9124c 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -47,11 +47,6 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
/* Get basic io resource and map it */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -EINVAL;
- }
-
dws->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dws->regs)) {
dev_err(&pdev->dev, "SPI region map failed\n");
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 7fd6a4c009d2..7cb0c1921495 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -84,7 +84,7 @@ struct fsl_espi_transfer {
/* SPCOM register values */
#define SPCOM_CS(x) ((x) << 30)
#define SPCOM_TRANLEN(x) ((x) << 0)
-#define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */
+#define SPCOM_TRANLEN_MAX 0x10000 /* Max transaction length */
#define AUTOSUSPEND_TIMEOUT 2000
@@ -233,7 +233,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
reinit_completion(&mpc8xxx_spi->done);
/* Set SPCOM[CS] and SPCOM[TRANLEN] field */
- if ((t->len - 1) > SPCOM_TRANLEN_MAX) {
+ if (t->len > SPCOM_TRANLEN_MAX) {
dev_err(mpc8xxx_spi->dev, "Transaction length (%d)"
" beyond the SPCOM[TRANLEN] field\n", t->len);
return -EINVAL;
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index d98c33cb64f9..e7a19be87c38 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -56,7 +56,6 @@
/* The maximum bytes that a sdma BD can transfer.*/
#define MAX_SDMA_BD_BYTES (1 << 15)
-#define IMX_DMA_TIMEOUT (msecs_to_jiffies(3000))
struct spi_imx_config {
unsigned int speed_hz;
unsigned int bpw;
@@ -86,12 +85,18 @@ struct spi_imx_devtype_data {
struct spi_imx_data {
struct spi_bitbang bitbang;
+ struct device *dev;
struct completion xfer_done;
void __iomem *base;
+ unsigned long base_phys;
+
struct clk *clk_per;
struct clk *clk_ipg;
unsigned long spi_clk;
+ unsigned int spi_bus_clk;
+
+ unsigned int bytes_per_word;
unsigned int count;
void (*tx)(struct spi_imx_data *);
@@ -101,8 +106,6 @@ struct spi_imx_data {
unsigned int txfifo; /* number of words pushed in tx FIFO */
/* DMA */
- unsigned int dma_is_inited;
- unsigned int dma_finished;
bool usedma;
u32 wml;
struct completion dma_rx_completion;
@@ -199,15 +202,35 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
return 7;
}
+static int spi_imx_bytes_per_word(const int bpw)
+{
+ return DIV_ROUND_UP(bpw, BITS_PER_BYTE);
+}
+
static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
+ unsigned int bpw = transfer->bits_per_word;
+
+ if (!master->dma_rx)
+ return false;
- if (spi_imx->dma_is_inited &&
- transfer->len > spi_imx->wml * sizeof(u32))
- return true;
- return false;
+ if (!bpw)
+ bpw = spi->bits_per_word;
+
+ bpw = spi_imx_bytes_per_word(bpw);
+
+ if (bpw != 1 && bpw != 2 && bpw != 4)
+ return false;
+
+ if (transfer->len < spi_imx->wml * bpw)
+ return false;
+
+ if (transfer->len % (spi_imx->wml * bpw))
+ return false;
+
+ return true;
}
#define MX51_ECSPI_CTRL 0x08
@@ -232,16 +255,13 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_INT_RREN (1 << 3)
#define MX51_ECSPI_DMA 0x14
-#define MX51_ECSPI_DMA_TX_WML_OFFSET 0
-#define MX51_ECSPI_DMA_TX_WML_MASK 0x3F
-#define MX51_ECSPI_DMA_RX_WML_OFFSET 16
-#define MX51_ECSPI_DMA_RX_WML_MASK (0x3F << 16)
-#define MX51_ECSPI_DMA_RXT_WML_OFFSET 24
-#define MX51_ECSPI_DMA_RXT_WML_MASK (0x3F << 24)
+#define MX51_ECSPI_DMA_TX_WML(wml) ((wml) & 0x3f)
+#define MX51_ECSPI_DMA_RX_WML(wml) (((wml) & 0x3f) << 16)
+#define MX51_ECSPI_DMA_RXT_WML(wml) (((wml) & 0x3f) << 24)
-#define MX51_ECSPI_DMA_TEDEN_OFFSET 7
-#define MX51_ECSPI_DMA_RXDEN_OFFSET 23
-#define MX51_ECSPI_DMA_RXTDEN_OFFSET 31
+#define MX51_ECSPI_DMA_TEDEN (1 << 7)
+#define MX51_ECSPI_DMA_RXDEN (1 << 23)
+#define MX51_ECSPI_DMA_RXTDEN (1 << 31)
#define MX51_ECSPI_STAT 0x18
#define MX51_ECSPI_STAT_RR (1 << 3)
@@ -250,14 +270,15 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_TESTREG_LBC BIT(31)
/* MX51 eCSPI */
-static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi,
- unsigned int *fres)
+static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
+ unsigned int fspi, unsigned int *fres)
{
/*
* there are two 4-bit dividers, the pre-divider divides by
* $pre, the post-divider by 2^$post
*/
unsigned int pre, post;
+ unsigned int fin = spi_imx->spi_clk;
if (unlikely(fspi > fin))
return 0;
@@ -270,14 +291,14 @@ static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi,
post = max(4U, post) - 4;
if (unlikely(post > 0xf)) {
- pr_err("%s: cannot set clock freq: %u (base freq: %u)\n",
- __func__, fspi, fin);
+ dev_err(spi_imx->dev, "cannot set clock freq: %u (base freq: %u)\n",
+ fspi, fin);
return 0xff;
}
pre = DIV_ROUND_UP(fin, fspi << post) - 1;
- pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
+ dev_dbg(spi_imx->dev, "%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
__func__, fin, fspi, post, pre);
/* Resulting frequency for the SCLK line. */
@@ -302,22 +323,17 @@ static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int
static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
{
- u32 reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
+ u32 reg;
- if (!spi_imx->usedma)
- reg |= MX51_ECSPI_CTRL_XCH;
- else if (!spi_imx->dma_finished)
- reg |= MX51_ECSPI_CTRL_SMC;
- else
- reg &= ~MX51_ECSPI_CTRL_SMC;
+ reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
+ reg |= MX51_ECSPI_CTRL_XCH;
writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
}
static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config)
{
- u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0, dma = 0;
- u32 tx_wml_cfg, rx_wml_cfg, rxt_wml_cfg;
+ u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0;
u32 clk = config->speed_hz, delay, reg;
/*
@@ -330,7 +346,8 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
/* set clock speed */
- ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz, &clk);
+ ctrl |= mx51_ecspi_clkdiv(spi_imx, config->speed_hz, &clk);
+ spi_imx->spi_bus_clk = clk;
/* set chip select to use */
ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
@@ -341,20 +358,16 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
if (config->mode & SPI_CPHA)
cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs);
- else
- cfg &= ~MX51_ECSPI_CONFIG_SCLKPHA(config->cs);
if (config->mode & SPI_CPOL) {
cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs);
cfg |= MX51_ECSPI_CONFIG_SCLKCTL(config->cs);
- } else {
- cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(config->cs);
- cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(config->cs);
}
if (config->mode & SPI_CS_HIGH)
cfg |= MX51_ECSPI_CONFIG_SSBPOL(config->cs);
- else
- cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(config->cs);
+
+ if (spi_imx->usedma)
+ ctrl |= MX51_ECSPI_CTRL_SMC;
/* CTRL register always go first to bring out controller from reset */
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
@@ -389,22 +402,12 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
* Configure the DMA register: setup the watermark
* and enable DMA request.
*/
- if (spi_imx->dma_is_inited) {
- dma = readl(spi_imx->base + MX51_ECSPI_DMA);
-
- rx_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
- tx_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
- rxt_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_RXT_WML_OFFSET;
- dma = (dma & ~MX51_ECSPI_DMA_TX_WML_MASK
- & ~MX51_ECSPI_DMA_RX_WML_MASK
- & ~MX51_ECSPI_DMA_RXT_WML_MASK)
- | rx_wml_cfg | tx_wml_cfg | rxt_wml_cfg
- |(1 << MX51_ECSPI_DMA_TEDEN_OFFSET)
- |(1 << MX51_ECSPI_DMA_RXDEN_OFFSET)
- |(1 << MX51_ECSPI_DMA_RXTDEN_OFFSET);
-
- writel(dma, spi_imx->base + MX51_ECSPI_DMA);
- }
+
+ writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml) |
+ MX51_ECSPI_DMA_TX_WML(spi_imx->wml) |
+ MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
+ MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
+ MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
return 0;
}
@@ -784,11 +787,63 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int spi_imx_dma_configure(struct spi_master *master,
+ int bytes_per_word)
+{
+ int ret;
+ enum dma_slave_buswidth buswidth;
+ struct dma_slave_config rx = {}, tx = {};
+ struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
+
+ if (bytes_per_word == spi_imx->bytes_per_word)
+ /* Same as last time */
+ return 0;
+
+ switch (bytes_per_word) {
+ case 4:
+ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ break;
+ case 2:
+ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ break;
+ case 1:
+ buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tx.direction = DMA_MEM_TO_DEV;
+ tx.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA;
+ tx.dst_addr_width = buswidth;
+ tx.dst_maxburst = spi_imx->wml;
+ ret = dmaengine_slave_config(master->dma_tx, &tx);
+ if (ret) {
+ dev_err(spi_imx->dev, "TX dma configuration failed with %d\n", ret);
+ return ret;
+ }
+
+ rx.direction = DMA_DEV_TO_MEM;
+ rx.src_addr = spi_imx->base_phys + MXC_CSPIRXDATA;
+ rx.src_addr_width = buswidth;
+ rx.src_maxburst = spi_imx->wml;
+ ret = dmaengine_slave_config(master->dma_rx, &rx);
+ if (ret) {
+ dev_err(spi_imx->dev, "RX dma configuration failed with %d\n", ret);
+ return ret;
+ }
+
+ spi_imx->bytes_per_word = bytes_per_word;
+
+ return 0;
+}
+
static int spi_imx_setupxfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
struct spi_imx_config config;
+ int ret;
config.bpw = t ? t->bits_per_word : spi->bits_per_word;
config.speed_hz = t ? t->speed_hz : spi->max_speed_hz;
@@ -812,6 +867,18 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->tx = spi_imx_buf_tx_u32;
}
+ if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t))
+ spi_imx->usedma = 1;
+ else
+ spi_imx->usedma = 0;
+
+ if (spi_imx->usedma) {
+ ret = spi_imx_dma_configure(spi->master,
+ spi_imx_bytes_per_word(config.bpw));
+ if (ret)
+ return ret;
+ }
+
spi_imx->devtype_data->config(spi_imx, &config);
return 0;
@@ -830,15 +897,11 @@ static void spi_imx_sdma_exit(struct spi_imx_data *spi_imx)
dma_release_channel(master->dma_tx);
master->dma_tx = NULL;
}
-
- spi_imx->dma_is_inited = 0;
}
static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
- struct spi_master *master,
- const struct resource *res)
+ struct spi_master *master)
{
- struct dma_slave_config slave_config = {};
int ret;
/* use pio mode for i.mx6dl chip TKT238285 */
@@ -856,16 +919,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
goto err;
}
- slave_config.direction = DMA_MEM_TO_DEV;
- slave_config.dst_addr = res->start + MXC_CSPITXDATA;
- slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- slave_config.dst_maxburst = spi_imx->wml;
- ret = dmaengine_slave_config(master->dma_tx, &slave_config);
- if (ret) {
- dev_err(dev, "error in TX dma configuration.\n");
- goto err;
- }
-
/* Prepare for RX : */
master->dma_rx = dma_request_slave_channel_reason(dev, "rx");
if (IS_ERR(master->dma_rx)) {
@@ -875,15 +928,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
goto err;
}
- slave_config.direction = DMA_DEV_TO_MEM;
- slave_config.src_addr = res->start + MXC_CSPIRXDATA;
- slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- slave_config.src_maxburst = spi_imx->wml;
- ret = dmaengine_slave_config(master->dma_rx, &slave_config);
- if (ret) {
- dev_err(dev, "error in RX dma configuration.\n");
- goto err;
- }
+ spi_imx_dma_configure(master, 1);
init_completion(&spi_imx->dma_rx_completion);
init_completion(&spi_imx->dma_tx_completion);
@@ -891,7 +936,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
master->max_dma_len = MAX_SDMA_BD_BYTES;
spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX |
SPI_MASTER_MUST_TX;
- spi_imx->dma_is_inited = 1;
return 0;
err:
@@ -913,106 +957,81 @@ static void spi_imx_dma_tx_callback(void *cookie)
complete(&spi_imx->dma_tx_completion);
}
+static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
+{
+ unsigned long timeout = 0;
+
+ /* Time with actual data transfer and CS change delay related to HW */
+ timeout = (8 + 4) * size / spi_imx->spi_bus_clk;
+
+ /* Add extra second for scheduler related activities */
+ timeout += 1;
+
+ /* Double calculated timeout */
+ return msecs_to_jiffies(2 * timeout * MSEC_PER_SEC);
+}
+
static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
struct spi_transfer *transfer)
{
- struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
- int ret;
+ struct dma_async_tx_descriptor *desc_tx, *desc_rx;
+ unsigned long transfer_timeout;
unsigned long timeout;
- u32 dma;
- int left;
struct spi_master *master = spi_imx->bitbang.master;
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
- if (tx) {
- desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
- tx->sgl, tx->nents, DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_tx)
- goto no_dma;
-
- desc_tx->callback = spi_imx_dma_tx_callback;
- desc_tx->callback_param = (void *)spi_imx;
- dmaengine_submit(desc_tx);
- }
+ /*
+ * The TX DMA setup starts the transfer, so make sure RX is configured
+ * before TX.
+ */
+ desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
+ rx->sgl, rx->nents, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_rx)
+ return -EINVAL;
- if (rx) {
- desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
- rx->sgl, rx->nents, DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_rx)
- goto no_dma;
+ desc_rx->callback = spi_imx_dma_rx_callback;
+ desc_rx->callback_param = (void *)spi_imx;
+ dmaengine_submit(desc_rx);
+ reinit_completion(&spi_imx->dma_rx_completion);
+ dma_async_issue_pending(master->dma_rx);
- desc_rx->callback = spi_imx_dma_rx_callback;
- desc_rx->callback_param = (void *)spi_imx;
- dmaengine_submit(desc_rx);
+ desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
+ tx->sgl, tx->nents, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_tx) {
+ dmaengine_terminate_all(master->dma_tx);
+ return -EINVAL;
}
- reinit_completion(&spi_imx->dma_rx_completion);
+ desc_tx->callback = spi_imx_dma_tx_callback;
+ desc_tx->callback_param = (void *)spi_imx;
+ dmaengine_submit(desc_tx);
reinit_completion(&spi_imx->dma_tx_completion);
-
- /* Trigger the cspi module. */
- spi_imx->dma_finished = 0;
-
- dma = readl(spi_imx->base + MX51_ECSPI_DMA);
- dma = dma & (~MX51_ECSPI_DMA_RXT_WML_MASK);
- /* Change RX_DMA_LENGTH trigger dma fetch tail data */
- left = transfer->len % spi_imx->wml;
- if (left)
- writel(dma | (left << MX51_ECSPI_DMA_RXT_WML_OFFSET),
- spi_imx->base + MX51_ECSPI_DMA);
- /*
- * Set these order to avoid potential RX overflow. The overflow may
- * happen if we enable SPI HW before starting RX DMA due to rescheduling
- * for another task and/or interrupt.
- * So RX DMA enabled first to make sure data would be read out from FIFO
- * ASAP. TX DMA enabled next to start filling TX FIFO with new data.
- * And finaly SPI HW enabled to start actual data transfer.
- */
- dma_async_issue_pending(master->dma_rx);
dma_async_issue_pending(master->dma_tx);
- spi_imx->devtype_data->trigger(spi_imx);
+
+ transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
/* Wait SDMA to finish the data transfer.*/
timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
- IMX_DMA_TIMEOUT);
+ transfer_timeout);
if (!timeout) {
- pr_warn("%s %s: I/O Error in DMA TX\n",
- dev_driver_string(&master->dev),
- dev_name(&master->dev));
+ dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
dmaengine_terminate_all(master->dma_tx);
dmaengine_terminate_all(master->dma_rx);
- } else {
- timeout = wait_for_completion_timeout(
- &spi_imx->dma_rx_completion, IMX_DMA_TIMEOUT);
- if (!timeout) {
- pr_warn("%s %s: I/O Error in DMA RX\n",
- dev_driver_string(&master->dev),
- dev_name(&master->dev));
- spi_imx->devtype_data->reset(spi_imx);
- dmaengine_terminate_all(master->dma_rx);
- }
- dma &= ~MX51_ECSPI_DMA_RXT_WML_MASK;
- writel(dma |
- spi_imx->wml << MX51_ECSPI_DMA_RXT_WML_OFFSET,
- spi_imx->base + MX51_ECSPI_DMA);
+ return -ETIMEDOUT;
}
- spi_imx->dma_finished = 1;
- spi_imx->devtype_data->trigger(spi_imx);
-
- if (!timeout)
- ret = -ETIMEDOUT;
- else
- ret = transfer->len;
-
- return ret;
+ timeout = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
+ transfer_timeout);
+ if (!timeout) {
+ dev_err(&master->dev, "I/O Error in DMA RX\n");
+ spi_imx->devtype_data->reset(spi_imx);
+ dmaengine_terminate_all(master->dma_rx);
+ return -ETIMEDOUT;
+ }
-no_dma:
- pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
- dev_driver_string(&master->dev),
- dev_name(&master->dev));
- return -EAGAIN;
+ return transfer->len;
}
static int spi_imx_pio_transfer(struct spi_device *spi,
@@ -1039,19 +1058,12 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
static int spi_imx_transfer(struct spi_device *spi,
struct spi_transfer *transfer)
{
- int ret;
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
- if (spi_imx->bitbang.master->can_dma &&
- spi_imx_can_dma(spi_imx->bitbang.master, spi, transfer)) {
- spi_imx->usedma = true;
- ret = spi_imx_dma_transfer(spi_imx, transfer);
- if (ret != -EAGAIN)
- return ret;
- }
- spi_imx->usedma = false;
-
- return spi_imx_pio_transfer(spi, transfer);
+ if (spi_imx->usedma)
+ return spi_imx_dma_transfer(spi_imx, transfer);
+ else
+ return spi_imx_pio_transfer(spi, transfer);
}
static int spi_imx_setup(struct spi_device *spi)
@@ -1141,6 +1153,7 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = master;
+ spi_imx->dev = &pdev->dev;
spi_imx->devtype_data = of_id ? of_id->data :
(struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
@@ -1181,6 +1194,7 @@ static int spi_imx_probe(struct platform_device *pdev)
ret = PTR_ERR(spi_imx->base);
goto out_master_put;
}
+ spi_imx->base_phys = res->start;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -1221,7 +1235,7 @@ static int spi_imx_probe(struct platform_device *pdev)
* other chips.
*/
if (is_imx51_ecspi(spi_imx)) {
- ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master, res);
+ ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master);
if (ret == -EPROBE_DEFER)
goto out_clk_put;
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c
index 894616f687b0..cf4bb36bee25 100644
--- a/drivers/spi/spi-loopback-test.c
+++ b/drivers/spi/spi-loopback-test.c
@@ -761,6 +761,7 @@ static int spi_test_run_iter(struct spi_device *spi,
test.iterate_transfer_mask = 1;
/* count number of transfers with tx/rx_buf != NULL */
+ rx_count = tx_count = 0;
for (i = 0; i < test.transfer_count; i++) {
if (test.transfers[i].tx_buf)
tx_count++;
diff --git a/drivers/spi/spi-lp8841-rtc.c b/drivers/spi/spi-lp8841-rtc.c
new file mode 100644
index 000000000000..faa577d282c0
--- /dev/null
+++ b/drivers/spi/spi-lp8841-rtc.c
@@ -0,0 +1,256 @@
+/*
+ * SPI master driver for ICP DAS LP-8841 RTC
+ *
+ * Copyright (C) 2016 Sergei Ianovich
+ *
+ * based on
+ *
+ * Dallas DS1302 RTC Support
+ * Copyright (C) 2002 David McCullough
+ * Copyright (C) 2003 - 2007 Paul Mundt
+ *
+ * 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.
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+
+#define DRIVER_NAME "spi_lp8841_rtc"
+
+#define SPI_LP8841_RTC_CE 0x01
+#define SPI_LP8841_RTC_CLK 0x02
+#define SPI_LP8841_RTC_nWE 0x04
+#define SPI_LP8841_RTC_MOSI 0x08
+#define SPI_LP8841_RTC_MISO 0x01
+
+/*
+ * REVISIT If there is support for SPI_3WIRE and SPI_LSB_FIRST in SPI
+ * GPIO driver, this SPI driver can be replaced by a simple GPIO driver
+ * providing 3 GPIO pins.
+ */
+
+struct spi_lp8841_rtc {
+ void *iomem;
+ unsigned long state;
+};
+
+static inline void
+setsck(struct spi_lp8841_rtc *data, int is_on)
+{
+ if (is_on)
+ data->state |= SPI_LP8841_RTC_CLK;
+ else
+ data->state &= ~SPI_LP8841_RTC_CLK;
+ writeb(data->state, data->iomem);
+}
+
+static inline void
+setmosi(struct spi_lp8841_rtc *data, int is_on)
+{
+ if (is_on)
+ data->state |= SPI_LP8841_RTC_MOSI;
+ else
+ data->state &= ~SPI_LP8841_RTC_MOSI;
+ writeb(data->state, data->iomem);
+}
+
+static inline int
+getmiso(struct spi_lp8841_rtc *data)
+{
+ return ioread8(data->iomem) & SPI_LP8841_RTC_MISO;
+}
+
+static inline u32
+bitbang_txrx_be_cpha0_lsb(struct spi_lp8841_rtc *data,
+ unsigned usecs, unsigned cpol, unsigned flags,
+ u32 word, u8 bits)
+{
+ /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
+
+ u32 shift = 32 - bits;
+ /* clock starts at inactive polarity */
+ for (; likely(bits); bits--) {
+
+ /* setup LSB (to slave) on leading edge */
+ if ((flags & SPI_MASTER_NO_TX) == 0)
+ setmosi(data, (word & 1));
+
+ usleep_range(usecs, usecs + 1); /* T(setup) */
+
+ /* sample LSB (from slave) on trailing edge */
+ word >>= 1;
+ if ((flags & SPI_MASTER_NO_RX) == 0)
+ word |= (getmiso(data) << 31);
+
+ setsck(data, !cpol);
+ usleep_range(usecs, usecs + 1);
+
+ setsck(data, cpol);
+ }
+
+ word >>= shift;
+ return word;
+}
+
+static int
+spi_lp8841_rtc_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct spi_lp8841_rtc *data = spi_master_get_devdata(master);
+ unsigned count = t->len;
+ const u8 *tx = t->tx_buf;
+ u8 *rx = t->rx_buf;
+ u8 word = 0;
+ int ret = 0;
+
+ if (tx) {
+ data->state &= ~SPI_LP8841_RTC_nWE;
+ writeb(data->state, data->iomem);
+ while (likely(count > 0)) {
+ word = *tx++;
+ bitbang_txrx_be_cpha0_lsb(data, 1, 0,
+ SPI_MASTER_NO_RX, word, 8);
+ count--;
+ }
+ } else if (rx) {
+ data->state |= SPI_LP8841_RTC_nWE;
+ writeb(data->state, data->iomem);
+ while (likely(count > 0)) {
+ word = bitbang_txrx_be_cpha0_lsb(data, 1, 0,
+ SPI_MASTER_NO_TX, word, 8);
+ *rx++ = word;
+ count--;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+ spi_finalize_current_transfer(master);
+
+ return ret;
+}
+
+static void
+spi_lp8841_rtc_set_cs(struct spi_device *spi, bool enable)
+{
+ struct spi_lp8841_rtc *data = spi_master_get_devdata(spi->master);
+
+ data->state = 0;
+ writeb(data->state, data->iomem);
+ if (enable) {
+ usleep_range(4, 5);
+ data->state |= SPI_LP8841_RTC_CE;
+ writeb(data->state, data->iomem);
+ usleep_range(4, 5);
+ }
+}
+
+static int
+spi_lp8841_rtc_setup(struct spi_device *spi)
+{
+ if ((spi->mode & SPI_CS_HIGH) == 0) {
+ dev_err(&spi->dev, "unsupported active low chip select\n");
+ return -EINVAL;
+ }
+
+ if ((spi->mode & SPI_LSB_FIRST) == 0) {
+ dev_err(&spi->dev, "unsupported MSB first mode\n");
+ return -EINVAL;
+ }
+
+ if ((spi->mode & SPI_3WIRE) == 0) {
+ dev_err(&spi->dev, "unsupported wiring. 3 wires required\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id spi_lp8841_rtc_dt_ids[] = {
+ { .compatible = "icpdas,lp8841-spi-rtc" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, spi_lp8841_rtc_dt_ids);
+#endif
+
+static int
+spi_lp8841_rtc_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct spi_master *master;
+ struct spi_lp8841_rtc *data;
+ void *iomem;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*data));
+ if (!master)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, master);
+
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->mode_bits = SPI_CS_HIGH | SPI_3WIRE | SPI_LSB_FIRST;
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = 1;
+ master->setup = spi_lp8841_rtc_setup;
+ master->set_cs = spi_lp8841_rtc_set_cs;
+ master->transfer_one = spi_lp8841_rtc_transfer_one;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+#ifdef CONFIG_OF
+ master->dev.of_node = pdev->dev.of_node;
+#endif
+
+ data = spi_master_get_devdata(master);
+
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->iomem = devm_ioremap_resource(&pdev->dev, iomem);
+ ret = PTR_ERR_OR_ZERO(data->iomem);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get IO address\n");
+ goto err_put_master;
+ }
+
+ /* register with the SPI framework */
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register spi master\n");
+ goto err_put_master;
+ }
+
+ return ret;
+
+
+err_put_master:
+ spi_master_put(master);
+
+ return ret;
+}
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
+static struct platform_driver spi_lp8841_rtc_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(spi_lp8841_rtc_dt_ids),
+ },
+ .probe = spi_lp8841_rtc_probe,
+};
+module_platform_driver(spi_lp8841_rtc_driver);
+
+MODULE_DESCRIPTION("SPI master driver for ICP DAS LP-8841 RTC");
+MODULE_AUTHOR("Sergei Ianovich");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 7273820275e9..0caa3c8bef46 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -1490,6 +1490,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
return status;
disable_pm:
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
free_master:
spi_master_put(master);
@@ -1501,6 +1503,7 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ pm_runtime_dont_use_autosuspend(mcspi->dev);
pm_runtime_put_sync(mcspi->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 5e5fd77e2711..f7f7ba17b40e 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -346,13 +346,6 @@ struct vendor_data {
* @clk: outgoing clock "SPICLK" for the SPI bus
* @master: SPI framework hookup
* @master_info: controller-specific data from machine setup
- * @kworker: thread struct for message pump
- * @kworker_task: pointer to task for message pump kworker thread
- * @pump_messages: work struct for scheduling work to the message pump
- * @queue_lock: spinlock to syncronise access to message queue
- * @queue: message queue
- * @busy: message pump is busy
- * @running: message pump is running
* @pump_transfers: Tasklet used in Interrupt Transfer mode
* @cur_msg: Pointer to current spi_message being processed
* @cur_transfer: Pointer to current spi_transfer
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index bd8b369a343c..365fc22c3572 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -254,8 +254,8 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
if (status & SSSR_ROR) {
dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
- dmaengine_terminate_all(drv_data->rx_chan);
- dmaengine_terminate_all(drv_data->tx_chan);
+ dmaengine_terminate_async(drv_data->rx_chan);
+ dmaengine_terminate_async(drv_data->tx_chan);
pxa2xx_spi_dma_transfer_complete(drv_data, true);
return IRQ_HANDLED;
@@ -331,13 +331,13 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
void pxa2xx_spi_dma_release(struct driver_data *drv_data)
{
if (drv_data->rx_chan) {
- dmaengine_terminate_all(drv_data->rx_chan);
+ dmaengine_terminate_sync(drv_data->rx_chan);
dma_release_channel(drv_data->rx_chan);
sg_free_table(&drv_data->rx_sgt);
drv_data->rx_chan = NULL;
}
if (drv_data->tx_chan) {
- dmaengine_terminate_all(drv_data->tx_chan);
+ dmaengine_terminate_sync(drv_data->tx_chan);
dma_release_channel(drv_data->tx_chan);
sg_free_table(&drv_data->tx_sgt);
drv_data->tx_chan = NULL;
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index d19d7f28aecb..520ed1dd5780 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -19,6 +19,7 @@ enum {
PORT_BSW1,
PORT_BSW2,
PORT_QUARK_X1000,
+ PORT_LPT,
};
struct pxa_spi_info {
@@ -42,6 +43,9 @@ static struct dw_dma_slave bsw1_rx_param = { .src_id = 7 };
static struct dw_dma_slave bsw2_tx_param = { .dst_id = 8 };
static struct dw_dma_slave bsw2_rx_param = { .src_id = 9 };
+static struct dw_dma_slave lpt_tx_param = { .dst_id = 0 };
+static struct dw_dma_slave lpt_rx_param = { .src_id = 1 };
+
static bool lpss_dma_filter(struct dma_chan *chan, void *param)
{
struct dw_dma_slave *dws = param;
@@ -98,6 +102,14 @@ static struct pxa_spi_info spi_info_configs[] = {
.num_chipselect = 1,
.max_clk_rate = 50000000,
},
+ [PORT_LPT] = {
+ .type = LPSS_LPT_SSP,
+ .port_id = 0,
+ .num_chipselect = 1,
+ .max_clk_rate = 50000000,
+ .tx_param = &lpt_tx_param,
+ .rx_param = &lpt_rx_param,
+ },
};
static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
@@ -202,6 +214,7 @@ static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
{ PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 },
{ PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 },
{ PCI_VDEVICE(INTEL, 0x22ac), PORT_BSW2 },
+ { PCI_VDEVICE(INTEL, 0x9ce6), PORT_LPT },
{ },
};
MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices);
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index ab9914ad8365..85e59a406a4c 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -65,8 +65,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
#define LPSS_CS_CONTROL_SW_MODE BIT(0)
#define LPSS_CS_CONTROL_CS_HIGH BIT(1)
-#define LPSS_CS_CONTROL_CS_SEL_SHIFT 8
-#define LPSS_CS_CONTROL_CS_SEL_MASK (3 << LPSS_CS_CONTROL_CS_SEL_SHIFT)
#define LPSS_CAPS_CS_EN_SHIFT 9
#define LPSS_CAPS_CS_EN_MASK (0xf << LPSS_CAPS_CS_EN_SHIFT)
@@ -82,6 +80,10 @@ struct lpss_config {
u32 rx_threshold;
u32 tx_threshold_lo;
u32 tx_threshold_hi;
+ /* Chip select control */
+ unsigned cs_sel_shift;
+ unsigned cs_sel_mask;
+ unsigned cs_num;
};
/* Keep these sorted with enum pxa_ssp_type */
@@ -106,6 +108,19 @@ static const struct lpss_config lpss_platforms[] = {
.tx_threshold_lo = 160,
.tx_threshold_hi = 224,
},
+ { /* LPSS_BSW_SSP */
+ .offset = 0x400,
+ .reg_general = 0x08,
+ .reg_ssp = 0x0c,
+ .reg_cs_ctrl = 0x18,
+ .reg_capabilities = -1,
+ .rx_threshold = 64,
+ .tx_threshold_lo = 160,
+ .tx_threshold_hi = 224,
+ .cs_sel_shift = 2,
+ .cs_sel_mask = 1 << 2,
+ .cs_num = 2,
+ },
{ /* LPSS_SPT_SSP */
.offset = 0x200,
.reg_general = -1,
@@ -125,6 +140,8 @@ static const struct lpss_config lpss_platforms[] = {
.rx_threshold = 1,
.tx_threshold_lo = 16,
.tx_threshold_hi = 48,
+ .cs_sel_shift = 8,
+ .cs_sel_mask = 3 << 8,
},
};
@@ -139,6 +156,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data)
switch (drv_data->ssp_type) {
case LPSS_LPT_SSP:
case LPSS_BYT_SSP:
+ case LPSS_BSW_SSP:
case LPSS_SPT_SSP:
case LPSS_BXT_SSP:
return true;
@@ -288,37 +306,50 @@ static void lpss_ssp_setup(struct driver_data *drv_data)
}
}
+static void lpss_ssp_select_cs(struct driver_data *drv_data,
+ const struct lpss_config *config)
+{
+ u32 value, cs;
+
+ if (!config->cs_sel_mask)
+ return;
+
+ value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
+
+ cs = drv_data->cur_msg->spi->chip_select;
+ cs <<= config->cs_sel_shift;
+ if (cs != (value & config->cs_sel_mask)) {
+ /*
+ * When switching another chip select output active the
+ * output must be selected first and wait 2 ssp_clk cycles
+ * before changing state to active. Otherwise a short
+ * glitch will occur on the previous chip select since
+ * output select is latched but state control is not.
+ */
+ value &= ~config->cs_sel_mask;
+ value |= cs;
+ __lpss_ssp_write_priv(drv_data,
+ config->reg_cs_ctrl, value);
+ ndelay(1000000000 /
+ (drv_data->master->max_speed_hz / 2));
+ }
+}
+
static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
{
const struct lpss_config *config;
- u32 value, cs;
+ u32 value;
config = lpss_get_config(drv_data);
+ if (enable)
+ lpss_ssp_select_cs(drv_data, config);
+
value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
- if (enable) {
- cs = drv_data->cur_msg->spi->chip_select;
- cs <<= LPSS_CS_CONTROL_CS_SEL_SHIFT;
- if (cs != (value & LPSS_CS_CONTROL_CS_SEL_MASK)) {
- /*
- * When switching another chip select output active
- * the output must be selected first and wait 2 ssp_clk
- * cycles before changing state to active. Otherwise
- * a short glitch will occur on the previous chip
- * select since output select is latched but state
- * control is not.
- */
- value &= ~LPSS_CS_CONTROL_CS_SEL_MASK;
- value |= cs;
- __lpss_ssp_write_priv(drv_data,
- config->reg_cs_ctrl, value);
- ndelay(1000000000 /
- (drv_data->master->max_speed_hz / 2));
- }
+ if (enable)
value &= ~LPSS_CS_CONTROL_CS_HIGH;
- } else {
+ else
value |= LPSS_CS_CONTROL_CS_HIGH;
- }
__lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
}
@@ -496,6 +527,7 @@ static void giveback(struct driver_data *drv_data)
{
struct spi_transfer* last_transfer;
struct spi_message *msg;
+ unsigned long timeout;
msg = drv_data->cur_msg;
drv_data->cur_msg = NULL;
@@ -508,6 +540,12 @@ static void giveback(struct driver_data *drv_data)
if (last_transfer->delay_usecs)
udelay(last_transfer->delay_usecs);
+ /* Wait until SSP becomes idle before deasserting the CS */
+ timeout = jiffies + msecs_to_jiffies(10);
+ while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY &&
+ !time_after(jiffies, timeout))
+ cpu_relax();
+
/* Drop chip select UNLESS cs_change is true or we are returning
* a message with an error, or next message is for another chip
*/
@@ -572,7 +610,7 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg)
static void int_transfer_complete(struct driver_data *drv_data)
{
- /* Stop SSP */
+ /* Clear and disable interrupts */
write_SSSR_CS(drv_data, drv_data->clear_sr);
reset_sccr1(drv_data);
if (!pxa25x_ssp_comp(drv_data))
@@ -957,8 +995,6 @@ static void pump_transfers(unsigned long data)
drv_data->tx_end = drv_data->tx + transfer->len;
drv_data->rx = transfer->rx_buf;
drv_data->rx_end = drv_data->rx + transfer->len;
- drv_data->rx_dma = transfer->rx_dma;
- drv_data->tx_dma = transfer->tx_dma;
drv_data->len = transfer->len;
drv_data->write = drv_data->tx ? chip->write : null_writer;
drv_data->read = drv_data->rx ? chip->read : null_reader;
@@ -1001,19 +1037,6 @@ static void pump_transfers(unsigned long data)
"pump_transfers: DMA burst size reduced to match bits_per_word\n");
}
- /* NOTE: PXA25x_SSP _could_ use external clocking ... */
- cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
- if (!pxa25x_ssp_comp(drv_data))
- dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
- drv_data->master->max_speed_hz
- / (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)),
- chip->enable_dma ? "DMA" : "PIO");
- else
- dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
- drv_data->master->max_speed_hz / 2
- / (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)),
- chip->enable_dma ? "DMA" : "PIO");
-
message->state = RUNNING_STATE;
drv_data->dma_mapped = 0;
@@ -1040,6 +1063,19 @@ static void pump_transfers(unsigned long data)
write_SSSR_CS(drv_data, drv_data->clear_sr);
}
+ /* NOTE: PXA25x_SSP _could_ use external clocking ... */
+ cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
+ if (!pxa25x_ssp_comp(drv_data))
+ dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
+ drv_data->master->max_speed_hz
+ / (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)),
+ drv_data->dma_mapped ? "DMA" : "PIO");
+ else
+ dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
+ drv_data->master->max_speed_hz / 2
+ / (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)),
+ drv_data->dma_mapped ? "DMA" : "PIO");
+
if (is_lpss_ssp(drv_data)) {
if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
!= chip->lpss_rx_threshold)
@@ -1166,6 +1202,7 @@ static int setup(struct spi_device *spi)
break;
case LPSS_LPT_SSP:
case LPSS_BYT_SSP:
+ case LPSS_BSW_SSP:
case LPSS_SPT_SSP:
case LPSS_BXT_SSP:
config = lpss_get_config(drv_data);
@@ -1313,7 +1350,7 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ "INT3430", LPSS_LPT_SSP },
{ "INT3431", LPSS_LPT_SSP },
{ "80860F0E", LPSS_BYT_SSP },
- { "8086228E", LPSS_BYT_SSP },
+ { "8086228E", LPSS_BSW_SSP },
{ },
};
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
@@ -1347,10 +1384,14 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
/* SPT-H */
{ PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP },
{ PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP },
- /* BXT */
+ /* BXT A-Step */
{ PCI_VDEVICE(INTEL, 0x0ac2), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x0ac4), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x0ac6), LPSS_BXT_SSP },
+ /* BXT B-Step */
+ { PCI_VDEVICE(INTEL, 0x1ac2), LPSS_BXT_SSP },
+ { PCI_VDEVICE(INTEL, 0x1ac4), LPSS_BXT_SSP },
+ { PCI_VDEVICE(INTEL, 0x1ac6), LPSS_BXT_SSP },
/* APL */
{ PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
@@ -1438,6 +1479,29 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
}
#endif
+static int pxa2xx_spi_fw_translate_cs(struct spi_master *master, unsigned cs)
+{
+ struct driver_data *drv_data = spi_master_get_devdata(master);
+
+ if (has_acpi_companion(&drv_data->pdev->dev)) {
+ switch (drv_data->ssp_type) {
+ /*
+ * For Atoms the ACPI DeviceSelection used by the Windows
+ * driver starts from 1 instead of 0 so translate it here
+ * to match what Linux expects.
+ */
+ case LPSS_BYT_SSP:
+ case LPSS_BSW_SSP:
+ return cs - 1;
+
+ default:
+ break;
+ }
+ }
+
+ return cs;
+}
+
static int pxa2xx_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1490,6 +1554,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
master->setup = setup;
master->transfer_one_message = pxa2xx_spi_transfer_one_message;
master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
+ master->fw_translate_cs = pxa2xx_spi_fw_translate_cs;
master->auto_runtime_pm = true;
drv_data->ssp_type = ssp->type;
@@ -1576,6 +1641,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
tmp &= LPSS_CAPS_CS_EN_MASK;
tmp >>= LPSS_CAPS_CS_EN_SHIFT;
platform_info->num_chipselect = ffz(tmp);
+ } else if (config->cs_num) {
+ platform_info->num_chipselect = config->cs_num;
}
}
master->num_chipselect = platform_info->num_chipselect;
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index 58efa98313aa..a1ef88948144 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -69,8 +69,6 @@ struct driver_data {
void *rx;
void *rx_end;
int dma_mapped;
- dma_addr_t rx_dma;
- dma_addr_t tx_dma;
size_t rx_map_len;
size_t tx_map_len;
u8 n_bytes;
@@ -147,20 +145,9 @@ static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
extern int pxa2xx_spi_flush(struct driver_data *drv_data);
extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data);
-/*
- * Select the right DMA implementation.
- */
-#if defined(CONFIG_SPI_PXA2XX_DMA)
-#define SPI_PXA2XX_USE_DMA 1
#define MAX_DMA_LEN SZ_64K
#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL)
-#else
-#undef SPI_PXA2XX_USE_DMA
-#define MAX_DMA_LEN 0
-#define DEFAULT_DMA_CR1 0
-#endif
-#ifdef SPI_PXA2XX_USE_DMA
extern bool pxa2xx_spi_dma_is_possible(size_t len);
extern int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data);
extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data);
@@ -173,29 +160,5 @@ extern int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
u8 bits_per_word,
u32 *burst_code,
u32 *threshold);
-#else
-static inline bool pxa2xx_spi_dma_is_possible(size_t len) { return false; }
-static inline int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
-{
- return 0;
-}
-#define pxa2xx_spi_dma_transfer NULL
-static inline void pxa2xx_spi_dma_prepare(struct driver_data *drv_data,
- u32 dma_burst) {}
-static inline void pxa2xx_spi_dma_start(struct driver_data *drv_data) {}
-static inline int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
-{
- return 0;
-}
-static inline void pxa2xx_spi_dma_release(struct driver_data *drv_data) {}
-static inline int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
- struct spi_device *spi,
- u8 bits_per_word,
- u32 *burst_code,
- u32 *threshold)
-{
- return -ENODEV;
-}
-#endif
#endif /* SPI_PXA2XX_H */
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 79a8bc4f6cec..8f50a4020f6f 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -13,20 +13,14 @@
*
*/
-#include <linux/init.h>
-#include <linux/module.h>
#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/scatterlist.h>
-#include <linux/of.h>
#include <linux/pm_runtime.h>
-#include <linux/io.h>
-#include <linux/dmaengine.h>
+#include <linux/scatterlist.h>
#define DRIVER_NAME "rockchip-spi"
@@ -179,7 +173,7 @@ struct rockchip_spi {
u8 tmode;
u8 bpw;
u8 n_bytes;
- u8 rsd_nsecs;
+ u32 rsd_nsecs;
unsigned len;
u32 speed;
@@ -192,13 +186,12 @@ struct rockchip_spi {
/* protect state */
spinlock_t lock;
- struct completion xfer_completion;
-
u32 use_dma;
struct sg_table tx_sg;
struct sg_table rx_sg;
struct rockchip_spi_dma_data dma_rx;
struct rockchip_spi_dma_data dma_tx;
+ struct dma_slave_caps dma_caps;
};
static inline void spi_enable_chip(struct rockchip_spi *rs, int enable)
@@ -265,7 +258,10 @@ static inline u32 rx_max(struct rockchip_spi *rs)
static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
{
u32 ser;
- struct rockchip_spi *rs = spi_master_get_devdata(spi->master);
+ struct spi_master *master = spi->master;
+ struct rockchip_spi *rs = spi_master_get_devdata(master);
+
+ pm_runtime_get_sync(rs->dev);
ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK;
@@ -290,6 +286,8 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
ser &= ~(1 << spi->chip_select);
writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER);
+
+ pm_runtime_put_sync(rs->dev);
}
static int rockchip_spi_prepare_message(struct spi_master *master,
@@ -319,12 +317,12 @@ static void rockchip_spi_handle_err(struct spi_master *master,
*/
if (rs->use_dma) {
if (rs->state & RXBUSY) {
- dmaengine_terminate_all(rs->dma_rx.ch);
+ dmaengine_terminate_async(rs->dma_rx.ch);
flush_fifo(rs);
}
if (rs->state & TXBUSY)
- dmaengine_terminate_all(rs->dma_tx.ch);
+ dmaengine_terminate_async(rs->dma_tx.ch);
}
spin_unlock_irqrestore(&rs->lock, flags);
@@ -433,7 +431,7 @@ static void rockchip_spi_dma_txcb(void *data)
spin_unlock_irqrestore(&rs->lock, flags);
}
-static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
+static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
{
unsigned long flags;
struct dma_slave_config rxconf, txconf;
@@ -449,13 +447,18 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
rxconf.direction = rs->dma_rx.direction;
rxconf.src_addr = rs->dma_rx.addr;
rxconf.src_addr_width = rs->n_bytes;
- rxconf.src_maxburst = rs->n_bytes;
+ if (rs->dma_caps.max_burst > 4)
+ rxconf.src_maxburst = 4;
+ else
+ rxconf.src_maxburst = 1;
dmaengine_slave_config(rs->dma_rx.ch, &rxconf);
rxdesc = dmaengine_prep_slave_sg(
rs->dma_rx.ch,
rs->rx_sg.sgl, rs->rx_sg.nents,
rs->dma_rx.direction, DMA_PREP_INTERRUPT);
+ if (!rxdesc)
+ return -EINVAL;
rxdesc->callback = rockchip_spi_dma_rxcb;
rxdesc->callback_param = rs;
@@ -466,13 +469,21 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
txconf.direction = rs->dma_tx.direction;
txconf.dst_addr = rs->dma_tx.addr;
txconf.dst_addr_width = rs->n_bytes;
- txconf.dst_maxburst = rs->n_bytes;
+ if (rs->dma_caps.max_burst > 4)
+ txconf.dst_maxburst = 4;
+ else
+ txconf.dst_maxburst = 1;
dmaengine_slave_config(rs->dma_tx.ch, &txconf);
txdesc = dmaengine_prep_slave_sg(
rs->dma_tx.ch,
rs->tx_sg.sgl, rs->tx_sg.nents,
rs->dma_tx.direction, DMA_PREP_INTERRUPT);
+ if (!txdesc) {
+ if (rxdesc)
+ dmaengine_terminate_sync(rs->dma_rx.ch);
+ return -EINVAL;
+ }
txdesc->callback = rockchip_spi_dma_txcb;
txdesc->callback_param = rs;
@@ -494,6 +505,8 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
dmaengine_submit(txdesc);
dma_async_issue_pending(rs->dma_tx.ch);
}
+
+ return 0;
}
static void rockchip_spi_config(struct rockchip_spi *rs)
@@ -503,7 +516,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
int rsd = 0;
u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET)
- | (CR0_SSD_ONE << CR0_SSD_OFFSET);
+ | (CR0_SSD_ONE << CR0_SSD_OFFSET)
+ | (CR0_EM_BIG << CR0_EM_OFFSET);
cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET);
@@ -606,12 +620,12 @@ static int rockchip_spi_transfer_one(
if (rs->use_dma) {
if (rs->tmode == CR0_XFM_RO) {
/* rx: dma must be prepared first */
- rockchip_spi_prepare_dma(rs);
+ ret = rockchip_spi_prepare_dma(rs);
spi_enable_chip(rs, 1);
} else {
/* tx or tr: spi must be enabled first */
spi_enable_chip(rs, 1);
- rockchip_spi_prepare_dma(rs);
+ ret = rockchip_spi_prepare_dma(rs);
}
} else {
spi_enable_chip(rs, 1);
@@ -717,8 +731,14 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->handle_err = rockchip_spi_handle_err;
rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx");
- if (!rs->dma_tx.ch)
+ if (IS_ERR_OR_NULL(rs->dma_tx.ch)) {
+ /* Check tx to see if we need defer probing driver */
+ if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_get_fifo_len;
+ }
dev_warn(rs->dev, "Failed to request TX DMA channel\n");
+ }
rs->dma_rx.ch = dma_request_slave_channel(rs->dev, "rx");
if (!rs->dma_rx.ch) {
@@ -730,6 +750,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
}
if (rs->dma_tx.ch && rs->dma_rx.ch) {
+ dma_get_slave_caps(rs->dma_rx.ch, &(rs->dma_caps));
rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);
rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR);
rs->dma_tx.direction = DMA_MEM_TO_DEV;
@@ -749,6 +770,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
return 0;
err_register_master:
+ pm_runtime_disable(&pdev->dev);
if (rs->dma_tx.ch)
dma_release_channel(rs->dma_tx.ch);
if (rs->dma_rx.ch)
@@ -778,6 +800,8 @@ static int rockchip_spi_remove(struct platform_device *pdev)
if (rs->dma_rx.ch)
dma_release_channel(rs->dma_rx.ch);
+ spi_master_put(master);
+
return 0;
}
@@ -868,6 +892,7 @@ static const struct of_device_id rockchip_spi_dt_match[] = {
{ .compatible = "rockchip,rk3066-spi", },
{ .compatible = "rockchip,rk3188-spi", },
{ .compatible = "rockchip,rk3288-spi", },
+ { .compatible = "rockchip,rk3399-spi", },
{ },
};
MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 64318fcfacf2..eac3c960b2de 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -31,6 +31,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -44,8 +46,9 @@ struct ti_qspi {
struct spi_master *master;
void __iomem *base;
- void __iomem *ctrl_base;
void __iomem *mmap_base;
+ struct regmap *ctrl_base;
+ unsigned int ctrl_reg;
struct clk *fclk;
struct device *dev;
@@ -55,7 +58,7 @@ struct ti_qspi {
u32 cmd;
u32 dc;
- bool ctrl_mod;
+ bool mmap_enabled;
};
#define QSPI_PID (0x0)
@@ -65,11 +68,8 @@ struct ti_qspi {
#define QSPI_SPI_CMD_REG (0x48)
#define QSPI_SPI_STATUS_REG (0x4c)
#define QSPI_SPI_DATA_REG (0x50)
-#define QSPI_SPI_SETUP0_REG (0x54)
+#define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n))
#define QSPI_SPI_SWITCH_REG (0x64)
-#define QSPI_SPI_SETUP1_REG (0x58)
-#define QSPI_SPI_SETUP2_REG (0x5c)
-#define QSPI_SPI_SETUP3_REG (0x60)
#define QSPI_SPI_DATA_REG_1 (0x68)
#define QSPI_SPI_DATA_REG_2 (0x6c)
#define QSPI_SPI_DATA_REG_3 (0x70)
@@ -109,6 +109,17 @@ struct ti_qspi {
#define QSPI_AUTOSUSPEND_TIMEOUT 2000
+#define MEM_CS_EN(n) ((n + 1) << 8)
+#define MEM_CS_MASK (7 << 8)
+
+#define MM_SWITCH 0x1
+
+#define QSPI_SETUP_RD_NORMAL (0x0 << 12)
+#define QSPI_SETUP_RD_DUAL (0x1 << 12)
+#define QSPI_SETUP_RD_QUAD (0x3 << 12)
+#define QSPI_SETUP_ADDR_SHIFT 8
+#define QSPI_SETUP_DUMMY_SHIFT 10
+
static inline unsigned long ti_qspi_read(struct ti_qspi *qspi,
unsigned long reg)
{
@@ -366,6 +377,72 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t)
return 0;
}
+static void ti_qspi_enable_memory_map(struct spi_device *spi)
+{
+ struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+
+ ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG);
+ if (qspi->ctrl_base) {
+ regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
+ MEM_CS_EN(spi->chip_select),
+ MEM_CS_MASK);
+ }
+ qspi->mmap_enabled = true;
+}
+
+static void ti_qspi_disable_memory_map(struct spi_device *spi)
+{
+ struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+
+ ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG);
+ if (qspi->ctrl_base)
+ regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
+ 0, MEM_CS_MASK);
+ qspi->mmap_enabled = false;
+}
+
+static void ti_qspi_setup_mmap_read(struct spi_device *spi,
+ struct spi_flash_read_message *msg)
+{
+ struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ u32 memval = msg->read_opcode;
+
+ switch (msg->data_nbits) {
+ case SPI_NBITS_QUAD:
+ memval |= QSPI_SETUP_RD_QUAD;
+ break;
+ case SPI_NBITS_DUAL:
+ memval |= QSPI_SETUP_RD_DUAL;
+ break;
+ default:
+ memval |= QSPI_SETUP_RD_NORMAL;
+ break;
+ }
+ memval |= ((msg->addr_width - 1) << QSPI_SETUP_ADDR_SHIFT |
+ msg->dummy_bytes << QSPI_SETUP_DUMMY_SHIFT);
+ ti_qspi_write(qspi, memval,
+ QSPI_SPI_SETUP_REG(spi->chip_select));
+}
+
+static int ti_qspi_spi_flash_read(struct spi_device *spi,
+ struct spi_flash_read_message *msg)
+{
+ struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ int ret = 0;
+
+ mutex_lock(&qspi->list_lock);
+
+ if (!qspi->mmap_enabled)
+ ti_qspi_enable_memory_map(spi);
+ ti_qspi_setup_mmap_read(spi, msg);
+ memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len);
+ msg->retlen = msg->len;
+
+ mutex_unlock(&qspi->list_lock);
+
+ return ret;
+}
+
static int ti_qspi_start_transfer_one(struct spi_master *master,
struct spi_message *m)
{
@@ -398,6 +475,9 @@ static int ti_qspi_start_transfer_one(struct spi_master *master,
mutex_lock(&qspi->list_lock);
+ if (qspi->mmap_enabled)
+ ti_qspi_disable_memory_map(spi);
+
list_for_each_entry(t, &m->transfers, transfer_list) {
qspi->cmd |= QSPI_WLEN(t->bits_per_word);
@@ -441,7 +521,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
{
struct ti_qspi *qspi;
struct spi_master *master;
- struct resource *r, *res_ctrl, *res_mmap;
+ struct resource *r, *res_mmap;
struct device_node *np = pdev->dev.of_node;
u32 max_freq;
int ret = 0, num_cs, irq;
@@ -487,16 +567,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
}
}
- res_ctrl = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "qspi_ctrlmod");
- if (res_ctrl == NULL) {
- res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- if (res_ctrl == NULL) {
- dev_dbg(&pdev->dev,
- "control module resources not required\n");
- }
- }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
@@ -511,20 +581,31 @@ static int ti_qspi_probe(struct platform_device *pdev)
goto free_master;
}
- if (res_ctrl) {
- qspi->ctrl_mod = true;
- qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl);
- if (IS_ERR(qspi->ctrl_base)) {
- ret = PTR_ERR(qspi->ctrl_base);
- goto free_master;
- }
- }
-
if (res_mmap) {
- qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap);
+ qspi->mmap_base = devm_ioremap_resource(&pdev->dev,
+ res_mmap);
+ master->spi_flash_read = ti_qspi_spi_flash_read;
if (IS_ERR(qspi->mmap_base)) {
- ret = PTR_ERR(qspi->mmap_base);
- goto free_master;
+ dev_err(&pdev->dev,
+ "falling back to PIO mode\n");
+ master->spi_flash_read = NULL;
+ }
+ }
+ qspi->mmap_enabled = false;
+
+ if (of_property_read_bool(np, "syscon-chipselects")) {
+ qspi->ctrl_base =
+ syscon_regmap_lookup_by_phandle(np,
+ "syscon-chipselects");
+ if (IS_ERR(qspi->ctrl_base))
+ return PTR_ERR(qspi->ctrl_base);
+ ret = of_property_read_u32_index(np,
+ "syscon-chipselects",
+ 1, &qspi->ctrl_reg);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "couldn't get ctrl_mod reg index\n");
+ return ret;
}
}
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 47eff8012a77..de2f2f90d799 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -144,6 +144,8 @@ SPI_STATISTICS_TRANSFER_BYTES_HISTO(14, "16384-32767");
SPI_STATISTICS_TRANSFER_BYTES_HISTO(15, "32768-65535");
SPI_STATISTICS_TRANSFER_BYTES_HISTO(16, "65536+");
+SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu");
+
static struct attribute *spi_dev_attrs[] = {
&dev_attr_modalias.attr,
NULL,
@@ -181,6 +183,7 @@ static struct attribute *spi_device_statistics_attrs[] = {
&dev_attr_spi_device_transfer_bytes_histo14.attr,
&dev_attr_spi_device_transfer_bytes_histo15.attr,
&dev_attr_spi_device_transfer_bytes_histo16.attr,
+ &dev_attr_spi_device_transfers_split_maxsize.attr,
NULL,
};
@@ -223,6 +226,7 @@ static struct attribute *spi_master_statistics_attrs[] = {
&dev_attr_spi_master_transfer_bytes_histo14.attr,
&dev_attr_spi_master_transfer_bytes_histo15.attr,
&dev_attr_spi_master_transfer_bytes_histo16.attr,
+ &dev_attr_spi_master_transfers_split_maxsize.attr,
NULL,
};
@@ -702,6 +706,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
enum dma_data_direction dir)
{
const bool vmalloced_buf = is_vmalloc_addr(buf);
+ unsigned int max_seg_size = dma_get_max_seg_size(dev);
int desc_len;
int sgs;
struct page *vm_page;
@@ -710,10 +715,10 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
int i, ret;
if (vmalloced_buf) {
- desc_len = PAGE_SIZE;
+ desc_len = min_t(int, max_seg_size, PAGE_SIZE);
sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len);
} else {
- desc_len = master->max_dma_len;
+ desc_len = min_t(int, max_seg_size, master->max_dma_len);
sgs = DIV_ROUND_UP(len, desc_len);
}
@@ -739,7 +744,6 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
sg_set_buf(&sgt->sgl[i], sg_buf, min);
}
-
buf += min;
len -= min;
}
@@ -1024,6 +1028,8 @@ out:
if (msg->status && master->handle_err)
master->handle_err(master, msg);
+ spi_res_release(master, msg);
+
spi_finalize_current_message(master);
return ret;
@@ -1047,6 +1053,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
* __spi_pump_messages - function which processes spi message queue
* @master: master to process queue for
* @in_kthread: true if we are in the context of the message pump thread
+ * @bus_locked: true if the bus mutex is held when calling this function
*
* This function checks if there is any spi message in the queue that
* needs processing and if so call out to the driver to initialize hardware
@@ -1056,7 +1063,8 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
* inside spi_sync(); the queue extraction handling at the top of the
* function should deal with this safely.
*/
-static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
+static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
+ bool bus_locked)
{
unsigned long flags;
bool was_busy = false;
@@ -1152,6 +1160,9 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
}
}
+ if (!bus_locked)
+ mutex_lock(&master->bus_lock_mutex);
+
trace_spi_message_start(master->cur_msg);
if (master->prepare_message) {
@@ -1161,7 +1172,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
"failed to prepare message: %d\n", ret);
master->cur_msg->status = ret;
spi_finalize_current_message(master);
- return;
+ goto out;
}
master->cur_msg_prepared = true;
}
@@ -1170,15 +1181,23 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
if (ret) {
master->cur_msg->status = ret;
spi_finalize_current_message(master);
- return;
+ goto out;
}
ret = master->transfer_one_message(master, master->cur_msg);
if (ret) {
dev_err(&master->dev,
"failed to transfer one message from queue\n");
- return;
+ goto out;
}
+
+out:
+ if (!bus_locked)
+ mutex_unlock(&master->bus_lock_mutex);
+
+ /* Prod the scheduler in case transfer_one() was busy waiting */
+ if (!ret)
+ cond_resched();
}
/**
@@ -1190,7 +1209,7 @@ static void spi_pump_messages(struct kthread_work *work)
struct spi_master *master =
container_of(work, struct spi_master, pump_messages);
- __spi_pump_messages(master, true);
+ __spi_pump_messages(master, true, false);
}
static int spi_init_queue(struct spi_master *master)
@@ -1581,13 +1600,30 @@ static void of_register_spi_devices(struct spi_master *master) { }
static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
{
struct spi_device *spi = data;
+ struct spi_master *master = spi->master;
if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
struct acpi_resource_spi_serialbus *sb;
sb = &ares->data.spi_serial_bus;
if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
- spi->chip_select = sb->device_selection;
+ /*
+ * ACPI DeviceSelection numbering is handled by the
+ * host controller driver in Windows and can vary
+ * from driver to driver. In Linux we always expect
+ * 0 .. max - 1 so we need to ask the driver to
+ * translate between the two schemes.
+ */
+ if (master->fw_translate_cs) {
+ int cs = master->fw_translate_cs(master,
+ sb->device_selection);
+ if (cs < 0)
+ return cs;
+ spi->chip_select = cs;
+ } else {
+ spi->chip_select = sb->device_selection;
+ }
+
spi->max_speed_hz = sb->connection_speed;
if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
@@ -2013,6 +2049,336 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
}
EXPORT_SYMBOL_GPL(spi_busnum_to_master);
+/*-------------------------------------------------------------------------*/
+
+/* Core methods for SPI resource management */
+
+/**
+ * spi_res_alloc - allocate a spi resource that is life-cycle managed
+ * during the processing of a spi_message while using
+ * spi_transfer_one
+ * @spi: the spi device for which we allocate memory
+ * @release: the release code to execute for this resource
+ * @size: size to alloc and return
+ * @gfp: GFP allocation flags
+ *
+ * Return: the pointer to the allocated data
+ *
+ * This may get enhanced in the future to allocate from a memory pool
+ * of the @spi_device or @spi_master to avoid repeated allocations.
+ */
+void *spi_res_alloc(struct spi_device *spi,
+ spi_res_release_t release,
+ size_t size, gfp_t gfp)
+{
+ struct spi_res *sres;
+
+ sres = kzalloc(sizeof(*sres) + size, gfp);
+ if (!sres)
+ return NULL;
+
+ INIT_LIST_HEAD(&sres->entry);
+ sres->release = release;
+
+ return sres->data;
+}
+EXPORT_SYMBOL_GPL(spi_res_alloc);
+
+/**
+ * spi_res_free - free an spi resource
+ * @res: pointer to the custom data of a resource
+ *
+ */
+void spi_res_free(void *res)
+{
+ struct spi_res *sres = container_of(res, struct spi_res, data);
+
+ if (!res)
+ return;
+
+ WARN_ON(!list_empty(&sres->entry));
+ kfree(sres);
+}
+EXPORT_SYMBOL_GPL(spi_res_free);
+
+/**
+ * spi_res_add - add a spi_res to the spi_message
+ * @message: the spi message
+ * @res: the spi_resource
+ */
+void spi_res_add(struct spi_message *message, void *res)
+{
+ struct spi_res *sres = container_of(res, struct spi_res, data);
+
+ WARN_ON(!list_empty(&sres->entry));
+ list_add_tail(&sres->entry, &message->resources);
+}
+EXPORT_SYMBOL_GPL(spi_res_add);
+
+/**
+ * spi_res_release - release all spi resources for this message
+ * @master: the @spi_master
+ * @message: the @spi_message
+ */
+void spi_res_release(struct spi_master *master,
+ struct spi_message *message)
+{
+ struct spi_res *res;
+
+ while (!list_empty(&message->resources)) {
+ res = list_last_entry(&message->resources,
+ struct spi_res, entry);
+
+ if (res->release)
+ res->release(master, message, res->data);
+
+ list_del(&res->entry);
+
+ kfree(res);
+ }
+}
+EXPORT_SYMBOL_GPL(spi_res_release);
+
+/*-------------------------------------------------------------------------*/
+
+/* Core methods for spi_message alterations */
+
+static void __spi_replace_transfers_release(struct spi_master *master,
+ struct spi_message *msg,
+ void *res)
+{
+ struct spi_replaced_transfers *rxfer = res;
+ size_t i;
+
+ /* call extra callback if requested */
+ if (rxfer->release)
+ rxfer->release(master, msg, res);
+
+ /* insert replaced transfers back into the message */
+ list_splice(&rxfer->replaced_transfers, rxfer->replaced_after);
+
+ /* remove the formerly inserted entries */
+ for (i = 0; i < rxfer->inserted; i++)
+ list_del(&rxfer->inserted_transfers[i].transfer_list);
+}
+
+/**
+ * spi_replace_transfers - replace transfers with several transfers
+ * and register change with spi_message.resources
+ * @msg: the spi_message we work upon
+ * @xfer_first: the first spi_transfer we want to replace
+ * @remove: number of transfers to remove
+ * @insert: the number of transfers we want to insert instead
+ * @release: extra release code necessary in some circumstances
+ * @extradatasize: extra data to allocate (with alignment guarantees
+ * of struct @spi_transfer)
+ * @gfp: gfp flags
+ *
+ * Returns: pointer to @spi_replaced_transfers,
+ * PTR_ERR(...) in case of errors.
+ */
+struct spi_replaced_transfers *spi_replace_transfers(
+ struct spi_message *msg,
+ struct spi_transfer *xfer_first,
+ size_t remove,
+ size_t insert,
+ spi_replaced_release_t release,
+ size_t extradatasize,
+ gfp_t gfp)
+{
+ struct spi_replaced_transfers *rxfer;
+ struct spi_transfer *xfer;
+ size_t i;
+
+ /* allocate the structure using spi_res */
+ rxfer = spi_res_alloc(msg->spi, __spi_replace_transfers_release,
+ insert * sizeof(struct spi_transfer)
+ + sizeof(struct spi_replaced_transfers)
+ + extradatasize,
+ gfp);
+ if (!rxfer)
+ return ERR_PTR(-ENOMEM);
+
+ /* the release code to invoke before running the generic release */
+ rxfer->release = release;
+
+ /* assign extradata */
+ if (extradatasize)
+ rxfer->extradata =
+ &rxfer->inserted_transfers[insert];
+
+ /* init the replaced_transfers list */
+ INIT_LIST_HEAD(&rxfer->replaced_transfers);
+
+ /* assign the list_entry after which we should reinsert
+ * the @replaced_transfers - it may be spi_message.messages!
+ */
+ rxfer->replaced_after = xfer_first->transfer_list.prev;
+
+ /* remove the requested number of transfers */
+ for (i = 0; i < remove; i++) {
+ /* if the entry after replaced_after it is msg->transfers
+ * then we have been requested to remove more transfers
+ * than are in the list
+ */
+ if (rxfer->replaced_after->next == &msg->transfers) {
+ dev_err(&msg->spi->dev,
+ "requested to remove more spi_transfers than are available\n");
+ /* insert replaced transfers back into the message */
+ list_splice(&rxfer->replaced_transfers,
+ rxfer->replaced_after);
+
+ /* free the spi_replace_transfer structure */
+ spi_res_free(rxfer);
+
+ /* and return with an error */
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* remove the entry after replaced_after from list of
+ * transfers and add it to list of replaced_transfers
+ */
+ list_move_tail(rxfer->replaced_after->next,
+ &rxfer->replaced_transfers);
+ }
+
+ /* create copy of the given xfer with identical settings
+ * based on the first transfer to get removed
+ */
+ for (i = 0; i < insert; i++) {
+ /* we need to run in reverse order */
+ xfer = &rxfer->inserted_transfers[insert - 1 - i];
+
+ /* copy all spi_transfer data */
+ memcpy(xfer, xfer_first, sizeof(*xfer));
+
+ /* add to list */
+ list_add(&xfer->transfer_list, rxfer->replaced_after);
+
+ /* clear cs_change and delay_usecs for all but the last */
+ if (i) {
+ xfer->cs_change = false;
+ xfer->delay_usecs = 0;
+ }
+ }
+
+ /* set up inserted */
+ rxfer->inserted = insert;
+
+ /* and register it with spi_res/spi_message */
+ spi_res_add(msg, rxfer);
+
+ return rxfer;
+}
+EXPORT_SYMBOL_GPL(spi_replace_transfers);
+
+static int __spi_split_transfer_maxsize(struct spi_master *master,
+ struct spi_message *msg,
+ struct spi_transfer **xferp,
+ size_t maxsize,
+ gfp_t gfp)
+{
+ struct spi_transfer *xfer = *xferp, *xfers;
+ struct spi_replaced_transfers *srt;
+ size_t offset;
+ size_t count, i;
+
+ /* warn once about this fact that we are splitting a transfer */
+ dev_warn_once(&msg->spi->dev,
+ "spi_transfer of length %i exceed max length of %zu - needed to split transfers\n",
+ xfer->len, maxsize);
+
+ /* calculate how many we have to replace */
+ count = DIV_ROUND_UP(xfer->len, maxsize);
+
+ /* create replacement */
+ srt = spi_replace_transfers(msg, xfer, 1, count, NULL, 0, gfp);
+ if (IS_ERR(srt))
+ return PTR_ERR(srt);
+ xfers = srt->inserted_transfers;
+
+ /* now handle each of those newly inserted spi_transfers
+ * note that the replacements spi_transfers all are preset
+ * to the same values as *xferp, so tx_buf, rx_buf and len
+ * are all identical (as well as most others)
+ * so we just have to fix up len and the pointers.
+ *
+ * this also includes support for the depreciated
+ * spi_message.is_dma_mapped interface
+ */
+
+ /* the first transfer just needs the length modified, so we
+ * run it outside the loop
+ */
+ xfers[0].len = min_t(size_t, maxsize, xfer[0].len);
+
+ /* all the others need rx_buf/tx_buf also set */
+ for (i = 1, offset = maxsize; i < count; offset += maxsize, i++) {
+ /* update rx_buf, tx_buf and dma */
+ if (xfers[i].rx_buf)
+ xfers[i].rx_buf += offset;
+ if (xfers[i].rx_dma)
+ xfers[i].rx_dma += offset;
+ if (xfers[i].tx_buf)
+ xfers[i].tx_buf += offset;
+ if (xfers[i].tx_dma)
+ xfers[i].tx_dma += offset;
+
+ /* update length */
+ xfers[i].len = min(maxsize, xfers[i].len - offset);
+ }
+
+ /* we set up xferp to the last entry we have inserted,
+ * so that we skip those already split transfers
+ */
+ *xferp = &xfers[count - 1];
+
+ /* increment statistics counters */
+ SPI_STATISTICS_INCREMENT_FIELD(&master->statistics,
+ transfers_split_maxsize);
+ SPI_STATISTICS_INCREMENT_FIELD(&msg->spi->statistics,
+ transfers_split_maxsize);
+
+ return 0;
+}
+
+/**
+ * spi_split_tranfers_maxsize - split spi transfers into multiple transfers
+ * when an individual transfer exceeds a
+ * certain size
+ * @master: the @spi_master for this transfer
+ * @msg: the @spi_message to transform
+ * @maxsize: the maximum when to apply this
+ * @gfp: GFP allocation flags
+ *
+ * Return: status of transformation
+ */
+int spi_split_transfers_maxsize(struct spi_master *master,
+ struct spi_message *msg,
+ size_t maxsize,
+ gfp_t gfp)
+{
+ struct spi_transfer *xfer;
+ int ret;
+
+ /* iterate over the transfer_list,
+ * but note that xfer is advanced to the last transfer inserted
+ * to avoid checking sizes again unnecessarily (also xfer does
+ * potentiall belong to a different list by the time the
+ * replacement has happened
+ */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (xfer->len > maxsize) {
+ ret = __spi_split_transfer_maxsize(
+ master, msg, &xfer, maxsize, gfp);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_split_transfers_maxsize);
/*-------------------------------------------------------------------------*/
@@ -2351,6 +2717,46 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message)
EXPORT_SYMBOL_GPL(spi_async_locked);
+int spi_flash_read(struct spi_device *spi,
+ struct spi_flash_read_message *msg)
+
+{
+ struct spi_master *master = spi->master;
+ int ret;
+
+ if ((msg->opcode_nbits == SPI_NBITS_DUAL ||
+ msg->addr_nbits == SPI_NBITS_DUAL) &&
+ !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
+ return -EINVAL;
+ if ((msg->opcode_nbits == SPI_NBITS_QUAD ||
+ msg->addr_nbits == SPI_NBITS_QUAD) &&
+ !(spi->mode & SPI_TX_QUAD))
+ return -EINVAL;
+ if (msg->data_nbits == SPI_NBITS_DUAL &&
+ !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
+ return -EINVAL;
+ if (msg->data_nbits == SPI_NBITS_QUAD &&
+ !(spi->mode & SPI_RX_QUAD))
+ return -EINVAL;
+
+ if (master->auto_runtime_pm) {
+ ret = pm_runtime_get_sync(master->dev.parent);
+ if (ret < 0) {
+ dev_err(&master->dev, "Failed to power device: %d\n",
+ ret);
+ return ret;
+ }
+ }
+ mutex_lock(&master->bus_lock_mutex);
+ ret = master->spi_flash_read(spi, msg);
+ mutex_unlock(&master->bus_lock_mutex);
+ if (master->auto_runtime_pm)
+ pm_runtime_put(master->dev.parent);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(spi_flash_read);
+
/*-------------------------------------------------------------------------*/
/* Utility methods for SPI master protocol drivers, layered on
@@ -2414,7 +2820,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
spi_sync_immediate);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
spi_sync_immediate);
- __spi_pump_messages(master, false);
+ __spi_pump_messages(master, false, bus_locked);
}
wait_for_completion(&done);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index be822f7a9ce6..aca282d45421 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -10,6 +10,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+#include <linux/bitmap.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
@@ -47,9 +48,9 @@
#define SPMI_MAPPING_BIT_IS_1_FLAG(X) (((X) >> 8) & 0x1)
#define SPMI_MAPPING_BIT_IS_1_RESULT(X) (((X) >> 0) & 0xFF)
-#define SPMI_MAPPING_TABLE_LEN 255
#define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */
-#define PPID_TO_CHAN_TABLE_SZ BIT(12) /* PPID is 12bit chan is 1byte*/
+#define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */
+#define PMIC_ARB_CHAN_VALID BIT(15)
/* Ownership Table */
#define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N)))
@@ -85,9 +86,7 @@ enum pmic_arb_cmd_op_code {
};
/* Maximum number of support PMIC peripherals */
-#define PMIC_ARB_MAX_PERIPHS 256
-#define PMIC_ARB_MAX_CHNL 128
-#define PMIC_ARB_PERIPH_ID_VALID (1 << 15)
+#define PMIC_ARB_MAX_PERIPHS 512
#define PMIC_ARB_TIMEOUT_US 100
#define PMIC_ARB_MAX_TRANS_BYTES (8)
@@ -125,18 +124,22 @@ struct spmi_pmic_arb_dev {
void __iomem *wr_base;
void __iomem *intr;
void __iomem *cnfg;
+ void __iomem *core;
+ resource_size_t core_size;
raw_spinlock_t lock;
u8 channel;
int irq;
u8 ee;
- u8 min_apid;
- u8 max_apid;
- u32 mapping_table[SPMI_MAPPING_TABLE_LEN];
+ u16 min_apid;
+ u16 max_apid;
+ u32 *mapping_table;
+ DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
struct irq_domain *domain;
struct spmi_controller *spmic;
- u16 apid_to_ppid[256];
+ u16 *apid_to_ppid;
const struct pmic_arb_ver_ops *ver_ops;
- u8 *ppid_to_chan;
+ u16 *ppid_to_chan;
+ u16 last_channel;
};
/**
@@ -158,7 +161,8 @@ struct spmi_pmic_arb_dev {
*/
struct pmic_arb_ver_ops {
/* spmi commands (read_cmd, write_cmd, cmd) functionality */
- u32 (*offset)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr);
+ int (*offset)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+ u32 *offset);
u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
/* Interrupts controller functionality (offset of PIC registers) */
@@ -212,7 +216,14 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
struct spmi_pmic_arb_dev *dev = spmi_controller_get_drvdata(ctrl);
u32 status = 0;
u32 timeout = PMIC_ARB_TIMEOUT_US;
- u32 offset = dev->ver_ops->offset(dev, sid, addr) + PMIC_ARB_STATUS;
+ u32 offset;
+ int rc;
+
+ rc = dev->ver_ops->offset(dev, sid, addr, &offset);
+ if (rc)
+ return rc;
+
+ offset += PMIC_ARB_STATUS;
while (timeout--) {
status = readl_relaxed(base + offset);
@@ -257,7 +268,11 @@ pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid)
unsigned long flags;
u32 cmd;
int rc;
- u32 offset = pmic_arb->ver_ops->offset(pmic_arb, sid, 0);
+ u32 offset;
+
+ rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, &offset);
+ if (rc)
+ return rc;
cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
@@ -297,7 +312,11 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
u8 bc = len - 1;
u32 cmd;
int rc;
- u32 offset = pmic_arb->ver_ops->offset(pmic_arb, sid, addr);
+ u32 offset;
+
+ rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
+ if (rc)
+ return rc;
if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
dev_err(&ctrl->dev,
@@ -344,7 +363,11 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
u8 bc = len - 1;
u32 cmd;
int rc;
- u32 offset = pmic_arb->ver_ops->offset(pmic_arb, sid, addr);
+ u32 offset;
+
+ rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
+ if (rc)
+ return rc;
if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
dev_err(&ctrl->dev,
@@ -614,6 +637,10 @@ static int search_mapping_table(struct spmi_pmic_arb_dev *pa,
u32 data;
for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
+ if (!test_and_set_bit(index, pa->mapping_table_valid))
+ mapping_table[index] = readl_relaxed(pa->cnfg +
+ SPMI_MAPPING_TABLE_REG(index));
+
data = mapping_table[index];
if (ppid & (1 << SPMI_MAPPING_BIT_INDEX(data))) {
@@ -701,18 +728,61 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
}
/* v1 offset per ee */
-static u32 pmic_arb_offset_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr)
+static int
+pmic_arb_offset_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, u32 *offset)
{
- return 0x800 + 0x80 * pa->channel;
+ *offset = 0x800 + 0x80 * pa->channel;
+ return 0;
}
+static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid)
+{
+ u32 regval, offset;
+ u16 chan;
+ u16 id;
+
+ /*
+ * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid.
+ * ppid_to_chan is an in-memory invert of that table.
+ */
+ for (chan = pa->last_channel; ; chan++) {
+ offset = PMIC_ARB_REG_CHNL(chan);
+ if (offset >= pa->core_size)
+ break;
+
+ regval = readl_relaxed(pa->core + offset);
+ if (!regval)
+ continue;
+
+ id = (regval >> 8) & PMIC_ARB_PPID_MASK;
+ pa->ppid_to_chan[id] = chan | PMIC_ARB_CHAN_VALID;
+ if (id == ppid) {
+ chan |= PMIC_ARB_CHAN_VALID;
+ break;
+ }
+ }
+ pa->last_channel = chan & ~PMIC_ARB_CHAN_VALID;
+
+ return chan;
+}
+
+
/* v2 offset per ppid (chan) and per ee */
-static u32 pmic_arb_offset_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr)
+static int
+pmic_arb_offset_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, u32 *offset)
{
u16 ppid = (sid << 8) | (addr >> 8);
- u8 chan = pa->ppid_to_chan[ppid];
+ u16 chan;
- return 0x1000 * pa->ee + 0x8000 * chan;
+ chan = pa->ppid_to_chan[ppid];
+ if (!(chan & PMIC_ARB_CHAN_VALID))
+ chan = pmic_arb_find_chan(pa, ppid);
+ if (!(chan & PMIC_ARB_CHAN_VALID))
+ return -ENODEV;
+ chan &= ~PMIC_ARB_CHAN_VALID;
+
+ *offset = 0x1000 * pa->ee + 0x8000 * chan;
+ return 0;
}
static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc)
@@ -797,7 +867,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
struct resource *res;
void __iomem *core;
u32 channel, ee, hw_ver;
- int err, i;
+ int err;
bool is_v1;
ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
@@ -808,6 +878,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pa->spmic = ctrl;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+ pa->core_size = resource_size(res);
core = devm_ioremap_resource(&ctrl->dev, res);
if (IS_ERR(core)) {
err = PTR_ERR(core);
@@ -825,10 +896,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pa->wr_base = core;
pa->rd_base = core;
} else {
- u8 chan;
- u16 ppid;
- u32 regval;
-
+ pa->core = core;
pa->ver_ops = &pmic_arb_v2;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -847,24 +915,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
goto err_put_ctrl;
}
- pa->ppid_to_chan = devm_kzalloc(&ctrl->dev,
- PPID_TO_CHAN_TABLE_SZ, GFP_KERNEL);
+ pa->ppid_to_chan = devm_kcalloc(&ctrl->dev,
+ PMIC_ARB_MAX_PPID,
+ sizeof(*pa->ppid_to_chan),
+ GFP_KERNEL);
if (!pa->ppid_to_chan) {
err = -ENOMEM;
goto err_put_ctrl;
}
- /*
- * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid.
- * ppid_to_chan is an in-memory invert of that table.
- */
- for (chan = 0; chan < PMIC_ARB_MAX_CHNL; ++chan) {
- regval = readl_relaxed(core + PMIC_ARB_REG_CHNL(chan));
- if (!regval)
- continue;
-
- ppid = (regval >> 8) & 0xFFF;
- pa->ppid_to_chan[ppid] = chan;
- }
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
@@ -915,9 +973,20 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pa->ee = ee;
- for (i = 0; i < ARRAY_SIZE(pa->mapping_table); ++i)
- pa->mapping_table[i] = readl_relaxed(
- pa->cnfg + SPMI_MAPPING_TABLE_REG(i));
+ pa->apid_to_ppid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS,
+ sizeof(*pa->apid_to_ppid),
+ GFP_KERNEL);
+ if (!pa->apid_to_ppid) {
+ err = -ENOMEM;
+ goto err_put_ctrl;
+ }
+
+ pa->mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS - 1,
+ sizeof(*pa->mapping_table), GFP_KERNEL);
+ if (!pa->mapping_table) {
+ err = -ENOMEM;
+ goto err_put_ctrl;
+ }
/* Initialize max_apid/min_apid to the opposite bounds, during
* the irq domain translation, we are sure to update these */
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
index 0c675861623f..d8e4219c2324 100644
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -83,6 +83,7 @@ config SSB_SDIOHOST
config SSB_HOST_SOC
bool "Support for SSB bus on SoC"
depends on SSB && BCM47XX_NVRAM
+ select SSB_SPROM
help
Host interface for a SSB directly mapped into memory. This is
for some Broadcom SoCs from the BCM47xx and BCM53xx lines.
diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c
index bad355100825..294c1c83aa4d 100644
--- a/drivers/staging/dgap/dgap.c
+++ b/drivers/staging/dgap/dgap.c
@@ -1530,7 +1530,7 @@ static void dgap_input(struct channel_t *ch)
if ((bd->state != BOARD_READY) || !tp ||
(tp->magic != TTY_MAGIC) ||
!(ch->ch_tun.un_flags & UN_ISOPEN) ||
- !(tp->termios.c_cflag & CREAD) ||
+ !C_CREAD(tp) ||
(ch->ch_tun.un_flags & UN_CLOSING)) {
writew(head, &bs->rx_tail);
writeb(1, &bs->idata);
@@ -1665,9 +1665,7 @@ static void dgap_input(struct channel_t *ch)
}
static void dgap_write_wakeup(struct board_t *bd, struct channel_t *ch,
- struct un_t *un, u32 mask,
- unsigned long *irq_flags1,
- unsigned long *irq_flags2)
+ struct un_t *un, u32 mask)
{
if (!(un->un_flags & mask))
return;
@@ -1677,17 +1675,7 @@ static void dgap_write_wakeup(struct board_t *bd, struct channel_t *ch,
if (!(un->un_flags & UN_ISOPEN))
return;
- if ((un->un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- un->un_tty->ldisc->ops->write_wakeup) {
- spin_unlock_irqrestore(&ch->ch_lock, *irq_flags2);
- spin_unlock_irqrestore(&bd->bd_lock, *irq_flags1);
-
- (un->un_tty->ldisc->ops->write_wakeup)(un->un_tty);
-
- spin_lock_irqsave(&bd->bd_lock, *irq_flags1);
- spin_lock_irqsave(&ch->ch_lock, *irq_flags2);
- }
- wake_up_interruptible(&un->un_tty->write_wait);
+ tty_wakeup(un->un_tty);
wake_up_interruptible(&un->un_flags_wait);
}
@@ -1952,10 +1940,8 @@ static int dgap_event(struct board_t *bd)
* Process Transmit low.
*/
if (reason & IFTLW) {
- dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_LOW,
- &lock_flags, &lock_flags2);
- dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_LOW,
- &lock_flags, &lock_flags2);
+ dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_LOW);
+ dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_LOW);
if (ch->ch_flags & CH_WLOW) {
ch->ch_flags &= ~CH_WLOW;
wake_up_interruptible(&ch->ch_flags_wait);
@@ -1966,10 +1952,8 @@ static int dgap_event(struct board_t *bd)
* Process Transmit empty.
*/
if (reason & IFTEM) {
- dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_EMPTY,
- &lock_flags, &lock_flags2);
- dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_EMPTY,
- &lock_flags, &lock_flags2);
+ dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_EMPTY);
+ dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_EMPTY);
if (ch->ch_flags & CH_WEMPTY) {
ch->ch_flags &= ~CH_WEMPTY;
wake_up_interruptible(&ch->ch_flags_wait);
@@ -3171,8 +3155,6 @@ static void dgap_tty_flush_buffer(struct tty_struct *tty)
spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
- if (waitqueue_active(&tty->write_wait))
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
}
@@ -4969,10 +4951,6 @@ static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
ch->ch_pun.un_flags &= ~(UN_LOW | UN_EMPTY);
wake_up_interruptible(&ch->ch_pun.un_flags_wait);
}
- if (waitqueue_active(&tty->write_wait))
- wake_up_interruptible(&tty->write_wait);
-
- /* Can't hold any locks when calling tty_wakeup! */
spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
tty_wakeup(tty);
diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c
index b79eab084c02..8b1ba65a6984 100644
--- a/drivers/staging/dgnc/dgnc_tty.c
+++ b/drivers/staging/dgnc/dgnc_tty.c
@@ -541,7 +541,7 @@ void dgnc_input(struct channel_t *ch)
*/
if (!tp || (tp->magic != TTY_MAGIC) ||
!(ch->ch_tun.un_flags & UN_ISOPEN) ||
- !(tp->termios.c_cflag & CREAD) ||
+ !C_CREAD(tp) ||
(ch->ch_tun.un_flags & UN_CLOSING)) {
ch->ch_r_head = tail;
@@ -933,14 +933,7 @@ void dgnc_wakeup_writes(struct channel_t *ch)
}
if (ch->ch_tun.un_flags & UN_ISOPEN) {
- if ((ch->ch_tun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- ch->ch_tun.un_tty->ldisc->ops->write_wakeup) {
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- ch->ch_tun.un_tty->ldisc->ops->write_wakeup(ch->ch_tun.un_tty);
- spin_lock_irqsave(&ch->ch_lock, flags);
- }
-
- wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
+ tty_wakeup(ch->ch_tun.un_tty);
/*
* If unit is set to wait until empty, check to make sure
@@ -975,14 +968,7 @@ void dgnc_wakeup_writes(struct channel_t *ch)
}
if (ch->ch_pun.un_flags & UN_ISOPEN) {
- if ((ch->ch_pun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- ch->ch_pun.un_tty->ldisc->ops->write_wakeup) {
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- ch->ch_pun.un_tty->ldisc->ops->write_wakeup(ch->ch_pun.un_tty);
- spin_lock_irqsave(&ch->ch_lock, flags);
- }
-
- wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
+ tty_wakeup(ch->ch_pun.un_tty);
/*
* If unit is set to wait until empty, check to make sure
diff --git a/drivers/staging/goldfish/goldfish_audio.c b/drivers/staging/goldfish/goldfish_audio.c
index b0927e49d0a8..364fdcdd3a06 100644
--- a/drivers/staging/goldfish/goldfish_audio.c
+++ b/drivers/staging/goldfish/goldfish_audio.c
@@ -63,7 +63,7 @@ struct goldfish_audio {
#define AUDIO_READ(data, addr) (readl(data->reg_base + addr))
#define AUDIO_WRITE(data, addr, x) (writel(x, data->reg_base + addr))
#define AUDIO_WRITE64(data, addr, addr2, x) \
- (gf_write_dma_addr((x), data->reg_base + addr, data->reg_base+addr2))
+ (gf_write_dma_addr((x), data->reg_base + addr, data->reg_base + addr2))
/*
* temporary variable used between goldfish_audio_probe() and
@@ -280,12 +280,12 @@ static int goldfish_audio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
+ if (!r) {
dev_err(&pdev->dev, "platform_get_resource failed\n");
return -ENODEV;
}
data->reg_base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
- if (data->reg_base == NULL)
+ if (!data->reg_base)
return -ENOMEM;
data->irq = platform_get_irq(pdev, 0);
@@ -295,7 +295,7 @@ static int goldfish_audio_probe(struct platform_device *pdev)
}
data->buffer_virt = dmam_alloc_coherent(&pdev->dev,
COMBINED_BUFFER_SIZE, &buf_addr, GFP_KERNEL);
- if (data->buffer_virt == NULL) {
+ if (!data->buffer_virt) {
dev_err(&pdev->dev, "allocate buffer failed\n");
return -ENOMEM;
}
diff --git a/drivers/staging/goldfish/goldfish_nand.c b/drivers/staging/goldfish/goldfish_nand.c
index 623353db5a08..76d60eed1490 100644
--- a/drivers/staging/goldfish/goldfish_nand.c
+++ b/drivers/staging/goldfish/goldfish_nand.c
@@ -27,6 +27,7 @@
#include <linux/mutex.h>
#include <linux/goldfish.h>
#include <asm/div64.h>
+#include <linux/dma-mapping.h>
#include "goldfish_nand_reg.h"
@@ -99,11 +100,11 @@ static int goldfish_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
{
loff_t ofs = instr->addr;
u32 len = instr->len;
- u32 rem;
+ s32 rem;
if (ofs + len > mtd->size)
goto invalid_arg;
- rem = do_div(ofs, mtd->writesize);
+ ofs = div_s64_rem(ofs, mtd->writesize, &rem);
if (rem)
goto invalid_arg;
ofs *= (mtd->writesize + mtd->oobsize);
@@ -132,7 +133,7 @@ invalid_arg:
static int goldfish_nand_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
- u32 rem;
+ s32 rem;
if (ofs + ops->len > mtd->size)
goto invalid_arg;
@@ -141,7 +142,7 @@ static int goldfish_nand_read_oob(struct mtd_info *mtd, loff_t ofs,
if (ops->ooblen + ops->ooboffs > mtd->oobsize)
goto invalid_arg;
- rem = do_div(ofs, mtd->writesize);
+ ofs = div_s64_rem(ofs, mtd->writesize, &rem);
if (rem)
goto invalid_arg;
ofs *= (mtd->writesize + mtd->oobsize);
@@ -164,7 +165,7 @@ invalid_arg:
static int goldfish_nand_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
- u32 rem;
+ s32 rem;
if (ofs + ops->len > mtd->size)
goto invalid_arg;
@@ -173,7 +174,7 @@ static int goldfish_nand_write_oob(struct mtd_info *mtd, loff_t ofs,
if (ops->ooblen + ops->ooboffs > mtd->oobsize)
goto invalid_arg;
- rem = do_div(ofs, mtd->writesize);
+ ofs = div_s64_rem(ofs, mtd->writesize, &rem);
if (rem)
goto invalid_arg;
ofs *= (mtd->writesize + mtd->oobsize);
@@ -196,12 +197,12 @@ invalid_arg:
static int goldfish_nand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- u32 rem;
+ s32 rem;
if (from + len > mtd->size)
goto invalid_arg;
- rem = do_div(from, mtd->writesize);
+ from = div_s64_rem(from, mtd->writesize, &rem);
if (rem)
goto invalid_arg;
from *= (mtd->writesize + mtd->oobsize);
@@ -218,12 +219,12 @@ invalid_arg:
static int goldfish_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
- u32 rem;
+ s32 rem;
if (to + len > mtd->size)
goto invalid_arg;
- rem = do_div(to, mtd->writesize);
+ to = div_s64_rem(to, mtd->writesize, &rem);
if (rem)
goto invalid_arg;
to *= (mtd->writesize + mtd->oobsize);
@@ -239,12 +240,12 @@ invalid_arg:
static int goldfish_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
- u32 rem;
+ s32 rem;
if (ofs >= mtd->size)
goto invalid_arg;
- rem = do_div(ofs, mtd->erasesize);
+ ofs = div_s64_rem(ofs, mtd->writesize, &rem);
if (rem)
goto invalid_arg;
ofs *= mtd->erasesize / mtd->writesize;
@@ -260,12 +261,12 @@ invalid_arg:
static int goldfish_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- u32 rem;
+ s32 rem;
if (ofs >= mtd->size)
goto invalid_arg;
- rem = do_div(ofs, mtd->erasesize);
+ ofs = div_s64_rem(ofs, mtd->writesize, &rem);
if (rem)
goto invalid_arg;
ofs *= mtd->erasesize / mtd->writesize;
@@ -284,17 +285,18 @@ invalid_arg:
static int nand_setup_cmd_params(struct platform_device *pdev,
struct goldfish_nand *nand)
{
- u64 paddr;
+ dma_addr_t dma_handle;
unsigned char __iomem *base = nand->base;
- nand->cmd_params = devm_kzalloc(&pdev->dev,
- sizeof(struct cmd_params), GFP_KERNEL);
- if (!nand->cmd_params)
- return -1;
-
- paddr = __pa(nand->cmd_params);
- writel((u32)(paddr >> 32), base + NAND_CMD_PARAMS_ADDR_HIGH);
- writel((u32)paddr, base + NAND_CMD_PARAMS_ADDR_LOW);
+ nand->cmd_params = dmam_alloc_coherent(&pdev->dev,
+ sizeof(struct cmd_params),
+ &dma_handle, GFP_KERNEL);
+ if (!nand->cmd_params) {
+ dev_err(&pdev->dev, "allocate buffer failed\n");
+ return -ENOMEM;
+ }
+ writel((u32)((u64)dma_handle >> 32), base + NAND_CMD_PARAMS_ADDR_HIGH);
+ writel((u32)dma_handle, base + NAND_CMD_PARAMS_ADDR_LOW);
return 0;
}
@@ -319,7 +321,7 @@ static int goldfish_nand_init_device(struct platform_device *pdev,
mtd->oobavail = mtd->oobsize;
mtd->erasesize = readl(base + NAND_DEV_ERASE_SIZE) /
(mtd->writesize + mtd->oobsize) * mtd->writesize;
- do_div(mtd->size, mtd->writesize + mtd->oobsize);
+ mtd->size = div_s64(mtd->size, mtd->writesize + mtd->oobsize);
mtd->size *= mtd->writesize;
dev_dbg(&pdev->dev,
"goldfish nand dev%d: size %llx, page %d, extra %d, erase %d\n",
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c
index 079d50ebfa3a..94c01aad844b 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c
@@ -27,7 +27,7 @@
* Copyright (c) 2012, Intel Corporation.
*/
-#include <linux/crypto.h>
+#include <crypto/hash.h>
#include <linux/scatterlist.h>
#include "../../../include/linux/libcfs/libcfs.h"
#include "linux-crypto.h"
@@ -38,9 +38,11 @@ static int cfs_crypto_hash_speeds[CFS_HASH_ALG_MAX];
static int cfs_crypto_hash_alloc(unsigned char alg_id,
const struct cfs_crypto_hash_type **type,
- struct hash_desc *desc, unsigned char *key,
+ struct ahash_request **req,
+ unsigned char *key,
unsigned int key_len)
{
+ struct crypto_ahash *tfm;
int err = 0;
*type = cfs_crypto_hash_type(alg_id);
@@ -50,18 +52,23 @@ static int cfs_crypto_hash_alloc(unsigned char alg_id,
alg_id, CFS_HASH_ALG_MAX);
return -EINVAL;
}
- desc->tfm = crypto_alloc_hash((*type)->cht_name, 0, 0);
+ tfm = crypto_alloc_ahash((*type)->cht_name, 0, CRYPTO_ALG_ASYNC);
- if (desc->tfm == NULL)
- return -EINVAL;
-
- if (IS_ERR(desc->tfm)) {
+ if (IS_ERR(tfm)) {
CDEBUG(D_INFO, "Failed to alloc crypto hash %s\n",
(*type)->cht_name);
- return PTR_ERR(desc->tfm);
+ return PTR_ERR(tfm);
}
- desc->flags = 0;
+ *req = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!*req) {
+ CDEBUG(D_INFO, "Failed to alloc ahash_request for %s\n",
+ (*type)->cht_name);
+ crypto_free_ahash(tfm);
+ return -ENOMEM;
+ }
+
+ ahash_request_set_callback(*req, 0, NULL, NULL);
/** Shash have different logic for initialization then digest
* shash: crypto_hash_setkey, crypto_hash_init
@@ -70,23 +77,27 @@ static int cfs_crypto_hash_alloc(unsigned char alg_id,
* cfs_crypto_hash_alloc.
*/
if (key != NULL)
- err = crypto_hash_setkey(desc->tfm, key, key_len);
+ err = crypto_ahash_setkey(tfm, key, key_len);
else if ((*type)->cht_key != 0)
- err = crypto_hash_setkey(desc->tfm,
+ err = crypto_ahash_setkey(tfm,
(unsigned char *)&((*type)->cht_key),
(*type)->cht_size);
if (err != 0) {
- crypto_free_hash(desc->tfm);
+ crypto_free_ahash(tfm);
return err;
}
CDEBUG(D_INFO, "Using crypto hash: %s (%s) speed %d MB/s\n",
- (crypto_hash_tfm(desc->tfm))->__crt_alg->cra_name,
- (crypto_hash_tfm(desc->tfm))->__crt_alg->cra_driver_name,
+ crypto_ahash_alg_name(tfm), crypto_ahash_driver_name(tfm),
cfs_crypto_hash_speeds[alg_id]);
- return crypto_hash_init(desc);
+ err = crypto_ahash_init(*req);
+ if (err) {
+ ahash_request_free(*req);
+ crypto_free_ahash(tfm);
+ }
+ return err;
}
int cfs_crypto_hash_digest(unsigned char alg_id,
@@ -95,27 +106,29 @@ int cfs_crypto_hash_digest(unsigned char alg_id,
unsigned char *hash, unsigned int *hash_len)
{
struct scatterlist sl;
- struct hash_desc hdesc;
+ struct ahash_request *req;
int err;
const struct cfs_crypto_hash_type *type;
if (buf == NULL || buf_len == 0 || hash_len == NULL)
return -EINVAL;
- err = cfs_crypto_hash_alloc(alg_id, &type, &hdesc, key, key_len);
+ err = cfs_crypto_hash_alloc(alg_id, &type, &req, key, key_len);
if (err != 0)
return err;
if (hash == NULL || *hash_len < type->cht_size) {
*hash_len = type->cht_size;
- crypto_free_hash(hdesc.tfm);
+ crypto_free_ahash(crypto_ahash_reqtfm(req));
+ ahash_request_free(req);
return -ENOSPC;
}
sg_init_one(&sl, buf, buf_len);
- hdesc.flags = 0;
- err = crypto_hash_digest(&hdesc, &sl, sl.length, hash);
- crypto_free_hash(hdesc.tfm);
+ ahash_request_set_crypt(req, &sl, hash, sl.length);
+ err = crypto_ahash_digest(req);
+ crypto_free_ahash(crypto_ahash_reqtfm(req));
+ ahash_request_free(req);
return err;
}
@@ -125,22 +138,15 @@ struct cfs_crypto_hash_desc *
cfs_crypto_hash_init(unsigned char alg_id,
unsigned char *key, unsigned int key_len)
{
-
- struct hash_desc *hdesc;
+ struct ahash_request *req;
int err;
const struct cfs_crypto_hash_type *type;
- hdesc = kmalloc(sizeof(*hdesc), 0);
- if (hdesc == NULL)
- return ERR_PTR(-ENOMEM);
+ err = cfs_crypto_hash_alloc(alg_id, &type, &req, key, key_len);
- err = cfs_crypto_hash_alloc(alg_id, &type, hdesc, key, key_len);
-
- if (err) {
- kfree(hdesc);
+ if (err)
return ERR_PTR(err);
- }
- return (struct cfs_crypto_hash_desc *)hdesc;
+ return (struct cfs_crypto_hash_desc *)req;
}
EXPORT_SYMBOL(cfs_crypto_hash_init);
@@ -148,23 +154,27 @@ int cfs_crypto_hash_update_page(struct cfs_crypto_hash_desc *hdesc,
struct page *page, unsigned int offset,
unsigned int len)
{
+ struct ahash_request *req = (void *)hdesc;
struct scatterlist sl;
sg_init_table(&sl, 1);
sg_set_page(&sl, page, len, offset & ~CFS_PAGE_MASK);
- return crypto_hash_update((struct hash_desc *)hdesc, &sl, sl.length);
+ ahash_request_set_crypt(req, &sl, NULL, sl.length);
+ return crypto_ahash_update(req);
}
EXPORT_SYMBOL(cfs_crypto_hash_update_page);
int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *hdesc,
const void *buf, unsigned int buf_len)
{
+ struct ahash_request *req = (void *)hdesc;
struct scatterlist sl;
sg_init_one(&sl, buf, buf_len);
- return crypto_hash_update((struct hash_desc *)hdesc, &sl, sl.length);
+ ahash_request_set_crypt(req, &sl, NULL, sl.length);
+ return crypto_ahash_update(req);
}
EXPORT_SYMBOL(cfs_crypto_hash_update);
@@ -173,25 +183,27 @@ int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *hdesc,
unsigned char *hash, unsigned int *hash_len)
{
int err;
- int size = crypto_hash_digestsize(((struct hash_desc *)hdesc)->tfm);
+ struct ahash_request *req = (void *)hdesc;
+ int size = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
if (hash_len == NULL) {
- crypto_free_hash(((struct hash_desc *)hdesc)->tfm);
- kfree(hdesc);
+ crypto_free_ahash(crypto_ahash_reqtfm(req));
+ ahash_request_free(req);
return 0;
}
if (hash == NULL || *hash_len < size) {
*hash_len = size;
return -ENOSPC;
}
- err = crypto_hash_final((struct hash_desc *) hdesc, hash);
+ ahash_request_set_crypt(req, NULL, hash, 0);
+ err = crypto_ahash_final(req);
if (err < 0) {
/* May be caller can fix error */
return err;
}
- crypto_free_hash(((struct hash_desc *)hdesc)->tfm);
- kfree(hdesc);
+ crypto_free_ahash(crypto_ahash_reqtfm(req));
+ ahash_request_free(req);
return err;
}
EXPORT_SYMBOL(cfs_crypto_hash_final);
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index 14697686eea5..0078b6a92f0b 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -27,10 +27,16 @@ source "drivers/staging/media/davinci_vpfe/Kconfig"
source "drivers/staging/media/mn88472/Kconfig"
-source "drivers/staging/media/mn88473/Kconfig"
+source "drivers/staging/media/mx2/Kconfig"
+
+source "drivers/staging/media/mx3/Kconfig"
+
+source "drivers/staging/media/omap1/Kconfig"
source "drivers/staging/media/omap4iss/Kconfig"
+source "drivers/staging/media/timb/Kconfig"
+
# Keep LIRC at the end, as it has sub-menus
source "drivers/staging/media/lirc/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 34c557b4c6d6..91495882a36c 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -2,6 +2,9 @@ obj-$(CONFIG_I2C_BCM2048) += bcm2048/
obj-$(CONFIG_DVB_CXD2099) += cxd2099/
obj-$(CONFIG_LIRC_STAGING) += lirc/
obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
+obj-$(CONFIG_VIDEO_MX2) += mx2/
+obj-$(CONFIG_VIDEO_MX3) += mx3/
+obj-$(CONFIG_VIDEO_OMAP1) += omap1/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
obj-$(CONFIG_DVB_MN88472) += mn88472/
-obj-$(CONFIG_DVB_MN88473) += mn88473/
+obj-$(CONFIG_VIDEO_TIMBERDALE) += timb/
diff --git a/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h b/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h
index 7b7e7b26c1e8..3cc9be776f8b 100644
--- a/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h
+++ b/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h
@@ -538,7 +538,7 @@ struct vpfe_isif_raw_config {
};
/**********************************************************************
- IPIPE API Structures
+* IPIPE API Structures
**********************************************************************/
/* IPIPE module configurations */
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index 3ec7e65a3ffa..db49af90217e 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -147,7 +147,7 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
mutex_lock(&mdev->graph_mutex);
ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
if (ret) {
- mutex_unlock(&video->lock);
+ mutex_unlock(&mdev->graph_mutex);
return -ENOMEM;
}
media_entity_graph_walk_start(&graph, entity);
diff --git a/drivers/staging/media/lirc/lirc_parallel.c b/drivers/staging/media/lirc/lirc_parallel.c
index d009bcb439f0..68ede6c56e6d 100644
--- a/drivers/staging/media/lirc/lirc_parallel.c
+++ b/drivers/staging/media/lirc/lirc_parallel.c
@@ -193,7 +193,7 @@ static int lirc_claim(void)
return 0;
}
}
- out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+ out(LIRC_LP_CONTROL, LP_PSELECP | LP_PINITP);
is_claimed = 1;
return 1;
}
@@ -264,7 +264,7 @@ static void lirc_lirc_irq_handler(void *blah)
init = 1;
}
- timeout = timer/10; /* timeout after 1/10 sec. */
+ timeout = timer / 10; /* timeout after 1/10 sec. */
signal = 1;
level = lirc_get_timer();
do {
@@ -286,15 +286,15 @@ static void lirc_lirc_irq_handler(void *blah)
/* adjust value to usecs */
__u64 helper;
- helper = ((__u64) signal)*1000000;
+ helper = ((__u64)signal) * 1000000;
do_div(helper, timer);
- signal = (long) helper;
+ signal = (long)helper;
if (signal > LIRC_SFH506_DELAY)
data = signal - LIRC_SFH506_DELAY;
else
data = 1;
- rbuf_write(PULSE_BIT|data); /* pulse */
+ rbuf_write(PULSE_BIT | data); /* pulse */
}
lastkt = ktime_get();
#else
@@ -331,7 +331,7 @@ static ssize_t lirc_read(struct file *filep, char __user *buf, size_t n,
set_current_state(TASK_INTERRUPTIBLE);
while (count < n) {
if (rptr != wptr) {
- if (copy_to_user(buf+count, &rbuf[rptr],
+ if (copy_to_user(buf + count, &rbuf[rptr],
sizeof(int))) {
result = -EFAULT;
break;
@@ -393,9 +393,9 @@ static ssize_t lirc_write(struct file *filep, const char __user *buf, size_t n,
for (i = 0; i < count; i++) {
__u64 helper;
- helper = ((__u64) wbuf[i])*timer;
+ helper = ((__u64)wbuf[i]) * timer;
do_div(helper, 1000000);
- wbuf[i] = (int) helper;
+ wbuf[i] = (int)helper;
}
local_irq_save(flags);
@@ -647,7 +647,7 @@ static int __init lirc_parallel_init(void)
goto exit_device_put;
pport = parport_find_base(io);
- if (pport == NULL) {
+ if (!pport) {
pr_notice("no port at %x found\n", io);
result = -ENXIO;
goto exit_device_put;
@@ -656,7 +656,7 @@ static int __init lirc_parallel_init(void)
pf, kf, lirc_lirc_irq_handler, 0,
NULL);
parport_put_port(pport);
- if (ppdevice == NULL) {
+ if (!ppdevice) {
pr_notice("parport_register_device() failed\n");
result = -ENXIO;
goto exit_device_put;
@@ -664,7 +664,7 @@ static int __init lirc_parallel_init(void)
if (parport_claim(ppdevice) != 0)
goto skip_init;
is_claimed = 1;
- out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+ out(LIRC_LP_CONTROL, LP_PSELECP | LP_PINITP);
#ifdef LIRC_TIMER
if (debug)
@@ -730,7 +730,7 @@ module_param(irq, int, S_IRUGO);
MODULE_PARM_DESC(irq, "Interrupt (7 or 5)");
module_param(tx_mask, int, S_IRUGO);
-MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)");
+MODULE_PARM_DESC(tx_mask, "Transmitter mask (default: 0x01)");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c
index ce3b5f230e2e..3551aed589c0 100644
--- a/drivers/staging/media/lirc/lirc_zilog.c
+++ b/drivers/staging/media/lirc/lirc_zilog.c
@@ -1680,9 +1680,7 @@ module_init(zilog_init);
module_exit(zilog_exit);
MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)");
-MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
- "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, "
- "Andy Walls");
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, Andy Walls");
MODULE_LICENSE("GPL");
/* for compat with old name, which isn't all that accurate anymore */
MODULE_ALIAS("lirc_pvr150");
diff --git a/drivers/staging/media/mn88473/Kconfig b/drivers/staging/media/mn88473/Kconfig
deleted file mode 100644
index 6c9ebf51c2c7..000000000000
--- a/drivers/staging/media/mn88473/Kconfig
+++ /dev/null
@@ -1,7 +0,0 @@
-config DVB_MN88473
- tristate "Panasonic MN88473"
- depends on DVB_CORE && I2C
- select REGMAP_I2C
- default m if !MEDIA_SUBDRV_AUTOSELECT
- help
- Say Y when you want to support this frontend.
diff --git a/drivers/staging/media/mn88473/Makefile b/drivers/staging/media/mn88473/Makefile
deleted file mode 100644
index fac55410ce55..000000000000
--- a/drivers/staging/media/mn88473/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-obj-$(CONFIG_DVB_MN88473) += mn88473.o
-
-ccflags-y += -Idrivers/media/dvb-core/
-ccflags-y += -Idrivers/media/dvb-frontends/
-ccflags-y += -Idrivers/media/tuners/
diff --git a/drivers/staging/media/mn88473/TODO b/drivers/staging/media/mn88473/TODO
deleted file mode 100644
index b90a14be3beb..000000000000
--- a/drivers/staging/media/mn88473/TODO
+++ /dev/null
@@ -1,21 +0,0 @@
-Driver general quality is not good enough for mainline. Also, other
-device drivers (USB-bridge, tuner) needed for Astrometa receiver in
-question could need some changes. However, if that driver is mainlined
-due to some other device than Astrometa, unrelated TODOs could be
-skipped. In that case rtl28xxu driver needs module parameter to prevent
-driver loading.
-
-Required TODOs:
-* missing lock flags
-* I2C errors
-* tuner sensitivity
-
-*Do not* send any patch fixing checkpatch.pl issues. Currently it passes
-checkpatch.pl tests. I don't want waste my time to review this kind of
-trivial stuff. *Do not* add missing register I/O error checks. Those are
-missing for the reason it is much easier to compare I2C data sniffs when
-there is less lines. Those error checks are about the last thing to be added.
-
-Patches should be submitted to:
-linux-media@vger.kernel.org and Antti Palosaari <crope@iki.fi>
-
diff --git a/drivers/staging/media/mx2/Kconfig b/drivers/staging/media/mx2/Kconfig
new file mode 100644
index 000000000000..beaa885cf104
--- /dev/null
+++ b/drivers/staging/media/mx2/Kconfig
@@ -0,0 +1,15 @@
+config VIDEO_MX2
+ tristate "i.MX27 Camera Sensor Interface driver"
+ depends on VIDEO_DEV && SOC_CAMERA
+ depends on SOC_IMX27 || COMPILE_TEST
+ depends on HAS_DMA
+ select VIDEOBUF2_DMA_CONTIG
+ ---help---
+ This is a v4l2 driver for the i.MX27 Camera Sensor Interface
+
+ This driver is deprecated: it should become a stand-alone driver
+ instead of using the soc-camera framework.
+
+ Unless someone is willing to take this on (unlikely with such
+ ancient hardware) it is going to be removed from the kernel
+ soon.
diff --git a/drivers/staging/media/mx2/Makefile b/drivers/staging/media/mx2/Makefile
new file mode 100644
index 000000000000..fc5b2826a558
--- /dev/null
+++ b/drivers/staging/media/mx2/Makefile
@@ -0,0 +1,3 @@
+# Makefile for i.MX27 Camera Sensor driver
+
+obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o
diff --git a/drivers/staging/media/mx2/TODO b/drivers/staging/media/mx2/TODO
new file mode 100644
index 000000000000..bc68fa443a3e
--- /dev/null
+++ b/drivers/staging/media/mx2/TODO
@@ -0,0 +1,10 @@
+This driver is deprecated: it should become a stand-alone driver instead of
+using the soc-camera framework.
+
+Unless someone is willing to take this on (unlikely with such ancient
+hardware) it is going to be removed from the kernel soon.
+
+Note that trivial patches will not be accepted anymore, only a full conversion.
+
+If you want to convert this driver, please contact the linux-media mailinglist
+(see http://linuxtv.org/lists.php).
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/staging/media/mx2/mx2_camera.c
index 48dd5b7851b5..48dd5b7851b5 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/staging/media/mx2/mx2_camera.c
diff --git a/drivers/staging/media/mx3/Kconfig b/drivers/staging/media/mx3/Kconfig
new file mode 100644
index 000000000000..595d5fe7cad1
--- /dev/null
+++ b/drivers/staging/media/mx3/Kconfig
@@ -0,0 +1,15 @@
+config VIDEO_MX3
+ tristate "i.MX3x Camera Sensor Interface driver"
+ depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
+ depends on MX3_IPU || COMPILE_TEST
+ depends on HAS_DMA
+ select VIDEOBUF2_DMA_CONTIG
+ ---help---
+ This is a v4l2 driver for the i.MX3x Camera Sensor Interface
+
+ This driver is deprecated: it should become a stand-alone driver
+ instead of using the soc-camera framework.
+
+ Unless someone is willing to take this on (unlikely with such
+ ancient hardware) it is going to be removed from the kernel
+ soon.
diff --git a/drivers/staging/media/mx3/Makefile b/drivers/staging/media/mx3/Makefile
new file mode 100644
index 000000000000..6d91dcd80c1d
--- /dev/null
+++ b/drivers/staging/media/mx3/Makefile
@@ -0,0 +1,3 @@
+# Makefile for i.MX3x Camera Sensor driver
+
+obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
diff --git a/drivers/staging/media/mx3/TODO b/drivers/staging/media/mx3/TODO
new file mode 100644
index 000000000000..bc68fa443a3e
--- /dev/null
+++ b/drivers/staging/media/mx3/TODO
@@ -0,0 +1,10 @@
+This driver is deprecated: it should become a stand-alone driver instead of
+using the soc-camera framework.
+
+Unless someone is willing to take this on (unlikely with such ancient
+hardware) it is going to be removed from the kernel soon.
+
+Note that trivial patches will not be accepted anymore, only a full conversion.
+
+If you want to convert this driver, please contact the linux-media mailinglist
+(see http://linuxtv.org/lists.php).
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/staging/media/mx3/mx3_camera.c
index 169ed1150226..aa39e9569b1a 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/staging/media/mx3/mx3_camera.c
@@ -146,8 +146,8 @@ static void mx3_cam_dma_done(void *arg)
struct idmac_channel *ichannel = to_idmac_chan(chan);
struct mx3_camera_dev *mx3_cam = ichannel->client;
- dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
- desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0);
+ dev_dbg(chan->device->dev, "callback cookie %d, active DMA %pad\n",
+ desc->txd.cookie, mx3_cam->active ? &sg_dma_address(&mx3_cam->active->sg) : NULL);
spin_lock(&mx3_cam->lock);
if (mx3_cam->active) {
@@ -314,8 +314,8 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
spin_unlock_irq(&mx3_cam->lock);
cookie = txd->tx_submit(txd);
- dev_dbg(icd->parent, "Submitted cookie %d DMA 0x%08x\n",
- cookie, sg_dma_address(&buf->sg));
+ dev_dbg(icd->parent, "Submitted cookie %d DMA %pad\n",
+ cookie, &sg_dma_address(&buf->sg));
if (cookie >= 0)
return;
@@ -344,8 +344,8 @@ static void mx3_videobuf_release(struct vb2_buffer *vb)
unsigned long flags;
dev_dbg(icd->parent,
- "Release%s DMA 0x%08x, queue %sempty\n",
- mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
+ "Release%s DMA %pad, queue %sempty\n",
+ mx3_cam->active == buf ? " active" : "", &sg_dma_address(&buf->sg),
list_empty(&buf->queue) ? "" : "not ");
spin_lock_irqsave(&mx3_cam->lock, flags);
diff --git a/drivers/staging/media/omap1/Kconfig b/drivers/staging/media/omap1/Kconfig
new file mode 100644
index 000000000000..6cfab3a04ae1
--- /dev/null
+++ b/drivers/staging/media/omap1/Kconfig
@@ -0,0 +1,13 @@
+config VIDEO_OMAP1
+ tristate "OMAP1 Camera Interface driver"
+ depends on VIDEO_DEV && SOC_CAMERA
+ depends on ARCH_OMAP1
+ depends on HAS_DMA
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF_DMA_SG
+ ---help---
+ This is a v4l2 driver for the TI OMAP1 camera interface
+
+ This driver is deprecated and will be removed soon unless someone
+ will start the work to convert this driver to the vb2 framework
+ and remove the soc-camera dependency.
diff --git a/drivers/staging/media/omap1/Makefile b/drivers/staging/media/omap1/Makefile
new file mode 100644
index 000000000000..2885622600f2
--- /dev/null
+++ b/drivers/staging/media/omap1/Makefile
@@ -0,0 +1,3 @@
+# Makefile for OMAP1 driver
+
+obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
diff --git a/drivers/staging/media/omap1/TODO b/drivers/staging/media/omap1/TODO
new file mode 100644
index 000000000000..1025f9f60ff0
--- /dev/null
+++ b/drivers/staging/media/omap1/TODO
@@ -0,0 +1,8 @@
+This driver is deprecated and will be removed soon unless someone will start
+the work to convert this driver to the vb2 framework and remove the
+soc-camera dependency.
+
+Note that trivial patches will not be accepted anymore, only a full conversion.
+
+If you want to convert this driver, please contact the linux-media mailinglist
+(see http://linuxtv.org/lists.php).
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/staging/media/omap1/omap1_camera.c
index bd721e35474a..bd721e35474a 100644
--- a/drivers/media/platform/soc_camera/omap1_camera.c
+++ b/drivers/staging/media/omap1/omap1_camera.c
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index 30b473cfb020..fb80d2bc5a25 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -363,215 +363,6 @@ static irqreturn_t iss_isr(int irq, void *_iss)
}
/* -----------------------------------------------------------------------------
- * Pipeline power management
- *
- * Entities must be powered up when part of a pipeline that contains at least
- * one open video device node.
- *
- * To achieve this use the entity use_count field to track the number of users.
- * For entities corresponding to video device nodes the use_count field stores
- * the users count of the node. For entities corresponding to subdevs the
- * use_count field stores the total number of users of all video device nodes
- * in the pipeline.
- *
- * The omap4iss_pipeline_pm_use() function must be called in the open() and
- * close() handlers of video device nodes. It increments or decrements the use
- * count of all subdev entities in the pipeline.
- *
- * To react to link management on powered pipelines, the link setup notification
- * callback updates the use count of all entities in the source and sink sides
- * of the link.
- */
-
-/*
- * iss_pipeline_pm_use_count - Count the number of users of a pipeline
- * @entity: The entity
- *
- * Return the total number of users of all video device nodes in the pipeline.
- */
-static int iss_pipeline_pm_use_count(struct media_entity *entity,
- struct media_entity_graph *graph)
-{
- int use = 0;
-
- media_entity_graph_walk_start(graph, entity);
-
- while ((entity = media_entity_graph_walk_next(graph))) {
- if (is_media_entity_v4l2_io(entity))
- use += entity->use_count;
- }
-
- return use;
-}
-
-/*
- * iss_pipeline_pm_power_one - Apply power change to an entity
- * @entity: The entity
- * @change: Use count change
- *
- * Change the entity use count by @change. If the entity is a subdev update its
- * power state by calling the core::s_power operation when the use count goes
- * from 0 to != 0 or from != 0 to 0.
- *
- * Return 0 on success or a negative error code on failure.
- */
-static int iss_pipeline_pm_power_one(struct media_entity *entity, int change)
-{
- struct v4l2_subdev *subdev;
-
- subdev = is_media_entity_v4l2_subdev(entity)
- ? media_entity_to_v4l2_subdev(entity) : NULL;
-
- if (entity->use_count == 0 && change > 0 && subdev) {
- int ret;
-
- ret = v4l2_subdev_call(subdev, core, s_power, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
- }
-
- entity->use_count += change;
- WARN_ON(entity->use_count < 0);
-
- if (entity->use_count == 0 && change < 0 && subdev)
- v4l2_subdev_call(subdev, core, s_power, 0);
-
- return 0;
-}
-
-/*
- * iss_pipeline_pm_power - Apply power change to all entities in a pipeline
- * @entity: The entity
- * @change: Use count change
- *
- * Walk the pipeline to update the use count and the power state of all non-node
- * entities.
- *
- * Return 0 on success or a negative error code on failure.
- */
-static int iss_pipeline_pm_power(struct media_entity *entity, int change,
- struct media_entity_graph *graph)
-{
- struct media_entity *first = entity;
- int ret = 0;
-
- if (!change)
- return 0;
-
- media_entity_graph_walk_start(graph, entity);
-
- while (!ret && (entity = media_entity_graph_walk_next(graph)))
- if (is_media_entity_v4l2_subdev(entity))
- ret = iss_pipeline_pm_power_one(entity, change);
-
- if (!ret)
- return 0;
-
- media_entity_graph_walk_start(graph, first);
-
- while ((first = media_entity_graph_walk_next(graph)) &&
- first != entity)
- if (is_media_entity_v4l2_subdev(first))
- iss_pipeline_pm_power_one(first, -change);
-
- return ret;
-}
-
-/*
- * omap4iss_pipeline_pm_use - Update the use count of an entity
- * @entity: The entity
- * @use: Use (1) or stop using (0) the entity
- *
- * Update the use count of all entities in the pipeline and power entities on or
- * off accordingly.
- *
- * Return 0 on success or a negative error code on failure. Powering entities
- * off is assumed to never fail. No failure can occur when the use parameter is
- * set to 0.
- */
-int omap4iss_pipeline_pm_use(struct media_entity *entity, int use,
- struct media_entity_graph *graph)
-{
- int change = use ? 1 : -1;
- int ret;
-
- mutex_lock(&entity->graph_obj.mdev->graph_mutex);
-
- /* Apply use count to node. */
- entity->use_count += change;
- WARN_ON(entity->use_count < 0);
-
- /* Apply power change to connected non-nodes. */
- ret = iss_pipeline_pm_power(entity, change, graph);
- if (ret < 0)
- entity->use_count -= change;
-
- mutex_unlock(&entity->graph_obj.mdev->graph_mutex);
-
- return ret;
-}
-
-/*
- * iss_pipeline_link_notify - Link management notification callback
- * @link: The link
- * @flags: New link flags that will be applied
- *
- * React to link management on powered pipelines by updating the use count of
- * all entities in the source and sink sides of the link. Entities are powered
- * on or off accordingly.
- *
- * Return 0 on success or a negative error code on failure. Powering entities
- * off is assumed to never fail. This function will not fail for disconnection
- * events.
- */
-static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
- unsigned int notification)
-{
- struct media_entity_graph *graph =
- &container_of(link->graph_obj.mdev, struct iss_device,
- media_dev)->pm_count_graph;
- struct media_entity *source = link->source->entity;
- struct media_entity *sink = link->sink->entity;
- int source_use;
- int sink_use;
- int ret;
-
- if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
- ret = media_entity_graph_walk_init(graph,
- link->graph_obj.mdev);
- if (ret)
- return ret;
- }
-
- source_use = iss_pipeline_pm_use_count(source, graph);
- sink_use = iss_pipeline_pm_use_count(sink, graph);
-
- if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
- !(flags & MEDIA_LNK_FL_ENABLED)) {
- /* Powering off entities is assumed to never fail. */
- iss_pipeline_pm_power(source, -sink_use, graph);
- iss_pipeline_pm_power(sink, -source_use, graph);
- return 0;
- }
-
- if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
- (flags & MEDIA_LNK_FL_ENABLED)) {
- ret = iss_pipeline_pm_power(source, sink_use, graph);
- if (ret < 0)
- return ret;
-
- ret = iss_pipeline_pm_power(sink, source_use, graph);
- if (ret < 0)
- iss_pipeline_pm_power(source, -sink_use, graph);
- }
-
- if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH)
- media_entity_graph_walk_cleanup(graph);
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
* Pipeline stream management
*/
@@ -1197,7 +988,7 @@ static int iss_register_entities(struct iss_device *iss)
strlcpy(iss->media_dev.model, "TI OMAP4 ISS",
sizeof(iss->media_dev.model));
iss->media_dev.hw_revision = iss->revision;
- iss->media_dev.link_notify = iss_pipeline_link_notify;
+ iss->media_dev.link_notify = v4l2_pipeline_link_notify;
ret = media_device_register(&iss->media_dev);
if (ret < 0) {
dev_err(iss->dev, "Media device registration failed (%d)\n",
diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h
index 05f08a3caa19..760ee27da704 100644
--- a/drivers/staging/media/omap4iss/iss.h
+++ b/drivers/staging/media/omap4iss/iss.h
@@ -15,6 +15,8 @@
#define _OMAP4_ISS_H_
#include <media/v4l2-device.h>
+#include <media/v4l2-mc.h>
+
#include <linux/device.h>
#include <linux/io.h>
#include <linux/platform_device.h>
@@ -87,7 +89,6 @@ struct iss_reg {
struct iss_device {
struct v4l2_device v4l2_dev;
struct media_device media_dev;
- struct media_entity_graph pm_count_graph;
struct device *dev;
u32 revision;
@@ -152,9 +153,6 @@ void omap4iss_isp_subclk_enable(struct iss_device *iss,
void omap4iss_isp_subclk_disable(struct iss_device *iss,
enum iss_isp_subclk_resource res);
-int omap4iss_pipeline_pm_use(struct media_entity *entity, int use,
- struct media_entity_graph *graph);
-
int omap4iss_register_entities(struct platform_device *pdev,
struct v4l2_device *v4l2_dev);
void omap4iss_unregister_entities(struct platform_device *pdev);
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 058233a9de67..f54349bce4de 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -19,8 +19,10 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
+
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
#include "iss_video.h"
#include "iss.h"
@@ -1009,13 +1011,7 @@ static int iss_video_open(struct file *file)
goto done;
}
- ret = media_entity_graph_walk_init(&handle->graph,
- &video->iss->media_dev);
- if (ret)
- goto done;
-
- ret = omap4iss_pipeline_pm_use(&video->video.entity, 1,
- &handle->graph);
+ ret = v4l2_pipeline_pm_use(&video->video.entity, 1);
if (ret < 0) {
omap4iss_put(video->iss);
goto done;
@@ -1054,7 +1050,6 @@ static int iss_video_open(struct file *file)
done:
if (ret < 0) {
v4l2_fh_del(&handle->vfh);
- media_entity_graph_walk_cleanup(&handle->graph);
kfree(handle);
}
@@ -1070,13 +1065,11 @@ static int iss_video_release(struct file *file)
/* Disable streaming and free the buffers queue resources. */
iss_video_streamoff(file, vfh, video->type);
- omap4iss_pipeline_pm_use(&video->video.entity, 0, &handle->graph);
+ v4l2_pipeline_pm_use(&video->video.entity, 0);
/* Release the videobuf2 queue */
vb2_queue_release(&handle->queue);
- /* Release the file handle. */
- media_entity_graph_walk_cleanup(&handle->graph);
v4l2_fh_del(vfh);
kfree(handle);
file->private_data = NULL;
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index 34588b7176ca..c8bd2958a3f8 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -183,7 +183,6 @@ struct iss_video_fh {
struct vb2_queue queue;
struct v4l2_format format;
struct v4l2_fract timeperframe;
- struct media_entity_graph graph;
};
#define to_iss_video_fh(fh) container_of(fh, struct iss_video_fh, vfh)
diff --git a/drivers/staging/media/timb/Kconfig b/drivers/staging/media/timb/Kconfig
new file mode 100644
index 000000000000..e413fecc1e67
--- /dev/null
+++ b/drivers/staging/media/timb/Kconfig
@@ -0,0 +1,11 @@
+config VIDEO_TIMBERDALE
+ tristate "Support for timberdale Video In/LogiWIN"
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && HAS_DMA
+ depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST
+ select VIDEO_ADV7180
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ Add support for the Video In peripherial of the timberdale FPGA.
+
+ This driver is deprecated and will be removed soon unless someone
+ will start the work to convert this driver to the vb2 framework.
diff --git a/drivers/staging/media/timb/Makefile b/drivers/staging/media/timb/Makefile
new file mode 100644
index 000000000000..4c989c23a0e0
--- /dev/null
+++ b/drivers/staging/media/timb/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
diff --git a/drivers/media/platform/timblogiw.c b/drivers/staging/media/timb/timblogiw.c
index 113c9f3c0b3e..113c9f3c0b3e 100644
--- a/drivers/media/platform/timblogiw.c
+++ b/drivers/staging/media/timb/timblogiw.c
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
index 2096d78913bd..8eac7cdd5f3e 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
@@ -9,6 +9,8 @@
* more details.
*/
+#include <crypto/hash.h>
+#include <crypto/skcipher.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -18,7 +20,6 @@
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/string.h>
-#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/crc32.h>
#include <linux/etherdevice.h>
@@ -48,10 +49,10 @@ struct rtllib_tkip_data {
u32 dot11RSNAStatsTKIPLocalMICFailures;
int key_idx;
- struct crypto_blkcipher *rx_tfm_arc4;
- struct crypto_hash *rx_tfm_michael;
- struct crypto_blkcipher *tx_tfm_arc4;
- struct crypto_hash *tx_tfm_michael;
+ struct crypto_skcipher *rx_tfm_arc4;
+ struct crypto_ahash *rx_tfm_michael;
+ struct crypto_skcipher *tx_tfm_arc4;
+ struct crypto_ahash *tx_tfm_michael;
/* scratch buffers for virt_to_page() (crypto API) */
u8 rx_hdr[16];
u8 tx_hdr[16];
@@ -65,32 +66,32 @@ static void *rtllib_tkip_init(int key_idx)
if (priv == NULL)
goto fail;
priv->key_idx = key_idx;
- priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
- CRYPTO_ALG_ASYNC);
+ priv->tx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0,
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm_arc4)) {
pr_debug("Could not allocate crypto API arc4\n");
priv->tx_tfm_arc4 = NULL;
goto fail;
}
- priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
- CRYPTO_ALG_ASYNC);
+ priv->tx_tfm_michael = crypto_alloc_ahash("michael_mic", 0,
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm_michael)) {
pr_debug("Could not allocate crypto API michael_mic\n");
priv->tx_tfm_michael = NULL;
goto fail;
}
- priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
- CRYPTO_ALG_ASYNC);
+ priv->rx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0,
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm_arc4)) {
pr_debug("Could not allocate crypto API arc4\n");
priv->rx_tfm_arc4 = NULL;
goto fail;
}
- priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
- CRYPTO_ALG_ASYNC);
+ priv->rx_tfm_michael = crypto_alloc_ahash("michael_mic", 0,
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm_michael)) {
pr_debug("Could not allocate crypto API michael_mic\n");
priv->rx_tfm_michael = NULL;
@@ -100,14 +101,10 @@ static void *rtllib_tkip_init(int key_idx)
fail:
if (priv) {
- if (priv->tx_tfm_michael)
- crypto_free_hash(priv->tx_tfm_michael);
- if (priv->tx_tfm_arc4)
- crypto_free_blkcipher(priv->tx_tfm_arc4);
- if (priv->rx_tfm_michael)
- crypto_free_hash(priv->rx_tfm_michael);
- if (priv->rx_tfm_arc4)
- crypto_free_blkcipher(priv->rx_tfm_arc4);
+ crypto_free_ahash(priv->tx_tfm_michael);
+ crypto_free_skcipher(priv->tx_tfm_arc4);
+ crypto_free_ahash(priv->rx_tfm_michael);
+ crypto_free_skcipher(priv->rx_tfm_arc4);
kfree(priv);
}
@@ -120,14 +117,10 @@ static void rtllib_tkip_deinit(void *priv)
struct rtllib_tkip_data *_priv = priv;
if (_priv) {
- if (_priv->tx_tfm_michael)
- crypto_free_hash(_priv->tx_tfm_michael);
- if (_priv->tx_tfm_arc4)
- crypto_free_blkcipher(_priv->tx_tfm_arc4);
- if (_priv->rx_tfm_michael)
- crypto_free_hash(_priv->rx_tfm_michael);
- if (_priv->rx_tfm_arc4)
- crypto_free_blkcipher(_priv->rx_tfm_arc4);
+ crypto_free_ahash(_priv->tx_tfm_michael);
+ crypto_free_skcipher(_priv->tx_tfm_arc4);
+ crypto_free_ahash(_priv->rx_tfm_michael);
+ crypto_free_skcipher(_priv->rx_tfm_arc4);
}
kfree(priv);
}
@@ -301,7 +294,6 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
struct rtllib_hdr_4addr *hdr;
struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
MAX_DEV_ADDR_SIZE);
- struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4};
int ret = 0;
u8 rc4key[16], *icv;
u32 crc;
@@ -347,6 +339,8 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
*pos++ = (tkey->tx_iv32 >> 24) & 0xff;
if (!tcb_desc->bHwSec) {
+ SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4);
+
icv = skb_put(skb, 4);
crc = ~crc32_le(~0, pos, len);
icv[0] = crc;
@@ -357,8 +351,12 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
sg_init_one(&sg, pos, len+4);
- crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
- ret = crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
+ crypto_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
+ skcipher_request_set_tfm(req, tkey->tx_tfm_arc4);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
+ ret = crypto_skcipher_encrypt(req);
+ skcipher_request_zero(req);
}
tkey->tx_iv16++;
@@ -384,12 +382,12 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
struct rtllib_hdr_4addr *hdr;
struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
MAX_DEV_ADDR_SIZE);
- struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4};
u8 rc4key[16];
u8 icv[4];
u32 crc;
struct scatterlist sg;
int plen;
+ int err;
if (skb->len < hdr_len + 8 + 4)
return -1;
@@ -425,6 +423,8 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
pos += 8;
if (!tcb_desc->bHwSec || (skb->cb[0] == 1)) {
+ SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4);
+
if ((iv32 < tkey->rx_iv32 ||
(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) &&
tkey->initialized) {
@@ -450,8 +450,13 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
sg_init_one(&sg, pos, plen+4);
- crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
- if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
+ crypto_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
+ skcipher_request_set_tfm(req, tkey->rx_tfm_arc4);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
+ err = crypto_skcipher_decrypt(req);
+ skcipher_request_zero(req);
+ if (err) {
if (net_ratelimit()) {
netdev_dbg(skb->dev,
"Failed to decrypt received packet from %pM\n",
@@ -500,11 +505,12 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
-static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, u8 *hdr,
+static int michael_mic(struct crypto_ahash *tfm_michael, u8 *key, u8 *hdr,
u8 *data, size_t data_len, u8 *mic)
{
- struct hash_desc desc;
+ AHASH_REQUEST_ON_STACK(req, tfm_michael);
struct scatterlist sg[2];
+ int err;
if (tfm_michael == NULL) {
pr_warn("michael_mic: tfm_michael == NULL\n");
@@ -514,12 +520,15 @@ static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, u8 *hdr,
sg_set_buf(&sg[0], hdr, 16);
sg_set_buf(&sg[1], data, data_len);
- if (crypto_hash_setkey(tfm_michael, key, 8))
+ if (crypto_ahash_setkey(tfm_michael, key, 8))
return -1;
- desc.tfm = tfm_michael;
- desc.flags = 0;
- return crypto_hash_digest(&desc, sg, data_len + 16, mic);
+ ahash_request_set_tfm(req, tfm_michael);
+ ahash_request_set_callback(req, 0, NULL, NULL);
+ ahash_request_set_crypt(req, sg, mic, data_len + 16);
+ err = crypto_ahash_digest(req);
+ ahash_request_zero(req);
+ return err;
}
static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr)
@@ -655,10 +664,10 @@ static int rtllib_tkip_set_key(void *key, int len, u8 *seq, void *priv)
{
struct rtllib_tkip_data *tkey = priv;
int keyidx;
- struct crypto_hash *tfm = tkey->tx_tfm_michael;
- struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
- struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
- struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
+ struct crypto_ahash *tfm = tkey->tx_tfm_michael;
+ struct crypto_skcipher *tfm2 = tkey->tx_tfm_arc4;
+ struct crypto_ahash *tfm3 = tkey->rx_tfm_michael;
+ struct crypto_skcipher *tfm4 = tkey->rx_tfm_arc4;
keyidx = tkey->key_idx;
memset(tkey, 0, sizeof(*tkey));
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_wep.c b/drivers/staging/rtl8192e/rtllib_crypt_wep.c
index 21d7eee4c9a9..b3343a5d0fd6 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_wep.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_wep.c
@@ -9,6 +9,7 @@
* more details.
*/
+#include <crypto/skcipher.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -17,8 +18,6 @@
#include <linux/string.h>
#include "rtllib.h"
-#include <linux/crypto.h>
-
#include <linux/scatterlist.h>
#include <linux/crc32.h>
@@ -28,8 +27,8 @@ struct prism2_wep_data {
u8 key[WEP_KEY_LEN + 1];
u8 key_len;
u8 key_idx;
- struct crypto_blkcipher *tx_tfm;
- struct crypto_blkcipher *rx_tfm;
+ struct crypto_skcipher *tx_tfm;
+ struct crypto_skcipher *rx_tfm;
};
@@ -42,13 +41,13 @@ static void *prism2_wep_init(int keyidx)
goto fail;
priv->key_idx = keyidx;
- priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ priv->tx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm)) {
pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n");
priv->tx_tfm = NULL;
goto fail;
}
- priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ priv->rx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm)) {
pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n");
priv->rx_tfm = NULL;
@@ -62,10 +61,8 @@ static void *prism2_wep_init(int keyidx)
fail:
if (priv) {
- if (priv->tx_tfm)
- crypto_free_blkcipher(priv->tx_tfm);
- if (priv->rx_tfm)
- crypto_free_blkcipher(priv->rx_tfm);
+ crypto_free_skcipher(priv->tx_tfm);
+ crypto_free_skcipher(priv->rx_tfm);
kfree(priv);
}
return NULL;
@@ -77,10 +74,8 @@ static void prism2_wep_deinit(void *priv)
struct prism2_wep_data *_priv = priv;
if (_priv) {
- if (_priv->tx_tfm)
- crypto_free_blkcipher(_priv->tx_tfm);
- if (_priv->rx_tfm)
- crypto_free_blkcipher(_priv->rx_tfm);
+ crypto_free_skcipher(_priv->tx_tfm);
+ crypto_free_skcipher(_priv->rx_tfm);
}
kfree(priv);
}
@@ -99,10 +94,10 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
u8 *pos;
struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
MAX_DEV_ADDR_SIZE);
- struct blkcipher_desc desc = {.tfm = wep->tx_tfm};
u32 crc;
u8 *icv;
struct scatterlist sg;
+ int err;
if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
skb->len < hdr_len){
@@ -140,6 +135,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
memcpy(key + 3, wep->key, wep->key_len);
if (!tcb_desc->bHwSec) {
+ SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm);
/* Append little-endian CRC32 and encrypt it to produce ICV */
crc = ~crc32_le(~0, pos, len);
@@ -150,8 +146,13 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
icv[3] = crc >> 24;
sg_init_one(&sg, pos, len+4);
- crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
- return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
+ crypto_skcipher_setkey(wep->tx_tfm, key, klen);
+ skcipher_request_set_tfm(req, wep->tx_tfm);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
+ err = crypto_skcipher_encrypt(req);
+ skcipher_request_zero(req);
+ return err;
}
return 0;
@@ -173,10 +174,10 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
u8 keyidx, *pos;
struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
MAX_DEV_ADDR_SIZE);
- struct blkcipher_desc desc = {.tfm = wep->rx_tfm};
u32 crc;
u8 icv[4];
struct scatterlist sg;
+ int err;
if (skb->len < hdr_len + 8)
return -1;
@@ -198,9 +199,16 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
plen = skb->len - hdr_len - 8;
if (!tcb_desc->bHwSec) {
+ SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
+
sg_init_one(&sg, pos, plen+4);
- crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
- if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
+ crypto_skcipher_setkey(wep->rx_tfm, key, klen);
+ skcipher_request_set_tfm(req, wep->rx_tfm);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
+ err = crypto_skcipher_decrypt(req);
+ skcipher_request_zero(req);
+ if (err)
return -7;
crc = ~crc32_le(~0, pos, plen);
icv[0] = crc;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
index 908bc2eb4d29..6fa96d57d316 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
@@ -21,7 +21,8 @@
#include "ieee80211.h"
-#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <crypto/skcipher.h>
#include <linux/scatterlist.h>
#include <linux/crc32.h>
@@ -52,10 +53,10 @@ struct ieee80211_tkip_data {
int key_idx;
- struct crypto_blkcipher *rx_tfm_arc4;
- struct crypto_hash *rx_tfm_michael;
- struct crypto_blkcipher *tx_tfm_arc4;
- struct crypto_hash *tx_tfm_michael;
+ struct crypto_skcipher *rx_tfm_arc4;
+ struct crypto_ahash *rx_tfm_michael;
+ struct crypto_skcipher *tx_tfm_arc4;
+ struct crypto_ahash *tx_tfm_michael;
/* scratch buffers for virt_to_page() (crypto API) */
u8 rx_hdr[16], tx_hdr[16];
@@ -70,7 +71,7 @@ static void *ieee80211_tkip_init(int key_idx)
goto fail;
priv->key_idx = key_idx;
- priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
+ priv->tx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm_arc4)) {
printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
@@ -79,7 +80,7 @@ static void *ieee80211_tkip_init(int key_idx)
goto fail;
}
- priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
+ priv->tx_tfm_michael = crypto_alloc_ahash("michael_mic", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm_michael)) {
printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
@@ -88,7 +89,7 @@ static void *ieee80211_tkip_init(int key_idx)
goto fail;
}
- priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
+ priv->rx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm_arc4)) {
printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
@@ -97,7 +98,7 @@ static void *ieee80211_tkip_init(int key_idx)
goto fail;
}
- priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
+ priv->rx_tfm_michael = crypto_alloc_ahash("michael_mic", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm_michael)) {
printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
@@ -110,14 +111,10 @@ static void *ieee80211_tkip_init(int key_idx)
fail:
if (priv) {
- if (priv->tx_tfm_michael)
- crypto_free_hash(priv->tx_tfm_michael);
- if (priv->tx_tfm_arc4)
- crypto_free_blkcipher(priv->tx_tfm_arc4);
- if (priv->rx_tfm_michael)
- crypto_free_hash(priv->rx_tfm_michael);
- if (priv->rx_tfm_arc4)
- crypto_free_blkcipher(priv->rx_tfm_arc4);
+ crypto_free_ahash(priv->tx_tfm_michael);
+ crypto_free_skcipher(priv->tx_tfm_arc4);
+ crypto_free_ahash(priv->rx_tfm_michael);
+ crypto_free_skcipher(priv->rx_tfm_arc4);
kfree(priv);
}
@@ -130,14 +127,10 @@ static void ieee80211_tkip_deinit(void *priv)
struct ieee80211_tkip_data *_priv = priv;
if (_priv) {
- if (_priv->tx_tfm_michael)
- crypto_free_hash(_priv->tx_tfm_michael);
- if (_priv->tx_tfm_arc4)
- crypto_free_blkcipher(_priv->tx_tfm_arc4);
- if (_priv->rx_tfm_michael)
- crypto_free_hash(_priv->rx_tfm_michael);
- if (_priv->rx_tfm_arc4)
- crypto_free_blkcipher(_priv->rx_tfm_arc4);
+ crypto_free_ahash(_priv->tx_tfm_michael);
+ crypto_free_skcipher(_priv->tx_tfm_arc4);
+ crypto_free_ahash(_priv->rx_tfm_michael);
+ crypto_free_skcipher(_priv->rx_tfm_arc4);
}
kfree(priv);
}
@@ -312,7 +305,6 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
u8 *pos;
struct rtl_80211_hdr_4addr *hdr;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4};
int ret = 0;
u8 rc4key[16], *icv;
u32 crc;
@@ -357,15 +349,21 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
*pos++ = (tkey->tx_iv32 >> 24) & 0xff;
if (!tcb_desc->bHwSec) {
+ SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4);
+
icv = skb_put(skb, 4);
crc = ~crc32_le(~0, pos, len);
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
icv[3] = crc >> 24;
- crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
+ crypto_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
sg_init_one(&sg, pos, len+4);
- ret = crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
+ skcipher_request_set_tfm(req, tkey->tx_tfm_arc4);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
+ ret = crypto_skcipher_encrypt(req);
+ skcipher_request_zero(req);
}
tkey->tx_iv16++;
@@ -390,12 +388,12 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
u16 iv16;
struct rtl_80211_hdr_4addr *hdr;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4};
u8 rc4key[16];
u8 icv[4];
u32 crc;
struct scatterlist sg;
int plen;
+ int err;
if (skb->len < hdr_len + 8 + 4)
return -1;
@@ -429,6 +427,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
pos += 8;
if (!tcb_desc->bHwSec) {
+ SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4);
+
if (iv32 < tkey->rx_iv32 ||
(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
if (net_ratelimit()) {
@@ -449,10 +449,16 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
plen = skb->len - hdr_len - 12;
- crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
+ crypto_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
sg_init_one(&sg, pos, plen+4);
- if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
+ skcipher_request_set_tfm(req, tkey->rx_tfm_arc4);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
+
+ err = crypto_skcipher_decrypt(req);
+ skcipher_request_zero(req);
+ if (err) {
if (net_ratelimit()) {
printk(KERN_DEBUG ": TKIP: failed to decrypt "
"received packet from %pM\n",
@@ -501,11 +507,12 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
return keyidx;
}
-static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, u8 *hdr,
+static int michael_mic(struct crypto_ahash *tfm_michael, u8 *key, u8 *hdr,
u8 *data, size_t data_len, u8 *mic)
{
- struct hash_desc desc;
+ AHASH_REQUEST_ON_STACK(req, tfm_michael);
struct scatterlist sg[2];
+ int err;
if (tfm_michael == NULL) {
printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
@@ -516,12 +523,15 @@ static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, u8 *hdr,
sg_set_buf(&sg[0], hdr, 16);
sg_set_buf(&sg[1], data, data_len);
- if (crypto_hash_setkey(tfm_michael, key, 8))
+ if (crypto_ahash_setkey(tfm_michael, key, 8))
return -1;
- desc.tfm = tfm_michael;
- desc.flags = 0;
- return crypto_hash_digest(&desc, sg, data_len + 16, mic);
+ ahash_request_set_tfm(req, tfm_michael);
+ ahash_request_set_callback(req, 0, NULL, NULL);
+ ahash_request_set_crypt(req, sg, mic, data_len + 16);
+ err = crypto_ahash_digest(req);
+ ahash_request_zero(req);
+ return err;
}
static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr)
@@ -660,10 +670,10 @@ static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv)
{
struct ieee80211_tkip_data *tkey = priv;
int keyidx;
- struct crypto_hash *tfm = tkey->tx_tfm_michael;
- struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
- struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
- struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
+ struct crypto_ahash *tfm = tkey->tx_tfm_michael;
+ struct crypto_skcipher *tfm2 = tkey->tx_tfm_arc4;
+ struct crypto_ahash *tfm3 = tkey->rx_tfm_michael;
+ struct crypto_skcipher *tfm4 = tkey->rx_tfm_arc4;
keyidx = tkey->key_idx;
memset(tkey, 0, sizeof(*tkey));
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
index 681611dc93d3..ababb6de125b 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
@@ -18,7 +18,7 @@
#include "ieee80211.h"
-#include <linux/crypto.h>
+#include <crypto/skcipher.h>
#include <linux/scatterlist.h>
#include <linux/crc32.h>
@@ -32,8 +32,8 @@ struct prism2_wep_data {
u8 key[WEP_KEY_LEN + 1];
u8 key_len;
u8 key_idx;
- struct crypto_blkcipher *tx_tfm;
- struct crypto_blkcipher *rx_tfm;
+ struct crypto_skcipher *tx_tfm;
+ struct crypto_skcipher *rx_tfm;
};
@@ -46,10 +46,10 @@ static void *prism2_wep_init(int keyidx)
return NULL;
priv->key_idx = keyidx;
- priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ priv->tx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm))
goto free_priv;
- priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ priv->rx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm))
goto free_tx;
@@ -58,7 +58,7 @@ static void *prism2_wep_init(int keyidx)
return priv;
free_tx:
- crypto_free_blkcipher(priv->tx_tfm);
+ crypto_free_skcipher(priv->tx_tfm);
free_priv:
kfree(priv);
return NULL;
@@ -70,10 +70,8 @@ static void prism2_wep_deinit(void *priv)
struct prism2_wep_data *_priv = priv;
if (_priv) {
- if (_priv->tx_tfm)
- crypto_free_blkcipher(_priv->tx_tfm);
- if (_priv->rx_tfm)
- crypto_free_blkcipher(_priv->rx_tfm);
+ crypto_free_skcipher(_priv->tx_tfm);
+ crypto_free_skcipher(_priv->rx_tfm);
}
kfree(priv);
}
@@ -91,10 +89,10 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
u8 key[WEP_KEY_LEN + 3];
u8 *pos;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- struct blkcipher_desc desc = {.tfm = wep->tx_tfm};
u32 crc;
u8 *icv;
struct scatterlist sg;
+ int err;
if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
skb->len < hdr_len)
@@ -129,6 +127,8 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
memcpy(key + 3, wep->key, wep->key_len);
if (!tcb_desc->bHwSec) {
+ SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm);
+
/* Append little-endian CRC32 and encrypt it to produce ICV */
crc = ~crc32_le(~0, pos, len);
icv = skb_put(skb, 4);
@@ -137,10 +137,16 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
icv[2] = crc >> 16;
icv[3] = crc >> 24;
- crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
+ crypto_skcipher_setkey(wep->tx_tfm, key, klen);
sg_init_one(&sg, pos, len+4);
- return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
+ skcipher_request_set_tfm(req, wep->tx_tfm);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
+
+ err = crypto_skcipher_encrypt(req);
+ skcipher_request_zero(req);
+ return err;
}
return 0;
@@ -161,10 +167,10 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
u8 key[WEP_KEY_LEN + 3];
u8 keyidx, *pos;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- struct blkcipher_desc desc = {.tfm = wep->rx_tfm};
u32 crc;
u8 icv[4];
struct scatterlist sg;
+ int err;
if (skb->len < hdr_len + 8)
return -1;
@@ -186,10 +192,18 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
plen = skb->len - hdr_len - 8;
if (!tcb_desc->bHwSec) {
- crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
+ SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
+
+ crypto_skcipher_setkey(wep->rx_tfm, key, klen);
sg_init_one(&sg, pos, plen+4);
- if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
+ skcipher_request_set_tfm(req, wep->rx_tfm);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
+
+ err = crypto_skcipher_decrypt(req);
+ skcipher_request_zero(req);
+ if (err)
return -7;
crc = ~crc32_le(~0, pos, plen);
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 576a7a43470c..961202f4e9aa 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -16,9 +16,9 @@
* GNU General Public License for more details.
******************************************************************************/
+#include <crypto/hash.h>
#include <linux/string.h>
#include <linux/kthread.h>
-#include <linux/crypto.h>
#include <linux/completion.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
@@ -1190,7 +1190,7 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
}
static u32 iscsit_do_crypto_hash_sg(
- struct hash_desc *hash,
+ struct ahash_request *hash,
struct iscsi_cmd *cmd,
u32 data_offset,
u32 data_length,
@@ -1201,7 +1201,7 @@ static u32 iscsit_do_crypto_hash_sg(
struct scatterlist *sg;
unsigned int page_off;
- crypto_hash_init(hash);
+ crypto_ahash_init(hash);
sg = cmd->first_data_sg;
page_off = cmd->first_data_sg_off;
@@ -1209,7 +1209,8 @@ static u32 iscsit_do_crypto_hash_sg(
while (data_length) {
u32 cur_len = min_t(u32, data_length, (sg->length - page_off));
- crypto_hash_update(hash, sg, cur_len);
+ ahash_request_set_crypt(hash, sg, NULL, cur_len);
+ crypto_ahash_update(hash);
data_length -= cur_len;
page_off = 0;
@@ -1221,33 +1222,34 @@ static u32 iscsit_do_crypto_hash_sg(
struct scatterlist pad_sg;
sg_init_one(&pad_sg, pad_bytes, padding);
- crypto_hash_update(hash, &pad_sg, padding);
+ ahash_request_set_crypt(hash, &pad_sg, (u8 *)&data_crc,
+ padding);
+ crypto_ahash_finup(hash);
+ } else {
+ ahash_request_set_crypt(hash, NULL, (u8 *)&data_crc, 0);
+ crypto_ahash_final(hash);
}
- crypto_hash_final(hash, (u8 *) &data_crc);
return data_crc;
}
static void iscsit_do_crypto_hash_buf(
- struct hash_desc *hash,
+ struct ahash_request *hash,
const void *buf,
u32 payload_length,
u32 padding,
u8 *pad_bytes,
u8 *data_crc)
{
- struct scatterlist sg;
+ struct scatterlist sg[2];
- crypto_hash_init(hash);
+ sg_init_table(sg, ARRAY_SIZE(sg));
+ sg_set_buf(sg, buf, payload_length);
+ sg_set_buf(sg + 1, pad_bytes, padding);
- sg_init_one(&sg, buf, payload_length);
- crypto_hash_update(hash, &sg, payload_length);
+ ahash_request_set_crypt(hash, sg, data_crc, payload_length + padding);
- if (padding) {
- sg_init_one(&sg, pad_bytes, padding);
- crypto_hash_update(hash, &sg, padding);
- }
- crypto_hash_final(hash, data_crc);
+ crypto_ahash_digest(hash);
}
int
@@ -1422,7 +1424,7 @@ iscsit_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
if (conn->conn_ops->DataDigest) {
u32 data_crc;
- data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd,
+ data_crc = iscsit_do_crypto_hash_sg(conn->conn_rx_hash, cmd,
be32_to_cpu(hdr->offset),
payload_length, padding,
cmd->pad_bytes);
@@ -1682,7 +1684,7 @@ static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
}
if (conn->conn_ops->DataDigest) {
- iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
+ iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
ping_data, payload_length,
padding, cmd->pad_bytes,
(u8 *)&data_crc);
@@ -2101,7 +2103,7 @@ iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
goto reject;
if (conn->conn_ops->DataDigest) {
- iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
+ iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
text_in, payload_length,
padding, (u8 *)&pad_bytes,
(u8 *)&data_crc);
@@ -2440,7 +2442,7 @@ static int iscsit_handle_immediate_data(
if (conn->conn_ops->DataDigest) {
u32 data_crc;
- data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd,
+ data_crc = iscsit_do_crypto_hash_sg(conn->conn_rx_hash, cmd,
cmd->write_data_done, length, padding,
cmd->pad_bytes);
@@ -2553,7 +2555,7 @@ static int iscsit_send_conn_drop_async_message(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
cmd->tx_size += ISCSI_CRC_LEN;
@@ -2683,7 +2685,7 @@ static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->pdu,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->pdu,
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -2711,7 +2713,7 @@ static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
cmd->padding);
}
if (conn->conn_ops->DataDigest) {
- cmd->data_crc = iscsit_do_crypto_hash_sg(&conn->conn_tx_hash, cmd,
+ cmd->data_crc = iscsit_do_crypto_hash_sg(conn->conn_tx_hash, cmd,
datain.offset, datain.length, cmd->padding, cmd->pad_bytes);
iov[iov_count].iov_base = &cmd->data_crc;
@@ -2857,7 +2859,7 @@ iscsit_send_logout(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, &cmd->pdu[0],
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, &cmd->pdu[0],
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -2915,7 +2917,7 @@ static int iscsit_send_unsolicited_nopin(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
tx_size += ISCSI_CRC_LEN;
@@ -2963,7 +2965,7 @@ iscsit_send_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -2993,7 +2995,7 @@ iscsit_send_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
" padding bytes.\n", padding);
}
if (conn->conn_ops->DataDigest) {
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash,
cmd->buf_ptr, cmd->buf_ptr_size,
padding, (u8 *)&cmd->pad_bytes,
(u8 *)&cmd->data_crc);
@@ -3049,7 +3051,7 @@ static int iscsit_send_r2t(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN;
@@ -3239,7 +3241,7 @@ static int iscsit_send_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
}
if (conn->conn_ops->DataDigest) {
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash,
cmd->sense_buffer,
(cmd->se_cmd.scsi_sense_length + padding),
0, NULL, (u8 *)&cmd->data_crc);
@@ -3262,7 +3264,7 @@ static int iscsit_send_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->pdu,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->pdu,
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -3332,7 +3334,7 @@ iscsit_send_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN;
@@ -3601,7 +3603,7 @@ static int iscsit_send_text_rsp(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -3611,7 +3613,7 @@ static int iscsit_send_text_rsp(
}
if (conn->conn_ops->DataDigest) {
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash,
cmd->buf_ptr, text_length,
0, NULL, (u8 *)&cmd->data_crc);
@@ -3668,7 +3670,7 @@ static int iscsit_send_reject(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -3678,7 +3680,7 @@ static int iscsit_send_reject(
}
if (conn->conn_ops->DataDigest) {
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->buf_ptr,
+ iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->buf_ptr,
ISCSI_HDR_LEN, 0, NULL, (u8 *)&cmd->data_crc);
iov[iov_count].iov_base = &cmd->data_crc;
@@ -4145,7 +4147,7 @@ int iscsi_target_rx_thread(void *arg)
goto transport_err;
}
- iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
+ iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
buffer, ISCSI_HDR_LEN,
0, NULL, (u8 *)&checksum);
@@ -4359,10 +4361,14 @@ int iscsit_close_connection(
*/
iscsit_check_conn_usage_count(conn);
- if (conn->conn_rx_hash.tfm)
- crypto_free_hash(conn->conn_rx_hash.tfm);
- if (conn->conn_tx_hash.tfm)
- crypto_free_hash(conn->conn_tx_hash.tfm);
+ ahash_request_free(conn->conn_tx_hash);
+ if (conn->conn_rx_hash) {
+ struct crypto_ahash *tfm;
+
+ tfm = crypto_ahash_reqtfm(conn->conn_rx_hash);
+ ahash_request_free(conn->conn_rx_hash);
+ crypto_free_ahash(tfm);
+ }
free_cpumask_var(conn->conn_cpumask);
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index 47e249dccb5f..667406fcf4d3 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -16,9 +16,9 @@
* GNU General Public License for more details.
******************************************************************************/
+#include <crypto/hash.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
@@ -185,9 +185,8 @@ static int chap_server_compute_md5(
unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
size_t compare_len;
struct iscsi_chap *chap = conn->auth_protocol;
- struct crypto_hash *tfm;
- struct hash_desc desc;
- struct scatterlist sg;
+ struct crypto_shash *tfm = NULL;
+ struct shash_desc *desc = NULL;
int auth_ret = -1, ret, challenge_len;
memset(identifier, 0, 10);
@@ -245,52 +244,47 @@ static int chap_server_compute_md5(
pr_debug("[server] Got CHAP_R=%s\n", chap_r);
chap_string_to_hex(client_digest, chap_r, strlen(chap_r));
- tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
+ tfm = crypto_alloc_shash("md5", 0, 0);
if (IS_ERR(tfm)) {
- pr_err("Unable to allocate struct crypto_hash\n");
+ tfm = NULL;
+ pr_err("Unable to allocate struct crypto_shash\n");
goto out;
}
- desc.tfm = tfm;
- desc.flags = 0;
- ret = crypto_hash_init(&desc);
- if (ret < 0) {
- pr_err("crypto_hash_init() failed\n");
- crypto_free_hash(tfm);
+ desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
+ if (!desc) {
+ pr_err("Unable to allocate struct shash_desc\n");
goto out;
}
- sg_init_one(&sg, &chap->id, 1);
- ret = crypto_hash_update(&desc, &sg, 1);
+ desc->tfm = tfm;
+ desc->flags = 0;
+
+ ret = crypto_shash_init(desc);
if (ret < 0) {
- pr_err("crypto_hash_update() failed for id\n");
- crypto_free_hash(tfm);
+ pr_err("crypto_shash_init() failed\n");
goto out;
}
- sg_init_one(&sg, &auth->password, strlen(auth->password));
- ret = crypto_hash_update(&desc, &sg, strlen(auth->password));
+ ret = crypto_shash_update(desc, &chap->id, 1);
if (ret < 0) {
- pr_err("crypto_hash_update() failed for password\n");
- crypto_free_hash(tfm);
+ pr_err("crypto_shash_update() failed for id\n");
goto out;
}
- sg_init_one(&sg, chap->challenge, CHAP_CHALLENGE_LENGTH);
- ret = crypto_hash_update(&desc, &sg, CHAP_CHALLENGE_LENGTH);
+ ret = crypto_shash_update(desc, (char *)&auth->password,
+ strlen(auth->password));
if (ret < 0) {
- pr_err("crypto_hash_update() failed for challenge\n");
- crypto_free_hash(tfm);
+ pr_err("crypto_shash_update() failed for password\n");
goto out;
}
- ret = crypto_hash_final(&desc, server_digest);
+ ret = crypto_shash_finup(desc, chap->challenge,
+ CHAP_CHALLENGE_LENGTH, server_digest);
if (ret < 0) {
- pr_err("crypto_hash_final() failed for server digest\n");
- crypto_free_hash(tfm);
+ pr_err("crypto_shash_finup() failed for challenge\n");
goto out;
}
- crypto_free_hash(tfm);
chap_binaryhex_to_asciihex(response, server_digest, MD5_SIGNATURE_SIZE);
pr_debug("[server] MD5 Server Digest: %s\n", response);
@@ -306,9 +300,8 @@ static int chap_server_compute_md5(
* authentication is not enabled.
*/
if (!auth->authenticate_target) {
- kfree(challenge);
- kfree(challenge_binhex);
- return 0;
+ auth_ret = 0;
+ goto out;
}
/*
* Get CHAP_I.
@@ -372,58 +365,37 @@ static int chap_server_compute_md5(
/*
* Generate CHAP_N and CHAP_R for mutual authentication.
*/
- tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm)) {
- pr_err("Unable to allocate struct crypto_hash\n");
- goto out;
- }
- desc.tfm = tfm;
- desc.flags = 0;
-
- ret = crypto_hash_init(&desc);
+ ret = crypto_shash_init(desc);
if (ret < 0) {
- pr_err("crypto_hash_init() failed\n");
- crypto_free_hash(tfm);
+ pr_err("crypto_shash_init() failed\n");
goto out;
}
/* To handle both endiannesses */
id_as_uchar = id;
- sg_init_one(&sg, &id_as_uchar, 1);
- ret = crypto_hash_update(&desc, &sg, 1);
+ ret = crypto_shash_update(desc, &id_as_uchar, 1);
if (ret < 0) {
- pr_err("crypto_hash_update() failed for id\n");
- crypto_free_hash(tfm);
+ pr_err("crypto_shash_update() failed for id\n");
goto out;
}
- sg_init_one(&sg, auth->password_mutual,
- strlen(auth->password_mutual));
- ret = crypto_hash_update(&desc, &sg, strlen(auth->password_mutual));
+ ret = crypto_shash_update(desc, auth->password_mutual,
+ strlen(auth->password_mutual));
if (ret < 0) {
- pr_err("crypto_hash_update() failed for"
+ pr_err("crypto_shash_update() failed for"
" password_mutual\n");
- crypto_free_hash(tfm);
goto out;
}
/*
* Convert received challenge to binary hex.
*/
- sg_init_one(&sg, challenge_binhex, challenge_len);
- ret = crypto_hash_update(&desc, &sg, challenge_len);
+ ret = crypto_shash_finup(desc, challenge_binhex, challenge_len,
+ digest);
if (ret < 0) {
- pr_err("crypto_hash_update() failed for ma challenge\n");
- crypto_free_hash(tfm);
+ pr_err("crypto_shash_finup() failed for ma challenge\n");
goto out;
}
- ret = crypto_hash_final(&desc, digest);
- if (ret < 0) {
- pr_err("crypto_hash_final() failed for ma digest\n");
- crypto_free_hash(tfm);
- goto out;
- }
- crypto_free_hash(tfm);
/*
* Generate CHAP_N and CHAP_R.
*/
@@ -440,6 +412,8 @@ static int chap_server_compute_md5(
pr_debug("[server] Sending CHAP_R=0x%s\n", response);
auth_ret = 0;
out:
+ kzfree(desc);
+ crypto_free_shash(tfm);
kfree(challenge);
kfree(challenge_binhex);
return auth_ret;
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 2f821de63049..a24443ba59ea 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -771,21 +771,11 @@ static int lio_target_init_nodeacl(struct se_node_acl *se_nacl,
{
struct iscsi_node_acl *acl =
container_of(se_nacl, struct iscsi_node_acl, se_node_acl);
- struct config_group *stats_cg = &se_nacl->acl_fabric_stat_group;
-
- stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
- GFP_KERNEL);
- if (!stats_cg->default_groups) {
- pr_err("Unable to allocate memory for"
- " stats_cg->default_groups\n");
- return -ENOMEM;
- }
- stats_cg->default_groups[0] = &acl->node_stat_grps.iscsi_sess_stats_group;
- stats_cg->default_groups[1] = NULL;
config_group_init_type_name(&acl->node_stat_grps.iscsi_sess_stats_group,
"iscsi_sess_stats", &iscsi_stat_sess_cit);
-
+ configfs_add_default_group(&acl->node_stat_grps.iscsi_sess_stats_group,
+ &se_nacl->acl_fabric_stat_group);
return 0;
}
@@ -793,17 +783,8 @@ static void lio_target_cleanup_nodeacl( struct se_node_acl *se_nacl)
{
struct iscsi_node_acl *acl = container_of(se_nacl,
struct iscsi_node_acl, se_node_acl);
- struct config_item *df_item;
- struct config_group *stats_cg;
- int i;
-
- stats_cg = &acl->se_node_acl.acl_fabric_stat_group;
- for (i = 0; stats_cg->default_groups[i]; i++) {
- df_item = &stats_cg->default_groups[i]->cg_item;
- stats_cg->default_groups[i] = NULL;
- config_item_put(df_item);
- }
- kfree(stats_cg->default_groups);
+
+ configfs_remove_default_groups(&acl->se_node_acl.acl_fabric_stat_group);
}
/* End items for lio_target_acl_cit */
@@ -1260,42 +1241,37 @@ static struct se_wwn *lio_target_call_coreaddtiqn(
struct config_group *group,
const char *name)
{
- struct config_group *stats_cg;
struct iscsi_tiqn *tiqn;
tiqn = iscsit_add_tiqn((unsigned char *)name);
if (IS_ERR(tiqn))
return ERR_CAST(tiqn);
- /*
- * Setup struct iscsi_wwn_stat_grps for se_wwn->fabric_stat_group.
- */
- stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
-
- stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6,
- GFP_KERNEL);
- if (!stats_cg->default_groups) {
- pr_err("Unable to allocate memory for"
- " stats_cg->default_groups\n");
- iscsit_del_tiqn(tiqn);
- return ERR_PTR(-ENOMEM);
- }
- stats_cg->default_groups[0] = &tiqn->tiqn_stat_grps.iscsi_instance_group;
- stats_cg->default_groups[1] = &tiqn->tiqn_stat_grps.iscsi_sess_err_group;
- stats_cg->default_groups[2] = &tiqn->tiqn_stat_grps.iscsi_tgt_attr_group;
- stats_cg->default_groups[3] = &tiqn->tiqn_stat_grps.iscsi_login_stats_group;
- stats_cg->default_groups[4] = &tiqn->tiqn_stat_grps.iscsi_logout_stats_group;
- stats_cg->default_groups[5] = NULL;
config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_instance_group,
"iscsi_instance", &iscsi_stat_instance_cit);
+ configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_instance_group,
+ &tiqn->tiqn_wwn.fabric_stat_group);
+
config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_sess_err_group,
"iscsi_sess_err", &iscsi_stat_sess_err_cit);
+ configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_sess_err_group,
+ &tiqn->tiqn_wwn.fabric_stat_group);
+
config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group,
"iscsi_tgt_attr", &iscsi_stat_tgt_attr_cit);
+ configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group,
+ &tiqn->tiqn_wwn.fabric_stat_group);
+
config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_login_stats_group,
"iscsi_login_stats", &iscsi_stat_login_cit);
+ configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_login_stats_group,
+ &tiqn->tiqn_wwn.fabric_stat_group);
+
config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group,
"iscsi_logout_stats", &iscsi_stat_logout_cit);
+ configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group,
+ &tiqn->tiqn_wwn.fabric_stat_group);
+
pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn);
pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated Node:"
@@ -1307,17 +1283,8 @@ static void lio_target_call_coredeltiqn(
struct se_wwn *wwn)
{
struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
- struct config_item *df_item;
- struct config_group *stats_cg;
- int i;
-
- stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
- for (i = 0; stats_cg->default_groups[i]; i++) {
- df_item = &stats_cg->default_groups[i]->cg_item;
- stats_cg->default_groups[i] = NULL;
- config_item_put(df_item);
- }
- kfree(stats_cg->default_groups);
+
+ configfs_remove_default_groups(&tiqn->tiqn_wwn.fabric_stat_group);
pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s\n",
tiqn->tiqn);
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 96e78c823d13..8436d56c5f0c 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -16,9 +16,9 @@
* GNU General Public License for more details.
******************************************************************************/
+#include <crypto/hash.h>
#include <linux/string.h>
#include <linux/kthread.h>
-#include <linux/crypto.h>
#include <linux/idr.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
@@ -115,27 +115,36 @@ out_login:
*/
int iscsi_login_setup_crypto(struct iscsi_conn *conn)
{
+ struct crypto_ahash *tfm;
+
/*
* Setup slicing by CRC32C algorithm for RX and TX libcrypto contexts
* which will default to crc32c_intel.ko for cpu_has_xmm4_2, or fallback
* to software 1x8 byte slicing from crc32c.ko
*/
- conn->conn_rx_hash.flags = 0;
- conn->conn_rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
- CRYPTO_ALG_ASYNC);
- if (IS_ERR(conn->conn_rx_hash.tfm)) {
- pr_err("crypto_alloc_hash() failed for conn_rx_tfm\n");
+ tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm)) {
+ pr_err("crypto_alloc_ahash() failed\n");
return -ENOMEM;
}
- conn->conn_tx_hash.flags = 0;
- conn->conn_tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
- CRYPTO_ALG_ASYNC);
- if (IS_ERR(conn->conn_tx_hash.tfm)) {
- pr_err("crypto_alloc_hash() failed for conn_tx_tfm\n");
- crypto_free_hash(conn->conn_rx_hash.tfm);
+ conn->conn_rx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!conn->conn_rx_hash) {
+ pr_err("ahash_request_alloc() failed for conn_rx_hash\n");
+ crypto_free_ahash(tfm);
+ return -ENOMEM;
+ }
+ ahash_request_set_callback(conn->conn_rx_hash, 0, NULL, NULL);
+
+ conn->conn_tx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!conn->conn_tx_hash) {
+ pr_err("ahash_request_alloc() failed for conn_tx_hash\n");
+ ahash_request_free(conn->conn_rx_hash);
+ conn->conn_rx_hash = NULL;
+ crypto_free_ahash(tfm);
return -ENOMEM;
}
+ ahash_request_set_callback(conn->conn_tx_hash, 0, NULL, NULL);
return 0;
}
@@ -1174,10 +1183,14 @@ old_sess_out:
iscsit_dec_session_usage_count(conn->sess);
}
- if (!IS_ERR(conn->conn_rx_hash.tfm))
- crypto_free_hash(conn->conn_rx_hash.tfm);
- if (!IS_ERR(conn->conn_tx_hash.tfm))
- crypto_free_hash(conn->conn_tx_hash.tfm);
+ ahash_request_free(conn->conn_tx_hash);
+ if (conn->conn_rx_hash) {
+ struct crypto_ahash *tfm;
+
+ tfm = crypto_ahash_reqtfm(conn->conn_rx_hash);
+ ahash_request_free(conn->conn_rx_hash);
+ crypto_free_ahash(tfm);
+ }
free_cpumask_var(conn->conn_cpumask);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 713c63d9681b..d498533f09ee 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -194,13 +194,11 @@ static struct config_group *target_core_register_fabric(
pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n",
&tf->tf_wwn_cit);
- tf->tf_group.default_groups = tf->tf_default_groups;
- tf->tf_group.default_groups[0] = &tf->tf_disc_group;
- tf->tf_group.default_groups[1] = NULL;
-
config_group_init_type_name(&tf->tf_group, name, &tf->tf_wwn_cit);
+
config_group_init_type_name(&tf->tf_disc_group, "discovery_auth",
&tf->tf_discovery_cit);
+ configfs_add_default_group(&tf->tf_disc_group, &tf->tf_group);
pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:"
" %s\n", tf->tf_group.cg_item.ci_name);
@@ -216,9 +214,6 @@ static void target_core_deregister_fabric(
{
struct target_fabric_configfs *tf = container_of(
to_config_group(item), struct target_fabric_configfs, tf_group);
- struct config_group *tf_group;
- struct config_item *df_item;
- int i;
pr_debug("Target_Core_ConfigFS: DEREGISTER -> Looking up %s in"
" tf list\n", config_item_name(item));
@@ -230,12 +225,7 @@ static void target_core_deregister_fabric(
pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci"
" %s\n", config_item_name(item));
- tf_group = &tf->tf_group;
- for (i = 0; tf_group->default_groups[i]; i++) {
- df_item = &tf_group->default_groups[i]->cg_item;
- tf_group->default_groups[i] = NULL;
- config_item_put(df_item);
- }
+ configfs_remove_default_groups(&tf->tf_group);
config_item_put(item);
}
@@ -2151,7 +2141,6 @@ static void target_core_dev_release(struct config_item *item)
struct se_device *dev =
container_of(dev_cg, struct se_device, dev_group);
- kfree(dev_cg->default_groups);
target_free_device(dev);
}
@@ -2819,8 +2808,6 @@ static struct config_group *target_core_make_subdev(
struct se_hba *hba = item_to_hba(hba_ci);
struct target_backend *tb = hba->backend;
struct se_device *dev;
- struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL;
- struct config_group *dev_stat_grp = NULL;
int errno = -ENOMEM, ret;
ret = mutex_lock_interruptible(&hba->hba_access_mutex);
@@ -2831,73 +2818,52 @@ static struct config_group *target_core_make_subdev(
if (!dev)
goto out_unlock;
- dev_cg = &dev->dev_group;
-
- dev_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6,
- GFP_KERNEL);
- if (!dev_cg->default_groups)
- goto out_free_device;
+ config_group_init_type_name(&dev->dev_group, name, &tb->tb_dev_cit);
- config_group_init_type_name(dev_cg, name, &tb->tb_dev_cit);
config_group_init_type_name(&dev->dev_attrib.da_group, "attrib",
&tb->tb_dev_attrib_cit);
+ configfs_add_default_group(&dev->dev_attrib.da_group, &dev->dev_group);
+
config_group_init_type_name(&dev->dev_pr_group, "pr",
&tb->tb_dev_pr_cit);
+ configfs_add_default_group(&dev->dev_pr_group, &dev->dev_group);
+
config_group_init_type_name(&dev->t10_wwn.t10_wwn_group, "wwn",
&tb->tb_dev_wwn_cit);
+ configfs_add_default_group(&dev->t10_wwn.t10_wwn_group,
+ &dev->dev_group);
+
config_group_init_type_name(&dev->t10_alua.alua_tg_pt_gps_group,
"alua", &tb->tb_dev_alua_tg_pt_gps_cit);
+ configfs_add_default_group(&dev->t10_alua.alua_tg_pt_gps_group,
+ &dev->dev_group);
+
config_group_init_type_name(&dev->dev_stat_grps.stat_group,
"statistics", &tb->tb_dev_stat_cit);
+ configfs_add_default_group(&dev->dev_stat_grps.stat_group,
+ &dev->dev_group);
- dev_cg->default_groups[0] = &dev->dev_attrib.da_group;
- dev_cg->default_groups[1] = &dev->dev_pr_group;
- dev_cg->default_groups[2] = &dev->t10_wwn.t10_wwn_group;
- dev_cg->default_groups[3] = &dev->t10_alua.alua_tg_pt_gps_group;
- dev_cg->default_groups[4] = &dev->dev_stat_grps.stat_group;
- dev_cg->default_groups[5] = NULL;
/*
* Add core/$HBA/$DEV/alua/default_tg_pt_gp
*/
tg_pt_gp = core_alua_allocate_tg_pt_gp(dev, "default_tg_pt_gp", 1);
if (!tg_pt_gp)
- goto out_free_dev_cg_default_groups;
+ goto out_free_device;
dev->t10_alua.default_tg_pt_gp = tg_pt_gp;
- tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group;
- tg_pt_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
- GFP_KERNEL);
- if (!tg_pt_gp_cg->default_groups) {
- pr_err("Unable to allocate tg_pt_gp_cg->"
- "default_groups\n");
- goto out_free_tg_pt_gp;
- }
-
config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group,
"default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit);
- tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group;
- tg_pt_gp_cg->default_groups[1] = NULL;
+ configfs_add_default_group(&tg_pt_gp->tg_pt_gp_group,
+ &dev->t10_alua.alua_tg_pt_gps_group);
+
/*
* Add core/$HBA/$DEV/statistics/ default groups
*/
- dev_stat_grp = &dev->dev_stat_grps.stat_group;
- dev_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 4,
- GFP_KERNEL);
- if (!dev_stat_grp->default_groups) {
- pr_err("Unable to allocate dev_stat_grp->default_groups\n");
- goto out_free_tg_pt_gp_cg_default_groups;
- }
target_stat_setup_dev_default_groups(dev);
mutex_unlock(&hba->hba_access_mutex);
- return dev_cg;
+ return &dev->dev_group;
-out_free_tg_pt_gp_cg_default_groups:
- kfree(tg_pt_gp_cg->default_groups);
-out_free_tg_pt_gp:
- core_alua_free_tg_pt_gp(tg_pt_gp);
-out_free_dev_cg_default_groups:
- kfree(dev_cg->default_groups);
out_free_device:
target_free_device(dev);
out_unlock:
@@ -2913,40 +2879,22 @@ static void target_core_drop_subdev(
struct se_device *dev =
container_of(dev_cg, struct se_device, dev_group);
struct se_hba *hba;
- struct config_item *df_item;
- struct config_group *tg_pt_gp_cg, *dev_stat_grp;
- int i;
hba = item_to_hba(&dev->se_hba->hba_group.cg_item);
mutex_lock(&hba->hba_access_mutex);
- dev_stat_grp = &dev->dev_stat_grps.stat_group;
- for (i = 0; dev_stat_grp->default_groups[i]; i++) {
- df_item = &dev_stat_grp->default_groups[i]->cg_item;
- dev_stat_grp->default_groups[i] = NULL;
- config_item_put(df_item);
- }
- kfree(dev_stat_grp->default_groups);
+ configfs_remove_default_groups(&dev->dev_stat_grps.stat_group);
+ configfs_remove_default_groups(&dev->t10_alua.alua_tg_pt_gps_group);
- tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group;
- for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) {
- df_item = &tg_pt_gp_cg->default_groups[i]->cg_item;
- tg_pt_gp_cg->default_groups[i] = NULL;
- config_item_put(df_item);
- }
- kfree(tg_pt_gp_cg->default_groups);
/*
* core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp
* directly from target_core_alua_tg_pt_gp_release().
*/
dev->t10_alua.default_tg_pt_gp = NULL;
- for (i = 0; dev_cg->default_groups[i]; i++) {
- df_item = &dev_cg->default_groups[i]->cg_item;
- dev_cg->default_groups[i] = NULL;
- config_item_put(df_item);
- }
+ configfs_remove_default_groups(dev_cg);
+
/*
* se_dev is released from target_core_dev_item_ops->release()
*/
@@ -3141,8 +3089,6 @@ void target_setup_backend_cits(struct target_backend *tb)
static int __init target_core_init_configfs(void)
{
- struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL;
- struct config_group *lu_gp_cg = NULL;
struct configfs_subsystem *subsys = &target_core_fabrics;
struct t10_alua_lu_gp *lu_gp;
int ret;
@@ -3161,51 +3107,24 @@ static int __init target_core_init_configfs(void)
* Create $CONFIGFS/target/core default group for HBA <-> Storage Object
* and ALUA Logical Unit Group and Target Port Group infrastructure.
*/
- target_cg = &subsys->su_group;
- target_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
- GFP_KERNEL);
- if (!target_cg->default_groups) {
- pr_err("Unable to allocate target_cg->default_groups\n");
- ret = -ENOMEM;
- goto out_global;
- }
+ config_group_init_type_name(&target_core_hbagroup, "core",
+ &target_core_cit);
+ configfs_add_default_group(&target_core_hbagroup, &subsys->su_group);
- config_group_init_type_name(&target_core_hbagroup,
- "core", &target_core_cit);
- target_cg->default_groups[0] = &target_core_hbagroup;
- target_cg->default_groups[1] = NULL;
/*
* Create ALUA infrastructure under /sys/kernel/config/target/core/alua/
*/
- hba_cg = &target_core_hbagroup;
- hba_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
- GFP_KERNEL);
- if (!hba_cg->default_groups) {
- pr_err("Unable to allocate hba_cg->default_groups\n");
- ret = -ENOMEM;
- goto out_global;
- }
- config_group_init_type_name(&alua_group,
- "alua", &target_core_alua_cit);
- hba_cg->default_groups[0] = &alua_group;
- hba_cg->default_groups[1] = NULL;
+ config_group_init_type_name(&alua_group, "alua", &target_core_alua_cit);
+ configfs_add_default_group(&alua_group, &target_core_hbagroup);
+
/*
* Add ALUA Logical Unit Group and Target Port Group ConfigFS
* groups under /sys/kernel/config/target/core/alua/
*/
- alua_cg = &alua_group;
- alua_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
- GFP_KERNEL);
- if (!alua_cg->default_groups) {
- pr_err("Unable to allocate alua_cg->default_groups\n");
- ret = -ENOMEM;
- goto out_global;
- }
+ config_group_init_type_name(&alua_lu_gps_group, "lu_gps",
+ &target_core_alua_lu_gps_cit);
+ configfs_add_default_group(&alua_lu_gps_group, &alua_group);
- config_group_init_type_name(&alua_lu_gps_group,
- "lu_gps", &target_core_alua_lu_gps_cit);
- alua_cg->default_groups[0] = &alua_lu_gps_group;
- alua_cg->default_groups[1] = NULL;
/*
* Add core/alua/lu_gps/default_lu_gp
*/
@@ -3215,20 +3134,12 @@ static int __init target_core_init_configfs(void)
goto out_global;
}
- lu_gp_cg = &alua_lu_gps_group;
- lu_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
- GFP_KERNEL);
- if (!lu_gp_cg->default_groups) {
- pr_err("Unable to allocate lu_gp_cg->default_groups\n");
- ret = -ENOMEM;
- goto out_global;
- }
-
config_group_init_type_name(&lu_gp->lu_gp_group, "default_lu_gp",
&target_core_alua_lu_gp_cit);
- lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group;
- lu_gp_cg->default_groups[1] = NULL;
+ configfs_add_default_group(&lu_gp->lu_gp_group, &alua_lu_gps_group);
+
default_lu_gp = lu_gp;
+
/*
* Register the target_core_mod subsystem with configfs.
*/
@@ -3267,55 +3178,21 @@ out_global:
core_alua_free_lu_gp(default_lu_gp);
default_lu_gp = NULL;
}
- if (lu_gp_cg)
- kfree(lu_gp_cg->default_groups);
- if (alua_cg)
- kfree(alua_cg->default_groups);
- if (hba_cg)
- kfree(hba_cg->default_groups);
- kfree(target_cg->default_groups);
release_se_kmem_caches();
return ret;
}
static void __exit target_core_exit_configfs(void)
{
- struct config_group *hba_cg, *alua_cg, *lu_gp_cg;
- struct config_item *item;
- int i;
+ configfs_remove_default_groups(&alua_lu_gps_group);
+ configfs_remove_default_groups(&alua_group);
+ configfs_remove_default_groups(&target_core_hbagroup);
- lu_gp_cg = &alua_lu_gps_group;
- for (i = 0; lu_gp_cg->default_groups[i]; i++) {
- item = &lu_gp_cg->default_groups[i]->cg_item;
- lu_gp_cg->default_groups[i] = NULL;
- config_item_put(item);
- }
- kfree(lu_gp_cg->default_groups);
- lu_gp_cg->default_groups = NULL;
-
- alua_cg = &alua_group;
- for (i = 0; alua_cg->default_groups[i]; i++) {
- item = &alua_cg->default_groups[i]->cg_item;
- alua_cg->default_groups[i] = NULL;
- config_item_put(item);
- }
- kfree(alua_cg->default_groups);
- alua_cg->default_groups = NULL;
-
- hba_cg = &target_core_hbagroup;
- for (i = 0; hba_cg->default_groups[i]; i++) {
- item = &hba_cg->default_groups[i]->cg_item;
- hba_cg->default_groups[i] = NULL;
- config_item_put(item);
- }
- kfree(hba_cg->default_groups);
- hba_cg->default_groups = NULL;
/*
* We expect subsys->su_group.default_groups to be released
* by configfs subsystem provider logic..
*/
configfs_unregister_subsystem(&target_core_fabrics);
- kfree(target_core_fabrics.su_group.default_groups);
core_alua_free_lu_gp(default_lu_gp);
default_lu_gp = NULL;
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index f916d18ccb48..8caef31da415 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -273,18 +273,10 @@ static struct config_group *target_fabric_make_mappedlun(
struct se_portal_group *se_tpg = se_nacl->se_tpg;
struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
struct se_lun_acl *lacl = NULL;
- struct config_item *acl_ci;
- struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
char *buf;
unsigned long long mapped_lun;
int ret = 0;
- acl_ci = &group->cg_item;
- if (!acl_ci) {
- pr_err("Unable to locatel acl_ci\n");
- return NULL;
- }
-
buf = kzalloc(strlen(name) + 1, GFP_KERNEL);
if (!buf) {
pr_err("Unable to allocate memory for name buf\n");
@@ -315,37 +307,19 @@ static struct config_group *target_fabric_make_mappedlun(
goto out;
}
- lacl_cg = &lacl->se_lun_group;
- lacl_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
- GFP_KERNEL);
- if (!lacl_cg->default_groups) {
- pr_err("Unable to allocate lacl_cg->default_groups\n");
- ret = -ENOMEM;
- goto out;
- }
-
config_group_init_type_name(&lacl->se_lun_group, name,
&tf->tf_tpg_mappedlun_cit);
+
config_group_init_type_name(&lacl->ml_stat_grps.stat_group,
"statistics", &tf->tf_tpg_mappedlun_stat_cit);
- lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group;
- lacl_cg->default_groups[1] = NULL;
-
- ml_stat_grp = &lacl->ml_stat_grps.stat_group;
- ml_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 3,
- GFP_KERNEL);
- if (!ml_stat_grp->default_groups) {
- pr_err("Unable to allocate ml_stat_grp->default_groups\n");
- ret = -ENOMEM;
- goto out;
- }
+ configfs_add_default_group(&lacl->ml_stat_grps.stat_group,
+ &lacl->se_lun_group);
+
target_stat_setup_mappedlun_default_groups(lacl);
kfree(buf);
return &lacl->se_lun_group;
out:
- if (lacl_cg)
- kfree(lacl_cg->default_groups);
kfree(lacl);
kfree(buf);
return ERR_PTR(ret);
@@ -357,25 +331,9 @@ static void target_fabric_drop_mappedlun(
{
struct se_lun_acl *lacl = container_of(to_config_group(item),
struct se_lun_acl, se_lun_group);
- struct config_item *df_item;
- struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
- int i;
-
- ml_stat_grp = &lacl->ml_stat_grps.stat_group;
- for (i = 0; ml_stat_grp->default_groups[i]; i++) {
- df_item = &ml_stat_grp->default_groups[i]->cg_item;
- ml_stat_grp->default_groups[i] = NULL;
- config_item_put(df_item);
- }
- kfree(ml_stat_grp->default_groups);
- lacl_cg = &lacl->se_lun_group;
- for (i = 0; lacl_cg->default_groups[i]; i++) {
- df_item = &lacl_cg->default_groups[i]->cg_item;
- lacl_cg->default_groups[i] = NULL;
- config_item_put(df_item);
- }
- kfree(lacl_cg->default_groups);
+ configfs_remove_default_groups(&lacl->ml_stat_grps.stat_group);
+ configfs_remove_default_groups(&lacl->se_lun_group);
config_item_put(item);
}
@@ -424,7 +382,6 @@ static struct config_group *target_fabric_make_nodeacl(
struct se_portal_group, tpg_acl_group);
struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
struct se_node_acl *se_nacl;
- struct config_group *nacl_cg;
se_nacl = core_tpg_add_initiator_node_acl(se_tpg, name);
if (IS_ERR(se_nacl))
@@ -438,24 +395,28 @@ static struct config_group *target_fabric_make_nodeacl(
}
}
- nacl_cg = &se_nacl->acl_group;
- nacl_cg->default_groups = se_nacl->acl_default_groups;
- nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group;
- nacl_cg->default_groups[1] = &se_nacl->acl_auth_group;
- nacl_cg->default_groups[2] = &se_nacl->acl_param_group;
- nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group;
- nacl_cg->default_groups[4] = NULL;
-
config_group_init_type_name(&se_nacl->acl_group, name,
&tf->tf_tpg_nacl_base_cit);
+
config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib",
&tf->tf_tpg_nacl_attrib_cit);
+ configfs_add_default_group(&se_nacl->acl_attrib_group,
+ &se_nacl->acl_group);
+
config_group_init_type_name(&se_nacl->acl_auth_group, "auth",
&tf->tf_tpg_nacl_auth_cit);
+ configfs_add_default_group(&se_nacl->acl_auth_group,
+ &se_nacl->acl_group);
+
config_group_init_type_name(&se_nacl->acl_param_group, "param",
&tf->tf_tpg_nacl_param_cit);
+ configfs_add_default_group(&se_nacl->acl_param_group,
+ &se_nacl->acl_group);
+
config_group_init_type_name(&se_nacl->acl_fabric_stat_group,
"fabric_statistics", &tf->tf_tpg_nacl_stat_cit);
+ configfs_add_default_group(&se_nacl->acl_fabric_stat_group,
+ &se_nacl->acl_group);
return &se_nacl->acl_group;
}
@@ -466,16 +427,9 @@ static void target_fabric_drop_nodeacl(
{
struct se_node_acl *se_nacl = container_of(to_config_group(item),
struct se_node_acl, acl_group);
- struct config_item *df_item;
- struct config_group *nacl_cg;
- int i;
-
- nacl_cg = &se_nacl->acl_group;
- for (i = 0; nacl_cg->default_groups[i]; i++) {
- df_item = &nacl_cg->default_groups[i]->cg_item;
- nacl_cg->default_groups[i] = NULL;
- config_item_put(df_item);
- }
+
+ configfs_remove_default_groups(&se_nacl->acl_group);
+
/*
* struct se_node_acl free is done in target_fabric_nacl_base_release()
*/
@@ -795,7 +749,6 @@ static struct config_group *target_fabric_make_lun(
struct se_portal_group *se_tpg = container_of(group,
struct se_portal_group, tpg_lun_group);
struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
- struct config_group *lun_cg = NULL, *port_stat_grp = NULL;
unsigned long long unpacked_lun;
int errno;
@@ -812,31 +765,14 @@ static struct config_group *target_fabric_make_lun(
if (IS_ERR(lun))
return ERR_CAST(lun);
- lun_cg = &lun->lun_group;
- lun_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
- GFP_KERNEL);
- if (!lun_cg->default_groups) {
- pr_err("Unable to allocate lun_cg->default_groups\n");
- kfree(lun);
- return ERR_PTR(-ENOMEM);
- }
-
config_group_init_type_name(&lun->lun_group, name,
&tf->tf_tpg_port_cit);
+
config_group_init_type_name(&lun->port_stat_grps.stat_group,
"statistics", &tf->tf_tpg_port_stat_cit);
- lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group;
- lun_cg->default_groups[1] = NULL;
-
- port_stat_grp = &lun->port_stat_grps.stat_group;
- port_stat_grp->default_groups = kzalloc(sizeof(struct config_group *) * 4,
- GFP_KERNEL);
- if (!port_stat_grp->default_groups) {
- pr_err("Unable to allocate port_stat_grp->default_groups\n");
- kfree(lun_cg->default_groups);
- kfree(lun);
- return ERR_PTR(-ENOMEM);
- }
+ configfs_add_default_group(&lun->port_stat_grps.stat_group,
+ &lun->lun_group);
+
target_stat_setup_port_default_groups(lun);
return &lun->lun_group;
@@ -848,25 +784,9 @@ static void target_fabric_drop_lun(
{
struct se_lun *lun = container_of(to_config_group(item),
struct se_lun, lun_group);
- struct config_item *df_item;
- struct config_group *lun_cg, *port_stat_grp;
- int i;
-
- port_stat_grp = &lun->port_stat_grps.stat_group;
- for (i = 0; port_stat_grp->default_groups[i]; i++) {
- df_item = &port_stat_grp->default_groups[i]->cg_item;
- port_stat_grp->default_groups[i] = NULL;
- config_item_put(df_item);
- }
- kfree(port_stat_grp->default_groups);
- lun_cg = &lun->lun_group;
- for (i = 0; lun_cg->default_groups[i]; i++) {
- df_item = &lun_cg->default_groups[i]->cg_item;
- lun_cg->default_groups[i] = NULL;
- config_item_put(df_item);
- }
- kfree(lun_cg->default_groups);
+ configfs_remove_default_groups(&lun->port_stat_grps.stat_group);
+ configfs_remove_default_groups(&lun->lun_group);
config_item_put(item);
}
@@ -922,32 +842,39 @@ static struct config_group *target_fabric_make_tpg(
se_tpg = tf->tf_ops->fabric_make_tpg(wwn, group, name);
if (!se_tpg || IS_ERR(se_tpg))
return ERR_PTR(-EINVAL);
- /*
- * Setup default groups from pre-allocated se_tpg->tpg_default_groups
- */
- se_tpg->tpg_group.default_groups = se_tpg->tpg_default_groups;
- se_tpg->tpg_group.default_groups[0] = &se_tpg->tpg_lun_group;
- se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group;
- se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group;
- se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group;
- se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_auth_group;
- se_tpg->tpg_group.default_groups[5] = &se_tpg->tpg_param_group;
- se_tpg->tpg_group.default_groups[6] = NULL;
config_group_init_type_name(&se_tpg->tpg_group, name,
&tf->tf_tpg_base_cit);
+
config_group_init_type_name(&se_tpg->tpg_lun_group, "lun",
&tf->tf_tpg_lun_cit);
+ configfs_add_default_group(&se_tpg->tpg_lun_group,
+ &se_tpg->tpg_group);
+
config_group_init_type_name(&se_tpg->tpg_np_group, "np",
&tf->tf_tpg_np_cit);
+ configfs_add_default_group(&se_tpg->tpg_np_group,
+ &se_tpg->tpg_group);
+
config_group_init_type_name(&se_tpg->tpg_acl_group, "acls",
&tf->tf_tpg_nacl_cit);
+ configfs_add_default_group(&se_tpg->tpg_acl_group,
+ &se_tpg->tpg_group);
+
config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib",
&tf->tf_tpg_attrib_cit);
+ configfs_add_default_group(&se_tpg->tpg_attrib_group,
+ &se_tpg->tpg_group);
+
config_group_init_type_name(&se_tpg->tpg_auth_group, "auth",
&tf->tf_tpg_auth_cit);
+ configfs_add_default_group(&se_tpg->tpg_auth_group,
+ &se_tpg->tpg_group);
+
config_group_init_type_name(&se_tpg->tpg_param_group, "param",
&tf->tf_tpg_param_cit);
+ configfs_add_default_group(&se_tpg->tpg_param_group,
+ &se_tpg->tpg_group);
return &se_tpg->tpg_group;
}
@@ -958,19 +885,8 @@ static void target_fabric_drop_tpg(
{
struct se_portal_group *se_tpg = container_of(to_config_group(item),
struct se_portal_group, tpg_group);
- struct config_group *tpg_cg = &se_tpg->tpg_group;
- struct config_item *df_item;
- int i;
- /*
- * Release default groups, but do not release tpg_cg->default_groups
- * memory as it is statically allocated at se_tpg->tpg_default_groups.
- */
- for (i = 0; tpg_cg->default_groups[i]; i++) {
- df_item = &tpg_cg->default_groups[i]->cg_item;
- tpg_cg->default_groups[i] = NULL;
- config_item_put(df_item);
- }
+ configfs_remove_default_groups(&se_tpg->tpg_group);
config_item_put(item);
}
@@ -1026,16 +942,12 @@ static struct config_group *target_fabric_make_wwn(
return ERR_PTR(-EINVAL);
wwn->wwn_tf = tf;
- /*
- * Setup default groups from pre-allocated wwn->wwn_default_groups
- */
- wwn->wwn_group.default_groups = wwn->wwn_default_groups;
- wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group;
- wwn->wwn_group.default_groups[1] = NULL;
config_group_init_type_name(&wwn->wwn_group, name, &tf->tf_tpg_cit);
+
config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics",
&tf->tf_wwn_fabric_stats_cit);
+ configfs_add_default_group(&wwn->fabric_stat_group, &wwn->wwn_group);
return &wwn->wwn_group;
}
@@ -1046,16 +958,8 @@ static void target_fabric_drop_wwn(
{
struct se_wwn *wwn = container_of(to_config_group(item),
struct se_wwn, wwn_group);
- struct config_item *df_item;
- struct config_group *cg = &wwn->wwn_group;
- int i;
-
- for (i = 0; cg->default_groups[i]; i++) {
- df_item = &cg->default_groups[i]->cg_item;
- cg->default_groups[i] = NULL;
- config_item_put(df_item);
- }
+ configfs_remove_default_groups(&wwn->wwn_group);
config_item_put(item);
}
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index db4412fe6b8a..4a7cf499cdfa 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -22,7 +22,6 @@ struct target_fabric_configfs {
struct list_head tf_list;
struct config_group tf_group;
struct config_group tf_disc_group;
- struct config_group *tf_default_groups[2];
const struct target_core_fabric_ops *tf_ops;
struct config_item_type tf_discovery_cit;
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index 81a6b3e07687..1a39033d2bff 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -407,19 +407,20 @@ static struct config_item_type target_stat_scsi_lu_cit = {
*/
void target_stat_setup_dev_default_groups(struct se_device *dev)
{
- struct config_group *dev_stat_grp = &dev->dev_stat_grps.stat_group;
-
config_group_init_type_name(&dev->dev_stat_grps.scsi_dev_group,
"scsi_dev", &target_stat_scsi_dev_cit);
+ configfs_add_default_group(&dev->dev_stat_grps.scsi_dev_group,
+ &dev->dev_stat_grps.stat_group);
+
config_group_init_type_name(&dev->dev_stat_grps.scsi_tgt_dev_group,
"scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit);
+ configfs_add_default_group(&dev->dev_stat_grps.scsi_tgt_dev_group,
+ &dev->dev_stat_grps.stat_group);
+
config_group_init_type_name(&dev->dev_stat_grps.scsi_lu_group,
"scsi_lu", &target_stat_scsi_lu_cit);
-
- dev_stat_grp->default_groups[0] = &dev->dev_stat_grps.scsi_dev_group;
- dev_stat_grp->default_groups[1] = &dev->dev_stat_grps.scsi_tgt_dev_group;
- dev_stat_grp->default_groups[2] = &dev->dev_stat_grps.scsi_lu_group;
- dev_stat_grp->default_groups[3] = NULL;
+ configfs_add_default_group(&dev->dev_stat_grps.scsi_lu_group,
+ &dev->dev_stat_grps.stat_group);
}
/*
@@ -818,19 +819,20 @@ static struct config_item_type target_stat_scsi_transport_cit = {
*/
void target_stat_setup_port_default_groups(struct se_lun *lun)
{
- struct config_group *port_stat_grp = &lun->port_stat_grps.stat_group;
-
config_group_init_type_name(&lun->port_stat_grps.scsi_port_group,
"scsi_port", &target_stat_scsi_port_cit);
+ configfs_add_default_group(&lun->port_stat_grps.scsi_port_group,
+ &lun->port_stat_grps.stat_group);
+
config_group_init_type_name(&lun->port_stat_grps.scsi_tgt_port_group,
"scsi_tgt_port", &target_stat_scsi_tgt_port_cit);
+ configfs_add_default_group(&lun->port_stat_grps.scsi_tgt_port_group,
+ &lun->port_stat_grps.stat_group);
+
config_group_init_type_name(&lun->port_stat_grps.scsi_transport_group,
"scsi_transport", &target_stat_scsi_transport_cit);
-
- port_stat_grp->default_groups[0] = &lun->port_stat_grps.scsi_port_group;
- port_stat_grp->default_groups[1] = &lun->port_stat_grps.scsi_tgt_port_group;
- port_stat_grp->default_groups[2] = &lun->port_stat_grps.scsi_transport_group;
- port_stat_grp->default_groups[3] = NULL;
+ configfs_add_default_group(&lun->port_stat_grps.scsi_transport_group,
+ &lun->port_stat_grps.stat_group);
}
/*
@@ -1351,14 +1353,13 @@ static struct config_item_type target_stat_scsi_att_intr_port_cit = {
*/
void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *lacl)
{
- struct config_group *ml_stat_grp = &lacl->ml_stat_grps.stat_group;
-
config_group_init_type_name(&lacl->ml_stat_grps.scsi_auth_intr_group,
"scsi_auth_intr", &target_stat_scsi_auth_intr_cit);
+ configfs_add_default_group(&lacl->ml_stat_grps.scsi_auth_intr_group,
+ &lacl->ml_stat_grps.stat_group);
+
config_group_init_type_name(&lacl->ml_stat_grps.scsi_att_intr_port_group,
"scsi_att_intr_port", &target_stat_scsi_att_intr_port_cit);
-
- ml_stat_grp->default_groups[0] = &lacl->ml_stat_grps.scsi_auth_intr_group;
- ml_stat_grp->default_groups[1] = &lacl->ml_stat_grps.scsi_att_intr_port_group;
- ml_stat_grp->default_groups[2] = NULL;
+ configfs_add_default_group(&lacl->ml_stat_grps.scsi_att_intr_port_group,
+ &lacl->ml_stat_grps.stat_group);
}
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 82a663ba9800..4f229e711e1c 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -177,7 +177,6 @@ void core_tmr_abort_task(
if (!__target_check_io_state(se_cmd, se_sess, 0)) {
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
- target_put_sess_cmd(se_cmd);
goto out;
}
list_del_init(&se_cmd->se_cmd_list);
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index c01f45095877..82c4d2e45319 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -226,7 +226,7 @@ config CYCLADES
config CYZ_INTR
bool "Cyclades-Z interrupt mode operation"
- depends on CYCLADES
+ depends on CYCLADES && PCI
help
The Cyclades-Z family of multiport cards allows 2 (two) driver op
modes: polling and interrupt. In polling mode, the driver will check
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 2caaf5a2516d..eacf4c9f3b29 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -639,7 +639,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
custom.adkcon = AC_UARTBRK;
mb();
- if (tty->termios.c_cflag & HUPCL)
+ if (C_HUPCL(tty))
info->MCR &= ~(SER_DTR|SER_RTS);
rtsdtr_ctrl(info->MCR);
@@ -965,8 +965,7 @@ static void rs_throttle(struct tty_struct * tty)
struct serial_state *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("throttle %s: %d....\n", tty_name(tty),
- tty->ldisc.chars_in_buffer(tty));
+ printk("throttle %s ....\n", tty_name(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_throttle"))
@@ -975,7 +974,7 @@ static void rs_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
info->MCR &= ~SER_RTS;
local_irq_save(flags);
@@ -988,8 +987,7 @@ static void rs_unthrottle(struct tty_struct * tty)
struct serial_state *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("unthrottle %s: %d....\n", tty_name(tty),
- tty->ldisc.chars_in_buffer(tty));
+ printk("unthrottle %s ....\n", tty_name(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
@@ -1001,7 +999,7 @@ static void rs_unthrottle(struct tty_struct * tty)
else
rs_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
info->MCR |= SER_RTS;
local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
@@ -1334,8 +1332,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(tty, info, old_termios);
/* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) &&
- !(cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
info->MCR &= ~(SER_DTR|SER_RTS);
local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
@@ -1343,21 +1340,17 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- (cflag & CBAUD)) {
+ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
info->MCR |= SER_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
info->MCR |= SER_RTS;
- }
local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
local_irq_restore(flags);
}
/* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@@ -1369,8 +1362,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* XXX It's not clear whether the current behavior is correct
* or not. Hence, this may change.....
*/
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios.c_cflag & CLOCAL))
+ if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
wake_up_interruptible(&info->open_wait);
#endif
}
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index abbed201dc74..d67e542bab1c 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -1440,7 +1440,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
info->port.xmit_buf = NULL;
free_page((unsigned long)temp);
}
- if (tty->termios.c_cflag & HUPCL)
+ if (C_HUPCL(tty))
cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
@@ -1469,7 +1469,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
free_page((unsigned long)temp);
}
- if (tty->termios.c_cflag & HUPCL)
+ if (C_HUPCL(tty))
tty_port_lower_dtr_rts(&info->port);
set_bit(TTY_IO_ERROR, &tty->flags);
@@ -2795,8 +2795,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
cy_set_line_char(info, tty);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
cy_start(tty);
}
@@ -2807,8 +2806,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* XXX It's not clear whether the current behavior is correct
* or not. Hence, this may change.....
*/
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios.c_cflag & CLOCAL))
+ if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
wake_up_interruptible(&info->port.open_wait);
#endif
} /* cy_set_termios */
@@ -2852,8 +2850,8 @@ static void cy_throttle(struct tty_struct *tty)
unsigned long flags;
#ifdef CY_DEBUG_THROTTLE
- printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty),
- tty->ldisc.chars_in_buffer(tty), info->line);
+ printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty),
+ info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_throttle"))
@@ -2868,7 +2866,7 @@ static void cy_throttle(struct tty_struct *tty)
info->throttle = 1;
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
cyy_change_rts_dtr(info, 0, TIOCM_RTS);
@@ -2891,8 +2889,8 @@ static void cy_unthrottle(struct tty_struct *tty)
unsigned long flags;
#ifdef CY_DEBUG_THROTTLE
- printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
- tty_name(tty), tty_chars_in_buffer(tty), info->line);
+ printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n",
+ tty_name(tty), info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
@@ -2905,7 +2903,7 @@ static void cy_unthrottle(struct tty_struct *tty)
cy_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
card = info->card;
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 342b36b9ad35..7ac9bcdf1e61 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -23,7 +23,6 @@
* byte channel used for the console is designated as the default tty.
*/
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -719,19 +718,6 @@ error:
return ret;
}
-static int ehv_bc_tty_remove(struct platform_device *pdev)
-{
- struct ehv_bc_data *bc = dev_get_drvdata(&pdev->dev);
-
- tty_unregister_device(ehv_bc_driver, bc - bcs);
-
- tty_port_destroy(&bc->port);
- irq_dispose_mapping(bc->tx_irq);
- irq_dispose_mapping(bc->rx_irq);
-
- return 0;
-}
-
static const struct of_device_id ehv_bc_tty_of_ids[] = {
{ .compatible = "epapr,hv-byte-channel" },
{}
@@ -741,15 +727,15 @@ static struct platform_driver ehv_bc_tty_driver = {
.driver = {
.name = "ehv-bc",
.of_match_table = ehv_bc_tty_of_ids,
+ .suppress_bind_attrs = true,
},
.probe = ehv_bc_tty_probe,
- .remove = ehv_bc_tty_remove,
};
/**
* ehv_bc_init - ePAPR hypervisor byte channel driver initialization
*
- * This function is called when this module is loaded.
+ * This function is called when this driver is loaded.
*/
static int __init ehv_bc_init(void)
{
@@ -814,24 +800,4 @@ error:
return ret;
}
-
-
-/**
- * ehv_bc_exit - ePAPR hypervisor byte channel driver termination
- *
- * This function is called when this driver is unloaded.
- */
-static void __exit ehv_bc_exit(void)
-{
- platform_driver_unregister(&ehv_bc_tty_driver);
- tty_unregister_driver(ehv_bc_driver);
- put_tty_driver(ehv_bc_driver);
- kfree(bcs);
-}
-
-module_init(ehv_bc_init);
-module_exit(ehv_bc_exit);
-
-MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("ePAPR hypervisor byte channel driver");
-MODULE_LICENSE("GPL v2");
+device_initcall(ehv_bc_init);
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index 0f82c0b146f6..3fc912373adf 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -68,8 +68,7 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
{
- struct platform_device *pdev = dev_id;
- struct goldfish_tty *qtty = &goldfish_ttys[pdev->id];
+ struct goldfish_tty *qtty = dev_id;
void __iomem *base = qtty->base;
unsigned long irq_flags;
unsigned char *buf;
@@ -162,7 +161,7 @@ static int goldfish_tty_console_setup(struct console *co, char *options)
return 0;
}
-static struct tty_port_operations goldfish_port_ops = {
+static const struct tty_port_operations goldfish_port_ops = {
.activate = goldfish_tty_activate,
.shutdown = goldfish_tty_shutdown
};
@@ -233,6 +232,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)
struct device *ttydev;
void __iomem *base;
u32 irq;
+ unsigned int line;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL)
@@ -248,10 +248,16 @@ static int goldfish_tty_probe(struct platform_device *pdev)
irq = r->start;
- if (pdev->id >= goldfish_tty_line_count)
- goto err_unmap;
-
mutex_lock(&goldfish_tty_lock);
+
+ if (pdev->id == PLATFORM_DEVID_NONE)
+ line = goldfish_tty_current_line_count;
+ else
+ line = pdev->id;
+
+ if (line >= goldfish_tty_line_count)
+ goto err_create_driver_failed;
+
if (goldfish_tty_current_line_count == 0) {
ret = goldfish_tty_create_driver();
if (ret)
@@ -259,7 +265,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)
}
goldfish_tty_current_line_count++;
- qtty = &goldfish_ttys[pdev->id];
+ qtty = &goldfish_ttys[line];
spin_lock_init(&qtty->lock);
tty_port_init(&qtty->port);
qtty->port.ops = &goldfish_port_ops;
@@ -269,13 +275,13 @@ static int goldfish_tty_probe(struct platform_device *pdev)
writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED,
- "goldfish_tty", pdev);
+ "goldfish_tty", qtty);
if (ret)
goto err_request_irq_failed;
ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
- pdev->id, &pdev->dev);
+ line, &pdev->dev);
if (IS_ERR(ttydev)) {
ret = PTR_ERR(ttydev);
goto err_tty_register_device_failed;
@@ -286,8 +292,9 @@ static int goldfish_tty_probe(struct platform_device *pdev)
qtty->console.device = goldfish_tty_console_device;
qtty->console.setup = goldfish_tty_console_setup;
qtty->console.flags = CON_PRINTBUFFER;
- qtty->console.index = pdev->id;
+ qtty->console.index = line;
register_console(&qtty->console);
+ platform_set_drvdata(pdev, qtty);
mutex_unlock(&goldfish_tty_lock);
return 0;
@@ -307,13 +314,12 @@ err_unmap:
static int goldfish_tty_remove(struct platform_device *pdev)
{
- struct goldfish_tty *qtty;
+ struct goldfish_tty *qtty = platform_get_drvdata(pdev);
mutex_lock(&goldfish_tty_lock);
- qtty = &goldfish_ttys[pdev->id];
unregister_console(&qtty->console);
- tty_unregister_device(goldfish_tty_driver, pdev->id);
+ tty_unregister_device(goldfish_tty_driver, qtty->console.index);
iounmap(qtty->base);
qtty->base = NULL;
free_irq(qtty->irq, pdev);
@@ -324,11 +330,19 @@ static int goldfish_tty_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id goldfish_tty_of_match[] = {
+ { .compatible = "google,goldfish-tty", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, goldfish_tty_of_match);
+
static struct platform_driver goldfish_tty_platform_driver = {
.probe = goldfish_tty_probe,
.remove = goldfish_tty_remove,
.driver = {
- .name = "goldfish_tty"
+ .name = "goldfish_tty",
+ .of_match_table = goldfish_tty_of_match,
}
};
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index f575a9b5ede7..b05dc5086627 100644
--- a/drivers/tty/hvc/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
@@ -41,7 +41,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/console.h>
-#include <linux/module.h>
#include <asm/hvconsole.h>
#include <asm/vio.h>
@@ -61,7 +60,6 @@ static struct vio_device_id hvc_driver_table[] = {
#endif
{ "", "" }
};
-MODULE_DEVICE_TABLE(vio, hvc_driver_table);
typedef enum hv_protocol {
HV_PROTOCOL_RAW,
@@ -363,26 +361,13 @@ static int hvc_vio_probe(struct vio_dev *vdev,
return 0;
}
-static int hvc_vio_remove(struct vio_dev *vdev)
-{
- struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
- int rc, termno;
-
- termno = hp->vtermno;
- rc = hvc_remove(hp);
- if (rc == 0) {
- if (hvterm_privs[termno] != &hvterm_priv0)
- kfree(hvterm_privs[termno]);
- hvterm_privs[termno] = NULL;
- }
- return rc;
-}
-
static struct vio_driver hvc_vio_driver = {
.id_table = hvc_driver_table,
.probe = hvc_vio_probe,
- .remove = hvc_vio_remove,
.name = hvc_driver_name,
+ .driver = {
+ .suppress_bind_attrs = true,
+ },
};
static int __init hvc_vio_init(void)
@@ -394,13 +379,7 @@ static int __init hvc_vio_init(void)
return rc;
}
-module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
-
-static void __exit hvc_vio_exit(void)
-{
- vio_unregister_driver(&hvc_vio_driver);
-}
-module_exit(hvc_vio_exit);
+device_initcall(hvc_vio_init); /* after drivers/tty/hvc/hvc_console.c */
void __init hvc_vio_init_early(void)
{
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index fa816b7193b6..f417fa1ee47c 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -162,7 +162,7 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
return recv;
}
-static struct hv_ops domU_hvc_ops = {
+static const struct hv_ops domU_hvc_ops = {
.get_chars = domU_read_console,
.put_chars = domU_write_console,
.notifier_add = notifier_add_irq,
@@ -188,7 +188,7 @@ static int dom0_write_console(uint32_t vtermno, const char *str, int len)
return len;
}
-static struct hv_ops dom0_hvc_ops = {
+static const struct hv_ops dom0_hvc_ops = {
.get_chars = dom0_read_console,
.put_chars = dom0_write_console,
.notifier_add = notifier_add_irq,
@@ -323,6 +323,7 @@ void xen_console_resume(void)
}
}
+#ifdef CONFIG_HVC_XEN_FRONTEND
static void xencons_disconnect_backend(struct xencons_info *info)
{
if (info->irq > 0)
@@ -363,7 +364,6 @@ static int xen_console_remove(struct xencons_info *info)
return 0;
}
-#ifdef CONFIG_HVC_XEN_FRONTEND
static int xencons_remove(struct xenbus_device *dev)
{
return xen_console_remove(dev_get_drvdata(&dev->dev));
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index 99875949bfb7..8bf67630018b 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -1204,8 +1204,7 @@ static void isicom_set_termios(struct tty_struct *tty,
isicom_config_port(tty);
spin_unlock_irqrestore(&port->card->card_lock, flags);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
isicom_start(tty);
}
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 4c4a23674569..2f12bb9f4336 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -254,6 +254,7 @@ struct mxser_port {
int xmit_head;
int xmit_tail;
int xmit_cnt;
+ int closing;
struct ktermios normal_termios;
@@ -1081,6 +1082,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
return;
if (tty_port_close_start(port, tty, filp) == 0)
return;
+ info->closing = 1;
mutex_lock(&port->mutex);
mxser_close_port(port);
mxser_flush_buffer(tty);
@@ -1091,6 +1093,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
mxser_shutdown_port(port);
clear_bit(ASYNCB_INITIALIZED, &port->flags);
mutex_unlock(&port->mutex);
+ info->closing = 0;
/* Right now the tty_port set is done outside of the close_end helper
as we don't yet have everyone using refcounts */
tty_port_close_end(port, tty);
@@ -1864,7 +1867,7 @@ static void mxser_stoprx(struct tty_struct *tty)
}
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
info->MCR &= ~UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -1901,7 +1904,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
}
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
info->MCR |= UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -1949,15 +1952,13 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
mxser_change_speed(tty, old_termios);
spin_unlock_irqrestore(&info->slock, flags);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
mxser_start(tty);
}
/* Handle sw stopped */
- if ((old_termios->c_iflag & IXON) &&
- !(tty->termios.c_iflag & IXON)) {
+ if ((old_termios->c_iflag & IXON) && !I_IXON(tty)) {
tty->stopped = 0;
if (info->board->chip_flag) {
@@ -2255,10 +2256,8 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
break;
iir &= MOXA_MUST_IIR_MASK;
tty = tty_port_tty_get(&port->port);
- if (!tty ||
- (port->port.flags & ASYNC_CLOSING) ||
- !(port->port.flags &
- ASYNC_INITIALIZED)) {
+ if (!tty || port->closing ||
+ !(port->port.flags & ASYNC_INITIALIZED)) {
status = inb(port->ioaddr + UART_LSR);
outb(0x27, port->ioaddr + UART_FCR);
inb(port->ioaddr + UART_MSR);
@@ -2337,7 +2336,7 @@ static const struct tty_operations mxser_ops = {
.get_icount = mxser_get_icount,
};
-static struct tty_port_operations mxser_port_ops = {
+static const struct tty_port_operations mxser_port_ops = {
.carrier_raised = mxser_carrier_raised,
.dtr_rts = mxser_dtr_rts,
.activate = mxser_activate,
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index c3fe026d3168..c01620780f5b 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1066,7 +1066,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
/* Carrier drop -> hangup */
if (tty) {
if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
- if (!(tty->termios.c_cflag & CLOCAL))
+ if (!C_CLOCAL(tty))
tty_hangup(tty);
}
if (brk & 0x01)
@@ -2304,21 +2304,6 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
/**
- * gsmld_chars_in_buffer - report available bytes
- * @tty: tty device
- *
- * Report the number of characters buffered to be delivered to user
- * at this instant in time.
- *
- * Locking: gsm lock
- */
-
-static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
-/**
* gsmld_flush_buffer - clean input queue
* @tty: terminal device
*
@@ -2830,7 +2815,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
.open = gsmld_open,
.close = gsmld_close,
.flush_buffer = gsmld_flush_buffer,
- .chars_in_buffer = gsmld_chars_in_buffer,
.read = gsmld_read,
.write = gsmld_write,
.ioctl = gsmld_ioctl,
@@ -3132,7 +3116,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
dlci->modem_tx &= ~TIOCM_DTR;
dlci->throttled = 1;
/* Send an MSC with DTR cleared */
@@ -3144,7 +3128,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
dlci->modem_tx |= TIOCM_DTR;
dlci->throttled = 0;
/* Send an MSC with DTR set */
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index bbc4ce66c2c1..bcaba17688f6 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -159,7 +159,6 @@ 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_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);
@@ -853,10 +852,10 @@ 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);
/* allocate free rx buffer list */
for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
@@ -885,16 +884,6 @@ 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
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
-{
- memset(list, 0, sizeof(*list));
- spin_lock_init(&list->spinlock);
-} /* end of n_hdlc_buf_list_init() */
-
-/**
* n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
* @list - pointer to buffer list
* @buf - pointer to buffer
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index b280abaad91b..fb76a7d80e7e 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -113,8 +113,6 @@ struct n_tty_data {
DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
unsigned char echo_buf[N_TTY_BUF_SIZE];
- int minimum_to_wake;
-
/* consumer-published */
size_t read_tail;
size_t line_start;
@@ -153,15 +151,6 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
}
-static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
- unsigned char __user *ptr)
-{
- struct n_tty_data *ldata = tty->disc_data;
-
- tty_audit_add_data(tty, &x, 1, ldata->icanon);
- return put_user(x, ptr);
-}
-
static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
size_t tail, size_t n)
{
@@ -171,7 +160,7 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
int uncopied;
if (n > size) {
- tty_audit_add_data(tty, from, size, ldata->icanon);
+ tty_audit_add_data(tty, from, size);
uncopied = copy_to_user(to, from, size);
if (uncopied)
return uncopied;
@@ -180,7 +169,7 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
from = ldata->read_buf;
}
- tty_audit_add_data(tty, from, n, ldata->icanon);
+ tty_audit_add_data(tty, from, n);
return copy_to_user(to, from, n);
}
@@ -239,8 +228,8 @@ static ssize_t chars_in_buffer(struct tty_struct *tty)
static void n_tty_write_wakeup(struct tty_struct *tty)
{
- if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
- kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
}
static void n_tty_check_throttle(struct tty_struct *tty)
@@ -272,8 +261,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
return;
- if (!tty->count)
- return;
n_tty_kick_worker(tty);
tty_wakeup(tty->link);
return;
@@ -292,8 +279,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
break;
- if (!tty->count)
- break;
n_tty_kick_worker(tty);
unthrottled = tty_unthrottle_safe(tty);
if (!unthrottled)
@@ -381,28 +366,6 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
}
/**
- * n_tty_chars_in_buffer - report available bytes
- * @tty: tty device
- *
- * Report the number of characters buffered to be delivered to user
- * at this instant in time.
- *
- * Locking: exclusive termios_rwsem
- */
-
-static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
-{
- ssize_t n;
-
- WARN_ONCE(1, "%s is deprecated and scheduled for removal.", __func__);
-
- down_write(&tty->termios_rwsem);
- n = chars_in_buffer(tty);
- up_write(&tty->termios_rwsem);
- return n;
-}
-
-/**
* is_utf8_continuation - utf8 multibyte check
* @c: byte to check
*
@@ -1561,8 +1524,6 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
flag = *fp++;
if (likely(flag == TTY_NORMAL))
n_tty_receive_char_closing(tty, *cp++);
- else
- n_tty_receive_char_flagged(tty, *cp++, flag);
}
}
@@ -1664,7 +1625,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
/* publish read_head to consumer */
smp_store_release(&ldata->commit_head, ldata->read_head);
- if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
+ if (read_cnt(ldata)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
}
@@ -1785,12 +1746,6 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
return n_tty_receive_buf_common(tty, cp, fp, count, 1);
}
-int is_ignored(int sig)
-{
- return (sigismember(&current->blocked, sig) ||
- current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
-}
-
/**
* n_tty_set_termios - termios data changed
* @tty: terminal
@@ -1937,7 +1892,6 @@ static int n_tty_open(struct tty_struct *tty)
reset_buffer_flags(tty->disc_data);
ldata->column = 0;
ldata->canon_column = 0;
- ldata->minimum_to_wake = 1;
ldata->num_overrun = 0;
ldata->no_room = 0;
ldata->lnext = 0;
@@ -2015,7 +1969,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
retval = copy_to_user(*b, from, n);
n -= retval;
is_eof = n == 1 && *from == EOF_CHAR(tty);
- tty_audit_add_data(tty, from, n, ldata->icanon);
+ tty_audit_add_data(tty, from, n);
smp_store_release(&ldata->read_tail, ldata->read_tail + n);
/* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
@@ -2109,7 +2063,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
ldata->line_start = ldata->read_tail;
else
ldata->push = 0;
- tty_audit_push(tty);
+ tty_audit_push();
}
return 0;
}
@@ -2200,14 +2154,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
minimum = MIN_CHAR(tty);
if (minimum) {
time = (HZ / 10) * TIME_CHAR(tty);
- if (time)
- ldata->minimum_to_wake = 1;
- else if (!waitqueue_active(&tty->read_wait) ||
- (ldata->minimum_to_wake > minimum))
- ldata->minimum_to_wake = minimum;
} else {
timeout = (HZ / 10) * TIME_CHAR(tty);
- ldata->minimum_to_wake = minimum = 1;
+ minimum = 1;
}
}
@@ -2225,19 +2174,15 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
cs = tty->link->ctrl_status;
tty->link->ctrl_status = 0;
spin_unlock_irq(&tty->link->ctrl_lock);
- if (tty_put_user(tty, cs, b++)) {
+ if (put_user(cs, b)) {
retval = -EFAULT;
- b--;
break;
}
+ b++;
nr--;
break;
}
- if (((minimum - (b - buf)) < ldata->minimum_to_wake) &&
- ((minimum - (b - buf)) >= 1))
- ldata->minimum_to_wake = (minimum - (b - buf));
-
done = check_other_done(tty);
if (!input_available_p(tty, 0)) {
@@ -2275,11 +2220,11 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
/* Deal with packet mode. */
if (packet && b == buf) {
- if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
+ if (put_user(TIOCPKT_DATA, b)) {
retval = -EFAULT;
- b--;
break;
}
+ b++;
nr--;
}
@@ -2303,9 +2248,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
up_read(&tty->termios_rwsem);
remove_wait_queue(&tty->read_wait, &wait);
- if (!waitqueue_active(&tty->read_wait))
- ldata->minimum_to_wake = minimum;
-
mutex_unlock(&ldata->atomic_read_lock);
if (b - buf)
@@ -2417,7 +2359,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
}
break_out:
remove_wait_queue(&tty->write_wait, &wait);
- if (b - buf != nr && tty->fasync)
+ if (nr && tty->fasync)
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
up_read(&tty->termios_rwsem);
return (b - buf) ? b - buf : retval;
@@ -2440,7 +2382,6 @@ break_out:
static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
poll_table *wait)
{
- struct n_tty_data *ldata = tty->disc_data;
unsigned int mask = 0;
poll_wait(file, &tty->read_wait, wait);
@@ -2453,12 +2394,6 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
mask |= POLLPRI | POLLIN | POLLRDNORM;
if (tty_hung_up_p(file))
mask |= POLLHUP;
- if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
- if (MIN_CHAR(tty) && !TIME_CHAR(tty))
- ldata->minimum_to_wake = MIN_CHAR(tty);
- else
- ldata->minimum_to_wake = 1;
- }
if (tty->ops->write && !tty_is_writelocked(tty) &&
tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
tty_write_room(tty) > 0)
@@ -2507,25 +2442,12 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
}
}
-static void n_tty_fasync(struct tty_struct *tty, int on)
-{
- struct n_tty_data *ldata = tty->disc_data;
-
- if (!waitqueue_active(&tty->read_wait)) {
- if (on)
- ldata->minimum_to_wake = 1;
- else if (!tty->fasync)
- ldata->minimum_to_wake = N_TTY_BUF_SIZE;
- }
-}
-
-struct tty_ldisc_ops tty_ldisc_N_TTY = {
+static struct tty_ldisc_ops n_tty_ops = {
.magic = TTY_LDISC_MAGIC,
.name = "n_tty",
.open = n_tty_open,
.close = n_tty_close,
.flush_buffer = n_tty_flush_buffer,
- .chars_in_buffer = n_tty_chars_in_buffer,
.read = n_tty_read,
.write = n_tty_write,
.ioctl = n_tty_ioctl,
@@ -2533,7 +2455,6 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
.poll = n_tty_poll,
.receive_buf = n_tty_receive_buf,
.write_wakeup = n_tty_write_wakeup,
- .fasync = n_tty_fasync,
.receive_buf2 = n_tty_receive_buf2,
};
@@ -2541,14 +2462,18 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
* n_tty_inherit_ops - inherit N_TTY methods
* @ops: struct tty_ldisc_ops where to save N_TTY methods
*
- * Enables a 'subclass' line discipline to 'inherit' N_TTY
- * methods.
+ * Enables a 'subclass' line discipline to 'inherit' N_TTY methods.
*/
void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
{
- *ops = tty_ldisc_N_TTY;
+ *ops = n_tty_ops;
ops->owner = NULL;
ops->refcount = ops->flags = 0;
}
EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
+
+void __init n_tty_init(void)
+{
+ tty_register_ldisc(N_TTY, &n_tty_ops);
+}
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index 80f9de907563..5cc80b80c82b 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -823,7 +823,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
struct tty_struct *tty = tty_port_tty_get(&port->port);
int i, ret;
- read_mem32((u32 *) &size, addr, 4);
+ size = __le32_to_cpu(readl(addr));
/* DBG1( "%d bytes port: %d", size, index); */
if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 2348fa613707..e16a49b507ef 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -263,8 +263,7 @@ static void pty_set_termios(struct tty_struct *tty,
{
/* See if packet mode change of state. */
if (tty->link && tty->link->packet) {
- int extproc = (old_termios->c_lflag & EXTPROC) |
- (tty->termios.c_lflag & EXTPROC);
+ int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty);
int old_flow = ((old_termios->c_iflag & IXON) &&
(old_termios->c_cc[VSTOP] == '\023') &&
(old_termios->c_cc[VSTART] == '\021'));
@@ -406,13 +405,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
if (legacy) {
/* We always use new tty termios data so we can do this
the easy way .. */
- retval = tty_init_termios(tty);
- if (retval)
- goto err_deinit_tty;
-
- retval = tty_init_termios(o_tty);
- if (retval)
- goto err_free_termios;
+ tty_init_termios(tty);
+ tty_init_termios(o_tty);
driver->other->ttys[idx] = o_tty;
driver->ttys[idx] = tty;
@@ -444,12 +438,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
tty->count++;
o_tty->count++;
return 0;
-err_free_termios:
- if (legacy)
- tty_free_termios(tty);
-err_deinit_tty:
- deinitialize_tty_struct(o_tty);
- free_tty_struct(o_tty);
+
err_put_module:
module_put(driver->other->owner);
err:
@@ -666,20 +655,13 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
return tty;
}
-/* We have no need to install and remove our tty objects as devpts does all
- the work for us */
-
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
{
return pty_common_install(driver, tty, false);
}
-static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
-{
-}
-
/* this is called once with whichever end is closed last */
-static void pty_unix98_shutdown(struct tty_struct *tty)
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
struct inode *ptmx_inode;
@@ -704,7 +686,6 @@ static const struct tty_operations ptm_unix98_ops = {
.unthrottle = pty_unthrottle,
.ioctl = pty_unix98_ioctl,
.resize = pty_resize,
- .shutdown = pty_unix98_shutdown,
.cleanup = pty_cleanup
};
@@ -722,7 +703,6 @@ static const struct tty_operations pty_unix98_ops = {
.set_termios = pty_set_termios,
.start = pty_start,
.stop = pty_stop,
- .shutdown = pty_unix98_shutdown,
.cleanup = pty_cleanup,
};
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 802eac7e561b..0b802cdd70d0 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -643,7 +643,6 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
info->chan = chan;
tty_port_init(&info->port);
info->port.ops = &rocket_port_ops;
- init_completion(&info->close_wait);
info->flags &= ~ROCKET_MODE_MASK;
switch (pc104[board][line]) {
case 422:
@@ -960,7 +959,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
tty->alt_speed = 460800;
configure_r_port(tty, info, NULL);
- if (tty->termios.c_cflag & CBAUD) {
+ if (C_BAUD(tty)) {
sSetDTR(cp);
sSetRTS(cp);
}
@@ -1043,13 +1042,12 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
}
}
spin_lock_irq(&port->lock);
- info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE);
+ info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE);
tty->closing = 0;
spin_unlock_irq(&port->lock);
mutex_unlock(&port->mutex);
tty_port_tty_set(port, NULL);
- complete_all(&info->close_wait);
atomic_dec(&rp_num_ports_open);
#ifdef ROCKET_DEBUG_OPEN
@@ -1086,18 +1084,18 @@ static void rp_set_termios(struct tty_struct *tty,
cp = &info->channel;
/* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
sClrDTR(cp);
sClrRTS(cp);
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
+ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
sSetRTS(cp);
sSetDTR(cp);
}
- if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS))
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty))
rp_start(tty);
}
@@ -1360,8 +1358,7 @@ static void rp_throttle(struct tty_struct *tty)
struct r_port *info = tty->driver_data;
#ifdef ROCKET_DEBUG_THROTTLE
- printk(KERN_INFO "throttle %s: %d....\n", tty->name,
- tty->ldisc.chars_in_buffer(tty));
+ printk(KERN_INFO "throttle %s ....\n", tty->name);
#endif
if (rocket_paranoia_check(info, "rp_throttle"))
@@ -1377,8 +1374,7 @@ static void rp_unthrottle(struct tty_struct *tty)
{
struct r_port *info = tty->driver_data;
#ifdef ROCKET_DEBUG_THROTTLE
- printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
- tty->ldisc.chars_in_buffer(tty));
+ printk(KERN_INFO "unthrottle %s ....\n", tty->name);
#endif
if (rocket_paranoia_check(info, "rp_unthrottle"))
diff --git a/drivers/tty/rocket_int.h b/drivers/tty/rocket_int.h
index 67e0f1e778a2..ef1e1be6b26d 100644
--- a/drivers/tty/rocket_int.h
+++ b/drivers/tty/rocket_int.h
@@ -1144,7 +1144,6 @@ struct r_port {
int read_status_mask;
int cps;
- struct completion close_wait; /* Not yet matching the core */
spinlock_t slock;
struct mutex write_mtx;
};
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
deleted file mode 100644
index 0982c1a44187..000000000000
--- a/drivers/tty/serial/68328serial.c
+++ /dev/null
@@ -1,1322 +0,0 @@
-/* 68328serial.c: Serial port driver for 68328 microcontroller
- *
- * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
- * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
- * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
- * Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com>
- * Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
- *
- * VZ Support/Fixes Evan Stawnyczy <e@lineo.ca>
- * Multiple UART support Daniel Potts <danielp@cse.unsw.edu.au>
- * Power management support Daniel Potts <danielp@cse.unsw.edu.au>
- * VZ Second Serial Port enable Phil Wilshire
- * 2.4/2.5 port David McCullough
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/serial.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
-#include <linux/reboot.h>
-#include <linux/keyboard.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-
-/* (es) */
-/* note: perhaps we can murge these files, so that you can just
- * define 1 of them, and they can sort that out for themselves
- */
-#if defined(CONFIG_M68EZ328)
-#include <asm/MC68EZ328.h>
-#else
-#if defined(CONFIG_M68VZ328)
-#include <asm/MC68VZ328.h>
-#else
-#include <asm/MC68328.h>
-#endif /* CONFIG_M68VZ328 */
-#endif /* CONFIG_M68EZ328 */
-
-/* Turn off usage of real serial interrupt code, to "support" Copilot */
-#ifdef CONFIG_XCOPILOT_BUGS
-#undef USE_INTS
-#else
-#define USE_INTS
-#endif
-
-/*
- * I believe this is the optimal setting that reduces the number of interrupts.
- * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
- * if that bothers you), but in most cases it will not, since we try to
- * transmit characters every time rs_interrupt is called. Thus, quite often
- * you'll see that a receive interrupt occures before the transmit one.
- * -- Vladimir Gurevich
- */
-#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-
-/*
- * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
- * "Old data interrupt" which occures whenever the data stay in the FIFO
- * longer than 30 bits time. This allows us to use FIFO without compromising
- * latency. '328 does not have this feature and without the real 328-based
- * board I would assume that RXRE is the safest setting.
- *
- * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
- * interrupts. RXFE (receive queue full) causes the system to lose data
- * at least at 115200 baud
- *
- * If your board is busy doing other stuff, you might consider to use
- * RXRE (data ready intrrupt) instead.
- *
- * The other option is to make these INTR masks run-time configurable, so
- * that people can dynamically adapt them according to the current usage.
- * -- Vladimir Gurevich
- */
-
-/* (es) */
-#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
-#elif defined(CONFIG_M68328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
-#else
-#error Please, define the Rx interrupt events for your CPU
-#endif
-/* (/es) */
-
-/*
- * This is our internal structure for each serial port's state.
- */
-struct m68k_serial {
- struct tty_port tport;
- char is_cons; /* Is this our console. */
- int magic;
- int baud_base;
- int port;
- int irq;
- int type; /* UART type */
- int custom_divisor;
- int x_char; /* xon/xoff character */
- int line;
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
-};
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * Define the number of ports supported and their irqs.
- */
-#define NR_PORTS 1
-
-static struct m68k_serial m68k_soft[NR_PORTS];
-
-static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM };
-
-/* multiple ports are contiguous in memory */
-m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
-
-struct tty_driver *serial_driver;
-
-static void change_speed(struct m68k_serial *info, struct tty_struct *tty);
-
-/*
- * Setup for console. Argument comes from the boot command line.
- */
-
-/* note: this is messy, but it works, again, perhaps defined somewhere else?*/
-#ifdef CONFIG_M68VZ328
-#define CONSOLE_BAUD_RATE 19200
-#define DEFAULT_CBAUD B19200
-#endif
-
-
-#ifndef CONSOLE_BAUD_RATE
-#define CONSOLE_BAUD_RATE 9600
-#define DEFAULT_CBAUD B9600
-#endif
-
-
-static int m68328_console_initted;
-static int m68328_console_baud = CONSOLE_BAUD_RATE;
-static int m68328_console_cbaud = DEFAULT_CBAUD;
-
-
-static inline int serial_paranoia_check(struct m68k_serial *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for serial struct %s in %s\n";
- static const char *badinfo =
- "Warning: null m68k_serial for %s in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 0 };
-
-/* Utility routines */
-static inline int get_baud(struct m68k_serial *ss)
-{
- unsigned long result = 115200;
- unsigned short int baud = uart_addr[ss->line].ubaud;
- if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400;
- result >>= GET_FIELD(baud, UBAUD_DIVIDE);
-
- return result;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
- local_irq_save(flags);
- uart->ustcnt &= ~USTCNT_TXEN;
- local_irq_restore(flags);
-}
-
-static int rs_put_char(char ch)
-{
- unsigned long flags;
- int loops = 0;
-
- local_irq_save(flags);
-
- while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
- loops++;
- udelay(5);
- }
-
- UTX_TXDATA = ch;
- udelay(5);
- local_irq_restore(flags);
- return 1;
-}
-
-static void rs_start(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_start"))
- return;
-
- local_irq_save(flags);
- if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
-#ifdef USE_INTS
- uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
- uart->ustcnt |= USTCNT_TXEN;
-#endif
- }
- local_irq_restore(flags);
-}
-
-static void receive_chars(struct m68k_serial *info, unsigned short rx)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned char ch, flag;
-
- /*
- * This do { } while() loop will get ALL chars out of Rx FIFO
- */
-#ifndef CONFIG_XCOPILOT_BUGS
- do {
-#endif
- ch = GET_FIELD(rx, URX_RXDATA);
-
- if (info->is_cons) {
- if (URX_BREAK & rx) { /* whee, break received */
- return;
-#ifdef CONFIG_MAGIC_SYSRQ
- } else if (ch == 0x10) { /* ^P */
- show_state();
- show_free_areas(0);
- show_buffers();
-/* show_net_buffers(); */
- return;
- } else if (ch == 0x12) { /* ^R */
- emergency_restart();
- return;
-#endif /* CONFIG_MAGIC_SYSRQ */
- }
- }
-
- flag = TTY_NORMAL;
-
- if (rx & URX_PARITY_ERROR)
- flag = TTY_PARITY;
- else if (rx & URX_OVRUN)
- flag = TTY_OVERRUN;
- else if (rx & URX_FRAME_ERROR)
- flag = TTY_FRAME;
-
- tty_insert_flip_char(&info->tport, ch, flag);
-#ifndef CONFIG_XCOPILOT_BUGS
- } while ((rx = uart->urx.w) & URX_DATA_READY);
-#endif
-
- tty_schedule_flip(&info->tport);
-}
-
-static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
-
- if (info->x_char) {
- /* Send next char */
- uart->utx.b.txdata = info->x_char;
- info->x_char = 0;
- goto clear_and_return;
- }
-
- if ((info->xmit_cnt <= 0) || !tty || tty->stopped) {
- /* That's peculiar... TX ints off */
- uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
- goto clear_and_return;
- }
-
- /* Send char */
- uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
-
- if (info->xmit_cnt <= 0) {
- /* All done for now... TX ints off */
- uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
- goto clear_and_return;
- }
-
-clear_and_return:
- /* Clear interrupt (should be auto)*/
- return;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-irqreturn_t rs_interrupt(int irq, void *dev_id)
-{
- struct m68k_serial *info = dev_id;
- struct tty_struct *tty = tty_port_tty_get(&info->tport);
- m68328_uart *uart;
- unsigned short rx;
- unsigned short tx;
-
- uart = &uart_addr[info->line];
- rx = uart->urx.w;
-
-#ifdef USE_INTS
- tx = uart->utx.w;
-
- if (rx & URX_DATA_READY)
- receive_chars(info, rx);
- if (tx & UTX_TX_AVAIL)
- transmit_chars(info, tty);
-#else
- receive_chars(info, rx);
-#endif
- tty_kref_put(tty);
-
- return IRQ_HANDLED;
-}
-
-static int startup(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (info->tport.flags & ASYNC_INITIALIZED)
- return 0;
-
- if (!info->xmit_buf) {
- info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
- if (!info->xmit_buf)
- return -ENOMEM;
- }
-
- local_irq_save(flags);
-
- /*
- * Clear the FIFO buffers and disable them
- * (they will be reenabled in change_speed())
- */
-
- uart->ustcnt = USTCNT_UEN;
- uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
- (void)uart->urx.w;
-
- /*
- * Finally, enable sequencing and interrupts
- */
-#ifdef USE_INTS
- uart->ustcnt = USTCNT_UEN | USTCNT_RXEN |
- USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK;
-#else
- uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
-#endif
-
- if (tty)
- clear_bit(TTY_IO_ERROR, &tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- /*
- * and set the speed of the serial port
- */
-
- change_speed(info, tty);
-
- info->tport.flags |= ASYNC_INITIALIZED;
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- uart->ustcnt = 0; /* All off! */
- if (!(info->tport.flags & ASYNC_INITIALIZED))
- return;
-
- local_irq_save(flags);
-
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
- }
-
- if (tty)
- set_bit(TTY_IO_ERROR, &tty->flags);
-
- info->tport.flags &= ~ASYNC_INITIALIZED;
- local_irq_restore(flags);
-}
-
-struct {
- int divisor, prescale;
-}
-#ifndef CONFIG_M68VZ328
- hw_baud_table[18] = {
- {0, 0}, /* 0 */
- {0, 0}, /* 50 */
- {0, 0}, /* 75 */
- {0, 0}, /* 110 */
- {0, 0}, /* 134 */
- {0, 0}, /* 150 */
- {0, 0}, /* 200 */
- {7, 0x26}, /* 300 */
- {6, 0x26}, /* 600 */
- {5, 0x26}, /* 1200 */
- {0, 0}, /* 1800 */
- {4, 0x26}, /* 2400 */
- {3, 0x26}, /* 4800 */
- {2, 0x26}, /* 9600 */
- {1, 0x26}, /* 19200 */
- {0, 0x26}, /* 38400 */
- {1, 0x38}, /* 57600 */
- {0, 0x38}, /* 115200 */
-};
-#else
- hw_baud_table[18] = {
- {0, 0}, /* 0 */
- {0, 0}, /* 50 */
- {0, 0}, /* 75 */
- {0, 0}, /* 110 */
- {0, 0}, /* 134 */
- {0, 0}, /* 150 */
- {0, 0}, /* 200 */
- {0, 0}, /* 300 */
- {7, 0x26}, /* 600 */
- {6, 0x26}, /* 1200 */
- {0, 0}, /* 1800 */
- {5, 0x26}, /* 2400 */
- {4, 0x26}, /* 4800 */
- {3, 0x26}, /* 9600 */
- {2, 0x26}, /* 19200 */
- {1, 0x26}, /* 38400 */
- {0, 0x26}, /* 57600 */
- {1, 0x38}, /* 115200 */
-};
-#endif
-/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned short port;
- unsigned short ustcnt;
- unsigned cflag;
- int i;
-
- cflag = tty->termios.c_cflag;
- port = info->port;
- if (!port)
- return;
-
- ustcnt = uart->ustcnt;
- uart->ustcnt = ustcnt & ~USTCNT_TXEN;
-
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i = (i & ~CBAUDEX) + B38400;
- }
-
- uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
- PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
-
- ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
-
- if ((cflag & CSIZE) == CS8)
- ustcnt |= USTCNT_8_7;
-
- if (cflag & CSTOPB)
- ustcnt |= USTCNT_STOP;
-
- if (cflag & PARENB)
- ustcnt |= USTCNT_PARITYEN;
- if (cflag & PARODD)
- ustcnt |= USTCNT_ODD_EVEN;
-
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
- if (cflag & CRTSCTS) {
- uart->utx.w &= ~UTX_NOCTS;
- } else {
- uart->utx.w |= UTX_NOCTS;
- }
-#endif
-
- ustcnt |= USTCNT_TXEN;
-
- uart->ustcnt = ustcnt;
- return;
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void rs_fair_output(void)
-{
- int left; /* Output no more than that */
- unsigned long flags;
- struct m68k_serial *info = &m68k_soft[0];
- char c;
-
- if (info == NULL) return;
- if (info->xmit_buf == NULL) return;
-
- local_irq_save(flags);
- left = info->xmit_cnt;
- while (left != 0) {
- c = info->xmit_buf[info->xmit_tail];
- info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- local_irq_restore(flags);
-
- rs_put_char(c);
-
- local_irq_save(flags);
- left = min(info->xmit_cnt, left-1);
- }
-
- /* Last character is being transmitted now (hopefully). */
- udelay(5);
-
- local_irq_restore(flags);
- return;
-}
-
-/*
- * m68k_console_print is registered for printk.
- */
-void console_print_68328(const char *p)
-{
- char c;
-
- while ((c = *(p++)) != 0) {
- if (c == '\n')
- rs_put_char('\r');
- rs_put_char(c);
- }
-
- /* Comment this if you want to have a strict interrupt-driven output */
- rs_fair_output();
-
- return;
-}
-
-static void rs_set_ldisc(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
- return;
-
- info->is_cons = (tty->termios.c_line == N_TTY);
-
- printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
- return;
-#ifndef USE_INTS
- for (;;) {
-#endif
-
- /* Enable transmitter */
- local_irq_save(flags);
-
- if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) {
- local_irq_restore(flags);
- return;
- }
-
-#ifdef USE_INTS
- uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
- uart->ustcnt |= USTCNT_TXEN;
-#endif
-
-#ifdef USE_INTS
- if (uart->utx.w & UTX_TX_AVAIL) {
-#else
- if (1) {
-#endif
- /* Send char */
- uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- }
-
-#ifndef USE_INTS
- while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
- }
-#endif
- local_irq_restore(flags);
-}
-
-extern void console_printn(const char *b, int count);
-
-static int rs_write(struct tty_struct *tty,
- const unsigned char *buf, int count)
-{
- int c, total = 0;
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_write"))
- return 0;
-
- if (!tty || !info->xmit_buf)
- return 0;
-
- local_save_flags(flags);
- while (1) {
- local_irq_disable();
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- local_irq_restore(flags);
-
- if (c <= 0)
- break;
-
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
-
- local_irq_disable();
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- local_irq_restore(flags);
- buf += c;
- count -= c;
- total += c;
- }
-
- if (info->xmit_cnt && !tty->stopped) {
- /* Enable transmitter */
- local_irq_disable();
-#ifndef USE_INTS
- while (info->xmit_cnt) {
-#endif
-
- uart->ustcnt |= USTCNT_TXEN;
-#ifdef USE_INTS
- uart->ustcnt |= USTCNT_TX_INTR_MASK;
-#else
- while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
-#endif
- if (uart->utx.w & UTX_TX_AVAIL) {
- uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- }
-
-#ifndef USE_INTS
- }
-#endif
- local_irq_restore(flags);
- }
-
- return total;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "rs_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
- return 0;
- return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
- return;
- local_irq_save(flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- local_irq_restore(flags);
- tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
-
- /* Turn off RTS line (do this atomic) */
-}
-
-static void rs_unthrottle(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
-
- /* Assert RTS line (do this atomic) */
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct m68k_serial *info,
- struct serial_struct *retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->port;
- tmp.irq = info->irq;
- tmp.flags = info->tport.flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->tport.close_delay;
- tmp.closing_wait = info->tport.closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
-
- return 0;
-}
-
-static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,
- struct serial_struct *new_info)
-{
- struct tty_port *port = &info->tport;
- struct serial_struct new_serial;
- struct m68k_serial old_info;
- int retval = 0;
-
- if (!new_info)
- return -EFAULT;
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.type != info->type) ||
- (new_serial.close_delay != port->close_delay) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
- return -EPERM;
- port->flags = ((port->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- if (port->count > 1)
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud_base = new_serial.baud_base;
- port->flags = ((port->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->type = new_serial.type;
- port->close_delay = new_serial.close_delay;
- port->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
- retval = startup(info, tty);
- return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct m68k_serial *info, unsigned int *value)
-{
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
- m68328_uart *uart = &uart_addr[info->line];
-#endif
- unsigned char status;
- unsigned long flags;
-
- local_irq_save(flags);
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
- status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
-#else
- status = 0;
-#endif
- local_irq_restore(flags);
- return put_user(status, value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(struct m68k_serial *info, unsigned int duration)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
- if (!info->port)
- return;
- local_irq_save(flags);
-#ifdef USE_INTS
- uart->utx.w |= UTX_SEND_BREAK;
- msleep_interruptible(duration);
- uart->utx.w &= ~UTX_SEND_BREAK;
-#endif
- local_irq_restore(flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- int retval;
-
- if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- send_break(info, 250); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- send_break(info, arg ? arg*(100) : 250);
- return 0;
- case TIOCGSERIAL:
- return get_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSSERIAL:
- return set_serial_info(info, tty,
- (struct serial_struct *) arg);
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
- case TIOCSERGSTRUCT:
- if (copy_to_user((struct m68k_serial *) arg,
- info, sizeof(struct m68k_serial)))
- return -EFAULT;
- return 0;
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- change_speed(info, tty);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS))
- rs_start(tty);
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed. First, we
- * wait for the last remaining data to be sent. Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file *filp)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- struct tty_port *port = &info->tport;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_close"))
- return;
-
- local_irq_save(flags);
-
- if (tty_hung_up_p(filp)) {
- local_irq_restore(flags);
- return;
- }
-
- if ((tty->count == 1) && (port->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("rs_close: bad serial port count; tty->count is 1, "
- "port->count is %d\n", port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- printk("rs_close: bad serial port count for ttyS%d: %d\n",
- info->line, port->count);
- port->count = 0;
- }
- if (port->count) {
- local_irq_restore(flags);
- return;
- }
- port->flags |= ASYNC_CLOSING;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, port->closing_wait);
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
-
- uart->ustcnt &= ~USTCNT_RXEN;
- uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
-
- shutdown(info, tty);
- rs_flush_buffer(tty);
-
- tty_ldisc_flush(tty);
- tty->closing = 0;
- tty_port_tty_set(&info->tport, NULL);
-#warning "This is not and has never been valid so fix it"
-#if 0
- if (tty->ldisc.num != ldiscs[N_TTY].num) {
- if (tty->ldisc.close)
- (tty->ldisc.close)(tty);
- tty->ldisc = ldiscs[N_TTY];
- tty->termios.c_line = N_TTY;
- if (tty->ldisc.open)
- (tty->ldisc.open)(tty);
- }
-#endif
- if (port->blocked_open) {
- if (port->close_delay)
- msleep_interruptible(jiffies_to_msecs(port->close_delay));
- wake_up_interruptible(&port->open_wait);
- }
- port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- local_irq_restore(flags);
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void rs_hangup(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_hangup"))
- return;
-
- rs_flush_buffer(tty);
- shutdown(info, tty);
- info->tport.count = 0;
- info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
- tty_port_tty_set(&info->tport, NULL);
- wake_up_interruptible(&info->tport.open_wait);
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its S structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-int rs_open(struct tty_struct *tty, struct file *filp)
-{
- struct m68k_serial *info;
- int retval;
-
- info = &m68k_soft[tty->index];
-
- if (serial_paranoia_check(info, tty->name, "rs_open"))
- return -ENODEV;
-
- info->tport.count++;
- tty->driver_data = info;
- tty_port_tty_set(&info->tport, tty);
-
- /*
- * Start up serial port
- */
- retval = startup(info, tty);
- if (retval)
- return retval;
-
- return tty_port_block_til_ready(&info->tport, tty, filp);
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
- printk("MC68328 serial driver version 1.00\n");
-}
-
-static const struct tty_operations rs_ops = {
- .open = rs_open,
- .close = rs_close,
- .write = rs_write,
- .flush_chars = rs_flush_chars,
- .write_room = rs_write_room,
- .chars_in_buffer = rs_chars_in_buffer,
- .flush_buffer = rs_flush_buffer,
- .ioctl = rs_ioctl,
- .throttle = rs_throttle,
- .unthrottle = rs_unthrottle,
- .set_termios = rs_set_termios,
- .stop = rs_stop,
- .start = rs_start,
- .hangup = rs_hangup,
- .set_ldisc = rs_set_ldisc,
-};
-
-static const struct tty_port_operations rs_port_ops = {
-};
-
-/* rs_init inits the driver */
-static int __init
-rs68328_init(void)
-{
- unsigned long flags;
- int i;
- struct m68k_serial *info;
-
- serial_driver = alloc_tty_driver(NR_PORTS);
- if (!serial_driver)
- return -ENOMEM;
-
- show_serial_version();
-
- /* Initialize the tty_driver structure */
- /* SPARC: Not all of this is exactly right for us. */
-
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &rs_ops);
-
- local_irq_save(flags);
-
- for (i = 0; i < NR_PORTS; i++) {
-
- info = &m68k_soft[i];
- tty_port_init(&info->tport);
- info->tport.ops = &rs_port_ops;
- info->magic = SERIAL_MAGIC;
- info->port = (int) &uart_addr[i];
- info->irq = uart_irqs[i];
- info->custom_divisor = 16;
- info->x_char = 0;
- info->line = i;
- info->is_cons = 1; /* Means shortcuts work */
-
- printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line,
- info->port, info->irq);
- printk(" is a builtin MC68328 UART\n");
-
-#ifdef CONFIG_M68VZ328
- if (i > 0)
- PJSEL &= 0xCF; /* PSW enable second port output */
-#endif
-
- if (request_irq(uart_irqs[i],
- rs_interrupt,
- 0,
- "M68328_UART", info))
- panic("Unable to attach 68328 serial interrupt\n");
-
- tty_port_link_device(&info->tport, serial_driver, i);
- }
- local_irq_restore(flags);
-
- if (tty_register_driver(serial_driver)) {
- put_tty_driver(serial_driver);
- for (i = 0; i < NR_PORTS; i++)
- tty_port_destroy(&m68k_soft[i].tport);
- printk(KERN_ERR "Couldn't register serial driver\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-module_init(rs68328_init);
-
-
-
-static void m68328_set_baud(void)
-{
- unsigned short ustcnt;
- int i;
-
- ustcnt = USTCNT;
- USTCNT = ustcnt & ~USTCNT_TXEN;
-
-again:
- for (i = 0; i < ARRAY_SIZE(baud_table); i++)
- if (baud_table[i] == m68328_console_baud)
- break;
- if (i >= ARRAY_SIZE(baud_table)) {
- m68328_console_baud = 9600;
- goto again;
- }
-
- UBAUD = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
- PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
- ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
- ustcnt |= USTCNT_8_7;
- ustcnt |= USTCNT_TXEN;
- USTCNT = ustcnt;
- m68328_console_initted = 1;
- return;
-}
-
-
-int m68328_console_setup(struct console *cp, char *arg)
-{
- int i, n = CONSOLE_BAUD_RATE;
-
- if (!cp)
- return(-1);
-
- if (arg)
- n = simple_strtoul(arg, NULL, 0);
-
- for (i = 0; i < ARRAY_SIZE(baud_table); i++)
- if (baud_table[i] == n)
- break;
- if (i < ARRAY_SIZE(baud_table)) {
- m68328_console_baud = n;
- m68328_console_cbaud = 0;
- if (i > 15) {
- m68328_console_cbaud |= CBAUDEX;
- i -= 15;
- }
- m68328_console_cbaud |= i;
- }
-
- m68328_set_baud(); /* make sure baud rate changes */
- return 0;
-}
-
-
-static struct tty_driver *m68328_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return serial_driver;
-}
-
-
-void m68328_console_write (struct console *co, const char *str,
- unsigned int count)
-{
- if (!m68328_console_initted)
- m68328_set_baud();
- while (count--) {
- if (*str == '\n')
- rs_put_char('\r');
- rs_put_char(*str++);
- }
-}
-
-
-static struct console m68328_driver = {
- .name = "ttyS",
- .write = m68328_console_write,
- .device = m68328_console_device,
- .setup = m68328_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-
-static int __init m68328_console_init(void)
-{
- register_console(&m68328_driver);
- return 0;
-}
-
-console_initcall(m68328_console_init);
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index d54dcd87c67e..047a7ba6796a 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -92,6 +92,18 @@ struct serial8250_config {
#define SERIAL8250_SHARE_IRQS 0
#endif
+#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF | (_flags), \
+ }
+
+#define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0)
+
+
static inline int serial_in(struct uart_8250_port *up, int offset)
{
return up->port.serial_in(&up->port, offset);
@@ -117,6 +129,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
struct uart_8250_port *serial8250_get_port(int line);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
+int serial8250_em485_init(struct uart_8250_port *p);
+void serial8250_em485_destroy(struct uart_8250_port *p);
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
diff --git a/drivers/tty/serial/8250/8250_accent.c b/drivers/tty/serial/8250/8250_accent.c
index 34b51c651192..522aeae05192 100644
--- a/drivers/tty/serial/8250/8250_accent.c
+++ b/drivers/tty/serial/8250/8250_accent.c
@@ -10,18 +10,11 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port accent_data[] = {
- PORT(0x330, 4),
- PORT(0x338, 4),
+ SERIAL8250_PORT(0x330, 4),
+ SERIAL8250_PORT(0x338, 4),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c
index 549aa07c0d27..402dfdd4940e 100644
--- a/drivers/tty/serial/8250/8250_acorn.c
+++ b/drivers/tty/serial/8250/8250_acorn.c
@@ -70,7 +70,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
uart.port.regshift = 2;
uart.port.dev = &ec->dev;
- for (i = 0; i < info->num_ports; i ++) {
+ for (i = 0; i < info->num_ports; i++) {
uart.port.membase = info->vaddr + type->offset[i];
uart.port.mapbase = bus_addr + type->offset[i];
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
new file mode 100644
index 000000000000..e10f1244409b
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -0,0 +1,146 @@
+/*
+ * Serial port driver for BCM2835AUX UART
+ *
+ * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org>
+ *
+ * Based on 8250_lpc18xx.c:
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "8250.h"
+
+struct bcm2835aux_data {
+ struct uart_8250_port uart;
+ struct clk *clk;
+ int line;
+};
+
+static int bcm2835aux_serial_probe(struct platform_device *pdev)
+{
+ struct bcm2835aux_data *data;
+ struct resource *res;
+ int ret;
+
+ /* allocate the custom structure */
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* initialize data */
+ spin_lock_init(&data->uart.port.lock);
+ data->uart.capabilities = UART_CAP_FIFO;
+ data->uart.port.dev = &pdev->dev;
+ data->uart.port.regshift = 2;
+ data->uart.port.type = PORT_16550;
+ data->uart.port.iotype = UPIO_MEM;
+ data->uart.port.fifosize = 8;
+ data->uart.port.flags = UPF_SHARE_IRQ |
+ UPF_FIXED_PORT |
+ UPF_FIXED_TYPE |
+ UPF_SKIP_TEST;
+
+ /* get the clock - this also enables the HW */
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ ret = PTR_ERR_OR_ZERO(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "could not get clk: %d\n", ret);
+ return ret;
+ }
+
+ /* get the interrupt */
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "irq not found - %i", ret);
+ return ret;
+ }
+ data->uart.port.irq = ret;
+
+ /* map the main registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "memory resource not found");
+ return -EINVAL;
+ }
+ data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res);
+ ret = PTR_ERR_OR_ZERO(data->uart.port.membase);
+ if (ret)
+ return ret;
+
+ /* Check for a fixed line number */
+ ret = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (ret >= 0)
+ data->uart.port.line = ret;
+
+ /* enable the clock as a last step */
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
+ ret);
+ return ret;
+ }
+
+ /* the HW-clock divider for bcm2835aux is 8,
+ * but 8250 expects a divider of 16,
+ * so we have to multiply the actual clock by 2
+ * to get identical baudrates.
+ */
+ data->uart.port.uartclk = clk_get_rate(data->clk) * 2;
+
+ /* register the port */
+ ret = serial8250_register_8250_port(&data->uart);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register 8250 port - %d\n",
+ ret);
+ goto dis_clk;
+ }
+ data->line = ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+dis_clk:
+ clk_disable_unprepare(data->clk);
+ return ret;
+}
+
+static int bcm2835aux_serial_remove(struct platform_device *pdev)
+{
+ struct bcm2835aux_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->uart.port.line);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835aux_serial_match[] = {
+ { .compatible = "brcm,bcm2835-aux-uart" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
+
+static struct platform_driver bcm2835aux_serial_driver = {
+ .driver = {
+ .name = "bcm2835-aux-uart",
+ .of_match_table = bcm2835aux_serial_match,
+ },
+ .probe = bcm2835aux_serial_probe,
+ .remove = bcm2835aux_serial_remove,
+};
+module_platform_driver(bcm2835aux_serial_driver);
+
+MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
+MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_boca.c b/drivers/tty/serial/8250/8250_boca.c
index d125dc107985..a63b5998e383 100644
--- a/drivers/tty/serial/8250/8250_boca.c
+++ b/drivers/tty/serial/8250/8250_boca.c
@@ -10,32 +10,25 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port boca_data[] = {
- PORT(0x100, 12),
- PORT(0x108, 12),
- PORT(0x110, 12),
- PORT(0x118, 12),
- PORT(0x120, 12),
- PORT(0x128, 12),
- PORT(0x130, 12),
- PORT(0x138, 12),
- PORT(0x140, 12),
- PORT(0x148, 12),
- PORT(0x150, 12),
- PORT(0x158, 12),
- PORT(0x160, 12),
- PORT(0x168, 12),
- PORT(0x170, 12),
- PORT(0x178, 12),
+ SERIAL8250_PORT(0x100, 12),
+ SERIAL8250_PORT(0x108, 12),
+ SERIAL8250_PORT(0x110, 12),
+ SERIAL8250_PORT(0x118, 12),
+ SERIAL8250_PORT(0x120, 12),
+ SERIAL8250_PORT(0x128, 12),
+ SERIAL8250_PORT(0x130, 12),
+ SERIAL8250_PORT(0x138, 12),
+ SERIAL8250_PORT(0x140, 12),
+ SERIAL8250_PORT(0x148, 12),
+ SERIAL8250_PORT(0x150, 12),
+ SERIAL8250_PORT(0x158, 12),
+ SERIAL8250_PORT(0x160, 12),
+ SERIAL8250_PORT(0x168, 12),
+ SERIAL8250_PORT(0x170, 12),
+ SERIAL8250_PORT(0x178, 12),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index c9720a97a977..2f4f5ee651db 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -597,6 +597,7 @@ static void univ8250_console_write(struct console *co, const char *s,
static int univ8250_console_setup(struct console *co, char *options)
{
struct uart_port *port;
+ int retval;
/*
* Check whether an invalid uart number has been specified, and
@@ -609,7 +610,10 @@ static int univ8250_console_setup(struct console *co, char *options)
/* link port to console */
port->cons = co;
- return serial8250_console_setup(port, options, false);
+ retval = serial8250_console_setup(port, options, false);
+ if (retval != 0)
+ port->cons = NULL;
+ return retval;
}
/**
@@ -687,7 +691,7 @@ static int __init univ8250_console_init(void)
}
console_initcall(univ8250_console_init);
-#define SERIAL8250_CONSOLE &univ8250_console
+#define SERIAL8250_CONSOLE (&univ8250_console)
#else
#define SERIAL8250_CONSOLE NULL
#endif
@@ -764,6 +768,7 @@ void serial8250_suspend_port(int line)
uart_suspend_port(&serial8250_reg, port);
}
+EXPORT_SYMBOL(serial8250_suspend_port);
/**
* serial8250_resume_port - resume one serial port
@@ -789,6 +794,7 @@ void serial8250_resume_port(int line)
}
uart_resume_port(&serial8250_reg, port);
}
+EXPORT_SYMBOL(serial8250_resume_port);
/*
* Register a set of serial devices attached to a platform device. The
@@ -1068,6 +1074,15 @@ void serial8250_unregister_port(int line)
struct uart_8250_port *uart = &serial8250_ports[line];
mutex_lock(&serial_mutex);
+
+ if (uart->em485) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ serial8250_em485_destroy(uart);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+ }
+
uart_remove_one_port(&serial8250_reg, &uart->port);
if (serial8250_isa_devs) {
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
@@ -1093,9 +1108,8 @@ static int __init serial8250_init(void)
serial8250_isa_init_ports();
- printk(KERN_INFO "Serial: 8250/16550 driver, "
- "%d ports, IRQ sharing %sabled\n", nr_uarts,
- share_irqs ? "en" : "dis");
+ pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
+ nr_uarts, share_irqs ? "en" : "dis");
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
@@ -1168,15 +1182,11 @@ static void __exit serial8250_exit(void)
module_init(serial8250_init);
module_exit(serial8250_exit);
-EXPORT_SYMBOL(serial8250_suspend_port);
-EXPORT_SYMBOL(serial8250_resume_port);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
module_param(share_irqs, uint, 0644);
-MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
- " (unsafe)");
+MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
module_param(nr_uarts, uint, 0644);
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index a5d319e4aae6..a3fb95d85d7c 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -68,12 +68,6 @@ struct dw8250_data {
unsigned int uart_16550_compatible:1;
};
-#define BYT_PRV_CLK 0x800
-#define BYT_PRV_CLK_EN (1 << 0)
-#define BYT_PRV_CLK_M_VAL_SHIFT 1
-#define BYT_PRV_CLK_N_VAL_SHIFT 16
-#define BYT_PRV_CLK_UPDATE (1 << 31)
-
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@@ -95,25 +89,45 @@ static void dw8250_force_idle(struct uart_port *p)
(void)p->serial_in(p, UART_RX);
}
-static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+static void dw8250_check_lcr(struct uart_port *p, int value)
{
- writeb(value, p->membase + (offset << p->regshift));
+ void __iomem *offset = p->membase + (UART_LCR << p->regshift);
+ int tries = 1000;
/* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- writeb(value, p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
+ while (tries--) {
+ unsigned int lcr = p->serial_in(p, UART_LCR);
+
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
+
+ dw8250_force_idle(p);
+
+#ifdef CONFIG_64BIT
+ __raw_writeq(value & 0xff, offset);
+#else
+ if (p->iotype == UPIO_MEM32)
+ writel(value, offset);
+ else if (p->iotype == UPIO_MEM32BE)
+ iowrite32be(value, offset);
+ else
+ writeb(value, offset);
+#endif
}
+ /*
+ * FIXME: this deadlocks if port->lock is already held
+ * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ */
+}
+
+static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+{
+ struct dw8250_data *d = p->private_data;
+
+ writeb(value, p->membase + (offset << p->regshift));
+
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
@@ -135,49 +149,26 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
{
+ struct dw8250_data *d = p->private_data;
+
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
__raw_readq(p->membase + (UART_LCR << p->regshift));
- /* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- __raw_writeq(value & 0xff,
- p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
- }
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
#endif /* CONFIG_64BIT */
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
+ struct dw8250_data *d = p->private_data;
+
writel(value, p->membase + (offset << p->regshift));
- /* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- writel(value, p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
- }
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
@@ -187,14 +178,33 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
return dw8250_modify_msr(p, offset, value);
}
+static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
+{
+ struct dw8250_data *d = p->private_data;
+
+ iowrite32be(value, p->membase + (offset << p->regshift));
+
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
+}
+
+static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
+{
+ unsigned int value = ioread32be(p->membase + (offset << p->regshift));
+
+ return dw8250_modify_msr(p, offset, value);
+}
+
+
static int dw8250_handle_irq(struct uart_port *p)
{
struct dw8250_data *d = p->private_data;
unsigned int iir = p->serial_in(p, UART_IIR);
- if (serial8250_handle_irq(p, iir)) {
+ if (serial8250_handle_irq(p, iir))
return 1;
- } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+
+ if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR */
(void)p->serial_in(p, d->usr_reg);
@@ -281,6 +291,11 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
data->skip_autocfg = true;
}
#endif
+ if (of_device_is_big_endian(p->dev->of_node)) {
+ p->iotype = UPIO_MEM32BE;
+ p->serial_in = dw8250_serial_in32be;
+ p->serial_out = dw8250_serial_out32be;
+ }
} else if (has_acpi_companion(p->dev)) {
p->iotype = UPIO_MEM32;
p->regshift = 2;
@@ -309,14 +324,20 @@ static void dw8250_setup_port(struct uart_port *p)
* If the Component Version Register returns zero, we know that
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
*/
- reg = readl(p->membase + DW_UART_UCV);
+ if (p->iotype == UPIO_MEM32BE)
+ reg = ioread32be(p->membase + DW_UART_UCV);
+ else
+ reg = readl(p->membase + DW_UART_UCV);
if (!reg)
return;
dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
- reg = readl(p->membase + DW_UART_CPR);
+ if (p->iotype == UPIO_MEM32BE)
+ reg = ioread32be(p->membase + DW_UART_CPR);
+ else
+ reg = readl(p->membase + DW_UART_CPR);
if (!reg)
return;
@@ -463,10 +484,8 @@ static int dw8250_probe(struct platform_device *pdev)
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
- if (data->uart_16550_compatible) {
- p->serial_out = NULL;
+ if (data->uart_16550_compatible)
p->handle_irq = NULL;
- }
if (!data->skip_autocfg)
dw8250_setup_port(p);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index af62131af21e..8d08ff5c4e34 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -39,15 +39,17 @@
static unsigned int __init serial8250_early_in(struct uart_port *port, int offset)
{
+ offset <<= port->regshift;
+
switch (port->iotype) {
case UPIO_MEM:
return readb(port->membase + offset);
case UPIO_MEM16:
- return readw(port->membase + (offset << 1));
+ return readw(port->membase + offset);
case UPIO_MEM32:
- return readl(port->membase + (offset << 2));
+ return readl(port->membase + offset);
case UPIO_MEM32BE:
- return ioread32be(port->membase + (offset << 2));
+ return ioread32be(port->membase + offset);
case UPIO_PORT:
return inb(port->iobase + offset);
default:
@@ -57,18 +59,20 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse
static void __init serial8250_early_out(struct uart_port *port, int offset, int value)
{
+ offset <<= port->regshift;
+
switch (port->iotype) {
case UPIO_MEM:
writeb(value, port->membase + offset);
break;
case UPIO_MEM16:
- writew(value, port->membase + (offset << 1));
+ writew(value, port->membase + offset);
break;
case UPIO_MEM32:
- writel(value, port->membase + (offset << 2));
+ writel(value, port->membase + offset);
break;
case UPIO_MEM32BE:
- iowrite32be(value, port->membase + (offset << 2));
+ iowrite32be(value, port->membase + offset);
break;
case UPIO_PORT:
outb(value, port->iobase + offset);
@@ -145,3 +149,25 @@ EARLYCON_DECLARE(uart8250, early_serial8250_setup);
EARLYCON_DECLARE(uart, early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
+OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
+
+#ifdef CONFIG_SERIAL_8250_OMAP
+
+static int __init early_omap8250_setup(struct earlycon_device *device,
+ const char *options)
+{
+ struct uart_port *port = &device->port;
+
+ if (!(device->port.membase || device->port.iobase))
+ return -ENODEV;
+
+ port->regshift = 2;
+ device->con->write = early_serial8250_write;
+ return 0;
+}
+
+OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup);
+OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup);
+OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup);
+
+#endif
diff --git a/drivers/tty/serial/8250/8250_exar_st16c554.c b/drivers/tty/serial/8250/8250_exar_st16c554.c
index bf53aabf9b5e..3a7cb8262bb9 100644
--- a/drivers/tty/serial/8250/8250_exar_st16c554.c
+++ b/drivers/tty/serial/8250/8250_exar_st16c554.c
@@ -13,20 +13,13 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port exar_data[] = {
- PORT(0x100, 5),
- PORT(0x108, 5),
- PORT(0x110, 5),
- PORT(0x118, 5),
+ SERIAL8250_PORT(0x100, 5),
+ SERIAL8250_PORT(0x108, 5),
+ SERIAL8250_PORT(0x110, 5),
+ SERIAL8250_PORT(0x118, 5),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_fourport.c b/drivers/tty/serial/8250/8250_fourport.c
index be1582609626..4045180a8cfc 100644
--- a/drivers/tty/serial/8250/8250_fourport.c
+++ b/drivers/tty/serial/8250/8250_fourport.c
@@ -10,24 +10,20 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF | UPF_FOURPORT, \
- }
+#include "8250.h"
+
+#define SERIAL8250_FOURPORT(_base, _irq) \
+ SERIAL8250_PORT_FLAGS(_base, _irq, UPF_FOURPORT)
static struct plat_serial8250_port fourport_data[] = {
- PORT(0x1a0, 9),
- PORT(0x1a8, 9),
- PORT(0x1b0, 9),
- PORT(0x1b8, 9),
- PORT(0x2a0, 5),
- PORT(0x2a8, 5),
- PORT(0x2b0, 5),
- PORT(0x2b8, 5),
+ SERIAL8250_FOURPORT(0x1a0, 9),
+ SERIAL8250_FOURPORT(0x1a8, 9),
+ SERIAL8250_FOURPORT(0x1b0, 9),
+ SERIAL8250_FOURPORT(0x1b8, 9),
+ SERIAL8250_FOURPORT(0x2a0, 5),
+ SERIAL8250_FOURPORT(0x2a8, 5),
+ SERIAL8250_FOURPORT(0x2b0, 5),
+ SERIAL8250_FOURPORT(0x2b8, 5),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c
index 2e3ea1a70d7b..b1e6ae9f1ff9 100644
--- a/drivers/tty/serial/8250/8250_gsc.c
+++ b/drivers/tty/serial/8250/8250_gsc.c
@@ -42,7 +42,7 @@ static int __init serial_init_chip(struct parisc_device *dev)
* the user what they're missing.
*/
if (parisc_parent(dev)->id.hw_type != HPHW_IOA)
- printk(KERN_INFO
+ dev_info(&dev->dev,
"Serial: device 0x%llx not configured.\n"
"Enable support for Wax, Lasi, Asp or Dino.\n",
(unsigned long long)dev->hpa.start);
@@ -66,8 +66,9 @@ static int __init serial_init_chip(struct parisc_device *dev)
err = serial8250_register_8250_port(&uart);
if (err < 0) {
- printk(KERN_WARNING
- "serial8250_register_8250_port returned error %d\n", err);
+ dev_warn(&dev->dev,
+ "serial8250_register_8250_port returned error %d\n",
+ err);
iounmap(uart.port.membase);
return err;
}
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index 2891958cd842..38166db2b824 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -24,8 +24,7 @@
#endif
#ifdef CONFIG_HPAPCI
-struct hp300_port
-{
+struct hp300_port {
struct hp300_port *next; /* next port */
int line; /* line (tty) number */
};
@@ -111,7 +110,7 @@ int __init hp300_setup_serial_console(void)
/* Check for APCI console */
if (scode == 256) {
#ifdef CONFIG_HPAPCI
- printk(KERN_INFO "Serial console is HP APCI 1\n");
+ pr_info("Serial console is HP APCI 1\n");
port.uartclk = HPAPCI_BAUD_BASE * 16;
port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
@@ -119,7 +118,7 @@ int __init hp300_setup_serial_console(void)
port.regshift = 2;
add_preferred_console("ttyS", port.line, "9600n8");
#else
- printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
+ pr_warn("Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
return 0;
#endif
} else {
@@ -128,7 +127,7 @@ int __init hp300_setup_serial_console(void)
if (!pa)
return 0;
- printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
+ pr_info("Serial console is HP DCA at select code %d\n", scode);
port.uartclk = HPDCA_BAUD_BASE * 16;
port.mapbase = (pa + UART_OFFSET);
@@ -142,13 +141,13 @@ int __init hp300_setup_serial_console(void)
if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
add_preferred_console("ttyS", port.line, "9600n8");
#else
- printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
+ pr_warn("Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
return 0;
#endif
}
if (early_serial_setup(&port) < 0)
- printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
+ pr_warn("%s: early_serial_setup() failed.\n", __func__);
return 0;
}
#endif /* CONFIG_SERIAL_8250_CONSOLE */
@@ -180,8 +179,9 @@ static int hpdca_init_one(struct dio_dev *d,
line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
- " irq %d failed\n", d->scode, uart.port.irq);
+ dev_notice(&d->dev,
+ "8250_hp300: register_serial() DCA scode %d irq %d failed\n",
+ d->scode, uart.port.irq);
return -ENOMEM;
}
@@ -249,8 +249,8 @@ static int __init hp300_8250_init(void)
/* Memory mapped I/O */
uart.port.iotype = UPIO_MEM;
- uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
- | UPF_BOOT_AUTOCONF;
+ uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
+ | UPF_BOOT_AUTOCONF;
/* XXX - no interrupt support yet */
uart.port.irq = 0;
uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
@@ -261,8 +261,9 @@ static int __init hp300_8250_init(void)
line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
- " %d irq %d failed\n", i, uart.port.irq);
+ dev_notice(uart.port.dev,
+ "8250_hp300: register_serial() APCI %d irq %d failed\n",
+ i, uart.port.irq);
kfree(port);
continue;
}
diff --git a/drivers/tty/serial/8250/8250_hub6.c b/drivers/tty/serial/8250/8250_hub6.c
index a5c778e83de0..27124e21eb96 100644
--- a/drivers/tty/serial/8250/8250_hub6.c
+++ b/drivers/tty/serial/8250/8250_hub6.c
@@ -10,7 +10,7 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define HUB6(card,port) \
+#define HUB6(card, port) \
{ \
.iobase = 0x302, \
.irq = 3, \
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index d6e1ec9b4fde..b0677f610863 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -48,7 +48,7 @@ static const struct of_device_id of_match[];
#define UART_MCR_MDCE BIT(7)
#define UART_MCR_FCM BIT(6)
-#ifdef CONFIG_SERIAL_EARLYCON
+#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
static struct earlycon_device *early_device;
static uint8_t __init early_in(struct uart_port *port, int offset)
@@ -154,14 +154,18 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
break;
case UART_IER:
- /* Enable receive timeout interrupt with the
- * receive line status interrupt */
+ /*
+ * Enable receive timeout interrupt with the receive line
+ * status interrupt.
+ */
value |= (value & 0x4) << 2;
break;
case UART_MCR:
- /* If we have enabled modem status IRQs we should enable modem
- * mode. */
+ /*
+ * If we have enabled modem status IRQs we should enable
+ * modem mode.
+ */
ier = p->serial_in(p, UART_IER);
if (ier & UART_IER_MSI)
diff --git a/drivers/tty/serial/8250/8250_moxa.c b/drivers/tty/serial/8250/8250_moxa.c
new file mode 100644
index 000000000000..26eb5393a263
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_moxa.c
@@ -0,0 +1,157 @@
+/*
+ * 8250_moxa.c - MOXA Smartio/Industio MUE multiport serial driver.
+ *
+ * Author: Mathieu OTHACEHE <m.othacehe@gmail.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "8250.h"
+
+#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
+#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
+#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045
+#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144
+#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160
+#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161
+#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182
+#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183
+#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322
+#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342
+#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
+#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
+
+#define MOXA_BASE_BAUD 921600
+#define MOXA_UART_OFFSET 0x200
+#define MOXA_BASE_BAR 1
+
+struct moxa8250_board {
+ unsigned int num_ports;
+ int line[0];
+};
+
+enum {
+ moxa8250_2p = 0,
+ moxa8250_4p,
+ moxa8250_8p
+};
+
+static struct moxa8250_board moxa8250_boards[] = {
+ [moxa8250_2p] = { .num_ports = 2},
+ [moxa8250_4p] = { .num_ports = 4},
+ [moxa8250_8p] = { .num_ports = 8},
+};
+
+static int moxa8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct uart_8250_port uart;
+ struct moxa8250_board *brd;
+ void __iomem *ioaddr;
+ resource_size_t baseaddr;
+ unsigned int i, nr_ports;
+ unsigned int offset;
+ int ret;
+
+ brd = &moxa8250_boards[id->driver_data];
+ nr_ports = brd->num_ports;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ brd = devm_kzalloc(&pdev->dev, sizeof(struct moxa8250_board) +
+ sizeof(unsigned int) * nr_ports, GFP_KERNEL);
+ if (!brd)
+ return -ENOMEM;
+
+ memset(&uart, 0, sizeof(struct uart_8250_port));
+
+ uart.port.dev = &pdev->dev;
+ uart.port.irq = pdev->irq;
+ uart.port.uartclk = MOXA_BASE_BAUD * 16;
+ uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+
+ baseaddr = pci_resource_start(pdev, MOXA_BASE_BAR);
+ ioaddr = pcim_iomap(pdev, MOXA_BASE_BAR, 0);
+ if (!ioaddr)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_ports; i++) {
+
+ /*
+ * MOXA Smartio MUE boards with 4 ports have
+ * a different offset for port #3
+ */
+ if (nr_ports == 4 && i == 3)
+ offset = 7 * MOXA_UART_OFFSET;
+ else
+ offset = i * MOXA_UART_OFFSET;
+
+ uart.port.iotype = UPIO_MEM;
+ uart.port.iobase = 0;
+ uart.port.mapbase = baseaddr + offset;
+ uart.port.membase = ioaddr + offset;
+ uart.port.regshift = 0;
+
+ dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
+ uart.port.iobase, uart.port.irq, uart.port.iotype);
+
+ brd->line[i] = serial8250_register_8250_port(&uart);
+ if (brd->line[i] < 0) {
+ dev_err(&pdev->dev,
+ "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+ uart.port.iobase, uart.port.irq,
+ uart.port.iotype, brd->line[i]);
+ break;
+ }
+ }
+
+ pci_set_drvdata(pdev, brd);
+ return 0;
+}
+
+static void moxa8250_remove(struct pci_dev *pdev)
+{
+ struct moxa8250_board *brd = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < brd->num_ports; i++)
+ serial8250_unregister_port(brd->line[i]);
+}
+
+#define MOXA_DEVICE(id, data) { PCI_VDEVICE(MOXA, id), (kernel_ulong_t)data }
+
+static const struct pci_device_id pci_ids[] = {
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102E, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102EL, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP104EL_A, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP114EL, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_B, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118EL_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118E_A_I, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP132EL, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP134EL_A, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP138E_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP168EL_A, moxa8250_8p),
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver moxa8250_pci_driver = {
+ .name = "8250_moxa",
+ .id_table = pci_ids,
+ .probe = moxa8250_probe,
+ .remove = moxa8250_remove,
+};
+
+module_pci_driver(moxa8250_pci_driver);
+
+MODULE_AUTHOR("Mathieu OTHACEHE");
+MODULE_DESCRIPTION("MOXA SmartIO MUE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 0e590b233f03..3489fbcb7313 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -16,7 +16,7 @@
*/
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/init.h>
+#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -41,12 +41,10 @@ static void
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
unsigned int baud, quot;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
-
serial8250_do_set_termios(port, termios, old);
/*
@@ -116,7 +114,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
tty_termios_encode_baud_rate(termios, baud, baud);
}
-static int mtk8250_runtime_suspend(struct device *dev)
+static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -126,7 +124,7 @@ static int mtk8250_runtime_suspend(struct device *dev)
return 0;
}
-static int mtk8250_runtime_resume(struct device *dev)
+static int __maybe_unused mtk8250_runtime_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
int err;
@@ -245,8 +243,24 @@ static int mtk8250_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int mtk8250_suspend(struct device *dev)
+static int mtk8250_remove(struct platform_device *pdev)
+{
+ struct mtk8250_data *data = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ serial8250_unregister_port(data->line);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mtk8250_runtime_suspend(&pdev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused mtk8250_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -255,7 +269,7 @@ static int mtk8250_suspend(struct device *dev)
return 0;
}
-static int mtk8250_resume(struct device *dev)
+static int __maybe_unused mtk8250_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -263,7 +277,6 @@ static int mtk8250_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops mtk8250_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
@@ -275,20 +288,20 @@ static const struct of_device_id mtk8250_of_match[] = {
{ .compatible = "mediatek,mt6577-uart" },
{ /* Sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mtk8250_of_match);
static struct platform_driver mtk8250_platform_driver = {
.driver = {
- .name = "mt6577-uart",
- .pm = &mtk8250_pm_ops,
- .of_match_table = mtk8250_of_match,
- .suppress_bind_attrs = true,
-
+ .name = "mt6577-uart",
+ .pm = &mtk8250_pm_ops,
+ .of_match_table = mtk8250_of_match,
},
.probe = mtk8250_probe,
+ .remove = mtk8250_remove,
};
-builtin_platform_driver(mtk8250_platform_driver);
+module_platform_driver(mtk8250_platform_driver);
-#ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
static int __init early_mtk8250_setup(struct earlycon_device *device,
const char *options)
{
@@ -302,3 +315,7 @@ static int __init early_mtk8250_setup(struct earlycon_device *device,
OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup);
#endif
+
+MODULE_AUTHOR("Matthias Brugger");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 33021c1f7d55..c7ed3d2bc8b2 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -335,6 +335,7 @@ static struct platform_driver of_platform_serial_driver = {
.driver = {
.name = "of_serial",
.of_match_table = of_platform_serial_table,
+ .pm = &of_serial_pm_ops,
},
.probe = of_platform_serial_probe,
.remove = of_platform_serial_remove,
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index a2c0734c76e2..6f760510e46d 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -318,8 +318,7 @@ static void omap_8250_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = up->port.private_data;
unsigned char cval = 0;
unsigned int baud;
@@ -682,9 +681,8 @@ static void omap_8250_shutdown(struct uart_port *port)
static void omap_8250_throttle(struct uart_port *port)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
pm_runtime_get_sync(port->dev);
@@ -697,11 +695,40 @@ static void omap_8250_throttle(struct uart_port *port)
pm_runtime_put_autosuspend(port->dev);
}
+static int omap_8250_rs485_config(struct uart_port *port,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ /* Clamp the delays to [0, 100ms] */
+ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+ rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
+
+ port->rs485 = *rs485;
+
+ /*
+ * Both serial8250_em485_init and serial8250_em485_destroy
+ * are idempotent
+ */
+ if (rs485->flags & SER_RS485_ENABLED) {
+ int ret = serial8250_em485_init(up);
+
+ if (ret) {
+ rs485->flags &= ~SER_RS485_ENABLED;
+ port->rs485.flags &= ~SER_RS485_ENABLED;
+ }
+ return ret;
+ }
+
+ serial8250_em485_destroy(up);
+
+ return 0;
+}
+
static void omap_8250_unthrottle(struct uart_port *port)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
pm_runtime_get_sync(port->dev);
@@ -1146,6 +1173,7 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.shutdown = omap_8250_shutdown;
up.port.throttle = omap_8250_throttle;
up.port.unthrottle = omap_8250_unthrottle;
+ up.port.rs485_config = omap_8250_rs485_config;
if (pdev->dev.of_node) {
const struct of_device_id *id;
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 7cd6f9a90542..98862aa5bb58 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -55,7 +55,6 @@ struct pci_serial_quirk {
struct serial_private {
struct pci_dev *dev;
unsigned int nr;
- void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES];
struct pci_serial_quirk *quirk;
int line[0];
};
@@ -85,15 +84,13 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port,
return -EINVAL;
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
- if (!priv->remapped_bar[bar])
- priv->remapped_bar[bar] = pci_ioremap_bar(dev, bar);
- if (!priv->remapped_bar[bar])
+ if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
return -ENOMEM;
port->port.iotype = UPIO_MEM;
port->port.iobase = 0;
port->port.mapbase = pci_resource_start(dev, bar) + offset;
- port->port.membase = priv->remapped_bar[bar] + offset;
+ port->port.membase = pcim_iomap_table(dev)[bar] + offset;
port->port.regshift = regshift;
} else {
port->port.iotype = UPIO_PORT;
@@ -721,7 +718,7 @@ static int pci_ni8430_init(struct pci_dev *dev)
*/
pcibios_resource_to_bus(dev->bus, &region, &dev->resource[bar]);
device_window = ((region.start + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
- | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
+ | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
writel(device_window, p + MITE_IOWBSR1);
/* Set window access to go to RAMSEL IO address space */
@@ -803,12 +800,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
unsigned int pi;
unsigned short sub_serports;
- pi = (c & 0xff);
+ pi = c & 0xff;
- if (pi == 2) {
+ if (pi == 2)
return 1;
- } else if ((pi == 0) &&
- (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
+
+ if ((pi == 0) && (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
/* two possibilities: 0x30ps encodes number of parallel and
* serial ports, or 0x1000 indicates *something*. This is not
* immediately obvious, since the 2s1p+4s configuration seems
@@ -816,12 +813,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
* advertising the same function 3 as the 4s+2s1p config.
*/
sub_serports = dev->subsystem_device & 0xf;
- if (sub_serports > 0) {
+ if (sub_serports > 0)
return sub_serports;
- } else {
- dev_err(&dev->dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
- return 0;
- }
+
+ dev_err(&dev->dev,
+ "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
+ return 0;
}
moan_device("unknown NetMos/Mostech program interface", dev);
@@ -842,21 +839,21 @@ static int pci_netmos_init(struct pci_dev *dev)
return 0;
switch (dev->device) { /* FALLTHROUGH on all */
- case PCI_DEVICE_ID_NETMOS_9904:
- case PCI_DEVICE_ID_NETMOS_9912:
- case PCI_DEVICE_ID_NETMOS_9922:
- case PCI_DEVICE_ID_NETMOS_9900:
- num_serial = pci_netmos_9900_numports(dev);
- break;
+ case PCI_DEVICE_ID_NETMOS_9904:
+ case PCI_DEVICE_ID_NETMOS_9912:
+ case PCI_DEVICE_ID_NETMOS_9922:
+ case PCI_DEVICE_ID_NETMOS_9900:
+ num_serial = pci_netmos_9900_numports(dev);
+ break;
- default:
- if (num_serial == 0 ) {
- moan_device("unknown NetMos/Mostech device", dev);
- }
+ default:
+ break;
}
- if (num_serial == 0)
+ if (num_serial == 0) {
+ moan_device("unknown NetMos/Mostech device", dev);
return -ENODEV;
+ }
return num_serial;
}
@@ -1198,8 +1195,9 @@ static int pci_quatech_has_qmcr(struct uart_8250_port *port)
static int pci_quatech_test(struct uart_8250_port *port)
{
- u8 reg;
- u8 qopr = pci_quatech_rqopr(port);
+ u8 reg, qopr;
+
+ qopr = pci_quatech_rqopr(port);
pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1);
reg = pci_quatech_rqopr(port) & 0xC0;
if (reg != QPCR_TEST_GET1)
@@ -1286,6 +1284,7 @@ static int pci_quatech_init(struct pci_dev *dev)
unsigned long base = pci_resource_start(dev, 0);
if (base) {
u32 tmp;
+
outl(inl(base + 0x38) | 0x00002000, base + 0x38);
tmp = inl(base + 0x3c);
outl(tmp | 0x01000000, base + 0x3c);
@@ -1334,29 +1333,6 @@ static int pci_default_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, board->reg_shift);
}
-static int pci_pericom_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
-{
- unsigned int bar, offset = board->first_offset, maxnr;
-
- bar = FL_GET_BASE(board->flags);
- if (board->flags & FL_BASE_BARS)
- bar += idx;
- else
- offset += idx * board->uart_offset;
-
- maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
- (board->reg_shift + 3);
-
- if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
- return 1;
-
- port->port.uartclk = 14745600;
-
- return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
static int
ce4100_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1541,10 +1517,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
static int pci_fintek_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485)
{
+ struct pci_dev *pci_dev = to_pci_dev(port->dev);
u8 setting;
u8 *index = (u8 *) port->private_data;
- struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev,
- dev);
pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting);
@@ -1766,7 +1741,7 @@ xr17v35x_has_slave(struct serial_private *priv)
const int dev_id = priv->dev->device;
return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) ||
- (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
+ (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
}
static int
@@ -1866,8 +1841,8 @@ pci_fastcom335_setup(struct serial_private *priv,
static int
pci_wch_ch353_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16550A;
@@ -1876,8 +1851,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
static int
pci_wch_ch38x_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16850;
@@ -2246,16 +2221,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.exit = pci_plx9050_exit,
},
/*
- * Pericom
- */
- {
- .vendor = PCI_VENDOR_ID_PERICOM,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
- },
- /*
* PLX
*/
{
@@ -3733,15 +3698,10 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 921600,
.reg_shift = 2,
},
- /*
- * Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on,
- * but is overridden by byt_set_termios.
- */
[pbn_byt] = {
.flags = FL_BASE0,
.num_ports = 1,
.base_baud = 2764800,
- .uart_offset = 0x80,
.reg_shift = 2,
},
[pbn_qrk] = {
@@ -3840,6 +3800,20 @@ static const struct pci_device_id blacklist[] = {
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
+ /* Moxa Smartio MUE boards handled by 8250_moxa */
+ { PCI_VDEVICE(MOXA, 0x1024), },
+ { PCI_VDEVICE(MOXA, 0x1025), },
+ { PCI_VDEVICE(MOXA, 0x1045), },
+ { PCI_VDEVICE(MOXA, 0x1144), },
+ { PCI_VDEVICE(MOXA, 0x1160), },
+ { PCI_VDEVICE(MOXA, 0x1161), },
+ { PCI_VDEVICE(MOXA, 0x1182), },
+ { PCI_VDEVICE(MOXA, 0x1183), },
+ { PCI_VDEVICE(MOXA, 0x1322), },
+ { PCI_VDEVICE(MOXA, 0x1342), },
+ { PCI_VDEVICE(MOXA, 0x1381), },
+ { PCI_VDEVICE(MOXA, 0x1683), },
+
/* Intel platforms with MID UART */
{ PCI_VDEVICE(INTEL, 0x081b), },
{ PCI_VDEVICE(INTEL, 0x081c), },
@@ -4027,12 +4001,6 @@ void pciserial_remove_ports(struct serial_private *priv)
for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]);
- for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
- if (priv->remapped_bar[i])
- iounmap(priv->remapped_bar[i]);
- priv->remapped_bar[i] = NULL;
- }
-
/*
* Find the exit quirks.
*/
@@ -4104,7 +4072,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
board = &pci_boards[ent->driver_data];
- rc = pci_enable_device(dev);
+ rc = pcim_enable_device(dev);
pci_save_state(dev);
if (rc)
return rc;
@@ -4123,7 +4091,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
*/
rc = serial_pci_guess_board(dev, &tmp);
if (rc)
- goto disable;
+ return rc;
} else {
/*
* We matched an explicit entry. If we are able to
@@ -4139,16 +4107,11 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
}
priv = pciserial_init_ports(dev, board);
- if (!IS_ERR(priv)) {
- pci_set_drvdata(dev, priv);
- return 0;
- }
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
- rc = PTR_ERR(priv);
-
- disable:
- pci_disable_device(dev);
- return rc;
+ pci_set_drvdata(dev, priv);
+ return 0;
}
static void pciserial_remove_one(struct pci_dev *dev)
@@ -4156,8 +4119,6 @@ static void pciserial_remove_one(struct pci_dev *dev)
struct serial_private *priv = pci_get_drvdata(dev);
pciserial_remove_ports(priv);
-
- pci_disable_device(dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -4538,7 +4499,7 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_2_921600 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
- PCI_ANY_ID , PCI_ANY_ID, 0, 0,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_8_1152000 },
/*
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 658b392d1170..34f05ed78b68 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -357,8 +357,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
/* Fujitsu Wacom 1FGT Tablet PC device */
{ "FUJ02E9", 0 },
/*
- * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
- * disguise)
+ * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6
+ * in disguise).
*/
{ "LTS0001", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
@@ -367,12 +367,14 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "PNPCXXX", UNKNOWN_DEV },
/* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
- /* Winbond CIR port, should not be probed. We should keep track
- of it to prevent the legacy serial driver from probing it */
+ /*
+ * Winbond CIR port, should not be probed. We should keep track of
+ * it to prevent the legacy serial driver from probing it.
+ */
{ "WEC1022", CIR_PORT },
/*
- * SMSC IrCC SIR/FIR port, should not be probed by serial driver
- * as well so its own driver can bind to it.
+ * SMSC IrCC SIR/FIR port, should not be probed by serial driver as
+ * well so its own driver can bind to it.
*/
{ "SMCF010", CIR_PORT },
{ "", 0 }
@@ -380,35 +382,35 @@ static const struct pnp_device_id pnp_dev_table[] = {
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-static char *modem_names[] = {
+static const char *modem_names[] = {
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
"56K", "56k", "K56", "33.6", "28.8", "14.4",
"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
"33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
};
-static int check_name(char *name)
+static bool check_name(const char *name)
{
- char **tmp;
+ const char **tmp;
for (tmp = modem_names; *tmp; tmp++)
if (strstr(name, *tmp))
- return 1;
+ return true;
- return 0;
+ return false;
}
-static int check_resources(struct pnp_dev *dev)
+static bool check_resources(struct pnp_dev *dev)
{
- resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
- int i;
+ static const resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
+ unsigned int i;
for (i = 0; i < ARRAY_SIZE(base); i++) {
if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/*
@@ -425,8 +427,8 @@ static int check_resources(struct pnp_dev *dev)
static int serial_pnp_guess_board(struct pnp_dev *dev)
{
if (!(check_name(pnp_dev_name(dev)) ||
- (dev->card && check_name(dev->card->name))))
- return -ENODEV;
+ (dev->card && check_name(dev->card->name))))
+ return -ENODEV;
if (check_resources(dev))
return 0;
@@ -462,11 +464,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
} else
return -ENODEV;
-#ifdef SERIAL_DEBUG_PNP
- printk(KERN_DEBUG
- "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
- uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
-#endif
+ dev_dbg(&dev->dev,
+ "Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
+ uart.port.iobase, &uart.port.mapbase,
+ uart.port.irq, uart.port.iotype);
+
if (flags & CIR_PORT) {
uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.type = PORT_8250_CIR;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 8d262bce97e4..e213da01a3d7 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
+#include <linux/timer.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -52,7 +53,7 @@
#define DEBUG_AUTOCONF(fmt...) do { } while (0)
#endif
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
* Here we define the default xmit fifo size used for each type of UART.
@@ -250,9 +251,11 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
-/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
-workaround of errata A-008006 which states that tx_loadsz should be
-configured less than Maximum supported fifo bytes */
+ /*
+ * tx_loadsz is set to 63-bytes instead of 64-bytes to implement
+ * workaround of errata A-008006 which states that tx_loadsz should
+ * be configured less than Maximum supported fifo bytes.
+ */
[PORT_16550A_FSL64] = {
.name = "16550A_FSL64",
.fifo_size = 64,
@@ -522,6 +525,20 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
+static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
+{
+ unsigned char mcr = serial_in(p, UART_MCR);
+
+ if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial_out(p, UART_MCR, mcr);
+}
+
+static void serial8250_em485_handle_start_tx(unsigned long arg);
+static void serial8250_em485_handle_stop_tx(unsigned long arg);
+
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
{
serial8250_clear_fifos(p);
@@ -546,6 +563,73 @@ void serial8250_rpm_put(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_rpm_put);
+/**
+ * serial8250_em485_init() - put uart_8250_port into rs485 emulating
+ * @p: uart_8250_port port instance
+ *
+ * The function is used to start rs485 software emulating on the
+ * &struct uart_8250_port* @p. Namely, RTS is switched before/after
+ * transmission. The function is idempotent, so it is safe to call it
+ * multiple times.
+ *
+ * The caller MUST enable interrupt on empty shift register before
+ * calling serial8250_em485_init(). This interrupt is not a part of
+ * 8250 standard, but implementation defined.
+ *
+ * The function is supposed to be called from .rs485_config callback
+ * or from any other callback protected with p->port.lock spinlock.
+ *
+ * See also serial8250_em485_destroy()
+ *
+ * Return 0 - success, -errno - otherwise
+ */
+int serial8250_em485_init(struct uart_8250_port *p)
+{
+ if (p->em485 != NULL)
+ return 0;
+
+ p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC);
+ if (p->em485 == NULL)
+ return -ENOMEM;
+
+ setup_timer(&p->em485->stop_tx_timer,
+ serial8250_em485_handle_stop_tx, (unsigned long)p);
+ setup_timer(&p->em485->start_tx_timer,
+ serial8250_em485_handle_start_tx, (unsigned long)p);
+ p->em485->active_timer = NULL;
+
+ serial8250_em485_rts_after_send(p);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_init);
+
+/**
+ * serial8250_em485_destroy() - put uart_8250_port into normal state
+ * @p: uart_8250_port port instance
+ *
+ * The function is used to stop rs485 software emulating on the
+ * &struct uart_8250_port* @p. The function is idempotent, so it is safe to
+ * call it multiple times.
+ *
+ * The function is supposed to be called from .rs485_config callback
+ * or from any other callback protected with p->port.lock spinlock.
+ *
+ * See also serial8250_em485_init()
+ */
+void serial8250_em485_destroy(struct uart_8250_port *p)
+{
+ if (p->em485 == NULL)
+ return;
+
+ del_timer(&p->em485->start_tx_timer);
+ del_timer(&p->em485->stop_tx_timer);
+
+ kfree(p->em485);
+ p->em485 = NULL;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
+
/*
* These two wrappers ensure that enable_runtime_pm_tx() can be called more than
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
@@ -731,22 +815,16 @@ static int size_fifo(struct uart_8250_port *up)
*/
static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
{
- unsigned char old_dll, old_dlm, old_lcr;
- unsigned int id;
+ unsigned char old_lcr;
+ unsigned int id, old_dl;
old_lcr = serial_in(p, UART_LCR);
serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A);
+ old_dl = serial_dl_read(p);
+ serial_dl_write(p, 0);
+ id = serial_dl_read(p);
+ serial_dl_write(p, old_dl);
- old_dll = serial_in(p, UART_DLL);
- old_dlm = serial_in(p, UART_DLM);
-
- serial_out(p, UART_DLL, 0);
- serial_out(p, UART_DLM, 0);
-
- id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8;
-
- serial_out(p, UART_DLL, old_dll);
- serial_out(p, UART_DLM, old_dlm);
serial_out(p, UART_LCR, old_lcr);
return id;
@@ -1238,8 +1316,7 @@ static void autoconfig(struct uart_8250_port *up)
out_lock:
spin_unlock_irqrestore(&port->lock, flags);
if (up->capabilities != old_capabilities) {
- printk(KERN_WARNING
- "ttyS%d: detected caps %08x should be %08x\n",
+ pr_warn("ttyS%d: detected caps %08x should be %08x\n",
serial_index(port), old_capabilities,
up->capabilities);
}
@@ -1304,7 +1381,69 @@ static void autoconfig_irq(struct uart_8250_port *up)
port->irq = (irq > 0) ? irq : 0;
}
-static inline void __stop_tx(struct uart_8250_port *p)
+static void serial8250_stop_rx(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ serial8250_rpm_get(up);
+
+ up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
+ up->port.read_status_mask &= ~UART_LSR_DR;
+ serial_port_out(port, UART_IER, up->ier);
+
+ serial8250_rpm_put(up);
+}
+
+static void __do_stop_tx_rs485(struct uart_8250_port *p)
+{
+ if (!p->em485)
+ return;
+
+ serial8250_em485_rts_after_send(p);
+ /*
+ * Empty the RX FIFO, we are not interested in anything
+ * received during the half-duplex transmission.
+ */
+ if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ serial8250_clear_fifos(p);
+}
+
+static void serial8250_em485_handle_stop_tx(unsigned long arg)
+{
+ struct uart_8250_port *p = (struct uart_8250_port *)arg;
+ struct uart_8250_em485 *em485 = p->em485;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->port.lock, flags);
+ if (em485 &&
+ em485->active_timer == &em485->stop_tx_timer) {
+ __do_stop_tx_rs485(p);
+ em485->active_timer = NULL;
+ }
+ spin_unlock_irqrestore(&p->port.lock, flags);
+}
+
+static void __stop_tx_rs485(struct uart_8250_port *p)
+{
+ struct uart_8250_em485 *em485 = p->em485;
+
+ if (!em485)
+ return;
+
+ /*
+ * __do_stop_tx_rs485 is going to set RTS according to config
+ * AND flush RX FIFO if required.
+ */
+ if (p->port.rs485.delay_rts_after_send > 0) {
+ em485->active_timer = &em485->stop_tx_timer;
+ mod_timer(&em485->stop_tx_timer, jiffies +
+ p->port.rs485.delay_rts_after_send * HZ / 1000);
+ } else {
+ __do_stop_tx_rs485(p);
+ }
+}
+
+static inline void __do_stop_tx(struct uart_8250_port *p)
{
if (p->ier & UART_IER_THRI) {
p->ier &= ~UART_IER_THRI;
@@ -1313,6 +1452,28 @@ static inline void __stop_tx(struct uart_8250_port *p)
}
}
+static inline void __stop_tx(struct uart_8250_port *p)
+{
+ struct uart_8250_em485 *em485 = p->em485;
+
+ if (em485) {
+ unsigned char lsr = serial_in(p, UART_LSR);
+ /*
+ * To provide required timeing and allow FIFO transfer,
+ * __stop_tx_rs485 must be called only when both FIFO and
+ * shift register are empty. It is for device driver to enable
+ * interrupt on TEMT.
+ */
+ if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
+ return;
+
+ del_timer(&em485->start_tx_timer);
+ em485->active_timer = NULL;
+ }
+ __do_stop_tx(p);
+ __stop_tx_rs485(p);
+}
+
static void serial8250_stop_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -1330,12 +1491,10 @@ static void serial8250_stop_tx(struct uart_port *port)
serial8250_rpm_put(up);
}
-static void serial8250_start_tx(struct uart_port *port)
+static inline void __start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- serial8250_rpm_get_tx(up);
-
if (up->dma && !up->dma->tx_dma(up))
return;
@@ -1345,6 +1504,7 @@ static void serial8250_start_tx(struct uart_port *port)
if (up->bugs & UART_BUG_TXEN) {
unsigned char lsr;
+
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
if (lsr & UART_LSR_THRE)
@@ -1361,33 +1521,83 @@ static void serial8250_start_tx(struct uart_port *port)
}
}
-static void serial8250_throttle(struct uart_port *port)
+static inline void start_tx_rs485(struct uart_port *port)
{
- port->throttle(port);
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
+ unsigned char mcr;
+
+ if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ serial8250_stop_rx(&up->port);
+
+ del_timer(&em485->stop_tx_timer);
+ em485->active_timer = NULL;
+
+ mcr = serial_in(up, UART_MCR);
+ if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
+ !!(mcr & UART_MCR_RTS)) {
+ if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial_out(up, UART_MCR, mcr);
+
+ if (up->port.rs485.delay_rts_before_send > 0) {
+ em485->active_timer = &em485->start_tx_timer;
+ mod_timer(&em485->start_tx_timer, jiffies +
+ up->port.rs485.delay_rts_before_send * HZ / 1000);
+ return;
+ }
+ }
+
+ __start_tx(port);
}
-static void serial8250_unthrottle(struct uart_port *port)
+static void serial8250_em485_handle_start_tx(unsigned long arg)
{
- port->unthrottle(port);
+ struct uart_8250_port *p = (struct uart_8250_port *)arg;
+ struct uart_8250_em485 *em485 = p->em485;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->port.lock, flags);
+ if (em485 &&
+ em485->active_timer == &em485->start_tx_timer) {
+ __start_tx(&p->port);
+ em485->active_timer = NULL;
+ }
+ spin_unlock_irqrestore(&p->port.lock, flags);
}
-static void serial8250_stop_rx(struct uart_port *port)
+static void serial8250_start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
- serial8250_rpm_get(up);
+ serial8250_rpm_get_tx(up);
- up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
- up->port.read_status_mask &= ~UART_LSR_DR;
- serial_port_out(port, UART_IER, up->ier);
+ if (em485 &&
+ em485->active_timer == &em485->start_tx_timer)
+ return;
- serial8250_rpm_put(up);
+ if (em485)
+ start_tx_rs485(port);
+ else
+ __start_tx(port);
+}
+
+static void serial8250_throttle(struct uart_port *port)
+{
+ port->throttle(port);
+}
+
+static void serial8250_unthrottle(struct uart_port *port)
+{
+ port->unthrottle(port);
}
static void serial8250_disable_ms(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
/* no MSR capabilities */
if (up->bugs & UART_BUG_NOMSR)
@@ -1412,81 +1622,85 @@ static void serial8250_enable_ms(struct uart_port *port)
serial8250_rpm_put(up);
}
+static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
+{
+ struct uart_port *port = &up->port;
+ unsigned char ch;
+ char flag = TTY_NORMAL;
+
+ if (likely(lsr & UART_LSR_DR))
+ ch = serial_in(up, UART_RX);
+ else
+ /*
+ * Intel 82571 has a Serial Over Lan device that will
+ * set UART_LSR_BI without setting UART_LSR_DR when
+ * it receives a break. To avoid reading from the
+ * receive buffer without UART_LSR_DR bit set, we
+ * just force the read character to be 0
+ */
+ ch = 0;
+
+ port->icount.rx++;
+
+ lsr |= up->lsr_saved_flags;
+ up->lsr_saved_flags = 0;
+
+ if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+ if (lsr & UART_LSR_BI) {
+ lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+ port->icount.brk++;
+ /*
+ * We do the SysRQ and SAK checking
+ * here because otherwise the break
+ * may get masked by ignore_status_mask
+ * or read_status_mask.
+ */
+ if (uart_handle_break(port))
+ return;
+ } else if (lsr & UART_LSR_PE)
+ port->icount.parity++;
+ else if (lsr & UART_LSR_FE)
+ port->icount.frame++;
+ if (lsr & UART_LSR_OE)
+ port->icount.overrun++;
+
+ /*
+ * Mask off conditions which should be ignored.
+ */
+ lsr &= port->read_status_mask;
+
+ if (lsr & UART_LSR_BI) {
+ DEBUG_INTR("handling break....");
+ flag = TTY_BREAK;
+ } else if (lsr & UART_LSR_PE)
+ flag = TTY_PARITY;
+ else if (lsr & UART_LSR_FE)
+ flag = TTY_FRAME;
+ }
+ if (uart_handle_sysrq_char(port, ch))
+ return;
+
+ uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
+}
+
/*
* serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled
* by this Rx routine.
*/
-unsigned char
-serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
+unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
{
struct uart_port *port = &up->port;
- unsigned char ch;
int max_count = 256;
- char flag;
do {
- if (likely(lsr & UART_LSR_DR))
- ch = serial_in(up, UART_RX);
- else
- /*
- * Intel 82571 has a Serial Over Lan device that will
- * set UART_LSR_BI without setting UART_LSR_DR when
- * it receives a break. To avoid reading from the
- * receive buffer without UART_LSR_DR bit set, we
- * just force the read character to be 0
- */
- ch = 0;
-
- flag = TTY_NORMAL;
- port->icount.rx++;
-
- lsr |= up->lsr_saved_flags;
- up->lsr_saved_flags = 0;
-
- if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
- if (lsr & UART_LSR_BI) {
- lsr &= ~(UART_LSR_FE | UART_LSR_PE);
- port->icount.brk++;
- /*
- * We do the SysRQ and SAK checking
- * here because otherwise the break
- * may get masked by ignore_status_mask
- * or read_status_mask.
- */
- if (uart_handle_break(port))
- goto ignore_char;
- } else if (lsr & UART_LSR_PE)
- port->icount.parity++;
- else if (lsr & UART_LSR_FE)
- port->icount.frame++;
- if (lsr & UART_LSR_OE)
- port->icount.overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- lsr &= port->read_status_mask;
-
- if (lsr & UART_LSR_BI) {
- DEBUG_INTR("handling break....");
- flag = TTY_BREAK;
- } else if (lsr & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (lsr & UART_LSR_FE)
- flag = TTY_FRAME;
- }
- if (uart_handle_sysrq_char(port, ch))
- goto ignore_char;
-
- uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
-
-ignore_char:
+ serial8250_read_char(up, lsr);
+ if (--max_count == 0)
+ break;
lsr = serial_in(up, UART_LSR);
- } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0));
- spin_unlock(&port->lock);
+ } while (lsr & (UART_LSR_DR | UART_LSR_BI));
+
tty_flip_buffer_push(&port->state->port);
- spin_lock(&port->lock);
return lsr;
}
EXPORT_SYMBOL_GPL(serial8250_rx_chars);
@@ -1519,11 +1733,9 @@ void serial8250_tx_chars(struct uart_8250_port *up)
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
- if (up->capabilities & UART_CAP_HFIFO) {
- if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) !=
- BOTH_EMPTY)
- break;
- }
+ if ((up->capabilities & UART_CAP_HFIFO) &&
+ (serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
+ break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -1752,6 +1964,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
unsigned int tmout;
+
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR);
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
@@ -1985,23 +2198,23 @@ int serial8250_do_startup(struct uart_port *port)
serial8250_set_mctrl(port, port->mctrl);
- /* Serial over Lan (SoL) hack:
- Intel 8257x Gigabit ethernet chips have a
- 16550 emulation, to be used for Serial Over Lan.
- Those chips take a longer time than a normal
- serial device to signalize that a transmission
- data was queued. Due to that, the above test generally
- fails. One solution would be to delay the reading of
- iir. However, this is not reliable, since the timeout
- is variable. So, let's just don't test if we receive
- TX irq. This way, we'll never enable UART_BUG_TXEN.
+ /*
+ * Serial over Lan (SoL) hack:
+ * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be
+ * used for Serial Over Lan. Those chips take a longer time than a
+ * normal serial device to signalize that a transmission data was
+ * queued. Due to that, the above test generally fails. One solution
+ * would be to delay the reading of iir. However, this is not
+ * reliable, since the timeout is variable. So, let's just don't
+ * test if we receive TX irq. This way, we'll never enable
+ * UART_BUG_TXEN.
*/
if (up->port.flags & UPF_NO_TXEN_TEST)
goto dont_test_tx_en;
/*
- * Do a quick test to see if we receive an
- * interrupt when we enable the TX irq.
+ * Do a quick test to see if we receive an interrupt when we enable
+ * the TX irq.
*/
serial_port_out(port, UART_IER, UART_IER_THRI);
lsr = serial_port_in(port, UART_LSR);
@@ -2084,8 +2297,12 @@ void serial8250_do_shutdown(struct uart_port *port)
/*
* Disable interrupts from this port
*/
+ spin_lock_irqsave(&port->lock, flags);
up->ier = 0;
serial_port_out(port, UART_IER, 0);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ synchronize_irq(port->irq);
if (up->dma)
serial8250_release_dma(up);
@@ -2251,9 +2468,9 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
serial_port_out(port, 0x2, quot_frac);
}
-static unsigned int
-serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+static unsigned int serial8250_get_baud_rate(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int tolerance = port->uartclk / 100;
@@ -2270,7 +2487,7 @@ serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
void
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+ struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char cval;
@@ -2583,8 +2800,7 @@ static int do_get_rxtrig(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- struct uart_8250_port *up =
- container_of(uport, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(uport);
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1)
return -EINVAL;
@@ -2620,8 +2836,7 @@ static int do_set_rxtrig(struct tty_port *port, unsigned char bytes)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- struct uart_8250_port *up =
- container_of(uport, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(uport);
int rxtrig;
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 ||
@@ -2745,8 +2960,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
-static const char *
-serial8250_type(struct uart_port *port)
+static const char *serial8250_type(struct uart_port *port)
{
int type = port->type;
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index bab6b3ae2540..1b7bd26555b7 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -35,7 +35,7 @@ struct uniphier8250_priv {
spinlock_t atomic_write_lock;
};
-#ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
static int __init uniphier_early_console_setup(struct earlycon_device *device,
const char *options)
{
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index b03cb5175113..64742a086ae3 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -262,7 +262,12 @@ config SERIAL_8250_RSA
bool "Support RSA serial ports"
depends on SERIAL_8250_EXTENDED
help
- ::: To be written :::
+ Say Y here if you have a IODATA RSA-DV II/S ISA card and
+ would like to use its >115kbps speeds.
+ You will need to provide module parameter "probe_rsa", or boot-time
+ parameter 8250.probe_rsa with I/O addresses of this card then.
+
+ If you don't have such card, or if unsure, say N.
config SERIAL_8250_ACORN
tristate "Acorn expansion card serial port support"
@@ -272,6 +277,30 @@ config SERIAL_8250_ACORN
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
+config SERIAL_8250_BCM2835AUX
+ tristate "BCM2835 auxiliar mini UART support"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on SERIAL_8250 && SERIAL_8250_SHARE_IRQ
+ help
+ Support for the BCM2835 auxiliar mini UART.
+
+ Features and limitations of the UART are
+ Registers are similar to 16650 registers,
+ set bits in the control registers that are unsupported
+ are ignored and read back as 0
+ 7/8 bit operation with 1 start and 1 stop bit
+ 8 symbols deep fifo for rx and tx
+ SW controlled RTS and SW readable CTS
+ Clock rate derived from system clock
+ Uses 8 times oversampling (compared to 16 times for 16650)
+ Missing break detection (but break generation)
+ Missing framing error detection
+ Missing parity bit
+ Missing receive time-out interrupt
+ Missing DCD, DSR, DTR and RI signals
+
+ If unsure, say N.
+
config SERIAL_8250_FSL
bool
depends on SERIAL_8250_CONSOLE
@@ -295,6 +324,7 @@ config SERIAL_8250_EM
config SERIAL_8250_RT288X
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
depends on SERIAL_8250
+ depends on MIPS || COMPILE_TEST
default y if MIPS_ALCHEMY || SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
help
Selecting this option will add support for the alternate register
@@ -346,7 +376,7 @@ config SERIAL_8250_LPC18XX
serial port, say Y to this option. If unsure, say Y.
config SERIAL_8250_MT6577
- bool "Mediatek serial port support"
+ tristate "Mediatek serial port support"
depends on SERIAL_8250 && ARCH_MEDIATEK
help
If you have a Mediatek based board and want to use the
@@ -360,9 +390,10 @@ config SERIAL_8250_UNIPHIER
serial ports, say Y to this option. If unsure, say N.
config SERIAL_8250_INGENIC
- bool "Support for Ingenic SoC serial ports"
- depends on OF_FLATTREE
- select LIBFDT
+ tristate "Support for Ingenic SoC serial ports"
+ depends on SERIAL_8250
+ depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON
+ depends on MIPS || COMPILE_TEST
help
If you have a system using an Ingenic SoC and wish to make use of
its UARTs, say Y to this option. If unsure, say N.
@@ -378,6 +409,16 @@ config SERIAL_8250_MID
present on the UART found on Intel Medfield SOC and various other
Intel platforms.
+config SERIAL_8250_MOXA
+ tristate "MOXA SmartIO MUE support"
+ depends on SERIAL_8250 && PCI
+ help
+ Say Y here if you have a Moxa SmartIO MUE multiport serial card.
+ If unsure, say N.
+
+ This driver can also be built as a module. The module will be called
+ 8250_moxa. If you want to do that, say M here.
+
config SERIAL_OF_PLATFORM
tristate "Devicetree based probing for 8250 ports"
depends on SERIAL_8250 && OF
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index b9b9bca5b6c3..c9a2d6ed87e9 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
+obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
@@ -28,6 +29,7 @@ obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
+obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 4d180c9423ef..933c2688dd7e 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -28,7 +28,7 @@
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
-
+
======================================================================*/
#include <linux/module.h>
@@ -257,7 +257,7 @@ static const struct serial_quirk quirks[] = {
};
-static int serial_config(struct pcmcia_device * link);
+static int serial_config(struct pcmcia_device *link);
static void serial_remove(struct pcmcia_device *link)
@@ -309,7 +309,7 @@ static int serial_probe(struct pcmcia_device *link)
dev_dbg(&link->dev, "serial_attach()\n");
/* Create new serial device */
- info = kzalloc(sizeof (*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->p_dev = link;
@@ -339,7 +339,7 @@ static void serial_detach(struct pcmcia_device *link)
/*====================================================================*/
-static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
+static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
unsigned int iobase, int irq)
{
struct uart_8250_port uart;
@@ -441,16 +441,20 @@ static int simple_config(struct pcmcia_device *link)
struct serial_info *info = link->priv;
int i = -ENODEV, try;
- /* First pass: look for a config entry that looks normal.
- * Two tries: without IO aliases, then with aliases */
+ /*
+ * First pass: look for a config entry that looks normal.
+ * Two tries: without IO aliases, then with aliases.
+ */
link->config_flags |= CONF_AUTO_SET_VPP;
for (try = 0; try < 4; try++)
if (!pcmcia_loop_config(link, simple_config_check, &try))
goto found_port;
- /* Second pass: try to find an entry that isn't picky about
- its base address, then try to grab any standard serial port
- address, and finally try to get any free port. */
+ /*
+ * Second pass: try to find an entry that isn't picky about
+ * its base address, then try to grab any standard serial port
+ * address, and finally try to get any free port.
+ */
if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
goto found_port;
@@ -480,8 +484,10 @@ static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
if (p_dev->resource[1]->end)
return -EINVAL;
- /* The quad port cards have bad CIS's, so just look for a
- window larger than 8 ports and assume it will be right */
+ /*
+ * The quad port cards have bad CIS's, so just look for a
+ * window larger than 8 ports and assume it will be right.
+ */
if (p_dev->resource[0]->end <= 8)
return -EINVAL;
@@ -527,8 +533,8 @@ static int multi_config(struct pcmcia_device *link)
info->multi = 2;
if (pcmcia_loop_config(link, multi_config_check_notpicky,
&base2)) {
- dev_warn(&link->dev, "no usable port range "
- "found, giving up\n");
+ dev_warn(&link->dev,
+ "no usable port range found, giving up\n");
return -ENODEV;
}
}
@@ -600,7 +606,7 @@ static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data)
}
-static int serial_config(struct pcmcia_device * link)
+static int serial_config(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
int i;
@@ -623,8 +629,10 @@ static int serial_config(struct pcmcia_device * link)
break;
}
- /* Another check for dual-serial cards: look for either serial or
- multifunction cards that ask for appropriate IO port ranges */
+ /*
+ * Another check for dual-serial cards: look for either serial or
+ * multifunction cards that ask for appropriate IO port ranges.
+ */
if ((info->multi == 0) &&
(link->has_func_id) &&
(link->socket->pcmcia_pfc == 0) &&
@@ -701,7 +709,7 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
- PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001", 0x18df0ba0, 0x831b1064),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
@@ -797,30 +805,30 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232 1.00.",0x19ca78af,0x69fb7490),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232", 0x19ca78af, 0xb6bc0235),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232", 0x63f2e0bd, 0xb9e175d3),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232-5", 0x63f2e0bd, 0xfce33442),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232", 0x3beb8cf2, 0x171e7190),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232-5", 0x3beb8cf2, 0x20da4262),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF428", 0x3beb8cf2, 0xea5dd57d),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF500", 0x3beb8cf2, 0xd77255fa),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: IC232", 0x3beb8cf2, 0x6a709903),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: SL232", 0x3beb8cf2, 0x18430676),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: XL232", 0x3beb8cf2, 0x6f933767),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial+Parallel Port: SP230", 0x3beb8cf2, 0xdb9e58bc),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(2, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(3, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
/* too generic */
/* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 39721ec4f415..13d4ed6caac4 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -610,6 +610,7 @@ config SERIAL_UARTLITE_CONSOLE
bool "Support for console on Xilinx uartlite serial port"
depends on SERIAL_UARTLITE=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
Say Y here if you wish to use a Xilinx uartlite as the system
console (the system console is the device which receives all kernel
@@ -732,7 +733,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support"
- depends on SUPERH || ARCH_SHMOBILE || H8300 || COMPILE_TEST
+ depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST
select SERIAL_CORE
config SERIAL_SH_SCI_NR_UARTS
@@ -745,6 +746,12 @@ config SERIAL_SH_SCI_CONSOLE
depends on SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE
+config SERIAL_SH_SCI_EARLYCON
+ bool "Support for early console on SuperH SCI(F)"
+ depends on SERIAL_SH_SCI=y
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+
config SERIAL_SH_SCI_DMA
bool "DMA support"
depends on SERIAL_SH_SCI && DMA_ENGINE
@@ -793,17 +800,6 @@ config SERIAL_CORE_CONSOLE
config CONSOLE_POLL
bool
-config SERIAL_68328
- bool "68328 serial support"
- depends on M68328 || M68EZ328 || M68VZ328
- help
- This driver supports the built-in serial port of the Motorola 68328
- (standard, EZ and VZ varieties).
-
-config SERIAL_68328_RTS_CTS
- bool "Support RTS/CTS on 68328 serial port"
- depends on SERIAL_68328
-
config SERIAL_MCF
bool "Coldfire serial support"
depends on COLDFIRE
@@ -1606,6 +1602,28 @@ config SERIAL_STM32_CONSOLE
depends on SERIAL_STM32=y
select SERIAL_CORE_CONSOLE
+config SERIAL_MVEBU_UART
+ bool "Marvell EBU serial port support"
+ select SERIAL_CORE
+ help
+ This driver is for Marvell EBU SoC's UART. If you have a machine
+ based on the Armada-3700 SoC and wish to use the on-board serial
+ port,
+ say 'Y' here.
+ Otherwise, say 'N'.
+
+config SERIAL_MVEBU_CONSOLE
+ bool "Console on Marvell EBU serial port"
+ depends on SERIAL_MVEBU_UART
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+ default y
+ help
+ Say 'Y' here if you wish to use Armada-3700 UART as the system console.
+ (the system console is the device which receives all kernel messages
+ and warnings and which allows logins in single user mode)
+ Otherwise, say 'N'.
+
endmenu
config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index b391c9b31960..8c261adac04e 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -34,7 +34,6 @@ obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
obj-$(CONFIG_SERIAL_MAX310X) += max310x.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
-obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_MCF) += mcf.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
@@ -91,6 +90,7 @@ obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
+obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index c0da0ccbbcf5..7c198e0a3178 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -187,7 +187,7 @@ static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = {
[REG_DMACR] = ZX_UART011_DMACR,
};
-static struct vendor_data vendor_zte = {
+static struct vendor_data vendor_zte __maybe_unused = {
.reg_offset = pl011_zte_offsets,
.access_32b = true,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
@@ -420,7 +420,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
/* Optionally make use of an RX channel as well */
chan = dma_request_slave_channel(dev, "rx");
- if (!chan && plat->dma_rx_param) {
+ if (!chan && plat && plat->dma_rx_param) {
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
if (!chan) {
@@ -1167,7 +1167,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
/* Disable RX and TX DMA */
while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
- barrier();
+ cpu_relax();
spin_lock_irq(&uap->port.lock);
uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
@@ -1611,7 +1611,7 @@ static void pl011_put_poll_char(struct uart_port *port,
container_of(port, struct uart_amba_port, port);
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
- barrier();
+ cpu_relax();
pl011_write(ch, uap, REG_DR);
}
@@ -1947,6 +1947,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
lcr_h |= UART01x_LCRH_PEN;
if (!(termios->c_cflag & PARODD))
lcr_h |= UART01x_LCRH_EPS;
+ if (termios->c_cflag & CMSPAR)
+ lcr_h |= UART011_LCRH_SPS;
}
if (uap->fifosize > 1)
lcr_h |= UART01x_LCRH_FEN;
@@ -2150,7 +2152,7 @@ static void pl011_console_putchar(struct uart_port *port, int ch)
container_of(port, struct uart_amba_port, port);
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
- barrier();
+ cpu_relax();
pl011_write(ch, uap, REG_DR);
}
@@ -2158,7 +2160,7 @@ static void
pl011_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_amba_port *uap = amba_ports[co->index];
- unsigned int status, old_cr = 0, new_cr;
+ unsigned int old_cr = 0, new_cr;
unsigned long flags;
int locked = 1;
@@ -2188,9 +2190,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
* Finally, wait for transmitter to become empty
* and restore the TCR
*/
- do {
- status = pl011_read(uap, REG_FR);
- } while (status & UART01x_FR_BUSY);
+ while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
+ cpu_relax();
if (!uap->vendor->always_enabled)
pl011_write(old_cr, uap, REG_CR);
@@ -2302,13 +2303,13 @@ static struct console amba_console = {
static void pl011_putc(struct uart_port *port, int c)
{
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
- ;
+ cpu_relax();
if (port->iotype == UPIO_MEM32)
writel(c, port->membase + UART01x_DR);
else
writeb(c, port->membase + UART01x_DR);
while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
- ;
+ cpu_relax();
}
static void pl011_early_write(struct console *con, const char *s, unsigned n)
@@ -2327,7 +2328,6 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
device->con->write = pl011_early_write;
return 0;
}
-EARLYCON_DECLARE(pl011, pl011_early_console_setup);
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
#else
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 03ebe401fff7..3a1de5c87cb4 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -576,7 +576,6 @@ static int __init arc_early_console_setup(struct earlycon_device *dev,
dev->con->write = arc_early_serial_write;
return 0;
}
-EARLYCON_DECLARE(arc_uart, arc_early_console_setup);
OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup);
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 1c0884d8ef32..d9439e6ab719 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -159,8 +159,9 @@ struct atmel_uart_port {
u32 rts_high;
u32 rts_low;
bool ms_irq_enabled;
- bool is_usart; /* usart or uart */
- struct timer_list uart_timer; /* uart timer */
+ u32 rtor; /* address of receiver timeout register if it exists */
+ bool has_hw_timer;
+ struct timer_list uart_timer;
bool suspended;
unsigned int pending;
@@ -1710,19 +1711,24 @@ static void atmel_get_ip_name(struct uart_port *port)
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
int name = atmel_uart_readl(port, ATMEL_US_NAME);
u32 version;
- int usart, uart;
- /* usart and uart ascii */
- usart = 0x55534152;
- uart = 0x44424755;
-
- atmel_port->is_usart = false;
-
- if (name == usart) {
- dev_dbg(port->dev, "This is usart\n");
- atmel_port->is_usart = true;
- } else if (name == uart) {
- dev_dbg(port->dev, "This is uart\n");
- atmel_port->is_usart = false;
+ u32 usart, dbgu_uart, new_uart;
+ /* ASCII decoding for IP version */
+ usart = 0x55534152; /* USAR(T) */
+ dbgu_uart = 0x44424755; /* DBGU */
+ new_uart = 0x55415254; /* UART */
+
+ atmel_port->has_hw_timer = false;
+
+ if (name == new_uart) {
+ dev_dbg(port->dev, "Uart with hw timer");
+ atmel_port->has_hw_timer = true;
+ atmel_port->rtor = ATMEL_UA_RTOR;
+ } else if (name == usart) {
+ dev_dbg(port->dev, "Usart\n");
+ atmel_port->has_hw_timer = true;
+ atmel_port->rtor = ATMEL_US_RTOR;
+ } else if (name == dbgu_uart) {
+ dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
} else {
/* fallback for older SoCs: use version field */
version = atmel_uart_readl(port, ATMEL_US_VERSION);
@@ -1730,12 +1736,12 @@ static void atmel_get_ip_name(struct uart_port *port)
case 0x302:
case 0x10213:
dev_dbg(port->dev, "This version is usart\n");
- atmel_port->is_usart = true;
+ atmel_port->has_hw_timer = true;
+ atmel_port->rtor = ATMEL_US_RTOR;
break;
case 0x203:
case 0x10202:
dev_dbg(port->dev, "This version is uart\n");
- atmel_port->is_usart = false;
break;
default:
dev_err(port->dev, "Not supported ip name nor version, set to uart\n");
@@ -1835,12 +1841,13 @@ static int atmel_startup(struct uart_port *port)
if (atmel_use_pdc_rx(port)) {
/* set UART timeout */
- if (!atmel_port->is_usart) {
+ if (!atmel_port->has_hw_timer) {
mod_timer(&atmel_port->uart_timer,
jiffies + uart_poll_timeout(port));
/* set USART timeout */
} else {
- atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT);
+ atmel_uart_writel(port, atmel_port->rtor,
+ PDC_RX_TIMEOUT);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO);
atmel_uart_writel(port, ATMEL_US_IER,
@@ -1850,12 +1857,13 @@ static int atmel_startup(struct uart_port *port)
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
} else if (atmel_use_dma_rx(port)) {
/* set UART timeout */
- if (!atmel_port->is_usart) {
+ if (!atmel_port->has_hw_timer) {
mod_timer(&atmel_port->uart_timer,
jiffies + uart_poll_timeout(port));
/* set USART timeout */
} else {
- atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT);
+ atmel_uart_writel(port, atmel_port->rtor,
+ PDC_RX_TIMEOUT);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO);
atmel_uart_writel(port, ATMEL_US_IER,
@@ -2478,13 +2486,13 @@ static int __init atmel_console_init(void)
struct atmel_uart_data *pdata =
dev_get_platdata(&atmel_default_console_device->dev);
int id = pdata->num;
- struct atmel_uart_port *port = &atmel_ports[id];
+ struct atmel_uart_port *atmel_port = &atmel_ports[id];
- port->backup_imr = 0;
- port->uart.line = id;
+ atmel_port->backup_imr = 0;
+ atmel_port->uart.line = id;
add_preferred_console(ATMEL_DEVICENAME, id, NULL);
- ret = atmel_init_port(port, atmel_default_console_device);
+ ret = atmel_init_port(atmel_port, atmel_default_console_device);
if (ret)
return ret;
register_console(&atmel_console);
@@ -2599,23 +2607,23 @@ static int atmel_serial_resume(struct platform_device *pdev)
#define atmel_serial_resume NULL
#endif
-static void atmel_serial_probe_fifos(struct atmel_uart_port *port,
+static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port,
struct platform_device *pdev)
{
- port->fifo_size = 0;
- port->rts_low = 0;
- port->rts_high = 0;
+ atmel_port->fifo_size = 0;
+ atmel_port->rts_low = 0;
+ atmel_port->rts_high = 0;
if (of_property_read_u32(pdev->dev.of_node,
"atmel,fifo-size",
- &port->fifo_size))
+ &atmel_port->fifo_size))
return;
- if (!port->fifo_size)
+ if (!atmel_port->fifo_size)
return;
- if (port->fifo_size < ATMEL_MIN_FIFO_SIZE) {
- port->fifo_size = 0;
+ if (atmel_port->fifo_size < ATMEL_MIN_FIFO_SIZE) {
+ atmel_port->fifo_size = 0;
dev_err(&pdev->dev, "Invalid FIFO size\n");
return;
}
@@ -2628,22 +2636,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *port,
* Threshold to a reasonably high value respecting this 16 data
* empirical rule when possible.
*/
- port->rts_high = max_t(int, port->fifo_size >> 1,
- port->fifo_size - ATMEL_RTS_HIGH_OFFSET);
- port->rts_low = max_t(int, port->fifo_size >> 2,
- port->fifo_size - ATMEL_RTS_LOW_OFFSET);
+ atmel_port->rts_high = max_t(int, atmel_port->fifo_size >> 1,
+ atmel_port->fifo_size - ATMEL_RTS_HIGH_OFFSET);
+ atmel_port->rts_low = max_t(int, atmel_port->fifo_size >> 2,
+ atmel_port->fifo_size - ATMEL_RTS_LOW_OFFSET);
dev_info(&pdev->dev, "Using FIFO (%u data)\n",
- port->fifo_size);
+ atmel_port->fifo_size);
dev_dbg(&pdev->dev, "RTS High Threshold : %2u data\n",
- port->rts_high);
+ atmel_port->rts_high);
dev_dbg(&pdev->dev, "RTS Low Threshold : %2u data\n",
- port->rts_low);
+ atmel_port->rts_low);
}
static int atmel_serial_probe(struct platform_device *pdev)
{
- struct atmel_uart_port *port;
+ struct atmel_uart_port *atmel_port;
struct device_node *np = pdev->dev.of_node;
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
void *data;
@@ -2674,99 +2682,133 @@ static int atmel_serial_probe(struct platform_device *pdev)
goto err;
}
- port = &atmel_ports[ret];
- port->backup_imr = 0;
- port->uart.line = ret;
- atmel_serial_probe_fifos(port, pdev);
+ atmel_port = &atmel_ports[ret];
+ atmel_port->backup_imr = 0;
+ atmel_port->uart.line = ret;
+ atmel_serial_probe_fifos(atmel_port, pdev);
- spin_lock_init(&port->lock_suspended);
+ spin_lock_init(&atmel_port->lock_suspended);
- ret = atmel_init_port(port, pdev);
+ ret = atmel_init_port(atmel_port, pdev);
if (ret)
goto err_clear_bit;
- port->gpios = mctrl_gpio_init(&port->uart, 0);
- if (IS_ERR(port->gpios)) {
- ret = PTR_ERR(port->gpios);
+ atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0);
+ if (IS_ERR(atmel_port->gpios)) {
+ ret = PTR_ERR(atmel_port->gpios);
goto err_clear_bit;
}
- if (!atmel_use_pdc_rx(&port->uart)) {
+ if (!atmel_use_pdc_rx(&atmel_port->uart)) {
ret = -ENOMEM;
data = kmalloc(sizeof(struct atmel_uart_char)
* ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
if (!data)
goto err_alloc_ring;
- port->rx_ring.buf = data;
+ atmel_port->rx_ring.buf = data;
}
- rs485_enabled = port->uart.rs485.flags & SER_RS485_ENABLED;
+ rs485_enabled = atmel_port->uart.rs485.flags & SER_RS485_ENABLED;
- ret = uart_add_one_port(&atmel_uart, &port->uart);
+ ret = uart_add_one_port(&atmel_uart, &atmel_port->uart);
if (ret)
goto err_add_port;
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
- if (atmel_is_console_port(&port->uart)
+ if (atmel_is_console_port(&atmel_port->uart)
&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
/*
* The serial core enabled the clock for us, so undo
* the clk_prepare_enable() in atmel_console_setup()
*/
- clk_disable_unprepare(port->clk);
+ clk_disable_unprepare(atmel_port->clk);
}
#endif
device_init_wakeup(&pdev->dev, 1);
- platform_set_drvdata(pdev, port);
+ platform_set_drvdata(pdev, atmel_port);
/*
* The peripheral clock has been disabled by atmel_init_port():
* enable it before accessing I/O registers
*/
- clk_prepare_enable(port->clk);
+ clk_prepare_enable(atmel_port->clk);
if (rs485_enabled) {
- atmel_uart_writel(&port->uart, ATMEL_US_MR,
+ atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR,
ATMEL_US_USMODE_NORMAL);
- atmel_uart_writel(&port->uart, ATMEL_US_CR, ATMEL_US_RTSEN);
+ atmel_uart_writel(&atmel_port->uart, ATMEL_US_CR,
+ ATMEL_US_RTSEN);
}
/*
* Get port name of usart or uart
*/
- atmel_get_ip_name(&port->uart);
+ atmel_get_ip_name(&atmel_port->uart);
/*
* The peripheral clock can now safely be disabled till the port
* is used
*/
- clk_disable_unprepare(port->clk);
+ clk_disable_unprepare(atmel_port->clk);
return 0;
err_add_port:
- kfree(port->rx_ring.buf);
- port->rx_ring.buf = NULL;
+ kfree(atmel_port->rx_ring.buf);
+ atmel_port->rx_ring.buf = NULL;
err_alloc_ring:
- if (!atmel_is_console_port(&port->uart)) {
- clk_put(port->clk);
- port->clk = NULL;
+ if (!atmel_is_console_port(&atmel_port->uart)) {
+ clk_put(atmel_port->clk);
+ atmel_port->clk = NULL;
}
err_clear_bit:
- clear_bit(port->uart.line, atmel_ports_in_use);
+ clear_bit(atmel_port->uart.line, atmel_ports_in_use);
err:
return ret;
}
+/*
+ * Even if the driver is not modular, it makes sense to be able to
+ * unbind a device: there can be many bound devices, and there are
+ * situations where dynamic binding and unbinding can be useful.
+ *
+ * For example, a connected device can require a specific firmware update
+ * protocol that needs bitbanging on IO lines, but use the regular serial
+ * port in the normal case.
+ */
+static int atmel_serial_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ int ret = 0;
+
+ tasklet_kill(&atmel_port->tasklet);
+
+ device_init_wakeup(&pdev->dev, 0);
+
+ ret = uart_remove_one_port(&atmel_uart, port);
+
+ kfree(atmel_port->rx_ring.buf);
+
+ /* "port" is allocated statically, so we shouldn't free it */
+
+ clear_bit(port->line, atmel_ports_in_use);
+
+ clk_put(atmel_port->clk);
+ atmel_port->clk = NULL;
+
+ return ret;
+}
+
static struct platform_driver atmel_serial_driver = {
.probe = atmel_serial_probe,
+ .remove = atmel_serial_remove,
.suspend = atmel_serial_suspend,
.resume = atmel_serial_resume,
.driver = {
.name = "atmel_usart",
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
- .suppress_bind_attrs = true,
},
};
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index b3a4e0cdddaa..5beafd2d2218 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -450,6 +450,7 @@ static int uart_clps711x_probe(struct platform_device *pdev)
struct clps711x_port *s;
struct resource *res;
struct clk *uart_clk;
+ int irq;
if (index < 0 || index >= UART_CLPS711X_NR)
return -EINVAL;
@@ -467,12 +468,13 @@ static int uart_clps711x_probe(struct platform_device *pdev)
if (IS_ERR(s->port.membase))
return PTR_ERR(s->port.membase);
- s->port.irq = platform_get_irq(pdev, 0);
- if (IS_ERR_VALUE(s->port.irq))
- return s->port.irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ s->port.irq = irq;
s->rx_irq = platform_get_irq(pdev, 1);
- if (IS_ERR_VALUE(s->rx_irq))
+ if (s->rx_irq < 0)
return s->rx_irq;
if (!np) {
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index f13f2ebd215b..c0172bf54a9b 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -1413,9 +1413,8 @@ rs_stop(struct tty_struct *tty)
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
STOP_CHAR(info->port.tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
- if (tty->termios.c_iflag & IXON ) {
+ if (I_IXON(tty))
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
- }
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
local_irq_restore(flags);
@@ -1436,9 +1435,8 @@ rs_start(struct tty_struct *tty)
info->xmit.tail,SERIAL_XMIT_SIZE)));
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
- if (tty->termios.c_iflag & IXON ) {
+ if (I_IXON(tty))
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
- }
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
if (!info->uses_dma_out &&
@@ -2968,7 +2966,7 @@ static int rs_raw_write(struct tty_struct *tty,
local_save_flags(flags);
DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
- DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
+ DFLOW(DEBUG_LOG(info->line, "ldisc\n"));
/* The local_irq_disable/restore_flags pairs below are needed
@@ -3161,13 +3159,12 @@ rs_throttle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("throttle %s: %lu....\n", tty_name(tty),
- (unsigned long)tty->ldisc.chars_in_buffer(tty));
+ printk("throttle %s ....\n", tty_name(tty));
#endif
- DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
+ DFLOW(DEBUG_LOG(info->line,"rs_throttle\n"));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
/* Turn off RTS line */
e100_rts(info, 0);
}
@@ -3181,13 +3178,12 @@ rs_unthrottle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("unthrottle %s: %lu....\n", tty_name(tty),
- (unsigned long)tty->ldisc.chars_in_buffer(tty));
+ printk("unthrottle %s ....\n", tty_name(tty));
#endif
- DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
+ DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc\n"));
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
/* Assert RTS line */
e100_rts(info, 1);
}
@@ -3555,8 +3551,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(info);
/* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS))
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty))
rs_start(tty);
}
@@ -3615,7 +3610,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
local_irq_restore(flags);
return;
}
- info->port.flags |= ASYNC_CLOSING;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
@@ -3654,7 +3648,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
schedule_timeout_interruptible(info->port.close_delay);
wake_up_interruptible(&info->port.open_wait);
}
- info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+ info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
local_irq_restore(flags);
/* port closed */
@@ -3767,9 +3761,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (tty->termios.c_cflag & CLOCAL) {
- do_clocal = 1;
- }
+ if (C_CLOCAL(tty))
+ do_clocal = 1;
/*
* Block waiting for the carrier detect and the line to become
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index a80cdad114f3..02ad6953b167 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -453,7 +453,7 @@ static struct uart_driver digicolor_uart = {
static int digicolor_uart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- int ret, index;
+ int irq, ret, index;
struct digicolor_port *dp;
struct resource *res;
struct clk *uart_clk;
@@ -481,9 +481,10 @@ static int digicolor_uart_probe(struct platform_device *pdev)
if (IS_ERR(dp->port.membase))
return PTR_ERR(dp->port.membase);
- dp->port.irq = platform_get_irq(pdev, 0);
- if (IS_ERR_VALUE(dp->port.irq))
- return dp->port.irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ dp->port.irq = irq;
dp->port.iotype = UPIO_MEM;
dp->port.uartclk = clk_get_rate(uart_clk);
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index 3f2423690d01..067783f0523c 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -19,7 +19,8 @@
#include <linux/io.h>
#include <linux/serial_core.h>
#include <linux/sizes.h>
-#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/fixmap.h>
@@ -28,22 +29,15 @@
#include <asm/serial.h>
static struct console early_con = {
- .name = "uart", /* 8250 console switch requires this name */
+ .name = "uart", /* fixed up at earlycon registration */
.flags = CON_PRINTBUFFER | CON_BOOT,
- .index = -1,
+ .index = 0,
};
static struct earlycon_device early_console_dev = {
.con = &early_con,
};
-extern struct earlycon_id __earlycon_table[];
-static const struct earlycon_id __earlycon_table_sentinel
- __used __section(__earlycon_table_end);
-
-static const struct of_device_id __earlycon_of_table_sentinel
- __used __section(__earlycon_of_table_end);
-
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
{
void __iomem *base;
@@ -61,6 +55,39 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
return base;
}
+static void __init earlycon_init(struct earlycon_device *device,
+ const char *name)
+{
+ struct console *earlycon = device->con;
+ struct uart_port *port = &device->port;
+ const char *s;
+ size_t len;
+
+ /* scan backwards from end of string for first non-numeral */
+ for (s = name + strlen(name);
+ s > name && s[-1] >= '0' && s[-1] <= '9';
+ s--)
+ ;
+ if (*s)
+ earlycon->index = simple_strtoul(s, NULL, 10);
+ len = s - name;
+ strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name)));
+ earlycon->data = &early_console_dev;
+
+ if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
+ port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
+ pr_info("%s%d at MMIO%s %pa (options '%s')\n",
+ earlycon->name, earlycon->index,
+ (port->iotype == UPIO_MEM) ? "" :
+ (port->iotype == UPIO_MEM16) ? "16" :
+ (port->iotype == UPIO_MEM32) ? "32" : "32be",
+ &port->mapbase, device->options);
+ else
+ pr_info("%s%d at I/O port 0x%lx (options '%s')\n",
+ earlycon->name, earlycon->index,
+ port->iobase, device->options);
+}
+
static int __init parse_options(struct earlycon_device *device, char *options)
{
struct uart_port *port = &device->port;
@@ -97,19 +124,6 @@ static int __init parse_options(struct earlycon_device *device, char *options)
strlcpy(device->options, options, length);
}
- if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
- port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
- pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
- (port->iotype == UPIO_MEM) ? "" :
- (port->iotype == UPIO_MEM16) ? "16" :
- (port->iotype == UPIO_MEM32) ? "32" : "32be",
- (unsigned long long)port->mapbase,
- device->options);
- else
- pr_info("Early serial console at I/O port 0x%lx (options '%s')\n",
- port->iobase,
- device->options);
-
return 0;
}
@@ -127,7 +141,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
if (port->mapbase)
port->membase = earlycon_map(port->mapbase, 64);
- early_console_dev.con->data = &early_console_dev;
+ earlycon_init(&early_console_dev, match->name);
err = match->setup(&early_console_dev, buf);
if (err < 0)
return err;
@@ -166,7 +180,7 @@ int __init setup_earlycon(char *buf)
if (early_con.flags & CON_ENABLED)
return -EALREADY;
- for (match = __earlycon_table; match->name[0]; match++) {
+ for (match = __earlycon_table; match < __earlycon_table_end; match++) {
size_t len = strlen(match->name);
if (strncmp(buf, match->name, len))
@@ -204,20 +218,62 @@ static int __init param_setup_earlycon(char *buf)
}
early_param("earlycon", param_setup_earlycon);
-int __init of_setup_earlycon(unsigned long addr,
- int (*setup)(struct earlycon_device *, const char *))
+#ifdef CONFIG_OF_EARLY_FLATTREE
+
+int __init of_setup_earlycon(const struct earlycon_id *match,
+ unsigned long node,
+ const char *options)
{
int err;
struct uart_port *port = &early_console_dev.port;
+ const __be32 *val;
+ bool big_endian;
+ u64 addr;
spin_lock_init(&port->lock);
port->iotype = UPIO_MEM;
+ addr = of_flat_dt_translate_address(node);
+ if (addr == OF_BAD_ADDR) {
+ pr_warn("[%s] bad address\n", match->name);
+ return -ENXIO;
+ }
port->mapbase = addr;
port->uartclk = BASE_BAUD * 16;
- port->membase = earlycon_map(addr, SZ_4K);
+ port->membase = earlycon_map(port->mapbase, SZ_4K);
+
+ val = of_get_flat_dt_prop(node, "reg-offset", NULL);
+ if (val)
+ port->mapbase += be32_to_cpu(*val);
+ val = of_get_flat_dt_prop(node, "reg-shift", NULL);
+ if (val)
+ port->regshift = be32_to_cpu(*val);
+ big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL ||
+ (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
+ of_get_flat_dt_prop(node, "native-endian", NULL) != NULL);
+ val = of_get_flat_dt_prop(node, "reg-io-width", NULL);
+ if (val) {
+ switch (be32_to_cpu(*val)) {
+ case 1:
+ port->iotype = UPIO_MEM;
+ break;
+ case 2:
+ port->iotype = UPIO_MEM16;
+ break;
+ case 4:
+ port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32;
+ break;
+ default:
+ pr_warn("[%s] unsupported reg-io-width\n", match->name);
+ return -EINVAL;
+ }
+ }
- early_console_dev.con->data = &early_console_dev;
- err = setup(&early_console_dev, NULL);
+ if (options) {
+ strlcpy(early_console_dev.options, options,
+ sizeof(early_console_dev.options));
+ }
+ earlycon_init(&early_console_dev, match->name);
+ err = match->setup(&early_console_dev, options);
if (err < 0)
return err;
if (!early_console_dev.con->write)
@@ -227,3 +283,5 @@ int __init of_setup_earlycon(unsigned long addr,
register_console(early_console_dev.con);
return 0;
}
+
+#endif /* CONFIG_OF_EARLY_FLATTREE */
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 88246f7e435a..2085a6cfa44b 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -395,8 +395,10 @@ static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
if (h1 == 0 && h2 == 0) {
*received_cts = 0;
+ *more = 0;
return IFX_SPI_HEADER_0;
} else if (h1 == 0xffff && h2 == 0xffff) {
+ *more = 0;
/* spi_slave_cts remains as it was */
return IFX_SPI_HEADER_F;
}
@@ -688,6 +690,7 @@ static void ifx_spi_complete(void *ctx)
ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
(size_t)actual_length);
} else {
+ more = 0;
dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
ifx_dev->spi_msg.status);
}
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 9362f54c816c..231e7d5caf6c 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2166,7 +2166,8 @@ static int imx_serial_port_suspend(struct device *dev)
uart_suspend_port(&imx_reg, &sport->port);
- return 0;
+ /* Needed to enable clock in suspend_noirq */
+ return clk_prepare(sport->clk_ipg);
}
static int imx_serial_port_resume(struct device *dev)
@@ -2179,6 +2180,8 @@ static int imx_serial_port_resume(struct device *dev)
uart_resume_port(&imx_reg, &sport->port);
+ clk_unprepare(sport->clk_ipg);
+
return 0;
}
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 524e86ab3cae..c5ddfe542451 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -529,7 +529,6 @@ void jsm_input(struct jsm_channel *ch)
int data_len;
unsigned long lock_flags;
int len = 0;
- int n = 0;
int s = 0;
int i = 0;
@@ -569,8 +568,7 @@ void jsm_input(struct jsm_channel *ch)
*If the device is not open, or CREAD is off, flush
*input data and return immediately.
*/
- if (!tp ||
- !(tp->termios.c_cflag & CREAD) ) {
+ if (!tp || !C_CREAD(tp)) {
jsm_dbg(READ, &ch->ch_bd->pci_dev,
"input. dropping %d bytes on port %d...\n",
@@ -598,16 +596,15 @@ void jsm_input(struct jsm_channel *ch)
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
len = tty_buffer_request_room(port, data_len);
- n = len;
/*
- * n now contains the most amount of data we can copy,
+ * len now contains the most amount of data we can copy,
* bounded either by the flip buffer size or the amount
* of data the card actually has pending...
*/
- while (n) {
+ while (len) {
s = ((head >= tail) ? head : RQUEUESIZE) - tail;
- s = min(s, n);
+ s = min(s, len);
if (s <= 0)
break;
@@ -638,7 +635,7 @@ void jsm_input(struct jsm_channel *ch)
tty_insert_flip_string(port, ch->ch_rqueue + tail, s);
}
tail += s;
- n -= s;
+ len -= s;
/* Flip queue if needed */
tail &= rmask;
}
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index 0eeb64f2499c..68765f7c2645 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -47,59 +47,26 @@
#define BAUD_RATE 115200
#include <linux/serial_core.h>
-#include "m32r_sio.h"
#include "m32r_sio_reg.h"
-/*
- * Debugging.
- */
-#if 0
-#define DEBUG_AUTOCONF(fmt...) printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...) do { } while (0)
-#endif
-
-#if 0
-#define DEBUG_INTR(fmt...) printk(fmt)
-#else
-#define DEBUG_INTR(fmt...) do { } while (0)
-#endif
-
#define PASS_LIMIT 256
-#define BASE_BAUD 115200
-
/* Standard COM flags */
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
-/*
- * SERIAL_PORT_DFNS tells us about built-in ports that have no
- * standard enumeration mechanism. Platforms that can find all
- * serial ports via mechanisms like ACPI or PCI need not supply it.
- */
+static const struct {
+ unsigned int port;
+ unsigned int irq;
+} old_serial_port[] = {
#if defined(CONFIG_PLAT_USRV)
-
-#define SERIAL_PORT_DFNS \
- /* UART CLK PORT IRQ FLAGS */ \
- { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */
-
-#else /* !CONFIG_PLAT_USRV */
-
-#if defined(CONFIG_SERIAL_M32R_PLDSIO)
-#define SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \
- STD_COM_FLAGS }, /* ttyS0 */
+ /* PORT IRQ FLAGS */
+ { 0x3F8, PLD_IRQ_UART0 }, /* ttyS0 */
+ { 0x2F8, PLD_IRQ_UART1 }, /* ttyS1 */
+#elif defined(CONFIG_SERIAL_M32R_PLDSIO)
+ { ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV }, /* ttyS0 */
#else
-#define SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, \
- STD_COM_FLAGS }, /* ttyS0 */
+ { M32R_SIO_OFFSET, M32R_IRQ_SIO0_R }, /* ttyS0 */
#endif
-
-#endif /* !CONFIG_PLAT_USRV */
-
-static struct old_serial_port old_serial_port[] = {
- SERIAL_PORT_DFNS
};
#define UART_NR ARRAY_SIZE(old_serial_port)
@@ -108,19 +75,7 @@ struct uart_sio_port {
struct uart_port port;
struct timer_list timer; /* "no irq" timer */
struct list_head list; /* ports on this IRQ */
- unsigned short rev;
- unsigned char acr;
unsigned char ier;
- unsigned char lcr;
- unsigned char mcr_mask; /* mask of user bits */
- unsigned char mcr_force; /* mask of forced bits */
- unsigned char lsr_break_flag;
-
- /*
- * We provide a per-port pm hook.
- */
- void (*pm)(struct uart_port *port,
- unsigned int state, unsigned int old);
};
struct irq_info {
@@ -345,14 +300,8 @@ static void receive_chars(struct uart_sio_port *up, int *status)
*/
*status &= up->port.read_status_mask;
- if (up->port.line == up->port.cons->index) {
- /* Recover the break flag from console xmit */
- *status |= up->lsr_break_flag;
- up->lsr_break_flag = 0;
- }
-
if (*status & UART_LSR_BI) {
- DEBUG_INTR("handling break....");
+ pr_debug("handling break....\n");
flag = TTY_BREAK;
} else if (*status & UART_LSR_PE)
flag = TTY_PARITY;
@@ -413,7 +362,7 @@ static void transmit_chars(struct uart_sio_port *up)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
- DEBUG_INTR("THRE...");
+ pr_debug("THRE...\n");
if (uart_circ_empty(xmit))
m32r_sio_stop_tx(&up->port);
@@ -425,7 +374,7 @@ static void transmit_chars(struct uart_sio_port *up)
static inline void m32r_sio_handle_port(struct uart_sio_port *up,
unsigned int status)
{
- DEBUG_INTR("status = %x...", status);
+ pr_debug("status = %x...\n", status);
if (status & 0x04)
receive_chars(up, &status);
@@ -453,7 +402,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
struct list_head *l, *end = NULL;
int pass_counter = 0;
- DEBUG_INTR("m32r_sio_interrupt(%d)...", irq);
+ pr_debug("m32r_sio_interrupt(%d)...\n", irq);
#ifdef CONFIG_SERIAL_M32R_PLDSIO
// if (irq == PLD_IRQ_SIO0_SND)
@@ -493,7 +442,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
spin_unlock(&i->lock);
- DEBUG_INTR("end.\n");
+ pr_debug("end.\n");
return IRQ_HANDLED;
}
@@ -782,20 +731,9 @@ static void m32r_sio_set_termios(struct uart_port *port,
serial_out(up, UART_IER, up->ier);
- up->lcr = cval; /* Save LCR */
spin_unlock_irqrestore(&up->port.lock, flags);
}
-static void m32r_sio_pm(struct uart_port *port, unsigned int state,
- unsigned int oldstate)
-{
- struct uart_sio_port *up =
- container_of(port, struct uart_sio_port, port);
-
- if (up->pm)
- up->pm(port, state, oldstate);
-}
-
/*
* Resource handling. This is complicated by the fact that resources
* depend on the port type. Maybe we should be claiming the standard
@@ -932,7 +870,6 @@ static struct uart_ops m32r_sio_pops = {
.startup = m32r_sio_startup,
.shutdown = m32r_sio_shutdown,
.set_termios = m32r_sio_set_termios,
- .pm = m32r_sio_pm,
.release_port = m32r_sio_release_port,
.request_port = m32r_sio_request_port,
.config_port = m32r_sio_config_port,
@@ -951,15 +888,14 @@ static void __init m32r_sio_init_ports(void)
return;
first = 0;
- for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port);
- i++, up++) {
+ for (i = 0, up = m32r_sio_ports; i < UART_NR; i++, up++) {
up->port.iobase = old_serial_port[i].port;
up->port.irq = irq_canonicalize(old_serial_port[i].irq);
- up->port.uartclk = old_serial_port[i].baud_base * 16;
- up->port.flags = old_serial_port[i].flags;
- up->port.membase = old_serial_port[i].iomem_base;
- up->port.iotype = old_serial_port[i].io_type;
- up->port.regshift = old_serial_port[i].iomem_reg_shift;
+ up->port.uartclk = BAUD_RATE * 16;
+ up->port.flags = STD_COM_FLAGS;
+ up->port.membase = 0;
+ up->port.iotype = 0;
+ up->port.regshift = 0;
up->port.ops = &m32r_sio_pops;
}
}
@@ -978,9 +914,6 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv)
init_timer(&up->timer);
up->timer.function = m32r_sio_timeout;
- up->mcr_mask = ~0;
- up->mcr_force = 0;
-
uart_add_one_port(drv, &up->port);
}
}
@@ -1112,28 +1045,6 @@ static struct uart_driver m32r_sio_reg = {
.cons = M32R_SIO_CONSOLE,
};
-/**
- * m32r_sio_suspend_port - suspend one serial port
- * @line: serial line number
- *
- * Suspend one serial port.
- */
-void m32r_sio_suspend_port(int line)
-{
- uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
-/**
- * m32r_sio_resume_port - resume one serial port
- * @line: serial line number
- *
- * Resume one serial port.
- */
-void m32r_sio_resume_port(int line)
-{
- uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
static int __init m32r_sio_init(void)
{
int ret, i;
@@ -1163,8 +1074,5 @@ static void __exit m32r_sio_exit(void)
module_init(m32r_sio_init);
module_exit(m32r_sio_exit);
-EXPORT_SYMBOL(m32r_sio_suspend_port);
-EXPORT_SYMBOL(m32r_sio_resume_port);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic M32R SIO serial driver");
diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h
deleted file mode 100644
index 8129824496c6..000000000000
--- a/drivers/tty/serial/m32r_sio.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * m32r_sio.h
- *
- * Driver for M32R serial ports
- *
- * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- * Based on drivers/serial/8250.h.
- *
- * Copyright (C) 2001 Russell King.
- * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>
- *
- * 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.
- */
-
-#include <linux/pci.h>
-
-struct m32r_sio_probe {
- struct module *owner;
- int (*pci_init_one)(struct pci_dev *dev);
- void (*pci_remove_one)(struct pci_dev *dev);
- void (*pnp_init)(void);
-};
-
-int m32r_sio_register_probe(struct m32r_sio_probe *probe);
-void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
-void m32r_sio_get_irq_map(unsigned int *map);
-void m32r_sio_suspend_port(int line);
-void m32r_sio_resume_port(int line);
-
-struct old_serial_port {
- unsigned int uart;
- unsigned int baud_base;
- unsigned int port;
- unsigned int irq;
- unsigned int flags;
- unsigned char io_type;
- unsigned char __iomem *iomem_base;
- unsigned short iomem_reg_shift;
-};
-
-#define _INLINE_ inline
-
-#define PROBE_RSA (1 << 0)
-#define PROBE_ANY (~0)
-
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index b12a37bd37b6..024445aa0521 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -78,6 +78,7 @@
/* AML_UART_REG5 bits */
#define AML_UART_BAUD_MASK 0x7fffff
#define AML_UART_BAUD_USE BIT(23)
+#define AML_UART_BAUD_XTAL BIT(24)
#define AML_UART_PORT_NUM 6
#define AML_UART_DEV_NAME "ttyAML"
@@ -299,7 +300,12 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
val = readl(port->membase + AML_UART_REG5);
val &= ~AML_UART_BAUD_MASK;
- val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
+ if (port->uartclk == 24000000) {
+ val = ((port->uartclk / 3) / baud) - 1;
+ val |= AML_UART_BAUD_XTAL;
+ } else {
+ val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
+ }
val |= AML_UART_BAUD_USE;
writel(val, port->membase + AML_UART_REG5);
}
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 8c3e51314470..3970d6a9aaca 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -346,7 +346,7 @@ static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
return mpc5xxx_uart_process_int(port);
}
-static struct psc_ops mpc52xx_psc_ops = {
+static const struct psc_ops mpc52xx_psc_ops = {
.fifo_init = mpc52xx_psc_fifo_init,
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
@@ -376,7 +376,7 @@ static struct psc_ops mpc52xx_psc_ops = {
.get_mr1 = mpc52xx_psc_get_mr1,
};
-static struct psc_ops mpc5200b_psc_ops = {
+static const struct psc_ops mpc5200b_psc_ops = {
.fifo_init = mpc52xx_psc_fifo_init,
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
@@ -969,7 +969,7 @@ static u8 mpc5125_psc_get_mr1(struct uart_port *port)
return in_8(&PSC_5125(port)->mr1);
}
-static struct psc_ops mpc5125_psc_ops = {
+static const struct psc_ops mpc5125_psc_ops = {
.fifo_init = mpc5125_psc_fifo_init,
.raw_rx_rdy = mpc5125_psc_raw_rx_rdy,
.raw_tx_rdy = mpc5125_psc_raw_tx_rdy,
@@ -1004,7 +1004,7 @@ static struct psc_ops mpc5125_psc_ops = {
.get_mr1 = mpc5125_psc_get_mr1,
};
-static struct psc_ops mpc512x_psc_ops = {
+static const struct psc_ops mpc512x_psc_ops = {
.fifo_init = mpc512x_psc_fifo_init,
.raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
.raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
index cadfd1cfae2b..4a3021bcc859 100644
--- a/drivers/tty/serial/mpsc.c
+++ b/drivers/tty/serial/mpsc.c
@@ -137,8 +137,6 @@ struct mpsc_port_info {
/* Internal driver state for this ctlr */
u8 ready;
u8 rcv_data;
- tcflag_t c_iflag; /* save termios->c_iflag */
- tcflag_t c_cflag; /* save termios->c_cflag */
/* Info passed in from platform */
u8 mirror_regs; /* Need to mirror regs? */
@@ -1407,9 +1405,6 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
ulong flags;
u32 chr_bits, stop_bits, par;
- pi->c_iflag = termios->c_iflag;
- pi->c_cflag = termios->c_cflag;
-
switch (termios->c_cflag & CSIZE) {
case CS5:
chr_bits = MPSC_MPCR_CL_5;
@@ -1870,12 +1865,12 @@ static int mpsc_shared_map_regs(struct platform_device *pd)
static void mpsc_shared_unmap_regs(void)
{
- if (!mpsc_shared_regs.mpsc_routing_base) {
+ if (mpsc_shared_regs.mpsc_routing_base) {
iounmap(mpsc_shared_regs.mpsc_routing_base);
release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
MPSC_ROUTING_REG_BLOCK_SIZE);
}
- if (!mpsc_shared_regs.sdma_intr_base) {
+ if (mpsc_shared_regs.sdma_intr_base) {
iounmap(mpsc_shared_regs.sdma_intr_base);
release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
MPSC_SDMA_INTR_REG_BLOCK_SIZE);
@@ -1891,44 +1886,39 @@ static void mpsc_shared_unmap_regs(void)
static int mpsc_shared_drv_probe(struct platform_device *dev)
{
struct mpsc_shared_pdata *pdata;
- int rc = -ENODEV;
-
- if (dev->id == 0) {
- rc = mpsc_shared_map_regs(dev);
- if (!rc) {
- pdata = (struct mpsc_shared_pdata *)
- dev_get_platdata(&dev->dev);
-
- mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
- mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
- mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
- mpsc_shared_regs.SDMA_INTR_CAUSE_m =
- pdata->intr_cause_val;
- mpsc_shared_regs.SDMA_INTR_MASK_m =
- pdata->intr_mask_val;
-
- rc = 0;
- }
- }
+ int rc;
- return rc;
+ if (dev->id != 0)
+ return -ENODEV;
+
+ rc = mpsc_shared_map_regs(dev);
+ if (rc)
+ return rc;
+
+ pdata = dev_get_platdata(&dev->dev);
+
+ mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
+ mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
+ mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
+ mpsc_shared_regs.SDMA_INTR_CAUSE_m = pdata->intr_cause_val;
+ mpsc_shared_regs.SDMA_INTR_MASK_m = pdata->intr_mask_val;
+
+ return 0;
}
static int mpsc_shared_drv_remove(struct platform_device *dev)
{
- int rc = -ENODEV;
+ if (dev->id != 0)
+ return -ENODEV;
- if (dev->id == 0) {
- mpsc_shared_unmap_regs();
- mpsc_shared_regs.MPSC_MRR_m = 0;
- mpsc_shared_regs.MPSC_RCRR_m = 0;
- mpsc_shared_regs.MPSC_TCRR_m = 0;
- mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
- mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
- rc = 0;
- }
+ mpsc_shared_unmap_regs();
+ mpsc_shared_regs.MPSC_MRR_m = 0;
+ mpsc_shared_regs.MPSC_RCRR_m = 0;
+ mpsc_shared_regs.MPSC_TCRR_m = 0;
+ mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
+ mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
- return rc;
+ return 0;
}
static struct platform_driver mpsc_shared_driver = {
@@ -1979,10 +1969,6 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
pi->sdma_base_p = r->start;
} else {
mpsc_resource_err("SDMA base");
- if (pi->mpsc_base) {
- iounmap(pi->mpsc_base);
- pi->mpsc_base = NULL;
- }
goto err;
}
@@ -1993,33 +1979,33 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
pi->brg_base_p = r->start;
} else {
mpsc_resource_err("BRG base");
- if (pi->mpsc_base) {
- iounmap(pi->mpsc_base);
- pi->mpsc_base = NULL;
- }
- if (pi->sdma_base) {
- iounmap(pi->sdma_base);
- pi->sdma_base = NULL;
- }
goto err;
}
return 0;
err:
+ if (pi->sdma_base) {
+ iounmap(pi->sdma_base);
+ pi->sdma_base = NULL;
+ }
+ if (pi->mpsc_base) {
+ iounmap(pi->mpsc_base);
+ pi->mpsc_base = NULL;
+ }
return -ENOMEM;
}
static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
{
- if (!pi->mpsc_base) {
+ if (pi->mpsc_base) {
iounmap(pi->mpsc_base);
release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
}
- if (!pi->sdma_base) {
+ if (pi->sdma_base) {
iounmap(pi->sdma_base);
release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
}
- if (!pi->brg_base) {
+ if (pi->brg_base) {
iounmap(pi->brg_base);
release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
}
@@ -2073,36 +2059,37 @@ static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
static int mpsc_drv_probe(struct platform_device *dev)
{
- struct mpsc_port_info *pi;
- int rc = -ENODEV;
-
- pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);
-
- if (dev->id < MPSC_NUM_CTLRS) {
- pi = &mpsc_ports[dev->id];
-
- rc = mpsc_drv_map_regs(pi, dev);
- if (!rc) {
- mpsc_drv_get_platform_data(pi, dev, dev->id);
- pi->port.dev = &dev->dev;
-
- rc = mpsc_make_ready(pi);
- if (!rc) {
- spin_lock_init(&pi->tx_lock);
- rc = uart_add_one_port(&mpsc_reg, &pi->port);
- if (!rc) {
- rc = 0;
- } else {
- mpsc_release_port((struct uart_port *)
- pi);
- mpsc_drv_unmap_regs(pi);
- }
- } else {
- mpsc_drv_unmap_regs(pi);
- }
- }
- }
+ struct mpsc_port_info *pi;
+ int rc;
+
+ dev_dbg(&dev->dev, "mpsc_drv_probe: Adding MPSC %d\n", dev->id);
+
+ if (dev->id >= MPSC_NUM_CTLRS)
+ return -ENODEV;
+
+ pi = &mpsc_ports[dev->id];
+
+ rc = mpsc_drv_map_regs(pi, dev);
+ if (rc)
+ return rc;
+ mpsc_drv_get_platform_data(pi, dev, dev->id);
+ pi->port.dev = &dev->dev;
+
+ rc = mpsc_make_ready(pi);
+ if (rc)
+ goto err_unmap;
+
+ spin_lock_init(&pi->tx_lock);
+ rc = uart_add_one_port(&mpsc_reg, &pi->port);
+ if (rc)
+ goto err_relport;
+
+ return 0;
+err_relport:
+ mpsc_release_port(&pi->port);
+err_unmap:
+ mpsc_drv_unmap_regs(pi);
return rc;
}
@@ -2124,19 +2111,22 @@ static int __init mpsc_drv_init(void)
memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
rc = uart_register_driver(&mpsc_reg);
- if (!rc) {
- rc = platform_driver_register(&mpsc_shared_driver);
- if (!rc) {
- rc = platform_driver_register(&mpsc_driver);
- if (rc) {
- platform_driver_unregister(&mpsc_shared_driver);
- uart_unregister_driver(&mpsc_reg);
- }
- } else {
- uart_unregister_driver(&mpsc_reg);
- }
- }
+ if (rc)
+ return rc;
+
+ rc = platform_driver_register(&mpsc_shared_driver);
+ if (rc)
+ goto err_unreg_uart;
+ rc = platform_driver_register(&mpsc_driver);
+ if (rc)
+ goto err_unreg_plat;
+
+ return 0;
+err_unreg_plat:
+ platform_driver_unregister(&mpsc_shared_driver);
+err_unreg_uart:
+ uart_unregister_driver(&mpsc_reg);
return rc;
}
device_initcall(mpsc_drv_init);
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index dcde955475dc..96d3ce8dc2dc 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1478,7 +1478,6 @@ msm_serial_early_console_setup(struct earlycon_device *device, const char *opt)
device->con->write = msm_serial_early_write;
return 0;
}
-EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup);
OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart",
msm_serial_early_console_setup);
@@ -1500,7 +1499,6 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device,
device->con->write = msm_serial_early_write_dm;
return 0;
}
-EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm);
OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm",
msm_serial_early_console_setup_dm);
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
new file mode 100644
index 000000000000..0ff27818bb87
--- /dev/null
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -0,0 +1,650 @@
+/*
+* ***************************************************************************
+* Copyright (C) 2015 Marvell International Ltd.
+* ***************************************************************************
+* 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 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.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+* ***************************************************************************
+*/
+
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/* Register Map */
+#define UART_RBR 0x00
+#define RBR_BRK_DET BIT(15)
+#define RBR_FRM_ERR_DET BIT(14)
+#define RBR_PAR_ERR_DET BIT(13)
+#define RBR_OVR_ERR_DET BIT(12)
+
+#define UART_TSH 0x04
+
+#define UART_CTRL 0x08
+#define CTRL_SOFT_RST BIT(31)
+#define CTRL_TXFIFO_RST BIT(15)
+#define CTRL_RXFIFO_RST BIT(14)
+#define CTRL_ST_MIRR_EN BIT(13)
+#define CTRL_LPBK_EN BIT(12)
+#define CTRL_SND_BRK_SEQ BIT(11)
+#define CTRL_PAR_EN BIT(10)
+#define CTRL_TWO_STOP BIT(9)
+#define CTRL_TX_HFL_INT BIT(8)
+#define CTRL_RX_HFL_INT BIT(7)
+#define CTRL_TX_EMP_INT BIT(6)
+#define CTRL_TX_RDY_INT BIT(5)
+#define CTRL_RX_RDY_INT BIT(4)
+#define CTRL_BRK_DET_INT BIT(3)
+#define CTRL_FRM_ERR_INT BIT(2)
+#define CTRL_PAR_ERR_INT BIT(1)
+#define CTRL_OVR_ERR_INT BIT(0)
+#define CTRL_RX_INT (CTRL_RX_RDY_INT | CTRL_BRK_DET_INT |\
+ CTRL_FRM_ERR_INT | CTRL_PAR_ERR_INT | CTRL_OVR_ERR_INT)
+
+#define UART_STAT 0x0c
+#define STAT_TX_FIFO_EMP BIT(13)
+#define STAT_RX_FIFO_EMP BIT(12)
+#define STAT_TX_FIFO_FUL BIT(11)
+#define STAT_TX_FIFO_HFL BIT(10)
+#define STAT_RX_TOGL BIT(9)
+#define STAT_RX_FIFO_FUL BIT(8)
+#define STAT_RX_FIFO_HFL BIT(7)
+#define STAT_TX_EMP BIT(6)
+#define STAT_TX_RDY BIT(5)
+#define STAT_RX_RDY BIT(4)
+#define STAT_BRK_DET BIT(3)
+#define STAT_FRM_ERR BIT(2)
+#define STAT_PAR_ERR BIT(1)
+#define STAT_OVR_ERR BIT(0)
+#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR | STAT_FRM_ERR\
+ | STAT_PAR_ERR | STAT_OVR_ERR)
+
+#define UART_BRDV 0x10
+
+#define MVEBU_NR_UARTS 1
+
+#define MVEBU_UART_TYPE "mvebu-uart"
+
+static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
+
+struct mvebu_uart_data {
+ struct uart_port *port;
+ struct clk *clk;
+};
+
+/* Core UART Driver Operations */
+static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
+{
+ unsigned long flags;
+ unsigned int st;
+
+ spin_lock_irqsave(&port->lock, flags);
+ st = readl(port->membase + UART_STAT);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return (st & STAT_TX_FIFO_EMP) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int mvebu_uart_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void mvebu_uart_set_mctrl(struct uart_port *port,
+ unsigned int mctrl)
+{
+/*
+ * Even if we do not support configuring the modem control lines, this
+ * function must be proided to the serial core
+ */
+}
+
+static void mvebu_uart_stop_tx(struct uart_port *port)
+{
+ unsigned int ctl = readl(port->membase + UART_CTRL);
+
+ ctl &= ~CTRL_TX_RDY_INT;
+ writel(ctl, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_start_tx(struct uart_port *port)
+{
+ unsigned int ctl = readl(port->membase + UART_CTRL);
+
+ ctl |= CTRL_TX_RDY_INT;
+ writel(ctl, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_stop_rx(struct uart_port *port)
+{
+ unsigned int ctl = readl(port->membase + UART_CTRL);
+
+ ctl &= ~CTRL_RX_INT;
+ writel(ctl, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_break_ctl(struct uart_port *port, int brk)
+{
+ unsigned int ctl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ ctl = readl(port->membase + UART_CTRL);
+ if (brk == -1)
+ ctl |= CTRL_SND_BRK_SEQ;
+ else
+ ctl &= ~CTRL_SND_BRK_SEQ;
+ writel(ctl, port->membase + UART_CTRL);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
+{
+ struct tty_port *tport = &port->state->port;
+ unsigned char ch = 0;
+ char flag = 0;
+
+ do {
+ if (status & STAT_RX_RDY) {
+ ch = readl(port->membase + UART_RBR);
+ ch &= 0xff;
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (status & STAT_PAR_ERR)
+ port->icount.parity++;
+ }
+
+ if (status & STAT_BRK_DET) {
+ port->icount.brk++;
+ status &= ~(STAT_FRM_ERR | STAT_PAR_ERR);
+ if (uart_handle_break(port))
+ goto ignore_char;
+ }
+
+ if (status & STAT_OVR_ERR)
+ port->icount.overrun++;
+
+ if (status & STAT_FRM_ERR)
+ port->icount.frame++;
+
+ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ if (status & port->ignore_status_mask & STAT_PAR_ERR)
+ status &= ~STAT_RX_RDY;
+
+ status &= port->read_status_mask;
+
+ if (status & STAT_PAR_ERR)
+ flag = TTY_PARITY;
+
+ status &= ~port->ignore_status_mask;
+
+ if (status & STAT_RX_RDY)
+ tty_insert_flip_char(tport, ch, flag);
+
+ if (status & STAT_BRK_DET)
+ tty_insert_flip_char(tport, 0, TTY_BREAK);
+
+ if (status & STAT_FRM_ERR)
+ tty_insert_flip_char(tport, 0, TTY_FRAME);
+
+ if (status & STAT_OVR_ERR)
+ tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+
+ignore_char:
+ status = readl(port->membase + UART_STAT);
+ } while (status & (STAT_RX_RDY | STAT_BRK_DET));
+
+ tty_flip_buffer_push(tport);
+}
+
+static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int count;
+ unsigned int st;
+
+ if (port->x_char) {
+ writel(port->x_char, port->membase + UART_TSH);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ mvebu_uart_stop_tx(port);
+ return;
+ }
+
+ for (count = 0; count < port->fifosize; count++) {
+ writel(xmit->buf[xmit->tail], port->membase + UART_TSH);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ if (uart_circ_empty(xmit))
+ break;
+
+ st = readl(port->membase + UART_STAT);
+ if (st & STAT_TX_FIFO_FUL)
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ mvebu_uart_stop_tx(port);
+}
+
+static irqreturn_t mvebu_uart_isr(int irq, void *dev_id)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ unsigned int st = readl(port->membase + UART_STAT);
+
+ if (st & (STAT_RX_RDY | STAT_OVR_ERR | STAT_FRM_ERR | STAT_BRK_DET))
+ mvebu_uart_rx_chars(port, st);
+
+ if (st & STAT_TX_RDY)
+ mvebu_uart_tx_chars(port, st);
+
+ return IRQ_HANDLED;
+}
+
+static int mvebu_uart_startup(struct uart_port *port)
+{
+ int ret;
+
+ writel(CTRL_TXFIFO_RST | CTRL_RXFIFO_RST,
+ port->membase + UART_CTRL);
+ udelay(1);
+ writel(CTRL_RX_INT, port->membase + UART_CTRL);
+
+ ret = request_irq(port->irq, mvebu_uart_isr, port->irqflags, "serial",
+ port);
+ if (ret) {
+ dev_err(port->dev, "failed to request irq\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mvebu_uart_shutdown(struct uart_port *port)
+{
+ writel(0, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->read_status_mask = STAT_RX_RDY | STAT_OVR_ERR |
+ STAT_TX_RDY | STAT_TX_FIFO_FUL;
+
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= STAT_FRM_ERR | STAT_PAR_ERR;
+
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |=
+ STAT_FRM_ERR | STAT_PAR_ERR | STAT_OVR_ERR;
+
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= STAT_RX_RDY | STAT_BRK_ERR;
+
+ if (old)
+ tty_termios_copy_hw(termios, old);
+
+ baud = uart_get_baud_rate(port, termios, old, 0, 460800);
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *mvebu_uart_type(struct uart_port *port)
+{
+ return MVEBU_UART_TYPE;
+}
+
+static void mvebu_uart_release_port(struct uart_port *port)
+{
+ /* Nothing to do here */
+}
+
+static int mvebu_uart_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int mvebu_uart_get_poll_char(struct uart_port *port)
+{
+ unsigned int st = readl(port->membase + UART_STAT);
+
+ if (!(st & STAT_RX_RDY))
+ return NO_POLL_CHAR;
+
+ return readl(port->membase + UART_RBR);
+}
+
+static void mvebu_uart_put_poll_char(struct uart_port *port, unsigned char c)
+{
+ unsigned int st;
+
+ for (;;) {
+ st = readl(port->membase + UART_STAT);
+
+ if (!(st & STAT_TX_FIFO_FUL))
+ break;
+
+ udelay(1);
+ }
+
+ writel(c, port->membase + UART_TSH);
+}
+#endif
+
+static const struct uart_ops mvebu_uart_ops = {
+ .tx_empty = mvebu_uart_tx_empty,
+ .set_mctrl = mvebu_uart_set_mctrl,
+ .get_mctrl = mvebu_uart_get_mctrl,
+ .stop_tx = mvebu_uart_stop_tx,
+ .start_tx = mvebu_uart_start_tx,
+ .stop_rx = mvebu_uart_stop_rx,
+ .break_ctl = mvebu_uart_break_ctl,
+ .startup = mvebu_uart_startup,
+ .shutdown = mvebu_uart_shutdown,
+ .set_termios = mvebu_uart_set_termios,
+ .type = mvebu_uart_type,
+ .release_port = mvebu_uart_release_port,
+ .request_port = mvebu_uart_request_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = mvebu_uart_get_poll_char,
+ .poll_put_char = mvebu_uart_put_poll_char,
+#endif
+};
+
+/* Console Driver Operations */
+
+#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
+/* Early Console */
+static void mvebu_uart_putc(struct uart_port *port, int c)
+{
+ unsigned int st;
+
+ for (;;) {
+ st = readl(port->membase + UART_STAT);
+ if (!(st & STAT_TX_FIFO_FUL))
+ break;
+ }
+
+ writel(c, port->membase + UART_TSH);
+
+ for (;;) {
+ st = readl(port->membase + UART_STAT);
+ if (st & STAT_TX_FIFO_EMP)
+ break;
+ }
+}
+
+static void mvebu_uart_putc_early_write(struct console *con,
+ const char *s,
+ unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, mvebu_uart_putc);
+}
+
+static int __init
+mvebu_uart_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = mvebu_uart_putc_early_write;
+
+ return 0;
+}
+
+EARLYCON_DECLARE(ar3700_uart, mvebu_uart_early_console_setup);
+OF_EARLYCON_DECLARE(ar3700_uart, "marvell,armada-3700-uart",
+ mvebu_uart_early_console_setup);
+
+static void wait_for_xmitr(struct uart_port *port)
+{
+ u32 val;
+
+ readl_poll_timeout_atomic(port->membase + UART_STAT, val,
+ (val & STAT_TX_EMP), 1, 10000);
+}
+
+static void mvebu_uart_console_putchar(struct uart_port *port, int ch)
+{
+ wait_for_xmitr(port);
+ writel(ch, port->membase + UART_TSH);
+}
+
+static void mvebu_uart_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port = &mvebu_uart_ports[co->index];
+ unsigned long flags;
+ unsigned int ier;
+ int locked = 1;
+
+ if (oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
+
+ ier = readl(port->membase + UART_CTRL) &
+ (CTRL_RX_INT | CTRL_TX_RDY_INT);
+ writel(0, port->membase + UART_CTRL);
+
+ uart_console_write(port, s, count, mvebu_uart_console_putchar);
+
+ wait_for_xmitr(port);
+
+ if (ier)
+ writel(ier, port->membase + UART_CTRL);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int mvebu_uart_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index < 0 || co->index >= MVEBU_NR_UARTS)
+ return -EINVAL;
+
+ port = &mvebu_uart_ports[co->index];
+
+ if (!port->mapbase || !port->membase) {
+ pr_debug("console on ttyMV%i not present\n", co->index);
+ return -ENODEV;
+ }
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver mvebu_uart_driver;
+
+static struct console mvebu_uart_console = {
+ .name = "ttyMV",
+ .write = mvebu_uart_console_write,
+ .device = uart_console_device,
+ .setup = mvebu_uart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &mvebu_uart_driver,
+};
+
+static int __init mvebu_uart_console_init(void)
+{
+ register_console(&mvebu_uart_console);
+ return 0;
+}
+
+console_initcall(mvebu_uart_console_init);
+
+
+#endif /* CONFIG_SERIAL_MVEBU_CONSOLE */
+
+static struct uart_driver mvebu_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "mvebu_serial",
+ .dev_name = "ttyMV",
+ .nr = MVEBU_NR_UARTS,
+#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
+ .cons = &mvebu_uart_console,
+#endif
+};
+
+static int mvebu_uart_probe(struct platform_device *pdev)
+{
+ struct resource *reg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct uart_port *port;
+ struct mvebu_uart_data *data;
+ int ret;
+
+ if (!reg || !irq) {
+ dev_err(&pdev->dev, "no registers/irq defined\n");
+ return -EINVAL;
+ }
+
+ port = &mvebu_uart_ports[0];
+
+ spin_lock_init(&port->lock);
+
+ port->dev = &pdev->dev;
+ port->type = PORT_MVEBU;
+ port->ops = &mvebu_uart_ops;
+ port->regshift = 0;
+
+ port->fifosize = 32;
+ port->iotype = UPIO_MEM32;
+ port->flags = UPF_FIXED_PORT;
+ port->line = 0; /* single port: force line number to 0 */
+
+ port->irq = irq->start;
+ port->irqflags = 0;
+ port->mapbase = reg->start;
+
+ port->membase = devm_ioremap_resource(&pdev->dev, reg);
+ if (IS_ERR(port->membase))
+ return -PTR_ERR(port->membase);
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_uart_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->port = port;
+
+ port->private_data = data;
+ platform_set_drvdata(pdev, data);
+
+ ret = uart_add_one_port(&mvebu_uart_driver, port);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+static int mvebu_uart_remove(struct platform_device *pdev)
+{
+ struct mvebu_uart_data *data = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&mvebu_uart_driver, data->port);
+ data->port->private_data = NULL;
+ data->port->mapbase = 0;
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id mvebu_uart_of_match[] = {
+ { .compatible = "marvell,armada-3700-uart", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mvebu_uart_of_match);
+
+static struct platform_driver mvebu_uart_platform_driver = {
+ .probe = mvebu_uart_probe,
+ .remove = mvebu_uart_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mvebu-uart",
+ .of_match_table = of_match_ptr(mvebu_uart_of_match),
+ },
+};
+
+static int __init mvebu_uart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&mvebu_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&mvebu_uart_platform_driver);
+ if (ret)
+ uart_unregister_driver(&mvebu_uart_driver);
+
+ return ret;
+}
+
+static void __exit mvebu_uart_exit(void)
+{
+ platform_driver_unregister(&mvebu_uart_platform_driver);
+ uart_unregister_driver(&mvebu_uart_driver);
+}
+
+arch_initcall(mvebu_uart_init);
+module_exit(mvebu_uart_exit);
+
+MODULE_AUTHOR("Wilson Ding <dingwei@marvell.com>");
+MODULE_DESCRIPTION("Marvell Armada-3700 Serial Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index fa49eb1e2fa2..a2a529994ba5 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1870,7 +1870,7 @@ static struct platform_driver serial_omap_driver = {
.probe = serial_omap_probe,
.remove = serial_omap_remove,
.driver = {
- .name = DRIVER_NAME,
+ .name = OMAP_SERIAL_DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
.of_match_table = of_match_ptr(omap_serial_of_match),
},
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index d72cd736bdc6..ac7f8df54406 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -601,14 +601,21 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
unsigned int ufcon, ch, flag, ufstat, uerstat;
+ unsigned int fifocnt = 0;
int max_count = port->fifosize;
while (max_count-- > 0) {
- ufcon = rd_regl(port, S3C2410_UFCON);
- ufstat = rd_regl(port, S3C2410_UFSTAT);
-
- if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
- break;
+ /*
+ * Receive all characters known to be in FIFO
+ * before reading FIFO level again
+ */
+ if (fifocnt == 0) {
+ ufstat = rd_regl(port, S3C2410_UFSTAT);
+ fifocnt = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
+ if (fifocnt == 0)
+ break;
+ }
+ fifocnt--;
uerstat = rd_regl(port, S3C2410_UERSTAT);
ch = rd_regb(port, S3C2410_URXH);
@@ -623,6 +630,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
}
} else {
if (txe) {
+ ufcon = rd_regl(port, S3C2410_UFCON);
ufcon |= S3C2410_UFCON_RESETRX;
wr_regl(port, S3C2410_UFCON, ufcon);
rx_enabled(port) = 1;
@@ -2451,7 +2459,6 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device,
}
OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
s3c2410_early_console_setup);
-EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);
/* S3C2412, S3C2440, S3C64xx */
static struct samsung_early_console_data s3c2440_early_console_data = {
@@ -2470,9 +2477,6 @@ OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
s3c2440_early_console_setup);
OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);
/* S5PV210, EXYNOS */
static struct samsung_early_console_data s5pv210_early_console_data = {
@@ -2489,8 +2493,6 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
s5pv210_early_console_setup);
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
s5pv210_early_console_setup);
-EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
-EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);
#endif
MODULE_ALIAS("platform:samsung-uart");
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 13f8d5f70272..025a4264430e 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -196,14 +196,14 @@
* or (IO6)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_CTS_BIT (1 << 0) /* CTS */
-#define SC16IS7XX_MSR_DSR_BIT (1 << 1) /* DSR (IO4)
+#define SC16IS7XX_MSR_CTS_BIT (1 << 4) /* CTS */
+#define SC16IS7XX_MSR_DSR_BIT (1 << 5) /* DSR (IO4)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_RI_BIT (1 << 2) /* RI (IO7)
+#define SC16IS7XX_MSR_RI_BIT (1 << 6) /* RI (IO7)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_CD_BIT (1 << 3) /* CD (IO6)
+#define SC16IS7XX_MSR_CD_BIT (1 << 7) /* CD (IO6)
* - only on 75x/76x
*/
#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */
@@ -240,7 +240,7 @@
/* IOControl register bits (Only 750/760) */
#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */
-#define SC16IS7XX_IOCONTROL_GPIO_BIT (1 << 1) /* Enable GPIO[7:4] */
+#define SC16IS7XX_IOCONTROL_MODEM_BIT (1 << 1) /* Enable GPIO[7:4] as modem pins */
#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */
/* EFCR register bits */
@@ -687,7 +687,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
case SC16IS7XX_IIR_CTSRTS_SRC:
msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
uart_handle_cts_change(port,
- !!(msr & SC16IS7XX_MSR_CTS_BIT));
+ !!(msr & SC16IS7XX_MSR_DCTS_BIT));
break;
case SC16IS7XX_IIR_THRI_SRC:
sc16is7xx_handle_tx(port);
@@ -761,12 +761,20 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws)
memset(&one->config, 0, sizeof(one->config));
spin_unlock_irqrestore(&one->port.lock, irqflags);
- if (config.flags & SC16IS7XX_RECONF_MD)
+ if (config.flags & SC16IS7XX_RECONF_MD) {
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_LOOP_BIT,
(one->port.mctrl & TIOCM_LOOP) ?
SC16IS7XX_MCR_LOOP_BIT : 0);
-
+ sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_RTS_BIT,
+ (one->port.mctrl & TIOCM_RTS) ?
+ SC16IS7XX_MCR_RTS_BIT : 0);
+ sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_DTR_BIT,
+ (one->port.mctrl & TIOCM_DTR) ?
+ SC16IS7XX_MCR_DTR_BIT : 0);
+ }
if (config.flags & SC16IS7XX_RECONF_IER)
sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG,
config.ier_clear, 0);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index b1f54ab1818c..a126a603b083 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -171,14 +171,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
*/
uart_change_speed(tty, state, NULL);
- if (init_hw) {
- /*
- * Setup the RTS and DTR signals once the
- * port is open and ready to respond.
- */
- if (tty->termios.c_cflag & CBAUD)
- uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
- }
+ /*
+ * Setup the RTS and DTR signals once the
+ * port is open and ready to respond.
+ */
+ if (init_hw && C_BAUD(tty))
+ uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
/*
@@ -240,7 +238,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
if (uart_console(uport) && tty)
uport->cons->cflag = tty->termios.c_cflag;
- if (!tty || (tty->termios.c_cflag & HUPCL))
+ if (!tty || C_HUPCL(tty))
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
uart_port_shutdown(port);
@@ -485,12 +483,15 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
spin_unlock_irq(&uport->lock);
}
-static inline int __uart_put_char(struct uart_port *port,
- struct circ_buf *circ, unsigned char c)
+static int uart_put_char(struct tty_struct *tty, unsigned char c)
{
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ struct circ_buf *circ;
unsigned long flags;
int ret = 0;
+ circ = &state->xmit;
if (!circ->buf)
return 0;
@@ -504,13 +505,6 @@ static inline int __uart_put_char(struct uart_port *port,
return ret;
}
-static int uart_put_char(struct tty_struct *tty, unsigned char ch)
-{
- struct uart_state *state = tty->driver_data;
-
- return __uart_put_char(state->uart_port, &state->xmit, ch);
-}
-
static void uart_flush_chars(struct tty_struct *tty)
{
uart_start(tty);
@@ -639,7 +633,7 @@ static void uart_throttle(struct tty_struct *tty)
if (I_IXOFF(tty))
mask |= UPSTAT_AUTOXOFF;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
mask |= UPSTAT_AUTORTS;
if (port->status & mask) {
@@ -647,11 +641,11 @@ static void uart_throttle(struct tty_struct *tty)
mask &= ~port->status;
}
- if (mask & UPSTAT_AUTOXOFF)
- uart_send_xchar(tty, STOP_CHAR(tty));
-
if (mask & UPSTAT_AUTORTS)
uart_clear_mctrl(port, TIOCM_RTS);
+
+ if (mask & UPSTAT_AUTOXOFF)
+ uart_send_xchar(tty, STOP_CHAR(tty));
}
static void uart_unthrottle(struct tty_struct *tty)
@@ -662,7 +656,7 @@ static void uart_unthrottle(struct tty_struct *tty)
if (I_IXOFF(tty))
mask |= UPSTAT_AUTOXOFF;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
mask |= UPSTAT_AUTORTS;
if (port->status & mask) {
@@ -670,21 +664,25 @@ static void uart_unthrottle(struct tty_struct *tty)
mask &= ~port->status;
}
- if (mask & UPSTAT_AUTOXOFF)
- uart_send_xchar(tty, START_CHAR(tty));
-
if (mask & UPSTAT_AUTORTS)
uart_set_mctrl(port, TIOCM_RTS);
+
+ if (mask & UPSTAT_AUTOXOFF)
+ uart_send_xchar(tty, START_CHAR(tty));
}
-static void do_uart_get_info(struct tty_port *port,
- struct serial_struct *retinfo)
+static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
memset(retinfo, 0, sizeof(*retinfo));
+ /*
+ * Ensure the state we copy is consistent and no hardware changes
+ * occur as we go
+ */
+ mutex_lock(&port->mutex);
retinfo->type = uport->type;
retinfo->line = uport->line;
retinfo->port = uport->iobase;
@@ -703,15 +701,6 @@ static void do_uart_get_info(struct tty_port *port,
retinfo->io_type = uport->iotype;
retinfo->iomem_reg_shift = uport->regshift;
retinfo->iomem_base = (void *)(unsigned long)uport->mapbase;
-}
-
-static void uart_get_info(struct tty_port *port,
- struct serial_struct *retinfo)
-{
- /* Ensure the state we copy is consistent and no hardware changes
- occur as we go */
- mutex_lock(&port->mutex);
- do_uart_get_info(port, retinfo);
mutex_unlock(&port->mutex);
}
@@ -719,6 +708,7 @@ static int uart_get_info_user(struct tty_port *port,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
+
uart_get_info(port, &tmp);
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
@@ -1391,8 +1381,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
uport = state->uart_port;
port = &state->port;
-
- pr_debug("uart_close(%d) called\n", uport ? uport->line : -1);
+ pr_debug("uart_close(%d) called\n", tty->index);
if (!port->count || tty_port_close_start(port, tty, filp) == 0)
return;
@@ -1434,7 +1423,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* Wake up anyone trying to open this port.
*/
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
- clear_bit(ASYNCB_CLOSING, &port->flags);
spin_unlock_irq(&port->lock);
wake_up_interruptible(&port->open_wait);
@@ -1510,7 +1498,7 @@ static void uart_hangup(struct tty_struct *tty)
struct tty_port *port = &state->port;
unsigned long flags;
- pr_debug("uart_hangup(%d)\n", state->uart_port->line);
+ pr_debug("uart_hangup(%d)\n", tty->index);
mutex_lock(&port->mutex);
if (port->flags & ASYNC_NORMAL_ACTIVE) {
@@ -1591,7 +1579,7 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
*/
static int uart_open(struct tty_struct *tty, struct file *filp)
{
- struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
+ struct uart_driver *drv = tty->driver->driver_state;
int retval, line = tty->index;
struct uart_state *state = drv->state + line;
struct tty_port *port = &state->port;
@@ -1633,15 +1621,12 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
/*
* If we succeeded, wait until the port is ready.
*/
+err_unlock:
mutex_unlock(&port->mutex);
if (retval == 0)
retval = tty_port_block_til_ready(port, tty, filp);
-
end:
return retval;
-err_unlock:
- mutex_unlock(&port->mutex);
- goto end;
}
static const char *uart_type(struct uart_port *port)
@@ -1700,17 +1685,13 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
seq_printf(m, " tx:%d rx:%d",
uport->icount.tx, uport->icount.rx);
if (uport->icount.frame)
- seq_printf(m, " fe:%d",
- uport->icount.frame);
+ seq_printf(m, " fe:%d", uport->icount.frame);
if (uport->icount.parity)
- seq_printf(m, " pe:%d",
- uport->icount.parity);
+ seq_printf(m, " pe:%d", uport->icount.parity);
if (uport->icount.brk)
- seq_printf(m, " brk:%d",
- uport->icount.brk);
+ seq_printf(m, " brk:%d", uport->icount.brk);
if (uport->icount.overrun)
- seq_printf(m, " oe:%d",
- uport->icount.overrun);
+ seq_printf(m, " oe:%d", uport->icount.overrun);
#define INFOBIT(bit, str) \
if (uport->mctrl & (bit)) \
@@ -1745,8 +1726,7 @@ static int uart_proc_show(struct seq_file *m, void *v)
struct uart_driver *drv = ttydrv->driver_state;
int i;
- seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
- "", "", "");
+ seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", "");
for (i = 0; i < drv->nr; i++)
uart_line_info(m, drv, i);
return 0;
@@ -1895,26 +1875,6 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
}
EXPORT_SYMBOL_GPL(uart_parse_options);
-struct baud_rates {
- unsigned int rate;
- unsigned int cflag;
-};
-
-static const struct baud_rates baud_rates[] = {
- { 921600, B921600 },
- { 460800, B460800 },
- { 230400, B230400 },
- { 115200, B115200 },
- { 57600, B57600 },
- { 38400, B38400 },
- { 19200, B19200 },
- { 9600, B9600 },
- { 4800, B4800 },
- { 2400, B2400 },
- { 1200, B1200 },
- { 0, B38400 }
-};
-
/**
* uart_set_options - setup the serial console parameters
* @port: pointer to the serial ports uart_port structure
@@ -1930,7 +1890,6 @@ uart_set_options(struct uart_port *port, struct console *co,
{
struct ktermios termios;
static struct ktermios dummy;
- int i;
/*
* Ensure that the serial console lock is initialised
@@ -1945,16 +1904,8 @@ uart_set_options(struct uart_port *port, struct console *co,
memset(&termios, 0, sizeof(struct ktermios));
- termios.c_cflag = CREAD | HUPCL | CLOCAL;
-
- /*
- * Construct a cflag setting.
- */
- for (i = 0; baud_rates[i].rate; i++)
- if (baud_rates[i].rate <= baud)
- break;
-
- termios.c_cflag |= baud_rates[i].cflag;
+ termios.c_cflag |= CREAD | HUPCL | CLOCAL;
+ tty_termios_encode_baud_rate(&termios, baud, baud);
if (bits == 7)
termios.c_cflag |= CS7;
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
index b4decf8787de..57f152394af5 100644
--- a/drivers/tty/serial/serial_ks8695.c
+++ b/drivers/tty/serial/serial_ks8695.c
@@ -554,7 +554,7 @@ static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
.uartclk = KS8695_CLOCK_RATE * 16,
.fifosize = 16,
.ops = &ks8695uart_pops,
- .flags = ASYNC_BOOT_AUTOCONF,
+ .flags = UPF_BOOT_AUTOCONF,
.line = 0,
}
};
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 226ad23b136c..02147361eaa9 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -20,6 +20,7 @@
#include <linux/gpio/consumer.h>
#include <linux/termios.h>
#include <linux/serial_core.h>
+#include <linux/module.h>
#include "serial_mctrl_gpio.h"
@@ -249,3 +250,5 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
}
}
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 4646a9f531ad..0130feb069ae 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -84,6 +84,22 @@ enum SCI_CLKS {
SCI_NUM_CLKS
};
+/* Bit x set means sampling rate x + 1 is supported */
+#define SCI_SR(x) BIT((x) - 1)
+#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
+
+#define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \
+ SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \
+ SCI_SR(19) | SCI_SR(27)
+
+#define min_sr(_port) ffs((_port)->sampling_rate_mask)
+#define max_sr(_port) fls((_port)->sampling_rate_mask)
+
+/* Iterate over all supported sampling rates, from high to low */
+#define for_each_sr(_sr, _port) \
+ for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \
+ if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
+
struct sci_port {
struct uart_port port;
@@ -93,7 +109,7 @@ struct sci_port {
unsigned int overrun_mask;
unsigned int error_mask;
unsigned int error_clear;
- unsigned int sampling_rate;
+ unsigned int sampling_rate_mask;
resource_size_t reg_size;
/* Break timer */
@@ -637,7 +653,8 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
}
}
-#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
#ifdef CONFIG_CONSOLE_POLL
static int sci_poll_get_char(struct uart_port *port)
@@ -678,7 +695,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
serial_port_out(port, SCxTDR, c);
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
}
-#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
+ CONFIG_SERIAL_SH_SCI_EARLYCON */
static void sci_init_pins(struct uart_port *port, unsigned int cflag)
{
@@ -1902,19 +1920,13 @@ static int sci_sck_calc(struct sci_port *s, unsigned int bps,
unsigned int *srr)
{
unsigned long freq = s->clk_rates[SCI_SCK];
- unsigned int min_sr, max_sr, sr;
int err, min_err = INT_MAX;
+ unsigned int sr;
- if (s->sampling_rate) {
- /* SCI(F) has a fixed sampling rate */
- min_sr = max_sr = s->sampling_rate / 2;
- } else {
- /* HSCIF has a variable 1/(8..32) sampling rate */
- min_sr = 8;
- max_sr = 32;
- }
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
- for (sr = max_sr; sr >= min_sr; sr--) {
+ for_each_sr(sr, s) {
err = DIV_ROUND_CLOSEST(freq, sr) - bps;
if (abs(err) >= abs(min_err))
continue;
@@ -1935,19 +1947,13 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
unsigned long freq, unsigned int *dlr,
unsigned int *srr)
{
- unsigned int min_sr, max_sr, sr, dl;
int err, min_err = INT_MAX;
+ unsigned int sr, dl;
- if (s->sampling_rate) {
- /* SCIF has a fixed sampling rate */
- min_sr = max_sr = s->sampling_rate / 2;
- } else {
- /* HSCIF has a variable 1/(8..32) sampling rate */
- min_sr = 8;
- max_sr = 32;
- }
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
- for (sr = max_sr; sr >= min_sr; sr--) {
+ for_each_sr(sr, s) {
dl = DIV_ROUND_CLOSEST(freq, sr * bps);
dl = clamp(dl, 1U, 65535U);
@@ -1973,19 +1979,12 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
unsigned int *brr, unsigned int *srr,
unsigned int *cks)
{
- unsigned int min_sr, max_sr, shift, sr, br, prediv, scrate, c;
unsigned long freq = s->clk_rates[SCI_FCK];
+ unsigned int sr, br, prediv, scrate, c;
int err, min_err = INT_MAX;
- if (s->sampling_rate) {
- min_sr = max_sr = s->sampling_rate;
- shift = 0;
- } else {
- /* HSCIF has a variable sample rate */
- min_sr = 8;
- max_sr = 32;
- shift = 1;
- }
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
/*
* Find the combination of sample rate and clock select with the
@@ -2002,10 +2001,10 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
* (|D - 0.5| / N * (1 + F))|
* NOTE: Usually, treat D for 0.5, F is 0 by this calculation.
*/
- for (sr = max_sr; sr >= min_sr; sr--) {
+ for_each_sr(sr, s) {
for (c = 0; c <= 3; c++) {
/* integerized formulas from HSCIF documentation */
- prediv = sr * (1 << (2 * c + shift));
+ prediv = sr * (1 << (2 * c + 1));
/*
* We need to calculate:
@@ -2062,7 +2061,7 @@ static void sci_reset(struct uart_port *port)
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- unsigned int baud, smr_val = 0, scr_val = 0, i;
+ unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i;
unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0;
unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0;
struct sci_port *s = to_sci_port(port);
@@ -2096,8 +2095,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
for (i = 0; i < SCI_NUM_CLKS; i++)
max_freq = max(max_freq, s->clk_rates[i]);
- baud = uart_get_baud_rate(port, termios, old, 0,
- max_freq / max(s->sampling_rate, 8U));
+ baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
if (!baud)
goto done;
@@ -2185,6 +2183,17 @@ done:
uart_update_timeout(port, termios->c_cflag, baud);
if (best_clk >= 0) {
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+ switch (srr + 1) {
+ case 5: smr_val |= SCSMR_SRC_5; break;
+ case 7: smr_val |= SCSMR_SRC_7; break;
+ case 11: smr_val |= SCSMR_SRC_11; break;
+ case 13: smr_val |= SCSMR_SRC_13; break;
+ case 16: smr_val |= SCSMR_SRC_16; break;
+ case 17: smr_val |= SCSMR_SRC_17; break;
+ case 19: smr_val |= SCSMR_SRC_19; break;
+ case 27: smr_val |= SCSMR_SRC_27; break;
+ }
smr_val |= cks;
dev_dbg(port->dev,
"SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n",
@@ -2200,7 +2209,8 @@ done:
} else {
/* Don't touch the bit rate configuration */
scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
- smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
+ smr_val |= serial_port_in(port, SCSMR) &
+ (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
dev_dbg(port->dev, "SCR 0x%x SMR 0x%x\n", scr_val, smr_val);
serial_port_out(port, SCSCR, scr_val);
serial_port_out(port, SCSMR, smr_val);
@@ -2232,6 +2242,16 @@ done:
scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0);
dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val);
serial_port_out(port, SCSCR, scr_val);
+ if ((srr + 1 == 5) &&
+ (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
+ /*
+ * In asynchronous mode, when the sampling rate is 1/5, first
+ * received data may become invalid on some SCIFA and SCIFB.
+ * To avoid this problem wait more than 1 serial data time (1
+ * bit time x serial data number) after setting SCSCR.RE = 1.
+ */
+ udelay(DIV_ROUND_UP(10 * 1000000, baud));
+ }
#ifdef CONFIG_SERIAL_SH_SCI_DMA
/*
@@ -2528,37 +2548,37 @@ static int sci_init_single(struct platform_device *dev,
port->fifosize = 256;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
break;
case PORT_HSCIF:
port->fifosize = 128;
sci_port->overrun_reg = SCLSR;
sci_port->overrun_mask = SCLSR_ORER;
- sci_port->sampling_rate = 0;
+ sci_port->sampling_rate_mask = SCI_SR_RANGE(8, 32);
break;
case PORT_SCIFA:
port->fifosize = 64;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
break;
case PORT_SCIF:
port->fifosize = 16;
if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR(16);
} else {
sci_port->overrun_reg = SCLSR;
sci_port->overrun_mask = SCLSR_ORER;
- sci_port->sampling_rate = 32;
+ sci_port->sampling_rate_mask = SCI_SR(32);
}
break;
default:
port->fifosize = 1;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCI_ORER;
- sci_port->sampling_rate = 32;
+ sci_port->sampling_rate_mask = SCI_SR(32);
break;
}
@@ -2567,7 +2587,7 @@ static int sci_init_single(struct platform_device *dev,
* data override the sampling rate for now.
*/
if (p->sampling_rate)
- sci_port->sampling_rate = p->sampling_rate;
+ sci_port->sampling_rate_mask = SCI_SR(p->sampling_rate);
if (!early) {
ret = sci_init_clocks(sci_port, &dev->dev);
@@ -2632,7 +2652,8 @@ static void sci_cleanup_single(struct sci_port *port)
pm_runtime_disable(port->port.dev);
}
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, int ch)
{
sci_poll_put_char(port, ch);
@@ -2652,9 +2673,12 @@ static void serial_console_write(struct console *co, const char *s,
int locked = 1;
local_irq_save(flags);
+#if defined(SUPPORT_SYSRQ)
if (port->sysrq)
locked = 0;
- else if (oops_in_progress)
+ else
+#endif
+ if (oops_in_progress)
locked = spin_trylock(&port->lock);
else
spin_lock(&port->lock);
@@ -2764,7 +2788,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)
#define SCI_CONSOLE NULL
-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE || CONFIG_SERIAL_SH_SCI_EARLYCON */
static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
@@ -2998,6 +3022,62 @@ static void __exit sci_exit(void)
early_platform_init_buffer("earlyprintk", &sci_driver,
early_serial_buf, ARRAY_SIZE(early_serial_buf));
#endif
+#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
+static struct __init plat_sci_port port_cfg;
+
+static int __init early_console_setup(struct earlycon_device *device,
+ int type)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->port.serial_in = sci_serial_in;
+ device->port.serial_out = sci_serial_out;
+ device->port.type = type;
+ memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
+ sci_ports[0].cfg = &port_cfg;
+ sci_ports[0].cfg->type = type;
+ sci_probe_regmap(sci_ports[0].cfg);
+ port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR) |
+ SCSCR_RE | SCSCR_TE;
+ sci_serial_out(&sci_ports[0].port, SCSCR, port_cfg.scscr);
+
+ device->con->write = serial_console_write;
+ return 0;
+}
+static int __init sci_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCI);
+}
+static int __init scif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIF);
+}
+static int __init scifa_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIFA);
+}
+static int __init scifb_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIFB);
+}
+static int __init hscif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_HSCIF);
+}
+
+OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
+OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
+OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
+OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
+OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
+#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */
+
module_init(sci_init);
module_exit(sci_exit);
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index fb1760250421..7a4fa185b93e 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -35,12 +35,27 @@ enum {
/* SCSMR (Serial Mode Register) */
+#define SCSMR_C_A BIT(7) /* Communication Mode */
+#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */
+#define SCSMR_ASYNC 0 /* - Asynchronous mode */
#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
#define SCSMR_PE BIT(5) /* Parity Enable */
#define SCSMR_ODD BIT(4) /* Odd Parity */
#define SCSMR_STOP BIT(3) /* Stop Bit Length */
#define SCSMR_CKS 0x0003 /* Clock Select */
+/* Serial Mode Register, SCIFA/SCIFB only bits */
+#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */
+#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */
+#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */
+#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */
+#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */
+#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */
+#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */
+#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */
+#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */
+#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */
+
/* Serial Control Register, SCIFA/SCIFB only bits */
#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */
#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index ef26c4a60be4..18971063f95f 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -624,8 +624,6 @@ static int __init sprd_early_console_setup(
device->con->write = sprd_early_write;
return 0;
}
-
-EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup);
OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart",
sprd_early_console_setup);
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index b1c6bd3d483f..c9fdfc8bf47f 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -28,7 +28,7 @@
#define ULITE_NAME "ttyUL"
#define ULITE_MAJOR 204
#define ULITE_MINOR 187
-#define ULITE_NR_UARTS 4
+#define ULITE_NR_UARTS 16
/* ---------------------------------------------------------------------
* Register definitions
@@ -72,7 +72,7 @@ static void uartlite_outbe32(u32 val, void __iomem *addr)
iowrite32be(val, addr);
}
-static struct uartlite_reg_ops uartlite_be = {
+static const struct uartlite_reg_ops uartlite_be = {
.in = uartlite_inbe32,
.out = uartlite_outbe32,
};
@@ -87,21 +87,21 @@ static void uartlite_outle32(u32 val, void __iomem *addr)
iowrite32(val, addr);
}
-static struct uartlite_reg_ops uartlite_le = {
+static const struct uartlite_reg_ops uartlite_le = {
.in = uartlite_inle32,
.out = uartlite_outle32,
};
static inline u32 uart_in32(u32 offset, struct uart_port *port)
{
- struct uartlite_reg_ops *reg_ops = port->private_data;
+ const struct uartlite_reg_ops *reg_ops = port->private_data;
return reg_ops->in(port->membase + offset);
}
static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
{
- struct uartlite_reg_ops *reg_ops = port->private_data;
+ const struct uartlite_reg_ops *reg_ops = port->private_data;
reg_ops->out(val, port->membase + offset);
}
@@ -193,12 +193,15 @@ static int ulite_transmit(struct uart_port *port, int stat)
static irqreturn_t ulite_isr(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
- int busy, n = 0;
+ int stat, busy, n = 0;
+ unsigned long flags;
do {
- int stat = uart_in32(ULITE_STATUS, port);
+ spin_lock_irqsave(&port->lock, flags);
+ stat = uart_in32(ULITE_STATUS, port);
busy = ulite_receive(port, stat);
busy |= ulite_transmit(port, stat);
+ spin_unlock_irqrestore(&port->lock, flags);
n++;
} while (busy);
@@ -259,7 +262,8 @@ static int ulite_startup(struct uart_port *port)
{
int ret;
- ret = request_irq(port->irq, ulite_isr, IRQF_SHARED, "uartlite", port);
+ ret = request_irq(port->irq, ulite_isr, IRQF_SHARED | IRQF_TRIGGER_RISING,
+ "uartlite", port);
if (ret)
return ret;
@@ -519,6 +523,47 @@ static int __init ulite_console_init(void)
console_initcall(ulite_console_init);
+static void early_uartlite_putc(struct uart_port *port, int c)
+{
+ /*
+ * Limit how many times we'll spin waiting for TX FIFO status.
+ * This will prevent lockups if the base address is incorrectly
+ * set, or any other issue on the UARTLITE.
+ * This limit is pretty arbitrary, unless we are at about 10 baud
+ * we'll never timeout on a working UART.
+ */
+
+ unsigned retries = 1000000;
+ /* read status bit - 0x8 offset */
+ while (--retries && (readl(port->membase + 8) & (1 << 3)))
+ ;
+
+ /* Only attempt the iowrite if we didn't timeout */
+ /* write to TX_FIFO - 0x4 offset */
+ if (retries)
+ writel(c & 0xff, port->membase + 4);
+}
+
+static void early_uartlite_write(struct console *console,
+ const char *s, unsigned n)
+{
+ struct earlycon_device *device = console->data;
+ uart_console_write(&device->port, s, n, early_uartlite_putc);
+}
+
+static int __init early_uartlite_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = early_uartlite_write;
+ return 0;
+}
+EARLYCON_DECLARE(uartlite, early_uartlite_setup);
+OF_EARLYCON_DECLARE(uartlite_b, "xlnx,opb-uartlite-1.00.b", early_uartlite_setup);
+OF_EARLYCON_DECLARE(uartlite_a, "xlnx,xps-uartlite-1.00.a", early_uartlite_setup);
+
#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
static struct uart_driver ulite_uart_driver = {
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 009e0dbc12d2..cd46e64c4255 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -50,24 +50,24 @@ module_param(rx_timeout, uint, S_IRUGO);
MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
/* Register offsets for the UART. */
-#define CDNS_UART_CR_OFFSET 0x00 /* Control Register */
-#define CDNS_UART_MR_OFFSET 0x04 /* Mode Register */
-#define CDNS_UART_IER_OFFSET 0x08 /* Interrupt Enable */
-#define CDNS_UART_IDR_OFFSET 0x0C /* Interrupt Disable */
-#define CDNS_UART_IMR_OFFSET 0x10 /* Interrupt Mask */
-#define CDNS_UART_ISR_OFFSET 0x14 /* Interrupt Status */
-#define CDNS_UART_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator */
-#define CDNS_UART_RXTOUT_OFFSET 0x1C /* RX Timeout */
-#define CDNS_UART_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level */
-#define CDNS_UART_MODEMCR_OFFSET 0x24 /* Modem Control */
-#define CDNS_UART_MODEMSR_OFFSET 0x28 /* Modem Status */
-#define CDNS_UART_SR_OFFSET 0x2C /* Channel Status */
-#define CDNS_UART_FIFO_OFFSET 0x30 /* FIFO */
-#define CDNS_UART_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider */
-#define CDNS_UART_FLOWDEL_OFFSET 0x38 /* Flow Delay */
-#define CDNS_UART_IRRX_PWIDTH_OFFSET 0x3C /* IR Min Received Pulse Width */
-#define CDNS_UART_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse Width */
-#define CDNS_UART_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level */
+#define CDNS_UART_CR 0x00 /* Control Register */
+#define CDNS_UART_MR 0x04 /* Mode Register */
+#define CDNS_UART_IER 0x08 /* Interrupt Enable */
+#define CDNS_UART_IDR 0x0C /* Interrupt Disable */
+#define CDNS_UART_IMR 0x10 /* Interrupt Mask */
+#define CDNS_UART_ISR 0x14 /* Interrupt Status */
+#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */
+#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
+#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */
+#define CDNS_UART_MODEMCR 0x24 /* Modem Control */
+#define CDNS_UART_MODEMSR 0x28 /* Modem Status */
+#define CDNS_UART_SR 0x2C /* Channel Status */
+#define CDNS_UART_FIFO 0x30 /* FIFO */
+#define CDNS_UART_BAUDDIV 0x34 /* Baud Rate Divider */
+#define CDNS_UART_FLOWDEL 0x38 /* Flow Delay */
+#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
+#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
+#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
/* Control Register Bit Definitions */
#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
@@ -126,6 +126,10 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
+#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | \
+ CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | \
+ CDNS_UART_IXR_TOUT)
+
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
#define CDNS_UART_IXR_BRK 0x80000000
@@ -172,43 +176,22 @@ struct cdns_uart {
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
clk_rate_change_nb);
-/**
- * cdns_uart_isr - Interrupt handler
- * @irq: Irq number
- * @dev_id: Id of the port
- *
- * Return: IRQHANDLED
- */
-static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
+static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
{
- struct uart_port *port = (struct uart_port *)dev_id;
- unsigned long flags;
- unsigned int isrstatus, numbytes;
- unsigned int data;
- char status = TTY_NORMAL;
-
- spin_lock_irqsave(&port->lock, flags);
-
- /* Read the interrupt status register to determine which
- * interrupt(s) is/are active.
- */
- isrstatus = readl(port->membase + CDNS_UART_ISR_OFFSET);
-
/*
* There is no hardware break detection, so we interpret framing
* error with all-zeros data as a break sequence. Most of the time,
* there's another non-zero byte at the end of the sequence.
*/
if (isrstatus & CDNS_UART_IXR_FRAMING) {
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_RXEMPTY)) {
- if (!readl(port->membase + CDNS_UART_FIFO_OFFSET)) {
+ if (!readl(port->membase + CDNS_UART_FIFO)) {
port->read_status_mask |= CDNS_UART_IXR_BRK;
isrstatus &= ~CDNS_UART_IXR_FRAMING;
}
}
- writel(CDNS_UART_IXR_FRAMING,
- port->membase + CDNS_UART_ISR_OFFSET);
+ writel(CDNS_UART_IXR_FRAMING, port->membase + CDNS_UART_ISR);
}
/* drop byte with parity error if IGNPAR specified */
@@ -218,94 +201,106 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
isrstatus &= port->read_status_mask;
isrstatus &= ~port->ignore_status_mask;
- if ((isrstatus & CDNS_UART_IXR_TOUT) ||
- (isrstatus & CDNS_UART_IXR_RXTRIG)) {
- /* Receive Timeout Interrupt */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_RXEMPTY)) {
- data = readl(port->membase + CDNS_UART_FIFO_OFFSET);
-
- /* Non-NULL byte after BREAK is garbage (99%) */
- if (data && (port->read_status_mask &
- CDNS_UART_IXR_BRK)) {
- port->read_status_mask &= ~CDNS_UART_IXR_BRK;
- port->icount.brk++;
- if (uart_handle_break(port))
- continue;
- }
+ if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG)))
+ return;
-#ifdef SUPPORT_SYSRQ
- /*
- * uart_handle_sysrq_char() doesn't work if
- * spinlocked, for some reason
- */
- if (port->sysrq) {
- spin_unlock(&port->lock);
- if (uart_handle_sysrq_char(port,
- (unsigned char)data)) {
- spin_lock(&port->lock);
- continue;
- }
- spin_lock(&port->lock);
- }
-#endif
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) {
+ u32 data;
+ char status = TTY_NORMAL;
- port->icount.rx++;
+ data = readl(port->membase + CDNS_UART_FIFO);
- if (isrstatus & CDNS_UART_IXR_PARITY) {
- port->icount.parity++;
- status = TTY_PARITY;
- } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
- port->icount.frame++;
- status = TTY_FRAME;
- } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
- port->icount.overrun++;
- }
+ /* Non-NULL byte after BREAK is garbage (99%) */
+ if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) {
+ port->read_status_mask &= ~CDNS_UART_IXR_BRK;
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ }
+
+ if (uart_handle_sysrq_char(port, data))
+ continue;
+
+ port->icount.rx++;
- uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
- data, status);
+ if (isrstatus & CDNS_UART_IXR_PARITY) {
+ port->icount.parity++;
+ status = TTY_PARITY;
+ } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
+ port->icount.frame++;
+ status = TTY_FRAME;
+ } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
+ port->icount.overrun++;
}
- spin_unlock(&port->lock);
- tty_flip_buffer_push(&port->state->port);
- spin_lock(&port->lock);
+
+ uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
+ data, status);
}
+ tty_flip_buffer_push(&port->state->port);
+}
- /* Dispatch an appropriate handler */
- if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) {
- if (uart_circ_empty(&port->state->xmit)) {
- writel(CDNS_UART_IXR_TXEMPTY,
- port->membase + CDNS_UART_IDR_OFFSET);
- } else {
- numbytes = port->fifosize;
- /* Break if no more data available in the UART buffer */
- while (numbytes--) {
- if (uart_circ_empty(&port->state->xmit))
- break;
- /* Get the data from the UART circular buffer
- * and write it to the cdns_uart's TX_FIFO
- * register.
- */
- writel(port->state->xmit.buf[
- port->state->xmit.tail],
- port->membase + CDNS_UART_FIFO_OFFSET);
-
- port->icount.tx++;
-
- /* Adjust the tail of the UART buffer and wrap
- * the buffer if it reaches limit.
- */
- port->state->xmit.tail =
- (port->state->xmit.tail + 1) &
- (UART_XMIT_SIZE - 1);
- }
+static void cdns_uart_handle_tx(struct uart_port *port)
+{
+ unsigned int numbytes;
- if (uart_circ_chars_pending(
- &port->state->xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
- }
+ if (uart_circ_empty(&port->state->xmit)) {
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
+ return;
+ }
+
+ numbytes = port->fifosize;
+ while (numbytes && !uart_circ_empty(&port->state->xmit) &&
+ !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
+ /*
+ * Get the data from the UART circular buffer
+ * and write it to the cdns_uart's TX_FIFO
+ * register.
+ */
+ writel(port->state->xmit.buf[port->state->xmit.tail],
+ port->membase + CDNS_UART_FIFO);
+ port->icount.tx++;
+
+ /*
+ * Adjust the tail of the UART buffer and wrap
+ * the buffer if it reaches limit.
+ */
+ port->state->xmit.tail =
+ (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
+
+ numbytes--;
}
- writel(isrstatus, port->membase + CDNS_UART_ISR_OFFSET);
+ if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+/**
+ * cdns_uart_isr - Interrupt handler
+ * @irq: Irq number
+ * @dev_id: Id of the port
+ *
+ * Return: IRQHANDLED
+ */
+static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ unsigned long flags;
+ unsigned int isrstatus;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Read the interrupt status register to determine which
+ * interrupt(s) is/are active.
+ */
+ isrstatus = readl(port->membase + CDNS_UART_ISR);
+
+ if (isrstatus & CDNS_UART_RX_IRQS)
+ cdns_uart_handle_rx(port, isrstatus);
+
+ if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY)
+ cdns_uart_handle_tx(port);
+
+ writel(isrstatus, port->membase + CDNS_UART_ISR);
/* be sure to release the lock and tty before leaving */
spin_unlock_irqrestore(&port->lock, flags);
@@ -395,14 +390,14 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
&div8);
/* Write new divisors to hardware */
- mreg = readl(port->membase + CDNS_UART_MR_OFFSET);
+ mreg = readl(port->membase + CDNS_UART_MR);
if (div8)
mreg |= CDNS_UART_MR_CLKSEL;
else
mreg &= ~CDNS_UART_MR_CLKSEL;
- writel(mreg, port->membase + CDNS_UART_MR_OFFSET);
- writel(cd, port->membase + CDNS_UART_BAUDGEN_OFFSET);
- writel(bdiv, port->membase + CDNS_UART_BAUDDIV_OFFSET);
+ writel(mreg, port->membase + CDNS_UART_MR);
+ writel(cd, port->membase + CDNS_UART_BAUDGEN);
+ writel(bdiv, port->membase + CDNS_UART_BAUDDIV);
cdns_uart->baud = baud;
return calc_baud;
@@ -449,9 +444,9 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
spin_lock_irqsave(&cdns_uart->port->lock, flags);
/* Disable the TX and RX to set baud rate */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
@@ -476,11 +471,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
spin_lock_irqsave(&cdns_uart->port->lock, flags);
/* Set TX/RX Reset */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
- while (readl(port->membase + CDNS_UART_CR_OFFSET) &
+ while (readl(port->membase + CDNS_UART_CR) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
@@ -489,11 +484,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
* enable bit and RX enable bit to enable the transmitter and
* receiver.
*/
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
@@ -510,43 +505,28 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
*/
static void cdns_uart_start_tx(struct uart_port *port)
{
- unsigned int status, numbytes = port->fifosize;
+ unsigned int status;
- if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port))
+ if (uart_tx_stopped(port))
return;
- status = readl(port->membase + CDNS_UART_CR_OFFSET);
- /* Set the TX enable bit and clear the TX disable bit to enable the
+ /*
+ * Set the TX enable bit and clear the TX disable bit to enable the
* transmitter.
*/
- writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
- port->membase + CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR);
+ status &= ~CDNS_UART_CR_TX_DIS;
+ status |= CDNS_UART_CR_TX_EN;
+ writel(status, port->membase + CDNS_UART_CR);
- while (numbytes-- && ((readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) {
- /* Break if no more data available in the UART buffer */
- if (uart_circ_empty(&port->state->xmit))
- break;
+ if (uart_circ_empty(&port->state->xmit))
+ return;
- /* Get the data from the UART circular buffer and
- * write it to the cdns_uart's TX_FIFO register.
- */
- writel(port->state->xmit.buf[port->state->xmit.tail],
- port->membase + CDNS_UART_FIFO_OFFSET);
- port->icount.tx++;
+ cdns_uart_handle_tx(port);
- /* Adjust the tail of the UART buffer and wrap
- * the buffer if it reaches limit.
- */
- port->state->xmit.tail = (port->state->xmit.tail + 1) &
- (UART_XMIT_SIZE - 1);
- }
- writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR_OFFSET);
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
/* Enable the TX Empty interrupt */
- writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER_OFFSET);
-
- if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
}
/**
@@ -557,10 +537,10 @@ static void cdns_uart_stop_tx(struct uart_port *port)
{
unsigned int regval;
- regval = readl(port->membase + CDNS_UART_CR_OFFSET);
+ regval = readl(port->membase + CDNS_UART_CR);
regval |= CDNS_UART_CR_TX_DIS;
/* Disable the transmitter */
- writel(regval, port->membase + CDNS_UART_CR_OFFSET);
+ writel(regval, port->membase + CDNS_UART_CR);
}
/**
@@ -571,10 +551,13 @@ static void cdns_uart_stop_rx(struct uart_port *port)
{
unsigned int regval;
- regval = readl(port->membase + CDNS_UART_CR_OFFSET);
- regval |= CDNS_UART_CR_RX_DIS;
+ /* Disable RX IRQs */
+ writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IDR);
+
/* Disable the receiver */
- writel(regval, port->membase + CDNS_UART_CR_OFFSET);
+ regval = readl(port->membase + CDNS_UART_CR);
+ regval |= CDNS_UART_CR_RX_DIS;
+ writel(regval, port->membase + CDNS_UART_CR);
}
/**
@@ -587,7 +570,7 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port)
{
unsigned int status;
- status = readl(port->membase + CDNS_UART_SR_OFFSET) &
+ status = readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_TXEMPTY;
return status ? TIOCSER_TEMT : 0;
}
@@ -605,15 +588,15 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
spin_lock_irqsave(&port->lock, flags);
- status = readl(port->membase + CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR);
if (ctl == -1)
writel(CDNS_UART_CR_STARTBRK | status,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
else {
if ((status & CDNS_UART_CR_STOPBRK) == 0)
writel(CDNS_UART_CR_STOPBRK | status,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
}
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -636,18 +619,18 @@ static void cdns_uart_set_termios(struct uart_port *port,
spin_lock_irqsave(&port->lock, flags);
/* Wait for the transmit FIFO to empty before making changes */
- if (!(readl(port->membase + CDNS_UART_CR_OFFSET) &
+ if (!(readl(port->membase + CDNS_UART_CR) &
CDNS_UART_CR_TX_DIS)) {
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_TXEMPTY)) {
cpu_relax();
}
}
/* Disable the TX and RX to set baud rate */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
/*
* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk
@@ -666,20 +649,20 @@ static void cdns_uart_set_termios(struct uart_port *port,
uart_update_timeout(port, termios->c_cflag, baud);
/* Set TX/RX Reset */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
/*
* Clear the RX disable and TX disable bits and then set the TX enable
* bit and RX enable bit to enable the transmitter and receiver.
*/
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
@@ -699,7 +682,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY |
CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
- mode_reg = readl(port->membase + CDNS_UART_MR_OFFSET);
+ mode_reg = readl(port->membase + CDNS_UART_MR);
/* Handling Data Size */
switch (termios->c_cflag & CSIZE) {
@@ -740,7 +723,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
cval |= CDNS_UART_MR_PARITY_NONE;
}
cval |= mode_reg & 1;
- writel(cval, port->membase + CDNS_UART_MR_OFFSET);
+ writel(cval, port->membase + CDNS_UART_MR);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -753,63 +736,67 @@ static void cdns_uart_set_termios(struct uart_port *port,
*/
static int cdns_uart_startup(struct uart_port *port)
{
- unsigned int retval = 0, status = 0;
+ int ret;
+ unsigned long flags;
+ unsigned int status = 0;
- retval = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME,
- (void *)port);
- if (retval)
- return retval;
+ spin_lock_irqsave(&port->lock, flags);
/* Disable the TX and RX */
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
/* Set the Control Register with TX/RX Enable, TX/RX Reset,
* no break chars.
*/
writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
- port->membase + CDNS_UART_CR_OFFSET);
-
- status = readl(port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
- /* Clear the RX disable and TX disable bits and then set the TX enable
- * bit and RX enable bit to enable the transmitter and receiver.
+ /*
+ * Clear the RX disable bit and then set the RX enable bit to enable
+ * the receiver.
*/
- writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS))
- | (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN |
- CDNS_UART_CR_STOPBRK),
- port->membase + CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR);
+ status &= CDNS_UART_CR_RX_DIS;
+ status |= CDNS_UART_CR_RX_EN;
+ writel(status, port->membase + CDNS_UART_CR);
/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
* no parity.
*/
writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT
| CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT,
- port->membase + CDNS_UART_MR_OFFSET);
+ port->membase + CDNS_UART_MR);
/*
* Set the RX FIFO Trigger level to use most of the FIFO, but it
* can be tuned with a module parameter
*/
- writel(rx_trigger_level, port->membase + CDNS_UART_RXWM_OFFSET);
+ writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
/*
* Receive Timeout register is enabled but it
* can be tuned with a module parameter
*/
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
/* Clear out any pending interrupts before enabling them */
- writel(readl(port->membase + CDNS_UART_ISR_OFFSET),
- port->membase + CDNS_UART_ISR_OFFSET);
+ writel(readl(port->membase + CDNS_UART_ISR),
+ port->membase + CDNS_UART_ISR);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port);
+ if (ret) {
+ dev_err(port->dev, "request_irq '%d' failed with %d\n",
+ port->irq, ret);
+ return ret;
+ }
/* Set the Interrupt Registers with desired interrupts */
- writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY |
- CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN |
- CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT,
- port->membase + CDNS_UART_IER_OFFSET);
+ writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
- return retval;
+ return 0;
}
/**
@@ -819,14 +806,21 @@ static int cdns_uart_startup(struct uart_port *port)
static void cdns_uart_shutdown(struct uart_port *port)
{
int status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
/* Disable interrupts */
- status = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(status, port->membase + CDNS_UART_IDR_OFFSET);
+ status = readl(port->membase + CDNS_UART_IMR);
+ writel(status, port->membase + CDNS_UART_IDR);
+ writel(0xffffffff, port->membase + CDNS_UART_ISR);
/* Disable the TX and RX */
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
free_irq(port->irq, port);
}
@@ -928,7 +922,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
u32 val;
- val = readl(port->membase + CDNS_UART_MODEMCR_OFFSET);
+ val = readl(port->membase + CDNS_UART_MODEMCR);
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
@@ -937,55 +931,46 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_DTR)
val |= CDNS_UART_MODEMCR_DTR;
- writel(val, port->membase + CDNS_UART_MODEMCR_OFFSET);
+ writel(val, port->membase + CDNS_UART_MODEMCR);
}
#ifdef CONFIG_CONSOLE_POLL
static int cdns_uart_poll_get_char(struct uart_port *port)
{
- u32 imr;
int c;
+ unsigned long flags;
- /* Disable all interrupts */
- imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
+ spin_lock_irqsave(&port->lock, flags);
/* Check if FIFO is empty */
- if (readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)
+ if (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)
c = NO_POLL_CHAR;
else /* Read a character */
- c = (unsigned char) readl(
- port->membase + CDNS_UART_FIFO_OFFSET);
+ c = (unsigned char) readl(port->membase + CDNS_UART_FIFO);
- /* Enable interrupts */
- writel(imr, port->membase + CDNS_UART_IER_OFFSET);
+ spin_unlock_irqrestore(&port->lock, flags);
return c;
}
static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
{
- u32 imr;
+ unsigned long flags;
- /* Disable all interrupts */
- imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
+ spin_lock_irqsave(&port->lock, flags);
/* Wait until FIFO is empty */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
cpu_relax();
/* Write a character */
- writel(c, port->membase + CDNS_UART_FIFO_OFFSET);
+ writel(c, port->membase + CDNS_UART_FIFO);
/* Wait until FIFO is empty */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
cpu_relax();
- /* Enable interrupts */
- writel(imr, port->membase + CDNS_UART_IER_OFFSET);
+ spin_unlock_irqrestore(&port->lock, flags);
return;
}
@@ -1059,8 +1044,7 @@ static struct uart_port *cdns_uart_get_port(int id)
*/
static void cdns_uart_console_wait_tx(struct uart_port *port)
{
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
barrier();
}
@@ -1072,7 +1056,7 @@ static void cdns_uart_console_wait_tx(struct uart_port *port)
static void cdns_uart_console_putchar(struct uart_port *port, int ch)
{
cdns_uart_console_wait_tx(port);
- writel(ch, port->membase + CDNS_UART_FIFO_OFFSET);
+ writel(ch, port->membase + CDNS_UART_FIFO);
}
static void __init cdns_early_write(struct console *con, const char *s,
@@ -1093,7 +1077,9 @@ static int __init cdns_early_console_setup(struct earlycon_device *device,
return 0;
}
-EARLYCON_DECLARE(cdns, cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "xlnx,xuartps", cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p8", cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup);
/**
* cdns_uart_console_write - perform write operation
@@ -1109,30 +1095,33 @@ static void cdns_uart_console_write(struct console *co, const char *s,
unsigned int imr, ctrl;
int locked = 1;
- if (oops_in_progress)
+ if (port->sysrq)
+ locked = 0;
+ else if (oops_in_progress)
locked = spin_trylock_irqsave(&port->lock, flags);
else
spin_lock_irqsave(&port->lock, flags);
/* save and disable interrupt */
- imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
+ imr = readl(port->membase + CDNS_UART_IMR);
+ writel(imr, port->membase + CDNS_UART_IDR);
/*
* Make sure that the tx part is enabled. Set the TX enable bit and
* clear the TX disable bit to enable the transmitter.
*/
- ctrl = readl(port->membase + CDNS_UART_CR_OFFSET);
- writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
- port->membase + CDNS_UART_CR_OFFSET);
+ ctrl = readl(port->membase + CDNS_UART_CR);
+ ctrl &= ~CDNS_UART_CR_TX_DIS;
+ ctrl |= CDNS_UART_CR_TX_EN;
+ writel(ctrl, port->membase + CDNS_UART_CR);
uart_console_write(port, s, count, cdns_uart_console_putchar);
cdns_uart_console_wait_tx(port);
- writel(ctrl, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl, port->membase + CDNS_UART_CR);
/* restore interrupt state */
- writel(imr, port->membase + CDNS_UART_IER_OFFSET);
+ writel(imr, port->membase + CDNS_UART_IER);
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
@@ -1244,14 +1233,13 @@ static int cdns_uart_suspend(struct device *device)
spin_lock_irqsave(&port->lock, flags);
/* Empty the receive FIFO 1st before making changes */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_RXEMPTY))
- readl(port->membase + CDNS_UART_FIFO_OFFSET);
+ readl(port->membase + CDNS_UART_FIFO);
/* set RX trigger level to 1 */
- writel(1, port->membase + CDNS_UART_RXWM_OFFSET);
+ writel(1, port->membase + CDNS_UART_RXWM);
/* disable RX timeout interrups */
- writel(CDNS_UART_IXR_TOUT,
- port->membase + CDNS_UART_IDR_OFFSET);
+ writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IDR);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1290,30 +1278,28 @@ static int cdns_uart_resume(struct device *device)
spin_lock_irqsave(&port->lock, flags);
/* Set TX/RX Reset */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
- while (readl(port->membase + CDNS_UART_CR_OFFSET) &
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
+ while (readl(port->membase + CDNS_UART_CR) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
/* restore rx timeout value */
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
/* Enable Tx/Rx */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
spin_unlock_irqrestore(&port->lock, flags);
} else {
spin_lock_irqsave(&port->lock, flags);
/* restore original rx trigger level */
- writel(rx_trigger_level,
- port->membase + CDNS_UART_RXWM_OFFSET);
+ writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
/* enable RX timeout interrupt */
- writel(CDNS_UART_IXR_TOUT,
- port->membase + CDNS_UART_IER_OFFSET);
+ writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IER);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1406,27 +1392,30 @@ static int cdns_uart_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Cannot get uart_port structure\n");
rc = -ENODEV;
goto err_out_notif_unreg;
- } else {
- /* Register the port.
- * This function also registers this device with the tty layer
- * and triggers invocation of the config_port() entry point.
- */
- port->mapbase = res->start;
- port->irq = irq;
- port->dev = &pdev->dev;
- port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
- port->private_data = cdns_uart_data;
- cdns_uart_data->port = port;
- platform_set_drvdata(pdev, port);
- rc = uart_add_one_port(&cdns_uart_uart_driver, port);
- if (rc) {
- dev_err(&pdev->dev,
- "uart_add_one_port() failed; err=%i\n", rc);
- goto err_out_notif_unreg;
- }
- return 0;
}
+ /*
+ * Register the port.
+ * This function also registers this device with the tty layer
+ * and triggers invocation of the config_port() entry point.
+ */
+ port->mapbase = res->start;
+ port->irq = irq;
+ port->dev = &pdev->dev;
+ port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
+ port->private_data = cdns_uart_data;
+ cdns_uart_data->port = port;
+ platform_set_drvdata(pdev, port);
+
+ rc = uart_add_one_port(&cdns_uart_uart_driver, port);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "uart_add_one_port() failed; err=%i\n", rc);
+ goto err_out_notif_unreg;
+ }
+
+ return 0;
+
err_out_notif_unreg:
#ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk,
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
index 2b65bb7ffb8a..eeefd76a30da 100644
--- a/drivers/tty/serial/zs.c
+++ b/drivers/tty/serial/zs.c
@@ -1181,6 +1181,10 @@ static void zs_console_write(struct console *co, const char *s,
if (txint & TxINT_ENAB) {
zport->regs[1] |= TxINT_ENAB;
write_zsreg(zport, R1, zport->regs[1]);
+
+ /* Resume any transmission as the TxIP bit won't be set. */
+ if (!zport->tx_stopped)
+ zs_raw_transmit_chars(zport);
}
spin_unlock_irqrestore(&scc->zlock, flags);
}
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 6188059fd523..f5476e270734 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -2363,7 +2363,7 @@ static void mgsl_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
mgsl_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals &= ~SerialSignal_RTS;
usc_set_serial_signals(info);
@@ -2397,7 +2397,7 @@ static void mgsl_unthrottle(struct tty_struct * tty)
mgsl_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals |= SerialSignal_RTS;
usc_set_serial_signals(info);
@@ -3039,30 +3039,25 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
mgsl_change_params(info);
/* Handle transition to B0 status */
- if (old_termios->c_cflag & CBAUD &&
- !(tty->termios.c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
spin_lock_irqsave(&info->irq_spinlock,flags);
usc_set_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
-
+
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios.c_cflag & CBAUD) {
+ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
info->serial_signals |= SerialSignal_RTS;
- }
spin_lock_irqsave(&info->irq_spinlock,flags);
usc_set_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
-
+
/* Handle turning off CRTSCTS */
- if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
mgsl_start(tty);
}
@@ -3281,7 +3276,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (tty->termios.c_cflag & CLOCAL)
+ if (C_CLOCAL(tty))
do_clocal = true;
/* Wait for carrier detect and the line to become
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 5505ea842179..c0a2f5a1b1c2 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -774,8 +774,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_params(info);
/* Handle transition to B0 status */
- if (old_termios->c_cflag & CBAUD &&
- !(tty->termios.c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -783,21 +782,17 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios.c_cflag & CBAUD) {
+ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
info->signals |= SerialSignal_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
info->signals |= SerialSignal_RTS;
- }
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
/* Handle turning off CRTSCTS */
- if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -1362,7 +1357,7 @@ static void throttle(struct tty_struct * tty)
DBGINFO(("%s throttle\n", info->device_name));
if (I_IXOFF(tty))
send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock,flags);
info->signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1387,7 +1382,7 @@ static void unthrottle(struct tty_struct * tty)
else
send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock,flags);
info->signals |= SerialSignal_RTS;
set_signals(info);
@@ -3280,7 +3275,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
- if (tty->termios.c_cflag & CLOCAL)
+ if (C_CLOCAL(tty))
do_clocal = true;
/* Wait for carrier detect and the line to become
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index fb00a06dfa4b..90da0c712262 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -549,8 +549,8 @@ static int tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static int set_break(struct tty_struct *tty, int break_state);
-static void add_device(SLMP_INFO *info);
-static void device_init(int adapter_num, struct pci_dev *pdev);
+static int add_device(SLMP_INFO *info);
+static int device_init(int adapter_num, struct pci_dev *pdev);
static int claim_resources(SLMP_INFO *info);
static void release_resources(SLMP_INFO *info);
@@ -871,8 +871,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_params(info);
/* Handle transition to B0 status */
- if (old_termios->c_cflag & CBAUD &&
- !(tty->termios.c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -880,21 +879,17 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios.c_cflag & CBAUD) {
+ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
info->serial_signals |= SerialSignal_RTS;
- }
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
/* Handle turning off CRTSCTS */
- if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -1472,7 +1467,7 @@ static void throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1501,7 +1496,7 @@ static void unthrottle(struct tty_struct * tty)
send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS;
set_signals(info);
@@ -3297,7 +3292,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
- if (tty->termios.c_cflag & CLOCAL)
+ if (C_CLOCAL(tty))
do_clocal = true;
/* Wait for carrier detect and the line to become
@@ -3693,7 +3688,7 @@ static void release_resources(SLMP_INFO *info)
/* Add the specified device instance data structure to the
* global linked list of devices and increment the device count.
*/
-static void add_device(SLMP_INFO *info)
+static int add_device(SLMP_INFO *info)
{
info->next_device = NULL;
info->line = synclinkmp_device_count;
@@ -3731,7 +3726,9 @@ static void add_device(SLMP_INFO *info)
info->max_frame_size );
#if SYNCLINK_GENERIC_HDLC
- hdlcdev_init(info);
+ return hdlcdev_init(info);
+#else
+ return 0;
#endif
}
@@ -3820,10 +3817,10 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
return info;
}
-static void device_init(int adapter_num, struct pci_dev *pdev)
+static int device_init(int adapter_num, struct pci_dev *pdev)
{
SLMP_INFO *port_array[SCA_MAX_PORTS];
- int port;
+ int port, rc;
/* allocate device instances for up to SCA_MAX_PORTS devices */
for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
@@ -3833,14 +3830,16 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
tty_port_destroy(&port_array[port]->port);
kfree(port_array[port]);
}
- return;
+ return -ENOMEM;
}
}
/* give copy of port_array to all ports and add to device list */
for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
memcpy(port_array[port]->port_array,port_array,sizeof(port_array));
- add_device( port_array[port] );
+ rc = add_device( port_array[port] );
+ if (rc)
+ goto err_add;
spin_lock_init(&port_array[port]->lock);
}
@@ -3860,21 +3859,30 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
alloc_dma_bufs(port_array[port]);
}
- if ( request_irq(port_array[0]->irq_level,
+ rc = request_irq(port_array[0]->irq_level,
synclinkmp_interrupt,
port_array[0]->irq_flags,
port_array[0]->device_name,
- port_array[0]) < 0 ) {
+ port_array[0]);
+ if ( rc ) {
printk( "%s(%d):%s Can't request interrupt, IRQ=%d\n",
__FILE__,__LINE__,
port_array[0]->device_name,
port_array[0]->irq_level );
+ goto err_irq;
}
- else {
- port_array[0]->irq_requested = true;
- adapter_test(port_array[0]);
- }
+ port_array[0]->irq_requested = true;
+ adapter_test(port_array[0]);
}
+ return 0;
+err_irq:
+ release_resources( port_array[0] );
+err_add:
+ for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
+ tty_port_destroy(&port_array[port]->port);
+ kfree(port_array[port]);
+ }
+ return rc;
}
static const struct tty_operations ops = {
@@ -5589,8 +5597,7 @@ static int synclinkmp_init_one (struct pci_dev *dev,
printk("error enabling pci device %p\n", dev);
return -EIO;
}
- device_init( ++synclinkmp_adapter_count, dev );
- return 0;
+ return device_init( ++synclinkmp_adapter_count, dev );
}
static void synclinkmp_remove_one (struct pci_dev *dev)
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
index 3d245cd3d8e6..df2d735338e2 100644
--- a/drivers/tty/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -14,16 +14,23 @@
#include <linux/tty.h>
struct tty_audit_buf {
- atomic_t count;
struct mutex mutex; /* Protects all data below */
- int major, minor; /* The TTY which the data is from */
+ dev_t dev; /* The TTY which the data is from */
unsigned icanon:1;
size_t valid;
unsigned char *data; /* Allocated size N_TTY_BUF_SIZE */
};
-static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
- unsigned icanon)
+static struct tty_audit_buf *tty_audit_buf_ref(void)
+{
+ struct tty_audit_buf *buf;
+
+ buf = current->signal->tty_audit_buf;
+ WARN_ON(buf == ERR_PTR(-ESRCH));
+ return buf;
+}
+
+static struct tty_audit_buf *tty_audit_buf_alloc(void)
{
struct tty_audit_buf *buf;
@@ -33,11 +40,9 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!buf->data)
goto err_buf;
- atomic_set(&buf->count, 1);
mutex_init(&buf->mutex);
- buf->major = major;
- buf->minor = minor;
- buf->icanon = icanon;
+ buf->dev = MKDEV(0, 0);
+ buf->icanon = 0;
buf->valid = 0;
return buf;
@@ -54,13 +59,7 @@ static void tty_audit_buf_free(struct tty_audit_buf *buf)
kfree(buf);
}
-static void tty_audit_buf_put(struct tty_audit_buf *buf)
-{
- if (atomic_dec_and_test(&buf->count))
- tty_audit_buf_free(buf);
-}
-
-static void tty_audit_log(const char *description, int major, int minor,
+static void tty_audit_log(const char *description, dev_t dev,
unsigned char *data, size_t size)
{
struct audit_buffer *ab;
@@ -76,7 +75,7 @@ static void tty_audit_log(const char *description, int major, int minor,
audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d"
" minor=%d comm=", description, pid, uid,
- loginuid, sessionid, major, minor);
+ loginuid, sessionid, MAJOR(dev), MINOR(dev));
get_task_comm(name, tsk);
audit_log_untrustedstring(ab, name);
audit_log_format(ab, " data=");
@@ -99,7 +98,7 @@ static void tty_audit_buf_push(struct tty_audit_buf *buf)
buf->valid = 0;
return;
}
- tty_audit_log("tty", buf->major, buf->minor, buf->data, buf->valid);
+ tty_audit_log("tty", buf->dev, buf->data, buf->valid);
buf->valid = 0;
}
@@ -108,21 +107,20 @@ static void tty_audit_buf_push(struct tty_audit_buf *buf)
*
* Make sure all buffered data is written out and deallocate the buffer.
* Only needs to be called if current->signal->tty_audit_buf != %NULL.
+ *
+ * The process is single-threaded at this point; no other threads share
+ * current->signal.
*/
void tty_audit_exit(void)
{
struct tty_audit_buf *buf;
- buf = current->signal->tty_audit_buf;
- current->signal->tty_audit_buf = NULL;
+ buf = xchg(&current->signal->tty_audit_buf, ERR_PTR(-ESRCH));
if (!buf)
return;
- mutex_lock(&buf->mutex);
tty_audit_buf_push(buf);
- mutex_unlock(&buf->mutex);
-
- tty_audit_buf_put(buf);
+ tty_audit_buf_free(buf);
}
/**
@@ -133,7 +131,6 @@ void tty_audit_exit(void)
void tty_audit_fork(struct signal_struct *sig)
{
sig->audit_tty = current->signal->audit_tty;
- sig->audit_tty_log_passwd = current->signal->audit_tty_log_passwd;
}
/**
@@ -141,123 +138,62 @@ void tty_audit_fork(struct signal_struct *sig)
*/
void tty_audit_tiocsti(struct tty_struct *tty, char ch)
{
- struct tty_audit_buf *buf;
- int major, minor, should_audit;
- unsigned long flags;
+ dev_t dev;
- spin_lock_irqsave(&current->sighand->siglock, flags);
- should_audit = current->signal->audit_tty;
- buf = current->signal->tty_audit_buf;
- if (buf)
- atomic_inc(&buf->count);
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
-
- major = tty->driver->major;
- minor = tty->driver->minor_start + tty->index;
- if (buf) {
- mutex_lock(&buf->mutex);
- if (buf->major == major && buf->minor == minor)
- tty_audit_buf_push(buf);
- mutex_unlock(&buf->mutex);
- tty_audit_buf_put(buf);
- }
-
- if (should_audit && audit_enabled) {
- kuid_t auid;
- unsigned int sessionid;
+ dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
+ if (tty_audit_push())
+ return;
- auid = audit_get_loginuid(current);
- sessionid = audit_get_sessionid(current);
- tty_audit_log("ioctl=TIOCSTI", major, minor, &ch, 1);
- }
+ if (audit_enabled)
+ tty_audit_log("ioctl=TIOCSTI", dev, &ch, 1);
}
/**
- * tty_audit_push_current - Flush current's pending audit data
+ * tty_audit_push - Flush current's pending audit data
*
- * Try to lock sighand and get a reference to the tty audit buffer if available.
- * Flush the buffer or return an appropriate error code.
+ * Returns 0 if success, -EPERM if tty audit is disabled
*/
-int tty_audit_push_current(void)
+int tty_audit_push(void)
{
- struct tty_audit_buf *buf = ERR_PTR(-EPERM);
- struct task_struct *tsk = current;
- unsigned long flags;
+ struct tty_audit_buf *buf;
- if (!lock_task_sighand(tsk, &flags))
- return -ESRCH;
+ if (~current->signal->audit_tty & AUDIT_TTY_ENABLE)
+ return -EPERM;
- if (tsk->signal->audit_tty) {
- buf = tsk->signal->tty_audit_buf;
- if (buf)
- atomic_inc(&buf->count);
+ buf = tty_audit_buf_ref();
+ if (!IS_ERR_OR_NULL(buf)) {
+ mutex_lock(&buf->mutex);
+ tty_audit_buf_push(buf);
+ mutex_unlock(&buf->mutex);
}
- unlock_task_sighand(tsk, &flags);
-
- /*
- * Return 0 when signal->audit_tty set
- * but tsk->signal->tty_audit_buf == NULL.
- */
- if (!buf || IS_ERR(buf))
- return PTR_ERR(buf);
-
- mutex_lock(&buf->mutex);
- tty_audit_buf_push(buf);
- mutex_unlock(&buf->mutex);
-
- tty_audit_buf_put(buf);
return 0;
}
/**
* tty_audit_buf_get - Get an audit buffer.
*
- * Get an audit buffer for @tty, allocate it if necessary. Return %NULL
- * if TTY auditing is disabled or out of memory. Otherwise, return a new
- * reference to the buffer.
+ * Get an audit buffer, allocate it if necessary. Return %NULL
+ * if out of memory or ERR_PTR(-ESRCH) if tty_audit_exit() has already
+ * occurred. Otherwise, return a new reference to the buffer.
*/
-static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
- unsigned icanon)
+static struct tty_audit_buf *tty_audit_buf_get(void)
{
- struct tty_audit_buf *buf, *buf2;
- unsigned long flags;
-
- buf = NULL;
- buf2 = NULL;
- spin_lock_irqsave(&current->sighand->siglock, flags);
- if (likely(!current->signal->audit_tty))
- goto out;
- buf = current->signal->tty_audit_buf;
- if (buf) {
- atomic_inc(&buf->count);
- goto out;
- }
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ struct tty_audit_buf *buf;
+
+ buf = tty_audit_buf_ref();
+ if (buf)
+ return buf;
- buf2 = tty_audit_buf_alloc(tty->driver->major,
- tty->driver->minor_start + tty->index,
- icanon);
- if (buf2 == NULL) {
+ buf = tty_audit_buf_alloc();
+ if (buf == NULL) {
audit_log_lost("out of memory in TTY auditing");
return NULL;
}
- spin_lock_irqsave(&current->sighand->siglock, flags);
- if (!current->signal->audit_tty)
- goto out;
- buf = current->signal->tty_audit_buf;
- if (!buf) {
- current->signal->tty_audit_buf = buf2;
- buf = buf2;
- buf2 = NULL;
- }
- atomic_inc(&buf->count);
- /* Fall through */
- out:
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
- if (buf2)
- tty_audit_buf_free(buf2);
- return buf;
+ /* Race to use this buffer, free it if another wins */
+ if (cmpxchg(&current->signal->tty_audit_buf, NULL, buf) != NULL)
+ tty_audit_buf_free(buf);
+ return tty_audit_buf_ref();
}
/**
@@ -265,39 +201,36 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
*
* Audit @data of @size from @tty, if necessary.
*/
-void tty_audit_add_data(struct tty_struct *tty, const void *data,
- size_t size, unsigned icanon)
+void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size)
{
struct tty_audit_buf *buf;
- int major, minor;
- int audit_log_tty_passwd;
- unsigned long flags;
+ unsigned int icanon = !!L_ICANON(tty);
+ unsigned int audit_tty;
+ dev_t dev;
- if (unlikely(size == 0))
+ audit_tty = READ_ONCE(current->signal->audit_tty);
+ if (~audit_tty & AUDIT_TTY_ENABLE)
return;
- spin_lock_irqsave(&current->sighand->siglock, flags);
- audit_log_tty_passwd = current->signal->audit_tty_log_passwd;
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
- if (!audit_log_tty_passwd && icanon && !L_ECHO(tty))
+ if (unlikely(size == 0))
return;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY
&& tty->driver->subtype == PTY_TYPE_MASTER)
return;
- buf = tty_audit_buf_get(tty, icanon);
- if (!buf)
+ if ((~audit_tty & AUDIT_TTY_LOG_PASSWD) && icanon && !L_ECHO(tty))
+ return;
+
+ buf = tty_audit_buf_get();
+ if (IS_ERR_OR_NULL(buf))
return;
mutex_lock(&buf->mutex);
- major = tty->driver->major;
- minor = tty->driver->minor_start + tty->index;
- if (buf->major != major || buf->minor != minor
- || buf->icanon != icanon) {
+ dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
+ if (buf->dev != dev || buf->icanon != icanon) {
tty_audit_buf_push(buf);
- buf->major = major;
- buf->minor = minor;
+ buf->dev = dev;
buf->icanon = icanon;
}
do {
@@ -314,38 +247,4 @@ void tty_audit_add_data(struct tty_struct *tty, const void *data,
tty_audit_buf_push(buf);
} while (size != 0);
mutex_unlock(&buf->mutex);
- tty_audit_buf_put(buf);
-}
-
-/**
- * tty_audit_push - Push buffered data out
- *
- * Make sure no audit data is pending for @tty on the current process.
- */
-void tty_audit_push(struct tty_struct *tty)
-{
- struct tty_audit_buf *buf;
- unsigned long flags;
-
- spin_lock_irqsave(&current->sighand->siglock, flags);
- if (likely(!current->signal->audit_tty)) {
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
- return;
- }
- buf = current->signal->tty_audit_buf;
- if (buf)
- atomic_inc(&buf->count);
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
-
- if (buf) {
- int major, minor;
-
- major = tty->driver->major;
- minor = tty->driver->minor_start + tty->index;
- mutex_lock(&buf->mutex);
- if (buf->major == major && buf->minor == minor)
- tty_audit_buf_push(buf);
- mutex_unlock(&buf->mutex);
- tty_audit_buf_put(buf);
- }
}
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 3cd31e0d4bd9..a946e49a2626 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -435,25 +435,42 @@ int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
+/**
+ * tty_ldisc_receive_buf - forward data to line discipline
+ * @ld: line discipline to process input
+ * @p: char buffer
+ * @f: TTY_* flags buffer
+ * @count: number of bytes to process
+ *
+ * Callers other than flush_to_ldisc() need to exclude the kworker
+ * from concurrent use of the line discipline, see paste_selection().
+ *
+ * Returns the number of bytes not processed
+ */
+int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p,
+ char *f, int count)
+{
+ if (ld->ops->receive_buf2)
+ count = ld->ops->receive_buf2(ld->tty, p, f, count);
+ else {
+ count = min_t(int, count, ld->tty->receive_room);
+ if (count && ld->ops->receive_buf)
+ ld->ops->receive_buf(ld->tty, p, f, count);
+ }
+ return count;
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf);
static int
-receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
+receive_buf(struct tty_ldisc *ld, struct tty_buffer *head, int count)
{
- struct tty_ldisc *disc = tty->ldisc;
unsigned char *p = char_buf_ptr(head, head->read);
char *f = NULL;
if (~head->flags & TTYB_NORMAL)
f = flag_buf_ptr(head, head->read);
- if (disc->ops->receive_buf2)
- count = disc->ops->receive_buf2(tty, p, f, count);
- else {
- count = min_t(int, count, tty->receive_room);
- if (count && disc->ops->receive_buf)
- disc->ops->receive_buf(tty, p, f, count);
- }
- return count;
+ return tty_ldisc_receive_buf(ld, p, f, count);
}
/**
@@ -514,7 +531,7 @@ static void flush_to_ldisc(struct work_struct *work)
continue;
}
- count = receive_buf(tty, head, count);
+ count = receive_buf(disc, head, count);
if (!count)
break;
head->read += count;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index a7eacef1bd22..8d26ed79bb4c 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -123,7 +123,8 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers */
ECHOCTL | ECHOKE | IEXTEN,
.c_cc = INIT_C_CC,
.c_ispeed = 38400,
- .c_ospeed = 38400
+ .c_ospeed = 38400,
+ /* .c_line = N_TTY, */
};
EXPORT_SYMBOL(tty_std_termios);
@@ -134,13 +135,8 @@ EXPORT_SYMBOL(tty_std_termios);
LIST_HEAD(tty_drivers); /* linked list of tty drivers */
-/* Mutex to protect creating and releasing a tty. This is shared with
- vt.c for deeply disgusting hack reasons */
+/* Mutex to protect creating and releasing a tty */
DEFINE_MUTEX(tty_mutex);
-EXPORT_SYMBOL(tty_mutex);
-
-/* Spinlock to protect the tty->tty_files list */
-DEFINE_SPINLOCK(tty_files_lock);
static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
@@ -168,10 +164,9 @@ static void release_tty(struct tty_struct *tty, int idx);
* Locking: none. Must be called after tty is definitely unused
*/
-void free_tty_struct(struct tty_struct *tty)
+static void free_tty_struct(struct tty_struct *tty)
{
- if (!tty)
- return;
+ tty_ldisc_deinit(tty);
put_device(tty->dev);
kfree(tty->write_buf);
tty->magic = 0xDEADDEAD;
@@ -204,9 +199,9 @@ void tty_add_file(struct tty_struct *tty, struct file *file)
priv->tty = tty;
priv->file = file;
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
list_add(&priv->list, &tty->tty_files);
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
}
/**
@@ -227,10 +222,11 @@ void tty_free_file(struct file *file)
static void tty_del_file(struct file *file)
{
struct tty_file_private *priv = file->private_data;
+ struct tty_struct *tty = priv->tty;
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
list_del(&priv->list);
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
tty_free_file(file);
}
@@ -288,11 +284,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
struct list_head *p;
int count = 0;
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
list_for_each(p, &tty->tty_files) {
count++;
}
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_SLAVE &&
tty->link && tty->link->count)
@@ -383,6 +379,12 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
EXPORT_SYMBOL_GPL(tty_find_polling_driver);
#endif
+static int is_ignored(int sig)
+{
+ return (sigismember(&current->blocked, sig) ||
+ current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
+}
+
/**
* tty_check_change - check for POSIX terminal changes
* @tty: tty to check
@@ -466,6 +468,11 @@ static long hung_up_tty_compat_ioctl(struct file *file,
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
+static int hung_up_tty_fasync(int fd, struct file *file, int on)
+{
+ return -ENOTTY;
+}
+
static const struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
@@ -498,6 +505,7 @@ static const struct file_operations hung_up_tty_fops = {
.unlocked_ioctl = hung_up_tty_ioctl,
.compat_ioctl = hung_up_tty_compat_ioctl,
.release = tty_release,
+ .fasync = hung_up_tty_fasync,
};
static DEFINE_SPINLOCK(redirect_lock);
@@ -709,7 +717,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
workqueue with the lock held */
check_tty_count(tty, "tty_hangup");
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
/* This breaks for file handles being sent over AF_UNIX sockets ? */
list_for_each_entry(priv, &tty->tty_files, list) {
filp = priv->file;
@@ -721,14 +729,14 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
__tty_fasync(-1, filp, 0); /* can't block */
filp->f_op = &hung_up_tty_fops;
}
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
refs = tty_signal_session_leader(tty, exit_session);
/* Account for the p->signal references we killed */
while (refs--)
tty_kref_put(tty);
- tty_ldisc_hangup(tty);
+ tty_ldisc_hangup(tty, cons_filp != NULL);
spin_lock_irq(&tty->ctrl_lock);
clear_bit(TTY_THROTTLED, &tty->flags);
@@ -753,10 +761,9 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
} else if (tty->ops->hangup)
tty->ops->hangup(tty);
/*
- * We don't want to have driver/ldisc interactions beyond
- * the ones we did here. The driver layer expects no
- * calls after ->hangup() from the ldisc side. However we
- * can't yet guarantee all that.
+ * We don't want to have driver/ldisc interactions beyond the ones
+ * we did here. The driver layer expects no calls after ->hangup()
+ * from the ldisc side, which is now guaranteed.
*/
set_bit(TTY_HUPPED, &tty->flags);
tty_unlock(tty);
@@ -1069,6 +1076,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
/* We want to wait for the line discipline to sort out in this
situation */
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_read(file, buf, count, ppos);
if (ld->ops->read)
i = ld->ops->read(tty, file, buf, count);
else
@@ -1243,6 +1252,8 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
if (tty->ops->write_room == NULL)
tty_err(tty, "missing write_room method\n");
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_write(file, buf, count, ppos);
if (!ld->ops->write)
ret = -EIO;
else
@@ -1378,7 +1389,7 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
* the tty_mutex currently so we can be relaxed about ordering.
*/
-int tty_init_termios(struct tty_struct *tty)
+void tty_init_termios(struct tty_struct *tty)
{
struct ktermios *tp;
int idx = tty->index;
@@ -1388,24 +1399,21 @@ int tty_init_termios(struct tty_struct *tty)
else {
/* Check for lazy saved data */
tp = tty->driver->termios[idx];
- if (tp != NULL)
+ if (tp != NULL) {
tty->termios = *tp;
- else
+ tty->termios.c_line = tty->driver->init_termios.c_line;
+ } else
tty->termios = tty->driver->init_termios;
}
/* Compatibility until drivers always set this */
tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
- return 0;
}
EXPORT_SYMBOL_GPL(tty_init_termios);
int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
{
- int ret = tty_init_termios(tty);
- if (ret)
- return ret;
-
+ tty_init_termios(tty);
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[tty->index] = tty;
@@ -1442,7 +1450,7 @@ static int tty_driver_install_tty(struct tty_driver *driver,
*
* Locking: tty_mutex for now
*/
-void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
+static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
{
if (driver->ops->remove)
driver->ops->remove(driver, tty);
@@ -1475,7 +1483,8 @@ static int tty_reopen(struct tty_struct *tty)
tty->count++;
- WARN_ON(!tty->ldisc);
+ if (!tty->ldisc)
+ return tty_ldisc_reinit(tty, tty->termios.c_line);
return 0;
}
@@ -1529,7 +1538,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
tty_lock(tty);
retval = tty_driver_install_tty(driver, tty);
if (retval < 0)
- goto err_deinit_tty;
+ goto err_free_tty;
if (!tty->port)
tty->port = driver->ports[idx];
@@ -1551,9 +1560,8 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
/* Return the tty locked so that it cannot vanish under the caller */
return tty;
-err_deinit_tty:
+err_free_tty:
tty_unlock(tty);
- deinitialize_tty_struct(tty);
free_tty_struct(tty);
err_module_put:
module_put(driver->owner);
@@ -1568,7 +1576,7 @@ err_release_tty:
return ERR_PTR(retval);
}
-void tty_free_termios(struct tty_struct *tty)
+static void tty_free_termios(struct tty_struct *tty)
{
struct ktermios *tp;
int idx = tty->index;
@@ -1587,7 +1595,6 @@ void tty_free_termios(struct tty_struct *tty)
}
*tp = tty->termios;
}
-EXPORT_SYMBOL(tty_free_termios);
/**
* tty_flush_works - flush all works of a tty/pty pair
@@ -1634,9 +1641,9 @@ static void release_one_tty(struct work_struct *work)
tty_driver_kref_put(driver);
module_put(owner);
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
list_del_init(&tty->tty_files);
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
put_pid(tty->pgrp);
put_pid(tty->session);
@@ -1967,7 +1974,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
* Locking: tty_mutex protects get_tty_driver
*/
static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
- int *noctty, int *index)
+ int *index)
{
struct tty_driver *driver;
@@ -1977,7 +1984,6 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
extern struct tty_driver *console_driver;
driver = tty_driver_kref_get(console_driver);
*index = fg_console;
- *noctty = 1;
break;
}
#endif
@@ -1988,7 +1994,6 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
if (driver) {
/* Don't let /dev/console block */
filp->f_flags |= O_NONBLOCK;
- *noctty = 1;
break;
}
}
@@ -2004,6 +2009,69 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
}
/**
+ * tty_open_by_driver - open a tty device
+ * @device: dev_t of device to open
+ * @inode: inode of device file
+ * @filp: file pointer to tty
+ *
+ * Performs the driver lookup, checks for a reopen, or otherwise
+ * performs the first-time tty initialization.
+ *
+ * Returns the locked initialized or re-opened &tty_struct
+ *
+ * Claims the global tty_mutex to serialize:
+ * - concurrent first-time tty initialization
+ * - concurrent tty driver removal w/ lookup
+ * - concurrent tty removal from driver table
+ */
+static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,
+ struct file *filp)
+{
+ struct tty_struct *tty;
+ struct tty_driver *driver = NULL;
+ int index = -1;
+ int retval;
+
+ mutex_lock(&tty_mutex);
+ driver = tty_lookup_driver(device, filp, &index);
+ if (IS_ERR(driver)) {
+ mutex_unlock(&tty_mutex);
+ return ERR_CAST(driver);
+ }
+
+ /* check whether we're reopening an existing tty */
+ tty = tty_driver_lookup_tty(driver, inode, index);
+ if (IS_ERR(tty)) {
+ mutex_unlock(&tty_mutex);
+ goto out;
+ }
+
+ if (tty) {
+ mutex_unlock(&tty_mutex);
+ retval = tty_lock_interruptible(tty);
+ if (retval) {
+ if (retval == -EINTR)
+ retval = -ERESTARTSYS;
+ tty = ERR_PTR(retval);
+ goto out;
+ }
+ /* safe to drop the kref from tty_driver_lookup_tty() */
+ tty_kref_put(tty);
+ retval = tty_reopen(tty);
+ if (retval < 0) {
+ tty_unlock(tty);
+ tty = ERR_PTR(retval);
+ }
+ } else { /* Returns with the tty_lock held for now */
+ tty = tty_init_dev(driver, index);
+ mutex_unlock(&tty_mutex);
+ }
+out:
+ tty_driver_kref_put(driver);
+ return tty;
+}
+
+/**
* tty_open - open a tty device
* @inode: inode of device file
* @filp: file pointer to tty
@@ -2031,8 +2099,6 @@ static int tty_open(struct inode *inode, struct file *filp)
{
struct tty_struct *tty;
int noctty, retval;
- struct tty_driver *driver = NULL;
- int index;
dev_t device = inode->i_rdev;
unsigned saved_flags = filp->f_flags;
@@ -2043,53 +2109,15 @@ retry_open:
if (retval)
return -ENOMEM;
- noctty = filp->f_flags & O_NOCTTY;
- index = -1;
- retval = 0;
-
tty = tty_open_current_tty(device, filp);
- if (!tty) {
- mutex_lock(&tty_mutex);
- driver = tty_lookup_driver(device, filp, &noctty, &index);
- if (IS_ERR(driver)) {
- retval = PTR_ERR(driver);
- goto err_unlock;
- }
-
- /* check whether we're reopening an existing tty */
- tty = tty_driver_lookup_tty(driver, inode, index);
- if (IS_ERR(tty)) {
- retval = PTR_ERR(tty);
- goto err_unlock;
- }
-
- if (tty) {
- mutex_unlock(&tty_mutex);
- retval = tty_lock_interruptible(tty);
- tty_kref_put(tty); /* drop kref from tty_driver_lookup_tty() */
- if (retval) {
- if (retval == -EINTR)
- retval = -ERESTARTSYS;
- goto err_unref;
- }
- retval = tty_reopen(tty);
- if (retval < 0) {
- tty_unlock(tty);
- tty = ERR_PTR(retval);
- }
- } else { /* Returns with the tty_lock held for now */
- tty = tty_init_dev(driver, index);
- mutex_unlock(&tty_mutex);
- }
-
- tty_driver_kref_put(driver);
- }
+ if (!tty)
+ tty = tty_open_by_driver(device, inode, filp);
if (IS_ERR(tty)) {
+ tty_free_file(filp);
retval = PTR_ERR(tty);
if (retval != -EAGAIN || signal_pending(current))
- goto err_file;
- tty_free_file(filp);
+ return retval;
schedule();
goto retry_open;
}
@@ -2097,10 +2125,6 @@ retry_open:
tty_add_file(tty, filp);
check_tty_count(tty, __func__);
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
- tty->driver->subtype == PTY_TYPE_MASTER)
- noctty = 1;
-
tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
if (tty->ops->open)
@@ -2133,6 +2157,12 @@ retry_open:
read_lock(&tasklist_lock);
spin_lock_irq(&current->sighand->siglock);
+ noctty = (filp->f_flags & O_NOCTTY) ||
+ device == MKDEV(TTY_MAJOR, 0) ||
+ device == MKDEV(TTYAUX_MAJOR, 1) ||
+ (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+ tty->driver->subtype == PTY_TYPE_MASTER);
+
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
@@ -2158,15 +2188,6 @@ retry_open:
read_unlock(&tasklist_lock);
tty_unlock(tty);
return 0;
-err_unlock:
- mutex_unlock(&tty_mutex);
-err_unref:
- /* after locks to avoid deadlock */
- if (!IS_ERR_OR_NULL(driver))
- tty_driver_kref_put(driver);
-err_file:
- tty_free_file(filp);
- return retval;
}
@@ -2193,6 +2214,8 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
return 0;
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_poll(filp, wait);
if (ld->ops->poll)
ret = ld->ops->poll(tty, filp, wait);
tty_ldisc_deref(ld);
@@ -2202,7 +2225,6 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
static int __tty_fasync(int fd, struct file *filp, int on)
{
struct tty_struct *tty = file_tty(filp);
- struct tty_ldisc *ldisc;
unsigned long flags;
int retval = 0;
@@ -2213,13 +2235,6 @@ static int __tty_fasync(int fd, struct file *filp, int on)
if (retval <= 0)
goto out;
- ldisc = tty_ldisc_ref(tty);
- if (ldisc) {
- if (ldisc->ops->fasync)
- ldisc->ops->fasync(tty, on);
- tty_ldisc_deref(ldisc);
- }
-
if (on) {
enum pid_type type;
struct pid *pid;
@@ -2245,10 +2260,11 @@ out:
static int tty_fasync(int fd, struct file *filp, int on)
{
struct tty_struct *tty = file_tty(filp);
- int retval;
+ int retval = -ENOTTY;
tty_lock(tty);
- retval = __tty_fasync(fd, filp, on);
+ if (!tty_hung_up_p(filp))
+ retval = __tty_fasync(fd, filp, on);
tty_unlock(tty);
return retval;
@@ -2282,6 +2298,8 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
return -EFAULT;
tty_audit_tiocsti(tty, ch);
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return -EIO;
ld->ops->receive_buf(tty, &ch, &mbz, 1);
tty_ldisc_deref(ld);
return 0;
@@ -2646,13 +2664,13 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
static int tiocsetd(struct tty_struct *tty, int __user *p)
{
- int ldisc;
+ int disc;
int ret;
- if (get_user(ldisc, p))
+ if (get_user(disc, p))
return -EFAULT;
- ret = tty_set_ldisc(tty, ldisc);
+ ret = tty_set_ldisc(tty, disc);
return ret;
}
@@ -2674,6 +2692,8 @@ static int tiocgetd(struct tty_struct *tty, int __user *p)
int ret;
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return -EIO;
ret = put_user(ld->ops->num, p);
tty_ldisc_deref(ld);
return ret;
@@ -2971,6 +2991,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return retval;
}
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_ioctl(file, cmd, arg);
retval = -EINVAL;
if (ld->ops->ioctl) {
retval = ld->ops->ioctl(tty, file, cmd, arg);
@@ -2999,6 +3021,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
}
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_compat_ioctl(file, cmd, arg);
if (ld->ops->compat_ioctl)
retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
else
@@ -3149,6 +3173,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
mutex_init(&tty->atomic_write_lock);
spin_lock_init(&tty->ctrl_lock);
spin_lock_init(&tty->flow_lock);
+ spin_lock_init(&tty->files_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
@@ -3162,20 +3187,6 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
}
/**
- * deinitialize_tty_struct
- * @tty: tty to deinitialize
- *
- * This subroutine deinitializes a tty structure that has been newly
- * allocated but tty_release cannot be called on that yet.
- *
- * Locking: none - tty in question must not be exposed at this point
- */
-void deinitialize_tty_struct(struct tty_struct *tty)
-{
- tty_ldisc_deinit(tty);
-}
-
-/**
* tty_put_char - write one character to a tty
* @tty: tty
* @ch: character
@@ -3569,7 +3580,7 @@ void __init console_init(void)
initcall_t *call;
/* Setup the default TTY line discipline. */
- tty_ldisc_begin();
+ n_tty_init();
/*
* set up the console device so that later boot sequences can
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 0ea351388724..23bf5bb1d8bf 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -719,16 +719,16 @@ static int get_sgflags(struct tty_struct *tty)
{
int flags = 0;
- if (!(tty->termios.c_lflag & ICANON)) {
- if (tty->termios.c_lflag & ISIG)
+ if (!L_ICANON(tty)) {
+ if (L_ISIG(tty))
flags |= 0x02; /* cbreak */
else
flags |= 0x20; /* raw */
}
- if (tty->termios.c_lflag & ECHO)
+ if (L_ECHO(tty))
flags |= 0x08; /* echo */
- if (tty->termios.c_oflag & OPOST)
- if (tty->termios.c_oflag & ONLCR)
+ if (O_OPOST(tty))
+ if (O_ONLCR(tty))
flags |= 0x10; /* crmod */
return flags;
}
@@ -908,7 +908,7 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
tty->termios.c_cflag |= bit;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old);
- if ((tty->termios.c_cflag & CLOCAL) != bit)
+ if (C_CLOCAL(tty) != bit)
ret = -EINVAL;
up_write(&tty->termios_rwsem);
return ret;
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index a054d03c22e7..68947f6de5ad 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -140,9 +140,16 @@ static void put_ldops(struct tty_ldisc_ops *ldops)
* @disc: ldisc number
*
* Takes a reference to a line discipline. Deals with refcounts and
- * module locking counts. Returns NULL if the discipline is not available.
- * Returns a pointer to the discipline and bumps the ref count if it is
- * available
+ * module locking counts.
+ *
+ * Returns: -EINVAL if the discipline index is not [N_TTY..NR_LDISCS] or
+ * if the discipline is not registered
+ * -EAGAIN if request_module() failed to load or register the
+ * the discipline
+ * -ENOMEM if allocation failure
+ *
+ * Otherwise, returns a pointer to the discipline and bumps the
+ * ref count
*
* Locking:
* takes tty_ldiscs_lock to guard against ldisc races
@@ -250,19 +257,23 @@ const struct file_operations tty_ldiscs_proc_fops = {
* reference to it. If the line discipline is in flux then
* wait patiently until it changes.
*
+ * Returns: NULL if the tty has been hungup and not re-opened with
+ * a new file descriptor, otherwise valid ldisc reference
+ *
* Note: Must not be called from an IRQ/timer context. The caller
* must also be careful not to hold other locks that will deadlock
* against a discipline change, such as an existing ldisc reference
* (which we check for)
*
- * Note: only callable from a file_operations routine (which
- * guarantees tty->ldisc != NULL when the lock is acquired).
+ * Note: a file_operations routine (read/poll/write) should use this
+ * function to wait for any ldisc lifetime events to finish.
*/
struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
{
ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT);
- WARN_ON(!tty->ldisc);
+ if (!tty->ldisc)
+ ldsem_up_read(&tty->ldisc_sem);
return tty->ldisc;
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
@@ -304,13 +315,13 @@ void tty_ldisc_deref(struct tty_ldisc *ld)
EXPORT_SYMBOL_GPL(tty_ldisc_deref);
-static inline int __lockfunc
+static inline int
__tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
{
return ldsem_down_write(&tty->ldisc_sem, timeout);
}
-static inline int __lockfunc
+static inline int
__tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
{
return ldsem_down_write_nested(&tty->ldisc_sem,
@@ -322,8 +333,7 @@ static inline void __tty_ldisc_unlock(struct tty_struct *tty)
ldsem_up_write(&tty->ldisc_sem);
}
-static int __lockfunc
-tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
+static int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
{
int ret;
@@ -340,7 +350,7 @@ static void tty_ldisc_unlock(struct tty_struct *tty)
__tty_ldisc_unlock(tty);
}
-static int __lockfunc
+static int
tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
unsigned long timeout)
{
@@ -376,14 +386,13 @@ tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
return 0;
}
-static void __lockfunc
-tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
+static void tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
{
tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT);
}
-static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
- struct tty_struct *tty2)
+static void tty_ldisc_unlock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
{
__tty_ldisc_unlock(tty);
if (tty2)
@@ -411,7 +420,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
/**
* tty_set_termios_ldisc - set ldisc field
* @tty: tty structure
- * @num: line discipline number
+ * @disc: line discipline number
*
* This is probably overkill for real world processors but
* they are not on hot paths so a little discipline won't do
@@ -424,10 +433,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
* Locking: takes termios_rwsem
*/
-static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+static void tty_set_termios_ldisc(struct tty_struct *tty, int disc)
{
down_write(&tty->termios_rwsem);
- tty->termios.c_line = num;
+ tty->termios.c_line = disc;
up_write(&tty->termios_rwsem);
tty->disc_data = NULL;
@@ -455,7 +464,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
if (ret)
clear_bit(TTY_LDISC_OPEN, &tty->flags);
- tty_ldisc_debug(tty, "%p: opened\n", tty->ldisc);
+ tty_ldisc_debug(tty, "%p: opened\n", ld);
return ret;
}
return 0;
@@ -476,7 +485,7 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
clear_bit(TTY_LDISC_OPEN, &tty->flags);
if (ld->ops->close)
ld->ops->close(tty);
- tty_ldisc_debug(tty, "%p: closed\n", tty->ldisc);
+ tty_ldisc_debug(tty, "%p: closed\n", ld);
}
/**
@@ -525,12 +534,12 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
* the close of one side of a tty/pty pair, and eventually hangup.
*/
-int tty_set_ldisc(struct tty_struct *tty, int ldisc)
+int tty_set_ldisc(struct tty_struct *tty, int disc)
{
int retval;
struct tty_ldisc *old_ldisc, *new_ldisc;
- new_ldisc = tty_ldisc_get(tty, ldisc);
+ new_ldisc = tty_ldisc_get(tty, disc);
if (IS_ERR(new_ldisc))
return PTR_ERR(new_ldisc);
@@ -539,8 +548,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
if (retval)
goto err;
+ if (!tty->ldisc) {
+ retval = -EIO;
+ goto out;
+ }
+
/* Check the no-op case */
- if (tty->ldisc->ops->num == ldisc)
+ if (tty->ldisc->ops->num == disc)
goto out;
if (test_bit(TTY_HUPPED, &tty->flags)) {
@@ -556,7 +570,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
/* Now set up the new line discipline. */
tty->ldisc = new_ldisc;
- tty_set_termios_ldisc(tty, ldisc);
+ tty_set_termios_ldisc(tty, disc);
retval = tty_ldisc_open(tty, new_ldisc);
if (retval < 0) {
@@ -590,6 +604,25 @@ err:
}
/**
+ * tty_ldisc_kill - teardown ldisc
+ * @tty: tty being released
+ *
+ * Perform final close of the ldisc and reset tty->ldisc
+ */
+static void tty_ldisc_kill(struct tty_struct *tty)
+{
+ if (!tty->ldisc)
+ return;
+ /*
+ * Now kill off the ldisc
+ */
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ /* Force an oops if we mess this up */
+ tty->ldisc = NULL;
+}
+
+/**
* tty_reset_termios - reset terminal state
* @tty: tty to reset
*
@@ -609,28 +642,44 @@ static void tty_reset_termios(struct tty_struct *tty)
/**
* tty_ldisc_reinit - reinitialise the tty ldisc
* @tty: tty to reinit
- * @ldisc: line discipline to reinitialize
+ * @disc: line discipline to reinitialize
+ *
+ * Completely reinitialize the line discipline state, by closing the
+ * current instance, if there is one, and opening a new instance. If
+ * an error occurs opening the new non-N_TTY instance, the instance
+ * is dropped and tty->ldisc reset to NULL. The caller can then retry
+ * with N_TTY instead.
*
- * Switch the tty to a line discipline and leave the ldisc
- * state closed
+ * Returns 0 if successful, otherwise error code < 0
*/
-static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
+int tty_ldisc_reinit(struct tty_struct *tty, int disc)
{
- struct tty_ldisc *ld = tty_ldisc_get(tty, ldisc);
+ struct tty_ldisc *ld;
+ int retval;
- if (IS_ERR(ld))
- return -1;
+ ld = tty_ldisc_get(tty, disc);
+ if (IS_ERR(ld)) {
+ BUG_ON(disc == N_TTY);
+ return PTR_ERR(ld);
+ }
- tty_ldisc_close(tty, tty->ldisc);
- tty_ldisc_put(tty->ldisc);
- /*
- * Switch the line discipline back
- */
- tty->ldisc = ld;
- tty_set_termios_ldisc(tty, ldisc);
+ if (tty->ldisc) {
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ }
- return 0;
+ /* switch the line discipline */
+ tty->ldisc = ld;
+ tty_set_termios_ldisc(tty, disc);
+ retval = tty_ldisc_open(tty, tty->ldisc);
+ if (retval) {
+ if (!WARN_ON(disc == N_TTY)) {
+ tty_ldisc_put(tty->ldisc);
+ tty->ldisc = NULL;
+ }
+ }
+ return retval;
}
/**
@@ -648,13 +697,11 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
* tty itself so we must be careful about locking rules.
*/
-void tty_ldisc_hangup(struct tty_struct *tty)
+void tty_ldisc_hangup(struct tty_struct *tty, bool reinit)
{
struct tty_ldisc *ld;
- int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
- int err = 0;
- tty_ldisc_debug(tty, "%p: closing\n", tty->ldisc);
+ tty_ldisc_debug(tty, "%p: hangup\n", tty->ldisc);
ld = tty_ldisc_ref(tty);
if (ld != NULL) {
@@ -680,31 +727,17 @@ void tty_ldisc_hangup(struct tty_struct *tty)
*/
tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT);
- if (tty->ldisc) {
-
- /* At this point we have a halted ldisc; we want to close it and
- reopen a new ldisc. We could defer the reopen to the next
- open but it means auditing a lot of other paths so this is
- a FIXME */
- if (reset == 0) {
+ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+ tty_reset_termios(tty);
- if (!tty_ldisc_reinit(tty, tty->termios.c_line))
- err = tty_ldisc_open(tty, tty->ldisc);
- else
- err = 1;
- }
- /* If the re-open fails or we reset then go to N_TTY. The
- N_TTY open cannot fail */
- if (reset || err) {
- BUG_ON(tty_ldisc_reinit(tty, N_TTY));
- WARN_ON(tty_ldisc_open(tty, tty->ldisc));
- }
+ if (tty->ldisc) {
+ if (reinit) {
+ if (tty_ldisc_reinit(tty, tty->termios.c_line) < 0)
+ tty_ldisc_reinit(tty, N_TTY);
+ } else
+ tty_ldisc_kill(tty);
}
tty_ldisc_unlock(tty);
- if (reset)
- tty_reset_termios(tty);
-
- tty_ldisc_debug(tty, "%p: re-opened\n", tty->ldisc);
}
/**
@@ -719,44 +752,26 @@ void tty_ldisc_hangup(struct tty_struct *tty)
int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
{
- struct tty_ldisc *ld = tty->ldisc;
- int retval;
-
- retval = tty_ldisc_open(tty, ld);
+ int retval = tty_ldisc_open(tty, tty->ldisc);
if (retval)
return retval;
if (o_tty) {
retval = tty_ldisc_open(o_tty, o_tty->ldisc);
if (retval) {
- tty_ldisc_close(tty, ld);
+ tty_ldisc_close(tty, tty->ldisc);
return retval;
}
}
return 0;
}
-static void tty_ldisc_kill(struct tty_struct *tty)
-{
- /*
- * Now kill off the ldisc
- */
- tty_ldisc_close(tty, tty->ldisc);
- tty_ldisc_put(tty->ldisc);
- /* Force an oops if we mess this up */
- tty->ldisc = NULL;
-
- /* Ensure the next open requests the N_TTY ldisc */
- tty_set_termios_ldisc(tty, N_TTY);
-}
-
/**
* tty_ldisc_release - release line discipline
* @tty: tty being shut down (or one end of pty pair)
*
* Called during the final close of a tty or a pty pair in order to shut
- * down the line discpline layer. On exit, each ldisc assigned is N_TTY and
- * each ldisc has not been opened.
+ * down the line discpline layer. On exit, each tty's ldisc is NULL.
*/
void tty_ldisc_release(struct tty_struct *tty)
@@ -797,7 +812,7 @@ void tty_ldisc_init(struct tty_struct *tty)
}
/**
- * tty_ldisc_init - ldisc cleanup for new tty
+ * tty_ldisc_deinit - ldisc cleanup for new tty
* @tty: tty that was allocated recently
*
* The tty structure must not becompletely set up (tty_ldisc_setup) when
@@ -805,12 +820,7 @@ void tty_ldisc_init(struct tty_struct *tty)
*/
void tty_ldisc_deinit(struct tty_struct *tty)
{
- tty_ldisc_put(tty->ldisc);
+ if (tty->ldisc)
+ tty_ldisc_put(tty->ldisc);
tty->ldisc = NULL;
}
-
-void tty_ldisc_begin(void)
-{
- /* Setup the default TTY line discipline. */
- (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
-}
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index dfa9ec03fa8e..d8bae67a6174 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -10,7 +10,7 @@
* Getting the big tty mutex.
*/
-void __lockfunc tty_lock(struct tty_struct *tty)
+void tty_lock(struct tty_struct *tty)
{
if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty))
return;
@@ -32,7 +32,7 @@ int tty_lock_interruptible(struct tty_struct *tty)
return ret;
}
-void __lockfunc tty_unlock(struct tty_struct *tty)
+void tty_unlock(struct tty_struct *tty)
{
if (WARN(tty->magic != TTY_MAGIC, "U Bad %p\n", tty))
return;
@@ -41,13 +41,13 @@ void __lockfunc tty_unlock(struct tty_struct *tty)
}
EXPORT_SYMBOL(tty_unlock);
-void __lockfunc tty_lock_slave(struct tty_struct *tty)
+void tty_lock_slave(struct tty_struct *tty)
{
if (tty && tty != tty->link)
tty_lock(tty);
}
-void __lockfunc tty_unlock_slave(struct tty_struct *tty)
+void tty_unlock_slave(struct tty_struct *tty)
{
if (tty && tty != tty->link)
tty_unlock(tty);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 846ed481c24f..dbcca30a54b1 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -370,7 +370,7 @@ int tty_port_block_til_ready(struct tty_port *port,
}
if (filp->f_flags & O_NONBLOCK) {
/* Indicate we are open */
- if (tty->termios.c_cflag & CBAUD)
+ if (C_BAUD(tty))
tty_port_raise_dtr_rts(port);
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
@@ -476,7 +476,6 @@ int tty_port_close_start(struct tty_port *port,
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
- set_bit(ASYNCB_CLOSING, &port->flags);
spin_unlock_irqrestore(&port->lock, flags);
tty->closing = 1;
@@ -510,14 +509,12 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
if (port->blocked_open) {
spin_unlock_irqrestore(&port->lock, flags);
- if (port->close_delay) {
- msleep_interruptible(
- jiffies_to_msecs(port->close_delay));
- }
+ if (port->close_delay)
+ msleep_interruptible(jiffies_to_msecs(port->close_delay));
spin_lock_irqsave(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
}
- port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+ port->flags &= ~ASYNC_NORMAL_ACTIVE;
spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_close_end);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 6f0336fff501..f973bfce5d08 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1706,16 +1706,12 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
return -EINVAL;
if (ct) {
- dia = kmalloc(sizeof(struct kbdiacr) * ct,
- GFP_KERNEL);
- if (!dia)
- return -ENOMEM;
- if (copy_from_user(dia, a->kbdiacr,
- sizeof(struct kbdiacr) * ct)) {
- kfree(dia);
- return -EFAULT;
- }
+ dia = memdup_user(a->kbdiacr,
+ sizeof(struct kbdiacr) * ct);
+ if (IS_ERR(dia))
+ return PTR_ERR(dia);
+
}
spin_lock_irqsave(&kbd_event_lock, flags);
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 381a2b13682c..4dd9dd2270a0 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -347,6 +347,8 @@ int paste_selection(struct tty_struct *tty)
console_unlock();
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return -EIO; /* ldisc was hung up */
tty_buffer_lock_exclusive(&vc->port);
add_wait_queue(&vc->paste_wait, &wait);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index bd51bdd0a7bf..3e3c7575e92d 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -568,7 +568,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
vc->vc_cols - vc->vc_x);
}
-static int softcursor_original;
+static int softcursor_original = -1;
static void add_softcursor(struct vc_data *vc)
{
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index d5c57f1e98fd..dca78565eb55 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -26,7 +26,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_HWA_HCD) += host/
obj-$(CONFIG_USB_IMX21_HCD) += host/
-obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
+obj-$(CONFIG_USB_FSL_USB2) += host/
obj-$(CONFIG_USB_FOTG210_HCD) += host/
obj-$(CONFIG_USB_MAX3421_HCD) += host/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 1173f9cbc137..0a866e90b49c 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -476,6 +476,8 @@ static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev,
return -EINVAL;
if (index < 0 || index > 0x7f)
return -EINVAL;
+ if (tmp < 0 || tmp > len - pos)
+ return -EINVAL;
pos += tmp;
/* skip trailing newline */
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index f14f4ab47ebb..9ce8c9f91674 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -28,6 +28,11 @@ struct ci_hdrc_imx_platform_flag {
bool runtime_pm;
};
+static const struct ci_hdrc_imx_platform_flag imx23_usb_data = {
+ .flags = CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_STREAMING,
+};
+
static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
CI_HDRC_DISABLE_STREAMING,
};
@@ -66,6 +71,7 @@ static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
};
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
+ { .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
@@ -244,7 +250,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;
@@ -302,9 +307,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
&pdata);
if (IS_ERR(data->ci_pdev)) {
ret = PTR_ERR(data->ci_pdev);
- dev_err(&pdev->dev,
- "Can't register ci_hdrc platform device, err=%d\n",
- ret);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "ci_hdrc_add_device failed, err=%d\n", ret);
goto err_clk;
}
diff --git a/drivers/usb/chipidea/ci_hdrc_pci.c b/drivers/usb/chipidea/ci_hdrc_pci.c
index b59195edf636..b635ab67490d 100644
--- a/drivers/usb/chipidea/ci_hdrc_pci.c
+++ b/drivers/usb/chipidea/ci_hdrc_pci.c
@@ -85,8 +85,8 @@ static int ci_hdrc_pci_probe(struct pci_dev *pdev,
/* register a nop PHY */
ci->phy = usb_phy_generic_register();
- if (!ci->phy)
- return -ENOMEM;
+ if (IS_ERR(ci->phy))
+ return PTR_ERR(ci->phy);
memset(res, 0, sizeof(res));
res[0].start = pci_resource_start(pdev, 0);
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 7404064b9bbc..69426e644d17 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -721,6 +721,9 @@ static int ci_get_platdata(struct device *dev,
return ret;
}
+ if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL))
+ platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA;
+
ext_id = ERR_PTR(-ENODEV);
ext_vbus = ERR_PTR(-ENODEV);
if (of_property_read_bool(dev->of_node, "extcon")) {
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index a4f7db2e18dd..6d23eede4d8c 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -100,6 +100,9 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
if (sscanf(buf, "%u", &mode) != 1)
return -EINVAL;
+ if (mode > 255)
+ return -EBADRQC;
+
pm_runtime_get_sync(ci->dev);
spin_lock_irqsave(&ci->lock, flags);
ret = hw_port_test_set(ci, mode);
@@ -172,7 +175,6 @@ static int ci_requests_show(struct seq_file *s, void *data)
{
struct ci_hdrc *ci = s->private;
unsigned long flags;
- struct list_head *ptr = NULL;
struct ci_hw_req *req = NULL;
struct td_node *node, *tmpnode;
unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
@@ -184,9 +186,7 @@ static int ci_requests_show(struct seq_file *s, void *data)
spin_lock_irqsave(&ci->lock, flags);
for (i = 0; i < ci->hw_ep_max; i++)
- list_for_each(ptr, &ci->ci_hw_ep[i].qh.queue) {
- req = list_entry(ptr, struct ci_hw_req, queue);
-
+ list_for_each_entry(req, &ci->ci_hw_ep[i].qh.queue, queue) {
list_for_each_entry_safe(node, tmpnode, &req->tds, td) {
seq_printf(s, "EP=%02i: TD=%08X %s\n",
i % (ci->hw_ep_max / 2),
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index 45f86da1d6d3..03b6743461d1 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -158,7 +158,7 @@ static void ci_otg_work(struct work_struct *work)
int ci_hdrc_otg_init(struct ci_hdrc *ci)
{
INIT_WORK(&ci->work, ci_otg_work);
- ci->wq = create_singlethread_workqueue("ci_otg");
+ ci->wq = create_freezable_workqueue("ci_otg");
if (!ci->wq) {
dev_err(ci->dev, "can't create workqueue\n");
return -ENODEV;
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index ba90dc66703d..de8e22ec3902 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -66,6 +66,11 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
return count;
}
ci->fsm.a_bus_req = 1;
+ if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
+ ci->gadget.host_request_flag = 1;
+ mutex_unlock(&ci->fsm.lock);
+ return count;
+ }
}
ci_otg_queue_work(ci);
@@ -144,8 +149,14 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr,
mutex_lock(&ci->fsm.lock);
if (buf[0] == '0')
ci->fsm.b_bus_req = 0;
- else if (buf[0] == '1')
+ else if (buf[0] == '1') {
ci->fsm.b_bus_req = 1;
+ if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
+ ci->gadget.host_request_flag = 1;
+ mutex_unlock(&ci->fsm.lock);
+ return count;
+ }
+ }
ci_otg_queue_work(ci);
mutex_unlock(&ci->fsm.lock);
@@ -198,6 +209,7 @@ static unsigned otg_timer_ms[] = {
TA_AIDL_BDIS,
TB_ASE0_BRST,
TA_BIDL_ADIS,
+ TB_AIDL_BDIS,
TB_SE0_SRP,
TB_SRP_FAIL,
0,
@@ -309,6 +321,12 @@ static int a_bidl_adis_tmout(struct ci_hdrc *ci)
return 0;
}
+static int b_aidl_bdis_tmout(struct ci_hdrc *ci)
+{
+ ci->fsm.a_bus_suspend = 1;
+ return 0;
+}
+
static int b_se0_srp_tmout(struct ci_hdrc *ci)
{
ci->fsm.b_se0_srp = 1;
@@ -353,6 +371,7 @@ static int (*otg_timer_handlers[])(struct ci_hdrc *) = {
a_aidl_bdis_tmout, /* A_AIDL_BDIS */
b_ase0_brst_tmout, /* B_ASE0_BRST */
a_bidl_adis_tmout, /* A_BIDL_ADIS */
+ b_aidl_bdis_tmout, /* B_AIDL_BDIS */
b_se0_srp_tmout, /* B_SE0_SRP */
b_srp_fail_tmout, /* B_SRP_FAIL */
NULL, /* A_WAIT_ENUM */
@@ -644,9 +663,9 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
break;
case OTG_STATE_B_PERIPHERAL:
if ((intr_sts & USBi_SLI) && port_conn && otg_bsess_vld) {
- fsm->a_bus_suspend = 1;
- ci_otg_queue_work(ci);
+ ci_otg_add_timer(ci, B_AIDL_BDIS);
} else if (intr_sts & USBi_PCI) {
+ ci_otg_del_timer(ci, B_AIDL_BDIS);
if (fsm->a_bus_suspend == 1)
fsm->a_bus_suspend = 0;
}
@@ -786,6 +805,10 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
ci->fsm.otg->state = OTG_STATE_UNDEFINED;
ci->fsm.ops = &ci_otg_ops;
+ ci->gadget.hnp_polling_support = 1;
+ ci->fsm.host_req_flag = devm_kzalloc(ci->dev, 1, GFP_KERNEL);
+ if (!ci->fsm.host_req_flag)
+ return -ENOMEM;
mutex_init(&ci->fsm.lock);
diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h
index 262d6ef8df7c..6366fe398ba6 100644
--- a/drivers/usb/chipidea/otg_fsm.h
+++ b/drivers/usb/chipidea/otg_fsm.h
@@ -62,6 +62,8 @@
/* SSEND time before SRP */
#define TB_SSEND_SRP (1500) /* minimum 1.5 sec, section:5.1.2 */
+#define TB_AIDL_BDIS (20) /* 4ms ~ 150ms, section 5.2.1 */
+
#if IS_ENABLED(CONFIG_USB_OTG_FSM)
int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 3eafa2c9a2ba..065f5d97aa67 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -819,7 +819,6 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
ci->ep0out : ci->ep0in;
if (!list_empty(&hwep->qh.queue)) {
_ep_nuke(hwep);
- retval = -EOVERFLOW;
dev_warn(hwep->ci->dev, "endpoint ctrl %X nuked\n",
_usb_addr(hwep));
}
@@ -1068,7 +1067,8 @@ __acquires(ci->lock)
}
break;
case USB_REQ_GET_STATUS:
- if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
+ if ((type != (USB_DIR_IN|USB_RECIP_DEVICE) ||
+ le16_to_cpu(req.wIndex) == OTG_STS_SELECTOR) &&
type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
type != (USB_DIR_IN|USB_RECIP_INTERFACE))
goto delegate;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index fa4e23930614..1d2c99af2532 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -713,9 +713,20 @@ static int acm_tty_write(struct tty_struct *tty,
}
if (acm->susp_count) {
+ if (acm->putbuffer) {
+ /* now to preserve order */
+ usb_anchor_urb(acm->putbuffer->urb, &acm->delayed);
+ acm->putbuffer = NULL;
+ }
usb_anchor_urb(wb->urb, &acm->delayed);
spin_unlock_irqrestore(&acm->write_lock, flags);
return count;
+ } else {
+ if (acm->putbuffer) {
+ /* at this point there is no good way to handle errors */
+ acm_start_wb(acm, acm->putbuffer);
+ acm->putbuffer = NULL;
+ }
}
stat = acm_start_wb(acm, wb);
@@ -726,6 +737,60 @@ static int acm_tty_write(struct tty_struct *tty,
return count;
}
+static void acm_tty_flush_chars(struct tty_struct *tty)
+{
+ struct acm *acm = tty->driver_data;
+ struct acm_wb *cur = acm->putbuffer;
+ int err;
+ unsigned long flags;
+
+ acm->putbuffer = NULL;
+ err = usb_autopm_get_interface_async(acm->control);
+ spin_lock_irqsave(&acm->write_lock, flags);
+ if (err < 0) {
+ cur->use = 0;
+ goto out;
+ }
+
+ if (acm->susp_count)
+ usb_anchor_urb(cur->urb, &acm->delayed);
+ else
+ acm_start_wb(acm, cur);
+out:
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+ return;
+}
+
+static int acm_tty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct acm *acm = tty->driver_data;
+ struct acm_wb *cur;
+ int wbn;
+ unsigned long flags;
+
+overflow:
+ cur = acm->putbuffer;
+ if (!cur) {
+ spin_lock_irqsave(&acm->write_lock, flags);
+ wbn = acm_wb_alloc(acm);
+ if (wbn >= 0) {
+ cur = &acm->wb[wbn];
+ acm->putbuffer = cur;
+ }
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+ if (!cur)
+ return 0;
+ }
+
+ if (cur->len == acm->writesize) {
+ acm_tty_flush_chars(tty);
+ goto overflow;
+ }
+
+ cur->buf[cur->len++] = ch;
+ return 1;
+}
+
static int acm_tty_write_room(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
@@ -1905,6 +1970,8 @@ static const struct tty_operations acm_ops = {
.cleanup = acm_tty_cleanup,
.hangup = acm_tty_hangup,
.write = acm_tty_write,
+ .put_char = acm_tty_put_char,
+ .flush_chars = acm_tty_flush_chars,
.write_room = acm_tty_write_room,
.ioctl = acm_tty_ioctl,
.throttle = acm_tty_throttle,
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index ccfaba9ab4e4..05ce308d5d2a 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -94,6 +94,7 @@ struct acm {
unsigned long read_urbs_free;
struct urb *read_urbs[ACM_NR];
struct acm_rb read_buffers[ACM_NR];
+ struct acm_wb *putbuffer; /* for acm_tty_put_char() */
int rx_buflimit;
int rx_endpoint;
spinlock_t read_lock;
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 7a11a8263171..917a55c4480d 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -27,6 +27,7 @@
#include <linux/uaccess.h>
#include <linux/kref.h>
#include <linux/slab.h>
+#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/usb.h>
#include <linux/usb/tmc.h>
@@ -87,6 +88,23 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read; /* needed for abort */
+ /* data for interrupt in endpoint handling */
+ u8 bNotify1;
+ u8 bNotify2;
+ u16 ifnum;
+ u8 iin_bTag;
+ u8 *iin_buffer;
+ atomic_t iin_data_valid;
+ unsigned int iin_ep;
+ int iin_ep_present;
+ int iin_interval;
+ struct urb *iin_urb;
+ u16 iin_wMaxPacketSize;
+ atomic_t srq_asserted;
+
+ /* coalesced usb488_caps from usbtmc_dev_capabilities */
+ __u8 usb488_caps;
+
u8 rigol_quirk;
/* attributes from the USB TMC spec for this device */
@@ -99,6 +117,8 @@ struct usbtmc_device_data {
struct usbtmc_dev_capabilities capabilities;
struct kref kref;
struct mutex io_mutex; /* only one i/o function running at a time */
+ wait_queue_head_t waitq;
+ struct fasync_struct *fasync;
};
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
@@ -373,6 +393,142 @@ exit:
return rv;
}
+static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
+ void __user *arg)
+{
+ struct device *dev = &data->intf->dev;
+ u8 *buffer;
+ u8 tag;
+ __u8 stb;
+ int rv;
+
+ dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
+ data->iin_ep_present);
+
+ buffer = kmalloc(8, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ atomic_set(&data->iin_data_valid, 0);
+
+ /* must issue read_stb before using poll or select */
+ atomic_set(&data->srq_asserted, 0);
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC488_REQUEST_READ_STATUS_BYTE,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ data->iin_bTag,
+ data->ifnum,
+ buffer, 0x03, USBTMC_TIMEOUT);
+ if (rv < 0) {
+ dev_err(dev, "stb usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "control status returned %x\n", buffer[0]);
+ rv = -EIO;
+ goto exit;
+ }
+
+ if (data->iin_ep_present) {
+ rv = wait_event_interruptible_timeout(
+ data->waitq,
+ atomic_read(&data->iin_data_valid) != 0,
+ USBTMC_TIMEOUT);
+ if (rv < 0) {
+ dev_dbg(dev, "wait interrupted %d\n", rv);
+ goto exit;
+ }
+
+ if (rv == 0) {
+ dev_dbg(dev, "wait timed out\n");
+ rv = -ETIME;
+ goto exit;
+ }
+
+ tag = data->bNotify1 & 0x7f;
+ if (tag != data->iin_bTag) {
+ dev_err(dev, "expected bTag %x got %x\n",
+ data->iin_bTag, tag);
+ }
+
+ stb = data->bNotify2;
+ } else {
+ stb = buffer[2];
+ }
+
+ rv = copy_to_user(arg, &stb, sizeof(stb));
+ if (rv)
+ rv = -EFAULT;
+
+ exit:
+ /* bump interrupt bTag */
+ data->iin_bTag += 1;
+ if (data->iin_bTag > 127)
+ /* 1 is for SRQ see USBTMC-USB488 subclass spec section 4.3.1 */
+ data->iin_bTag = 2;
+
+ kfree(buffer);
+ return rv;
+}
+
+static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
+ void __user *arg, unsigned int cmd)
+{
+ struct device *dev = &data->intf->dev;
+ __u8 val;
+ u8 *buffer;
+ u16 wValue;
+ int rv;
+
+ if (!(data->usb488_caps & USBTMC488_CAPABILITY_SIMPLE))
+ return -EINVAL;
+
+ buffer = kmalloc(8, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ if (cmd == USBTMC488_REQUEST_REN_CONTROL) {
+ rv = copy_from_user(&val, arg, sizeof(val));
+ if (rv) {
+ rv = -EFAULT;
+ goto exit;
+ }
+ wValue = val ? 1 : 0;
+ } else {
+ wValue = 0;
+ }
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ cmd,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ wValue,
+ data->ifnum,
+ buffer, 0x01, USBTMC_TIMEOUT);
+ if (rv < 0) {
+ dev_err(dev, "simple usb_control_msg failed %d\n", rv);
+ goto exit;
+ } else if (rv != 1) {
+ dev_warn(dev, "simple usb_control_msg returned %d\n", rv);
+ rv = -EIO;
+ goto exit;
+ }
+
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "simple control status returned %x\n", buffer[0]);
+ rv = -EIO;
+ goto exit;
+ }
+ rv = 0;
+
+ exit:
+ kfree(buffer);
+ return rv;
+}
+
/*
* Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-IN endpoint.
* @transfer_size: number of bytes to request from the device.
@@ -895,6 +1051,7 @@ static int get_capabilities(struct usbtmc_device_data *data)
data->capabilities.device_capabilities = buffer[5];
data->capabilities.usb488_interface_capabilities = buffer[14];
data->capabilities.usb488_device_capabilities = buffer[15];
+ data->usb488_caps = (buffer[14] & 0x07) | ((buffer[15] & 0x0f) << 4);
rv = 0;
err_out:
@@ -1069,6 +1226,33 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case USBTMC_IOCTL_ABORT_BULK_IN:
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
+
+ case USBTMC488_IOCTL_GET_CAPS:
+ retval = copy_to_user((void __user *)arg,
+ &data->usb488_caps,
+ sizeof(data->usb488_caps));
+ if (retval)
+ retval = -EFAULT;
+ break;
+
+ case USBTMC488_IOCTL_READ_STB:
+ retval = usbtmc488_ioctl_read_stb(data, (void __user *)arg);
+ break;
+
+ case USBTMC488_IOCTL_REN_CONTROL:
+ retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
+ USBTMC488_REQUEST_REN_CONTROL);
+ break;
+
+ case USBTMC488_IOCTL_GOTO_LOCAL:
+ retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
+ USBTMC488_REQUEST_GOTO_LOCAL);
+ break;
+
+ case USBTMC488_IOCTL_LOCAL_LOCKOUT:
+ retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
+ USBTMC488_REQUEST_LOCAL_LOCKOUT);
+ break;
}
skip_io_on_zombie:
@@ -1076,6 +1260,34 @@ skip_io_on_zombie:
return retval;
}
+static int usbtmc_fasync(int fd, struct file *file, int on)
+{
+ struct usbtmc_device_data *data = file->private_data;
+
+ return fasync_helper(fd, file, on, &data->fasync);
+}
+
+static unsigned int usbtmc_poll(struct file *file, poll_table *wait)
+{
+ struct usbtmc_device_data *data = file->private_data;
+ unsigned int mask;
+
+ mutex_lock(&data->io_mutex);
+
+ if (data->zombie) {
+ mask = POLLHUP | POLLERR;
+ goto no_poll;
+ }
+
+ poll_wait(file, &data->waitq, wait);
+
+ mask = (atomic_read(&data->srq_asserted)) ? POLLIN | POLLRDNORM : 0;
+
+no_poll:
+ mutex_unlock(&data->io_mutex);
+ return mask;
+}
+
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = usbtmc_read,
@@ -1083,6 +1295,8 @@ static const struct file_operations fops = {
.open = usbtmc_open,
.release = usbtmc_release,
.unlocked_ioctl = usbtmc_ioctl,
+ .fasync = usbtmc_fasync,
+ .poll = usbtmc_poll,
.llseek = default_llseek,
};
@@ -1092,6 +1306,67 @@ static struct usb_class_driver usbtmc_class = {
.minor_base = USBTMC_MINOR_BASE,
};
+static void usbtmc_interrupt(struct urb *urb)
+{
+ struct usbtmc_device_data *data = urb->context;
+ struct device *dev = &data->intf->dev;
+ int status = urb->status;
+ int rv;
+
+ dev_dbg(&data->intf->dev, "int status: %d len %d\n",
+ status, urb->actual_length);
+
+ switch (status) {
+ case 0: /* SUCCESS */
+ /* check for valid STB notification */
+ if (data->iin_buffer[0] > 0x81) {
+ data->bNotify1 = data->iin_buffer[0];
+ data->bNotify2 = data->iin_buffer[1];
+ atomic_set(&data->iin_data_valid, 1);
+ wake_up_interruptible(&data->waitq);
+ goto exit;
+ }
+ /* check for SRQ notification */
+ if (data->iin_buffer[0] == 0x81) {
+ if (data->fasync)
+ kill_fasync(&data->fasync,
+ SIGIO, POLL_IN);
+
+ atomic_set(&data->srq_asserted, 1);
+ wake_up_interruptible(&data->waitq);
+ goto exit;
+ }
+ dev_warn(dev, "invalid notification: %x\n", data->iin_buffer[0]);
+ break;
+ case -EOVERFLOW:
+ dev_err(dev, "overflow with length %d, actual length is %d\n",
+ data->iin_wMaxPacketSize, urb->actual_length);
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ case -EILSEQ:
+ case -ETIME:
+ /* urb terminated, clean up */
+ dev_dbg(dev, "urb terminated, status: %d\n", status);
+ return;
+ default:
+ dev_err(dev, "unknown status received: %d\n", status);
+ }
+exit:
+ rv = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rv)
+ dev_err(dev, "usb_submit_urb failed: %d\n", rv);
+}
+
+static void usbtmc_free_int(struct usbtmc_device_data *data)
+{
+ if (!data->iin_ep_present || !data->iin_urb)
+ return;
+ usb_kill_urb(data->iin_urb);
+ kfree(data->iin_buffer);
+ usb_free_urb(data->iin_urb);
+ kref_put(&data->kref, usbtmc_delete);
+}
static int usbtmc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -1114,6 +1389,9 @@ static int usbtmc_probe(struct usb_interface *intf,
usb_set_intfdata(intf, data);
kref_init(&data->kref);
mutex_init(&data->io_mutex);
+ init_waitqueue_head(&data->waitq);
+ atomic_set(&data->iin_data_valid, 0);
+ atomic_set(&data->srq_asserted, 0);
data->zombie = 0;
/* Determine if it is a Rigol or not */
@@ -1134,9 +1412,12 @@ static int usbtmc_probe(struct usb_interface *intf,
data->bTag = 1;
data->TermCharEnabled = 0;
data->TermChar = '\n';
+ /* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */
+ data->iin_bTag = 2;
/* USBTMC devices have only one setting, so use that */
iface_desc = data->intf->cur_altsetting;
+ data->ifnum = iface_desc->desc.bInterfaceNumber;
/* Find bulk in endpoint */
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
@@ -1161,6 +1442,20 @@ static int usbtmc_probe(struct usb_interface *intf,
break;
}
}
+ /* Find int endpoint */
+ for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
+ endpoint = &iface_desc->endpoint[n].desc;
+
+ if (usb_endpoint_is_int_in(endpoint)) {
+ data->iin_ep_present = 1;
+ data->iin_ep = endpoint->bEndpointAddress;
+ data->iin_wMaxPacketSize = usb_endpoint_maxp(endpoint);
+ data->iin_interval = endpoint->bInterval;
+ dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
+ data->iin_ep);
+ break;
+ }
+ }
retcode = get_capabilities(data);
if (retcode)
@@ -1169,6 +1464,39 @@ static int usbtmc_probe(struct usb_interface *intf,
retcode = sysfs_create_group(&intf->dev.kobj,
&capability_attr_grp);
+ if (data->iin_ep_present) {
+ /* allocate int urb */
+ data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!data->iin_urb) {
+ dev_err(&intf->dev, "Failed to allocate int urb\n");
+ goto error_register;
+ }
+
+ /* will reference data in int urb */
+ kref_get(&data->kref);
+
+ /* allocate buffer for interrupt in */
+ data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
+ GFP_KERNEL);
+ if (!data->iin_buffer) {
+ dev_err(&intf->dev, "Failed to allocate int buf\n");
+ goto error_register;
+ }
+
+ /* fill interrupt urb */
+ usb_fill_int_urb(data->iin_urb, data->usb_dev,
+ usb_rcvintpipe(data->usb_dev, data->iin_ep),
+ data->iin_buffer, data->iin_wMaxPacketSize,
+ usbtmc_interrupt,
+ data, data->iin_interval);
+
+ retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
+ if (retcode) {
+ dev_err(&intf->dev, "Failed to submit iin_urb\n");
+ goto error_register;
+ }
+ }
+
retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp);
retcode = usb_register_dev(intf, &usbtmc_class);
@@ -1185,6 +1513,7 @@ static int usbtmc_probe(struct usb_interface *intf,
error_register:
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
+ usbtmc_free_int(data);
kref_put(&data->kref, usbtmc_delete);
return retcode;
}
@@ -1201,7 +1530,9 @@ static void usbtmc_disconnect(struct usb_interface *intf)
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
mutex_lock(&data->io_mutex);
data->zombie = 1;
+ wake_up_all(&data->waitq);
mutex_unlock(&data->io_mutex);
+ usbtmc_free_int(data);
kref_put(&data->kref, usbtmc_delete);
}
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index e6ec125e4485..49fbfe8b0f24 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -51,6 +51,7 @@ static const char *const speed_names[] = {
[USB_SPEED_HIGH] = "high-speed",
[USB_SPEED_WIRELESS] = "wireless",
[USB_SPEED_SUPER] = "super-speed",
+ [USB_SPEED_SUPER_PLUS] = "super-speed-plus",
};
const char *usb_speed_string(enum usb_device_speed speed)
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 61d538aa2346..504708f59b93 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -78,6 +78,8 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
fsm->b_srp_done = 0;
break;
case OTG_STATE_B_PERIPHERAL:
+ if (fsm->otg->gadget)
+ fsm->otg->gadget->host_request_flag = 0;
break;
case OTG_STATE_B_WAIT_ACON:
otg_del_timer(fsm, B_ASE0_BRST);
@@ -107,6 +109,8 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
case OTG_STATE_A_PERIPHERAL:
otg_del_timer(fsm, A_BIDL_ADIS);
fsm->a_bidl_adis_tmout = 0;
+ if (fsm->otg->gadget)
+ fsm->otg->gadget->host_request_flag = 0;
break;
case OTG_STATE_A_WAIT_VFALL:
otg_del_timer(fsm, A_WAIT_VFALL);
@@ -120,6 +124,87 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
}
}
+static void otg_hnp_polling_work(struct work_struct *work)
+{
+ struct otg_fsm *fsm = container_of(to_delayed_work(work),
+ struct otg_fsm, hnp_polling_work);
+ struct usb_device *udev;
+ enum usb_otg_state state = fsm->otg->state;
+ u8 flag;
+ int retval;
+
+ if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
+ return;
+
+ udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
+ if (!udev) {
+ dev_err(fsm->otg->host->controller,
+ "no usb dev connected, can't start HNP polling\n");
+ return;
+ }
+
+ *fsm->host_req_flag = 0;
+ /* Get host request flag from connected USB device */
+ retval = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ USB_REQ_GET_STATUS,
+ USB_DIR_IN | USB_RECIP_DEVICE,
+ 0,
+ OTG_STS_SELECTOR,
+ fsm->host_req_flag,
+ 1,
+ USB_CTRL_GET_TIMEOUT);
+ if (retval != 1) {
+ dev_err(&udev->dev, "Get one byte OTG status failed\n");
+ return;
+ }
+
+ flag = *fsm->host_req_flag;
+ if (flag == 0) {
+ /* Continue HNP polling */
+ schedule_delayed_work(&fsm->hnp_polling_work,
+ msecs_to_jiffies(T_HOST_REQ_POLL));
+ return;
+ } else if (flag != HOST_REQUEST_FLAG) {
+ dev_err(&udev->dev, "host request flag %d is invalid\n", flag);
+ return;
+ }
+
+ /* Host request flag is set */
+ if (state == OTG_STATE_A_HOST) {
+ /* Set b_hnp_enable */
+ if (!fsm->otg->host->b_hnp_enable) {
+ retval = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, 0,
+ USB_DEVICE_B_HNP_ENABLE,
+ 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ if (retval >= 0)
+ fsm->otg->host->b_hnp_enable = 1;
+ }
+ fsm->a_bus_req = 0;
+ } else if (state == OTG_STATE_B_HOST) {
+ fsm->b_bus_req = 0;
+ }
+
+ otg_statemachine(fsm);
+}
+
+static void otg_start_hnp_polling(struct otg_fsm *fsm)
+{
+ /*
+ * The memory of host_req_flag should be allocated by
+ * controller driver, otherwise, hnp polling is not started.
+ */
+ if (!fsm->host_req_flag)
+ return;
+
+ INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work);
+ schedule_delayed_work(&fsm->hnp_polling_work,
+ msecs_to_jiffies(T_HOST_REQ_POLL));
+}
+
/* Called when entering a state */
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
{
@@ -169,6 +254,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
otg_set_protocol(fsm, PROTO_HOST);
usb_bus_start_enum(fsm->otg->host,
fsm->otg->host->otg_port);
+ otg_start_hnp_polling(fsm);
break;
case OTG_STATE_A_IDLE:
otg_drv_vbus(fsm, 0);
@@ -203,6 +289,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
*/
if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
otg_add_timer(fsm, A_WAIT_ENUM);
+ otg_start_hnp_polling(fsm);
break;
case OTG_STATE_A_SUSPEND:
otg_drv_vbus(fsm, 1);
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 2f6f93220046..9780877010b4 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -5,7 +5,7 @@
usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
usbcore-y += devio.o notify.o generic.o quirks.o devices.o
-usbcore-y += port.o
+usbcore-y += port.o of.o
usbcore-$(CONFIG_PCI) += hcd-pci.o
usbcore-$(CONFIG_ACPI) += usb-acpi.o
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 89f2e7765093..2741566ee4f2 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -62,8 +62,9 @@ int hcd_buffer_create(struct usb_hcd *hcd)
char name[16];
int i, size;
- if (!hcd->self.controller->dma_mask &&
- !(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (!IS_ENABLED(CONFIG_HAS_DMA) ||
+ (!hcd->self.controller->dma_mask &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM)))
return 0;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
@@ -93,6 +94,9 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
{
int i;
+ if (!IS_ENABLED(CONFIG_HAS_DMA))
+ return;
+
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
struct dma_pool *pool = hcd->pool[i];
@@ -119,8 +123,9 @@ void *hcd_buffer_alloc(
int i;
/* some USB hosts just use PIO */
- if (!bus->controller->dma_mask &&
- !(hcd->driver->flags & HCD_LOCAL_MEM)) {
+ if (!IS_ENABLED(CONFIG_HAS_DMA) ||
+ (!bus->controller->dma_mask &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM))) {
*dma = ~(dma_addr_t) 0;
return kmalloc(size, mem_flags);
}
@@ -145,8 +150,9 @@ void hcd_buffer_free(
if (!addr)
return;
- if (!bus->controller->dma_mask &&
- !(hcd->driver->flags & HCD_LOCAL_MEM)) {
+ if (!IS_ENABLED(CONFIG_HAS_DMA) ||
+ (!bus->controller->dma_mask &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM))) {
kfree(addr);
return;
}
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 5050760f5e17..5eb1a87228b4 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -43,6 +43,27 @@ static int find_next_descriptor(unsigned char *buffer, int size,
return buffer - buffer0;
}
+static void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev,
+ int cfgno, int inum, int asnum, struct usb_host_endpoint *ep,
+ unsigned char *buffer, int size)
+{
+ struct usb_ssp_isoc_ep_comp_descriptor *desc;
+
+ /*
+ * The SuperSpeedPlus Isoc endpoint companion descriptor immediately
+ * follows the SuperSpeed Endpoint Companion descriptor
+ */
+ desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer;
+ if (desc->bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP ||
+ size < USB_DT_SSP_ISOC_EP_COMP_SIZE) {
+ dev_warn(ddev, "Invalid SuperSpeedPlus isoc endpoint companion"
+ "for config %d interface %d altsetting %d ep %d.\n",
+ cfgno, inum, asnum, ep->desc.bEndpointAddress);
+ return;
+ }
+ memcpy(&ep->ssp_isoc_ep_comp, desc, USB_DT_SSP_ISOC_EP_COMP_SIZE);
+}
+
static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
int inum, int asnum, struct usb_host_endpoint *ep,
unsigned char *buffer, int size)
@@ -54,6 +75,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
* be the first thing immediately following the endpoint descriptor.
*/
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
+ buffer += desc->bLength;
+ size -= desc->bLength;
+
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP ||
size < USB_DT_SS_EP_COMP_SIZE) {
dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
@@ -112,6 +136,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bmAttributes = 16;
} else if (usb_endpoint_xfer_isoc(&ep->desc) &&
+ !USB_SS_SSP_ISOC_COMP(desc->bmAttributes) &&
USB_SS_MULT(desc->bmAttributes) > 3) {
dev_warn(ddev, "Isoc endpoint has Mult of %d in "
"config %d interface %d altsetting %d ep %d: "
@@ -121,6 +146,12 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
ep->ss_ep_comp.bmAttributes = 2;
}
+ /* Parse a possible SuperSpeedPlus isoc ep companion descriptor */
+ if (usb_endpoint_xfer_isoc(&ep->desc) &&
+ USB_SS_SSP_ISOC_COMP(desc->bmAttributes))
+ usb_parse_ssp_isoc_endpoint_companion(ddev, cfgno, inum, asnum,
+ ep, buffer, size);
+
if (usb_endpoint_xfer_isoc(&ep->desc))
max_tx = (desc->bMaxBurst + 1) *
(USB_SS_MULT(desc->bmAttributes)) *
@@ -191,6 +222,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
if (usb_endpoint_xfer_int(d)) {
i = 1;
switch (to_usb_device(ddev)->speed) {
+ case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER:
case USB_SPEED_HIGH:
/* Many device manufacturers are using full-speed
@@ -274,7 +306,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
}
/* Parse a possible SuperSpeed endpoint companion descriptor */
- if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)
+ if (to_usb_device(ddev)->speed >= USB_SPEED_SUPER)
usb_parse_ss_endpoint_companion(ddev, cfgno,
inum, asnum, endpoint, buffer, size);
@@ -862,6 +894,9 @@ int usb_get_bos_descriptor(struct usb_device *dev)
dev->bos->ss_id =
(struct usb_ss_container_id_descriptor *)buffer;
break;
+ case USB_PTM_CAP_TYPE:
+ dev->bos->ptm_cap =
+ (struct usb_ptm_cap_descriptor *)buffer;
default:
break;
}
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index cffa0a0d7de2..ef04b50e6bbb 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -110,13 +110,6 @@ static const char format_endpt[] =
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
"E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
-
-/*
- * Need access to the driver and USB bus lists.
- * extern struct list_head usb_bus_list;
- * However, these will come from functions that return ptrs to each of them.
- */
-
/*
* Wait for an connect/disconnect event to happen. We initialize
* the event counter with an odd number, and each event will increment
@@ -221,7 +214,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
break;
case USB_ENDPOINT_XFER_INT:
type = "Int.";
- if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER)
+ if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER)
interval = 1 << (desc->bInterval - 1);
else
interval = desc->bInterval;
@@ -230,7 +223,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
return start;
}
interval *= (speed == USB_SPEED_HIGH ||
- speed == USB_SPEED_SUPER) ? 125 : 1000;
+ speed >= USB_SPEED_SUPER) ? 125 : 1000;
if (interval % 1000)
unit = 'u';
else {
@@ -322,7 +315,7 @@ static char *usb_dump_config_descriptor(char *start, char *end,
if (start > end)
return start;
- if (speed == USB_SPEED_SUPER)
+ if (speed >= USB_SPEED_SUPER)
mul = 8;
else
mul = 2;
@@ -534,6 +527,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
speed = "480"; break;
case USB_SPEED_SUPER:
speed = "5000"; break;
+ case USB_SPEED_SUPER_PLUS:
+ speed = "10000"; break;
default:
speed = "??";
}
@@ -553,7 +548,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
/* super/high speed reserves 80%, full/low reserves 90% */
if (usbdev->speed == USB_SPEED_HIGH ||
- usbdev->speed == USB_SPEED_SUPER)
+ usbdev->speed >= USB_SPEED_SUPER)
max = 800;
else
max = FRAME_TIME_MAX_USECS_ALLOC;
@@ -616,6 +611,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
struct usb_bus *bus;
ssize_t ret, total_written = 0;
loff_t skip_bytes = *ppos;
+ int id;
if (*ppos < 0)
return -EINVAL;
@@ -624,9 +620,9 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
if (!access_ok(VERIFY_WRITE, buf, nbytes))
return -EFAULT;
- mutex_lock(&usb_bus_list_lock);
+ mutex_lock(&usb_bus_idr_lock);
/* print devices for all busses */
- list_for_each_entry(bus, &usb_bus_list, bus_list) {
+ idr_for_each_entry(&usb_bus_idr, bus, id) {
/* recurse through all children of the root hub */
if (!bus_to_hcd(bus)->rh_registered)
continue;
@@ -635,12 +631,12 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
bus->root_hub, bus, 0, 0, 0);
usb_unlock_device(bus->root_hub);
if (ret < 0) {
- mutex_unlock(&usb_bus_list_lock);
+ mutex_unlock(&usb_bus_idr_lock);
return ret;
}
total_written += ret;
}
- mutex_unlock(&usb_bus_list_lock);
+ mutex_unlock(&usb_bus_idr_lock);
return total_written;
}
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 59e7a3369084..52c4461dfccd 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -50,6 +50,7 @@
#include <linux/user_namespace.h>
#include <linux/scatterlist.h>
#include <linux/uaccess.h>
+#include <linux/dma-mapping.h>
#include <asm/byteorder.h>
#include <linux/moduleparam.h>
@@ -69,6 +70,7 @@ struct usb_dev_state {
spinlock_t lock; /* protects the async urb lists */
struct list_head async_pending;
struct list_head async_completed;
+ struct list_head memory_list;
wait_queue_head_t wait; /* wake up if a request completed */
unsigned int discsignr;
struct pid *disc_pid;
@@ -77,6 +79,19 @@ struct usb_dev_state {
unsigned long ifclaimed;
u32 secid;
u32 disabled_bulk_eps;
+ bool privileges_dropped;
+ unsigned long interface_allowed_mask;
+};
+
+struct usb_memory {
+ struct list_head memlist;
+ int vma_use_count;
+ int urb_use_count;
+ u32 size;
+ void *mem;
+ dma_addr_t dma_handle;
+ unsigned long vm_start;
+ struct usb_dev_state *ps;
};
struct async {
@@ -89,6 +104,7 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
+ struct usb_memory *usbm;
unsigned int mem_usage;
int status;
u32 secid;
@@ -162,6 +178,111 @@ static int connected(struct usb_dev_state *ps)
ps->dev->state != USB_STATE_NOTATTACHED);
}
+static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count)
+{
+ struct usb_dev_state *ps = usbm->ps;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ --*count;
+ if (usbm->urb_use_count == 0 && usbm->vma_use_count == 0) {
+ list_del(&usbm->memlist);
+ spin_unlock_irqrestore(&ps->lock, flags);
+
+ usb_free_coherent(ps->dev, usbm->size, usbm->mem,
+ usbm->dma_handle);
+ usbfs_decrease_memory_usage(
+ usbm->size + sizeof(struct usb_memory));
+ kfree(usbm);
+ } else {
+ spin_unlock_irqrestore(&ps->lock, flags);
+ }
+}
+
+static void usbdev_vm_open(struct vm_area_struct *vma)
+{
+ struct usb_memory *usbm = vma->vm_private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&usbm->ps->lock, flags);
+ ++usbm->vma_use_count;
+ spin_unlock_irqrestore(&usbm->ps->lock, flags);
+}
+
+static void usbdev_vm_close(struct vm_area_struct *vma)
+{
+ struct usb_memory *usbm = vma->vm_private_data;
+
+ dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
+}
+
+struct vm_operations_struct usbdev_vm_ops = {
+ .open = usbdev_vm_open,
+ .close = usbdev_vm_close
+};
+
+static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct usb_memory *usbm = NULL;
+ struct usb_dev_state *ps = file->private_data;
+ size_t size = vma->vm_end - vma->vm_start;
+ void *mem;
+ unsigned long flags;
+ dma_addr_t dma_handle;
+ int ret;
+
+ ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory));
+ if (ret)
+ goto error;
+
+ usbm = kzalloc(sizeof(struct usb_memory), GFP_KERNEL);
+ if (!usbm) {
+ ret = -ENOMEM;
+ goto error_decrease_mem;
+ }
+
+ mem = usb_alloc_coherent(ps->dev, size, GFP_USER, &dma_handle);
+ if (!mem) {
+ ret = -ENOMEM;
+ goto error_free_usbm;
+ }
+
+ memset(mem, 0, size);
+
+ usbm->mem = mem;
+ usbm->dma_handle = dma_handle;
+ usbm->size = size;
+ usbm->ps = ps;
+ usbm->vm_start = vma->vm_start;
+ usbm->vma_use_count = 1;
+ INIT_LIST_HEAD(&usbm->memlist);
+
+ if (remap_pfn_range(vma, vma->vm_start,
+ virt_to_phys(usbm->mem) >> PAGE_SHIFT,
+ size, vma->vm_page_prot) < 0) {
+ dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
+ return -EAGAIN;
+ }
+
+ vma->vm_flags |= VM_IO;
+ vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP);
+ vma->vm_ops = &usbdev_vm_ops;
+ vma->vm_private_data = usbm;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_add_tail(&usbm->memlist, &ps->memory_list);
+ spin_unlock_irqrestore(&ps->lock, flags);
+
+ return 0;
+
+error_free_usbm:
+ kfree(usbm);
+error_decrease_mem:
+ usbfs_decrease_memory_usage(size + sizeof(struct usb_memory));
+error:
+ return ret;
+}
+
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
@@ -278,8 +399,13 @@ static void free_async(struct async *as)
if (sg_page(&as->urb->sg[i]))
kfree(sg_virt(&as->urb->sg[i]));
}
+
kfree(as->urb->sg);
- kfree(as->urb->transfer_buffer);
+ if (as->usbm == NULL)
+ kfree(as->urb->transfer_buffer);
+ else
+ dec_usb_memory_use_count(as->usbm, &as->usbm->urb_use_count);
+
kfree(as->urb->setup_packet);
usb_free_urb(as->urb);
usbfs_decrease_memory_usage(as->mem_usage);
@@ -624,6 +750,10 @@ static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
if (test_bit(ifnum, &ps->ifclaimed))
return 0;
+ if (ps->privileges_dropped &&
+ !test_bit(ifnum, &ps->interface_allowed_mask))
+ return -EACCES;
+
intf = usb_ifnum_to_if(dev, ifnum);
if (!intf)
err = -ENOENT;
@@ -848,7 +978,7 @@ static struct usb_device *usbdev_lookup_by_devt(dev_t devt)
(void *) (unsigned long) devt, match_devt);
if (!dev)
return NULL;
- return container_of(dev, struct usb_device, dev);
+ return to_usb_device(dev);
}
/*
@@ -861,7 +991,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
int ret;
ret = -ENOMEM;
- ps = kmalloc(sizeof(struct usb_dev_state), GFP_KERNEL);
+ ps = kzalloc(sizeof(struct usb_dev_state), GFP_KERNEL);
if (!ps)
goto out_free_ps;
@@ -889,16 +1019,15 @@ static int usbdev_open(struct inode *inode, struct file *file)
ps->dev = dev;
ps->file = file;
+ ps->interface_allowed_mask = 0xFFFFFFFF; /* 32 bits */
spin_lock_init(&ps->lock);
INIT_LIST_HEAD(&ps->list);
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
+ INIT_LIST_HEAD(&ps->memory_list);
init_waitqueue_head(&ps->wait);
- ps->discsignr = 0;
ps->disc_pid = get_pid(task_pid(current));
ps->cred = get_current_cred();
- ps->disccontext = NULL;
- ps->ifclaimed = 0;
security_task_getsecid(current, &ps->secid);
smp_wmb();
list_add_tail(&ps->list, &dev->filelist);
@@ -945,6 +1074,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
free_async(as);
as = async_getcompleted(ps);
}
+
kfree(ps);
return 0;
}
@@ -1198,6 +1328,28 @@ static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
static int proc_resetdevice(struct usb_dev_state *ps)
{
+ struct usb_host_config *actconfig = ps->dev->actconfig;
+ struct usb_interface *interface;
+ int i, number;
+
+ /* Don't allow a device reset if the process has dropped the
+ * privilege to do such things and any of the interfaces are
+ * currently claimed.
+ */
+ if (ps->privileges_dropped && actconfig) {
+ for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
+ interface = actconfig->interface[i];
+ number = interface->cur_altsetting->desc.bInterfaceNumber;
+ if (usb_interface_claimed(interface) &&
+ !test_bit(number, &ps->ifclaimed)) {
+ dev_warn(&ps->dev->dev,
+ "usbfs: interface %d claimed by %s while '%s' resets device\n",
+ number, interface->dev.driver->name, current->comm);
+ return -EACCES;
+ }
+ }
+ }
+
return usb_reset_device(ps->dev);
}
@@ -1266,6 +1418,31 @@ static int proc_setconfig(struct usb_dev_state *ps, void __user *arg)
return status;
}
+static struct usb_memory *
+find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb)
+{
+ struct usb_memory *usbm = NULL, *iter;
+ unsigned long flags;
+ unsigned long uurb_start = (unsigned long)uurb->buffer;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_for_each_entry(iter, &ps->memory_list, memlist) {
+ if (uurb_start >= iter->vm_start &&
+ uurb_start < iter->vm_start + iter->size) {
+ if (uurb->buffer_length > iter->vm_start + iter->size -
+ uurb_start) {
+ usbm = ERR_PTR(-EINVAL);
+ } else {
+ usbm = iter;
+ usbm->urb_use_count++;
+ }
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&ps->lock, flags);
+ return usbm;
+}
+
static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
void __user *arg)
@@ -1378,11 +1555,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
number_of_packets = uurb->number_of_packets;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
number_of_packets;
- isopkt = kmalloc(isofrmlen, GFP_KERNEL);
- if (!isopkt)
- return -ENOMEM;
- if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
- ret = -EFAULT;
+ isopkt = memdup_user(iso_frame_desc, isofrmlen);
+ if (IS_ERR(isopkt)) {
+ ret = PTR_ERR(isopkt);
+ isopkt = NULL;
goto error;
}
for (totlen = u = 0; u < number_of_packets; u++) {
@@ -1422,6 +1598,19 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
goto error;
}
+ as->usbm = find_memory_area(ps, uurb);
+ if (IS_ERR(as->usbm)) {
+ ret = PTR_ERR(as->usbm);
+ as->usbm = NULL;
+ goto error;
+ }
+
+ /* do not use SG buffers when memory mapped segments
+ * are in use
+ */
+ if (as->usbm)
+ num_sgs = 0;
+
u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length +
num_sgs * sizeof(struct scatterlist);
ret = usbfs_increase_memory_usage(u);
@@ -1459,29 +1648,35 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
totlen -= u;
}
} else if (uurb->buffer_length > 0) {
- as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
- GFP_KERNEL);
- if (!as->urb->transfer_buffer) {
- ret = -ENOMEM;
- goto error;
- }
+ if (as->usbm) {
+ unsigned long uurb_start = (unsigned long)uurb->buffer;
- if (!is_in) {
- if (copy_from_user(as->urb->transfer_buffer,
- uurb->buffer,
- uurb->buffer_length)) {
- ret = -EFAULT;
+ as->urb->transfer_buffer = as->usbm->mem +
+ (uurb_start - as->usbm->vm_start);
+ } else {
+ as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
+ GFP_KERNEL);
+ if (!as->urb->transfer_buffer) {
+ ret = -ENOMEM;
goto error;
}
- } else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
- /*
- * Isochronous input data may end up being
- * discontiguous if some of the packets are short.
- * Clear the buffer so that the gaps don't leak
- * kernel data to userspace.
- */
- memset(as->urb->transfer_buffer, 0,
- uurb->buffer_length);
+ if (!is_in) {
+ if (copy_from_user(as->urb->transfer_buffer,
+ uurb->buffer,
+ uurb->buffer_length)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
+ /*
+ * Isochronous input data may end up being
+ * discontiguous if some of the packets are
+ * short. Clear the buffer so that the gaps
+ * don't leak kernel data to userspace.
+ */
+ memset(as->urb->transfer_buffer, 0,
+ uurb->buffer_length);
+ }
}
}
as->urb->dev = ps->dev;
@@ -1528,10 +1723,14 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
isopkt = NULL;
as->ps = ps;
as->userurb = arg;
- if (is_in && uurb->buffer_length > 0)
+ if (as->usbm) {
+ unsigned long uurb_start = (unsigned long)uurb->buffer;
+
+ as->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ as->urb->transfer_dma = as->usbm->dma_handle +
+ (uurb_start - as->usbm->vm_start);
+ } else if (is_in && uurb->buffer_length > 0)
as->userbuffer = uurb->buffer;
- else
- as->userbuffer = NULL;
as->signr = uurb->signr;
as->ifnum = ifnum;
as->pid = get_pid(task_pid(current));
@@ -1587,6 +1786,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
return 0;
error:
+ if (as && as->usbm)
+ dec_usb_memory_use_count(as->usbm, &as->usbm->urb_use_count);
kfree(isopkt);
kfree(dr);
if (as)
@@ -1903,7 +2104,7 @@ static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)
ret = releaseintf(ps, ifnum);
if (ret < 0)
return ret;
- destroy_async_on_interface (ps, ifnum);
+ destroy_async_on_interface(ps, ifnum);
return 0;
}
@@ -1915,6 +2116,9 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
struct usb_interface *intf = NULL;
struct usb_driver *driver = NULL;
+ if (ps->privileges_dropped)
+ return -EACCES;
+
/* alloc buffer */
size = _IOC_SIZE(ctl->ioctl_code);
if (size > 0) {
@@ -2040,7 +2244,8 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
__u32 caps;
caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
- USBDEVFS_CAP_REAP_AFTER_DISCONNECT;
+ USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP |
+ USBDEVFS_CAP_DROP_PRIVILEGES;
if (!ps->dev->bus->no_stop_on_short)
caps |= USBDEVFS_CAP_BULK_CONTINUATION;
if (ps->dev->bus->sg_tablesize)
@@ -2067,6 +2272,9 @@ static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg)
if (intf->dev.driver) {
struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+ if (ps->privileges_dropped)
+ return -EACCES;
+
if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) &&
strncmp(dc.driver, intf->dev.driver->name,
sizeof(dc.driver)) != 0)
@@ -2123,6 +2331,23 @@ static int proc_free_streams(struct usb_dev_state *ps, void __user *arg)
return r;
}
+static int proc_drop_privileges(struct usb_dev_state *ps, void __user *arg)
+{
+ u32 data;
+
+ if (copy_from_user(&data, arg, sizeof(data)))
+ return -EFAULT;
+
+ /* This is an one way operation. Once privileges are
+ * dropped, you cannot regain them. You may however reissue
+ * this ioctl to shrink the allowed interfaces mask.
+ */
+ ps->interface_allowed_mask &= data;
+ ps->privileges_dropped = true;
+
+ return 0;
+}
+
/*
* NOTE: All requests here that have interface numbers as parameters
* are assuming that somehow the configuration has been prevented from
@@ -2311,6 +2536,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
case USBDEVFS_FREE_STREAMS:
ret = proc_free_streams(ps, p);
break;
+ case USBDEVFS_DROP_PRIVILEGES:
+ ret = proc_drop_privileges(ps, p);
+ break;
}
done:
@@ -2366,6 +2594,7 @@ const struct file_operations usbdev_file_operations = {
#ifdef CONFIG_COMPAT
.compat_ioctl = usbdev_compat_ioctl,
#endif
+ .mmap = usbdev_mmap,
.open = usbdev_open,
.release = usbdev_release,
};
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index ea337a718cc1..822ced9639aa 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -19,6 +19,7 @@
#include <linux/errno.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/usb.h>
#include "usb.h"
@@ -155,7 +156,6 @@ int usb_register_dev(struct usb_interface *intf,
int minor_base = class_driver->minor_base;
int minor;
char name[20];
- char *temp;
#ifdef CONFIG_USB_DYNAMIC_MINORS
/*
@@ -192,14 +192,9 @@ int usb_register_dev(struct usb_interface *intf,
/* create a usb class device for this usb interface */
snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
- temp = strrchr(name, '/');
- if (temp && (temp[1] != '\0'))
- ++temp;
- else
- temp = name;
intf->usb_dev = device_create(usb_class->class, &intf->dev,
MKDEV(USB_MAJOR, minor), class_driver,
- "%s", temp);
+ "%s", kbasename(name));
if (IS_ERR(intf->usb_dev)) {
down_write(&minor_rwsem);
usb_minors[minor] = NULL;
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 9eb1cff28bd4..f9d42cf23e55 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -28,7 +28,6 @@
#ifdef CONFIG_PPC_PMAC
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
-#include <asm/pci-bridge.h>
#include <asm/prom.h>
#endif
@@ -197,7 +196,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
* The xHCI driver has its own irq management
* make sure irq setup is not touched for xhci in generic hcd code
*/
- if ((driver->flags & HCD_MASK) != HCD_USB3) {
+ if ((driver->flags & HCD_MASK) < HCD_USB3) {
if (!dev->irq) {
dev_err(&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index df0e3b92533a..2ca2cef7f681 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -90,16 +90,15 @@ unsigned long usb_hcds_loaded;
EXPORT_SYMBOL_GPL(usb_hcds_loaded);
/* host controllers we manage */
-LIST_HEAD (usb_bus_list);
-EXPORT_SYMBOL_GPL (usb_bus_list);
+DEFINE_IDR (usb_bus_idr);
+EXPORT_SYMBOL_GPL (usb_bus_idr);
/* used when allocating bus numbers */
#define USB_MAXBUS 64
-static DECLARE_BITMAP(busmap, USB_MAXBUS);
/* used when updating list of hcds */
-DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */
-EXPORT_SYMBOL_GPL (usb_bus_list_lock);
+DEFINE_MUTEX(usb_bus_idr_lock); /* exported only for usbfs */
+EXPORT_SYMBOL_GPL (usb_bus_idr_lock);
/* used for controlling access to virtual root hubs */
static DEFINE_SPINLOCK(hcd_root_hub_lock);
@@ -128,6 +127,27 @@ static inline int is_root_hub(struct usb_device *udev)
#define KERNEL_REL bin2bcd(((LINUX_VERSION_CODE >> 16) & 0x0ff))
#define KERNEL_VER bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff))
+/* usb 3.1 root hub device descriptor */
+static const u8 usb31_rh_dev_descriptor[18] = {
+ 0x12, /* __u8 bLength; */
+ USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
+ 0x10, 0x03, /* __le16 bcdUSB; v3.1 */
+
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x03, /* __u8 bDeviceProtocol; USB 3 hub */
+ 0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
+
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
+ 0x03, 0x00, /* __le16 idProduct; device 0x0003 */
+ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
+
+ 0x03, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
/* usb 3.0 root hub device descriptor */
static const u8 usb3_rh_dev_descriptor[18] = {
0x12, /* __u8 bLength; */
@@ -557,6 +577,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case USB_DT_DEVICE << 8:
switch (hcd->speed) {
case HCD_USB31:
+ bufp = usb31_rh_dev_descriptor;
+ break;
case HCD_USB3:
bufp = usb3_rh_dev_descriptor;
break;
@@ -645,9 +667,15 @@ nongeneric:
/* non-generic request */
switch (typeReq) {
case GetHubStatus:
- case GetPortStatus:
len = 4;
break;
+ case GetPortStatus:
+ if (wValue == HUB_PORT_STATUS)
+ len = 4;
+ else
+ /* other port status types return 8 bytes */
+ len = 8;
+ break;
case GetHubDescriptor:
len = sizeof (struct usb_hub_descriptor);
break;
@@ -967,8 +995,6 @@ static void usb_bus_init (struct usb_bus *bus)
bus->bandwidth_int_reqs = 0;
bus->bandwidth_isoc_reqs = 0;
mutex_init(&bus->usb_address0_mutex);
-
- INIT_LIST_HEAD (&bus->bus_list);
}
/*-------------------------------------------------------------------------*/
@@ -988,18 +1014,14 @@ static int usb_register_bus(struct usb_bus *bus)
int result = -E2BIG;
int busnum;
- mutex_lock(&usb_bus_list_lock);
- busnum = find_next_zero_bit(busmap, USB_MAXBUS, 1);
- if (busnum >= USB_MAXBUS) {
- printk (KERN_ERR "%s: too many buses\n", usbcore_name);
+ mutex_lock(&usb_bus_idr_lock);
+ busnum = idr_alloc(&usb_bus_idr, bus, 1, USB_MAXBUS, GFP_KERNEL);
+ if (busnum < 0) {
+ pr_err("%s: failed to get bus number\n", usbcore_name);
goto error_find_busnum;
}
- set_bit(busnum, busmap);
bus->busnum = busnum;
-
- /* Add it to the local list of buses */
- list_add (&bus->bus_list, &usb_bus_list);
- mutex_unlock(&usb_bus_list_lock);
+ mutex_unlock(&usb_bus_idr_lock);
usb_notify_add_bus(bus);
@@ -1008,7 +1030,7 @@ static int usb_register_bus(struct usb_bus *bus)
return 0;
error_find_busnum:
- mutex_unlock(&usb_bus_list_lock);
+ mutex_unlock(&usb_bus_idr_lock);
return result;
}
@@ -1029,13 +1051,11 @@ static void usb_deregister_bus (struct usb_bus *bus)
* controller code, as well as having it call this when cleaning
* itself up
*/
- mutex_lock(&usb_bus_list_lock);
- list_del (&bus->bus_list);
- mutex_unlock(&usb_bus_list_lock);
+ mutex_lock(&usb_bus_idr_lock);
+ idr_remove(&usb_bus_idr, bus->busnum);
+ mutex_unlock(&usb_bus_idr_lock);
usb_notify_remove_bus(bus);
-
- clear_bit(bus->busnum, busmap);
}
/**
@@ -1063,12 +1083,12 @@ static int register_root_hub(struct usb_hcd *hcd)
set_bit (devnum, usb_dev->bus->devmap.devicemap);
usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
- mutex_lock(&usb_bus_list_lock);
+ mutex_lock(&usb_bus_idr_lock);
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
if (retval != sizeof usb_dev->descriptor) {
- mutex_unlock(&usb_bus_list_lock);
+ mutex_unlock(&usb_bus_idr_lock);
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
dev_name(&usb_dev->dev), retval);
return (retval < 0) ? retval : -EMSGSIZE;
@@ -1078,8 +1098,8 @@ static int register_root_hub(struct usb_hcd *hcd)
retval = usb_get_bos_descriptor(usb_dev);
if (!retval) {
usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
- } else if (usb_dev->speed == USB_SPEED_SUPER) {
- mutex_unlock(&usb_bus_list_lock);
+ } else if (usb_dev->speed >= USB_SPEED_SUPER) {
+ mutex_unlock(&usb_bus_idr_lock);
dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
dev_name(&usb_dev->dev), retval);
return retval;
@@ -1099,7 +1119,7 @@ static int register_root_hub(struct usb_hcd *hcd)
if (HCD_DEAD(hcd))
usb_hc_died (hcd); /* This time clean up */
}
- mutex_unlock(&usb_bus_list_lock);
+ mutex_unlock(&usb_bus_idr_lock);
return retval;
}
@@ -1408,7 +1428,8 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
- if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
+ if (IS_ENABLED(CONFIG_HAS_DMA) &&
+ (urb->transfer_flags & URB_SETUP_MAP_SINGLE))
dma_unmap_single(hcd->self.controller,
urb->setup_dma,
sizeof(struct usb_ctrlrequest),
@@ -1440,17 +1461,20 @@ void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
usb_hcd_unmap_urb_setup_for_dma(hcd, urb);
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
- if (urb->transfer_flags & URB_DMA_MAP_SG)
+ if (IS_ENABLED(CONFIG_HAS_DMA) &&
+ (urb->transfer_flags & URB_DMA_MAP_SG))
dma_unmap_sg(hcd->self.controller,
urb->sg,
urb->num_sgs,
dir);
- else if (urb->transfer_flags & URB_DMA_MAP_PAGE)
+ else if (IS_ENABLED(CONFIG_HAS_DMA) &&
+ (urb->transfer_flags & URB_DMA_MAP_PAGE))
dma_unmap_page(hcd->self.controller,
urb->transfer_dma,
urb->transfer_buffer_length,
dir);
- else if (urb->transfer_flags & URB_DMA_MAP_SINGLE)
+ else if (IS_ENABLED(CONFIG_HAS_DMA) &&
+ (urb->transfer_flags & URB_DMA_MAP_SINGLE))
dma_unmap_single(hcd->self.controller,
urb->transfer_dma,
urb->transfer_buffer_length,
@@ -1492,7 +1516,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
if (usb_endpoint_xfer_control(&urb->ep->desc)) {
if (hcd->self.uses_pio_for_control)
return ret;
- if (hcd->self.uses_dma) {
+ if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
hcd->self.controller,
urb->setup_packet,
@@ -1518,7 +1542,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (urb->transfer_buffer_length != 0
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
- if (hcd->self.uses_dma) {
+ if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
if (urb->num_sgs) {
int n;
@@ -2112,7 +2136,7 @@ int usb_alloc_streams(struct usb_interface *interface,
hcd = bus_to_hcd(dev->bus);
if (!hcd->driver->alloc_streams || !hcd->driver->free_streams)
return -EINVAL;
- if (dev->speed != USB_SPEED_SUPER)
+ if (dev->speed < USB_SPEED_SUPER)
return -EINVAL;
if (dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
@@ -2160,7 +2184,7 @@ int usb_free_streams(struct usb_interface *interface,
dev = interface_to_usbdev(interface);
hcd = bus_to_hcd(dev->bus);
- if (dev->speed != USB_SPEED_SUPER)
+ if (dev->speed < USB_SPEED_SUPER)
return -EINVAL;
/* Double-free is not allowed */
@@ -2208,7 +2232,7 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
{
- struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
+ struct usb_hcd *hcd = bus_to_hcd(rhdev->bus);
int status;
int old_state = hcd->state;
@@ -2257,7 +2281,7 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
{
- struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
+ struct usb_hcd *hcd = bus_to_hcd(rhdev->bus);
int status;
int old_state = hcd->state;
@@ -2371,7 +2395,7 @@ int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
* boards with root hubs hooked up to internal devices (instead of
* just the OTG port) may need more attention to resetting...
*/
- hcd = container_of (bus, struct usb_hcd, self);
+ hcd = bus_to_hcd(bus);
if (port_num && hcd->driver->start_port_reset)
status = hcd->driver->start_port_reset(hcd, port_num);
@@ -2778,9 +2802,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
rhdev->speed = USB_SPEED_WIRELESS;
break;
case HCD_USB3:
- case HCD_USB31:
rhdev->speed = USB_SPEED_SUPER;
break;
+ case HCD_USB31:
+ rhdev->speed = USB_SPEED_SUPER_PLUS;
+ break;
default:
retval = -EINVAL;
goto err_set_rh_speed;
@@ -2863,9 +2889,9 @@ error_create_attr_group:
#ifdef CONFIG_PM
cancel_work_sync(&hcd->wakeup_work);
#endif
- mutex_lock(&usb_bus_list_lock);
+ mutex_lock(&usb_bus_idr_lock);
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
- mutex_unlock(&usb_bus_list_lock);
+ mutex_unlock(&usb_bus_idr_lock);
err_register_root_hub:
hcd->rh_pollable = 0;
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
@@ -2932,9 +2958,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work);
#endif
- mutex_lock(&usb_bus_list_lock);
+ mutex_lock(&usb_bus_idr_lock);
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
- mutex_unlock(&usb_bus_list_lock);
+ mutex_unlock(&usb_bus_idr_lock);
/*
* tasklet_kill() isn't needed here because:
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 350dcd9af5d8..38cc4bae0a82 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -49,7 +49,7 @@ static void hub_event(struct work_struct *work);
DEFINE_MUTEX(usb_port_peer_mutex);
/* cycle leds on hubs that aren't blinking for attention */
-static bool blinkenlights = 0;
+static bool blinkenlights;
module_param(blinkenlights, bool, S_IRUGO);
MODULE_PARM_DESC(blinkenlights, "true to cycle leds on hubs");
@@ -78,7 +78,7 @@ MODULE_PARM_DESC(initial_descriptor_timeout,
* otherwise the new scheme is used. If that fails and "use_both_schemes"
* is set, then the driver will make another attempt, using the other scheme.
*/
-static bool old_scheme_first = 0;
+static bool old_scheme_first;
module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(old_scheme_first,
"start with the old device initialization scheme");
@@ -298,7 +298,7 @@ static void usb_set_lpm_parameters(struct usb_device *udev)
unsigned int hub_u1_del;
unsigned int hub_u2_del;
- if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
+ if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER)
return;
hub = usb_hub_to_struct_hub(udev->parent);
@@ -537,29 +537,34 @@ static int get_hub_status(struct usb_device *hdev,
/*
* USB 2.0 spec Section 11.24.2.7
+ * USB 3.1 takes into use the wValue and wLength fields, spec Section 10.16.2.6
*/
static int get_port_status(struct usb_device *hdev, int port1,
- struct usb_port_status *data)
+ void *data, u16 value, u16 length)
{
int i, status = -ETIMEDOUT;
for (i = 0; i < USB_STS_RETRIES &&
(status == -ETIMEDOUT || status == -EPIPE); i++) {
status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
- USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1,
- data, sizeof(*data), USB_STS_TIMEOUT);
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, value,
+ port1, data, length, USB_STS_TIMEOUT);
}
return status;
}
-static int hub_port_status(struct usb_hub *hub, int port1,
- u16 *status, u16 *change)
+static int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
+ u16 *status, u16 *change, u32 *ext_status)
{
int ret;
+ int len = 4;
+
+ if (type != HUB_PORT_STATUS)
+ len = 8;
mutex_lock(&hub->status_mutex);
- ret = get_port_status(hub->hdev, port1, &hub->status->port);
- if (ret < 4) {
+ ret = get_port_status(hub->hdev, port1, &hub->status->port, type, len);
+ if (ret < len) {
if (ret != -ENODEV)
dev_err(hub->intfdev,
"%s failed (err = %d)\n", __func__, ret);
@@ -568,13 +573,22 @@ static int hub_port_status(struct usb_hub *hub, int port1,
} else {
*status = le16_to_cpu(hub->status->port.wPortStatus);
*change = le16_to_cpu(hub->status->port.wPortChange);
-
+ if (type != HUB_PORT_STATUS && ext_status)
+ *ext_status = le32_to_cpu(
+ hub->status->port.dwExtPortStatus);
ret = 0;
}
mutex_unlock(&hub->status_mutex);
return ret;
}
+static int hub_port_status(struct usb_hub *hub, int port1,
+ u16 *status, u16 *change)
+{
+ return hub_ext_port_status(hub, port1, HUB_PORT_STATUS,
+ status, change, NULL);
+}
+
static void kick_hub_wq(struct usb_hub *hub)
{
struct usb_interface *intf;
@@ -2131,7 +2145,7 @@ static void hub_disconnect_children(struct usb_device *udev)
* Something got disconnected. Get rid of it and all of its children.
*
* If *pdev is a normal device then the parent hub must already be locked.
- * If *pdev is a root hub then the caller must hold the usb_bus_list_lock,
+ * If *pdev is a root hub then the caller must hold the usb_bus_idr_lock,
* which protects the set of root hubs as well as the list of buses.
*
* Only hub drivers (including virtual root hub drivers for host
@@ -2429,7 +2443,7 @@ static void set_usb_port_removable(struct usb_device *udev)
* enumerated. The device descriptor is available, but not descriptors
* for any device configuration. The caller must have locked either
* the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * usb_bus_idr_lock (if udev is a root hub). The parent's pointer to
* udev has already been installed, but udev is not yet visible through
* sysfs or other filesystem code.
*
@@ -2612,6 +2626,32 @@ out_authorized:
return result;
}
+/*
+ * Return 1 if port speed is SuperSpeedPlus, 0 otherwise
+ * check it from the link protocol field of the current speed ID attribute.
+ * current speed ID is got from ext port status request. Sublink speed attribute
+ * table is returned with the hub BOS SSP device capability descriptor
+ */
+static int port_speed_is_ssp(struct usb_device *hdev, int speed_id)
+{
+ int ssa_count;
+ u32 ss_attr;
+ int i;
+ struct usb_ssp_cap_descriptor *ssp_cap = hdev->bos->ssp_cap;
+
+ if (!ssp_cap)
+ return 0;
+
+ ssa_count = le32_to_cpu(ssp_cap->bmAttributes) &
+ USB_SSP_SUBLINK_SPEED_ATTRIBS;
+
+ for (i = 0; i <= ssa_count; i++) {
+ ss_attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]);
+ if (speed_id == (ss_attr & USB_SSP_SUBLINK_SPEED_SSID))
+ return !!(ss_attr & USB_SSP_SUBLINK_SPEED_LP);
+ }
+ return 0;
+}
/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
static unsigned hub_is_wusb(struct usb_hub *hub)
@@ -2619,7 +2659,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
struct usb_hcd *hcd;
if (hub->hdev->parent != NULL) /* not a root hub? */
return 0;
- hcd = container_of(hub->hdev->bus, struct usb_hcd, self);
+ hcd = bus_to_hcd(hub->hdev->bus);
return hcd->wireless;
}
@@ -2645,7 +2685,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
*/
static bool use_new_scheme(struct usb_device *udev, int retry)
{
- if (udev->speed == USB_SPEED_SUPER)
+ if (udev->speed >= USB_SPEED_SUPER)
return false;
return USE_NEW_SCHEME(retry);
@@ -2676,6 +2716,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
int delay_time, ret;
u16 portstatus;
u16 portchange;
+ u32 ext_portstatus = 0;
for (delay_time = 0;
delay_time < HUB_RESET_TIMEOUT;
@@ -2684,7 +2725,14 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
msleep(delay);
/* read and decode port status */
- ret = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (hub_is_superspeedplus(hub->hdev))
+ ret = hub_ext_port_status(hub, port1,
+ HUB_EXT_PORT_STATUS,
+ &portstatus, &portchange,
+ &ext_portstatus);
+ else
+ ret = hub_port_status(hub, port1, &portstatus,
+ &portchange);
if (ret < 0)
return ret;
@@ -2727,6 +2775,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
if (hub_is_wusb(hub))
udev->speed = USB_SPEED_WIRELESS;
+ else if (hub_is_superspeedplus(hub->hdev) &&
+ port_speed_is_ssp(hub->hdev, ext_portstatus &
+ USB_EXT_PORT_STAT_RX_SPEED_ID))
+ udev->speed = USB_SPEED_SUPER_PLUS;
else if (hub_is_superspeed(hub->hdev))
udev->speed = USB_SPEED_SUPER;
else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
@@ -3989,7 +4041,7 @@ int usb_disable_lpm(struct usb_device *udev)
struct usb_hcd *hcd;
if (!udev || !udev->parent ||
- udev->speed != USB_SPEED_SUPER ||
+ udev->speed < USB_SPEED_SUPER ||
!udev->lpm_capable ||
udev->state < USB_STATE_DEFAULT)
return 0;
@@ -4048,7 +4100,7 @@ void usb_enable_lpm(struct usb_device *udev)
struct usb_port *port_dev;
if (!udev || !udev->parent ||
- udev->speed != USB_SPEED_SUPER ||
+ udev->speed < USB_SPEED_SUPER ||
!udev->lpm_capable ||
udev->state < USB_STATE_DEFAULT)
return;
@@ -4292,7 +4344,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
{
struct usb_device *hdev = hub->hdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
- int i, j, retval;
+ int retries, operations, retval, i;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
const char *speed;
@@ -4323,7 +4375,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
retval = -ENODEV;
- if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
+ /* Don't allow speed changes at reset, except usb 3.0 to faster */
+ if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed &&
+ !(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
dev_dbg(&udev->dev, "device reset changed speed!\n");
goto fail;
}
@@ -4335,6 +4389,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
*/
switch (udev->speed) {
+ case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER:
case USB_SPEED_WIRELESS: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
@@ -4361,7 +4416,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
else
speed = usb_speed_string(udev->speed);
- if (udev->speed != USB_SPEED_SUPER)
+ if (udev->speed < USB_SPEED_SUPER)
dev_info(&udev->dev,
"%s %s USB device number %d using %s\n",
(udev->config) ? "reset" : "new", speed,
@@ -4394,7 +4449,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* first 8 bytes of the device descriptor to get the ep0 maxpacket
* value.
*/
- for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
+ for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
bool did_new_scheme = false;
if (use_new_scheme(udev, retry_counter)) {
@@ -4421,7 +4476,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* 255 is for WUSB devices, we actually need to use
* 512 (WUSB1.0[4.8.1]).
*/
- for (j = 0; j < 3; ++j) {
+ for (operations = 0; operations < 3; ++operations) {
buf->bMaxPacketSize0 = 0;
r = usb_control_msg(udev, usb_rcvaddr0pipe(),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
@@ -4441,7 +4496,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
r = -EPROTO;
break;
}
- if (r == 0)
+ /*
+ * Some devices time out if they are powered on
+ * when already connected. They need a second
+ * reset. But only on the first attempt,
+ * lest we get into a time out/reset loop
+ */
+ if (r == 0 || (r == -ETIMEDOUT && retries == 0))
break;
}
udev->descriptor.bMaxPacketSize0 =
@@ -4473,7 +4534,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* authorization will assign the final address.
*/
if (udev->wusb == 0) {
- for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
+ for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
retval = hub_set_address(udev, devnum);
if (retval >= 0)
break;
@@ -4485,11 +4546,12 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
devnum, retval);
goto fail;
}
- if (udev->speed == USB_SPEED_SUPER) {
+ if (udev->speed >= USB_SPEED_SUPER) {
devnum = udev->devnum;
dev_info(&udev->dev,
- "%s SuperSpeed USB device number %d using %s\n",
+ "%s SuperSpeed%s USB device number %d using %s\n",
(udev->config) ? "reset" : "new",
+ (udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "",
devnum, udev->bus->controller->driver->name);
}
@@ -4528,7 +4590,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* got from those devices show they aren't superspeed devices. Warm
* reset the port attached by the devices can fix them.
*/
- if ((udev->speed == USB_SPEED_SUPER) &&
+ if ((udev->speed >= USB_SPEED_SUPER) &&
(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
dev_err(&udev->dev, "got a wrong device descriptor, "
"warm reset device\n");
@@ -4539,7 +4601,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
}
if (udev->descriptor.bMaxPacketSize0 == 0xff ||
- udev->speed == USB_SPEED_SUPER)
+ udev->speed >= USB_SPEED_SUPER)
i = 512;
else
i = udev->descriptor.bMaxPacketSize0;
@@ -4749,7 +4811,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
udev->level = hdev->level + 1;
udev->wusb = hub_is_wusb(hub);
- /* Only USB 3.0 devices are connected to SuperSpeed hubs. */
+ /* Devices connected to SuperSpeed hubs are USB 3.0 or later */
if (hub_is_superspeed(hub->hdev))
udev->speed = USB_SPEED_SUPER;
else
@@ -5401,6 +5463,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
}
bos = udev->bos;
+ udev->bos = NULL;
for (i = 0; i < SET_CONFIG_TRIES; ++i) {
@@ -5493,11 +5556,8 @@ done:
usb_set_usb2_hardware_lpm(udev, 1);
usb_unlocked_enable_lpm(udev);
usb_enable_ltm(udev);
- /* release the new BOS descriptor allocated by hub_port_init() */
- if (udev->bos != bos) {
- usb_release_bos_descriptor(udev);
- udev->bos = bos;
- }
+ usb_release_bos_descriptor(udev);
+ udev->bos = bos;
return 0;
re_enumerate:
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 45d070dd1d03..34c1a7e22aae 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -140,6 +140,13 @@ static inline int hub_is_superspeed(struct usb_device *hdev)
return hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS;
}
+static inline int hub_is_superspeedplus(struct usb_device *hdev)
+{
+ return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS &&
+ le16_to_cpu(hdev->descriptor.bcdUSB) >= 0x0310 &&
+ hdev->bos->ssp_cap);
+}
+
static inline unsigned hub_power_on_good_delay(struct usb_hub *hub)
{
unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2;
diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c
new file mode 100644
index 000000000000..2289700c31d6
--- /dev/null
+++ b/drivers/usb/core/of.c
@@ -0,0 +1,47 @@
+/*
+ * of.c The helpers for hcd device tree support
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Author: Peter Chen <peter.chen@freescale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/of.h>
+
+/**
+ * usb_of_get_child_node - Find the device node match port number
+ * @parent: the parent device node
+ * @portnum: the port number which device is connecting
+ *
+ * Find the node from device tree according to its port number.
+ *
+ * Return: On success, a pointer to the device node, %NULL on failure.
+ */
+struct device_node *usb_of_get_child_node(struct device_node *parent,
+ int portnum)
+{
+ struct device_node *node;
+ u32 port;
+
+ for_each_child_of_node(parent, node) {
+ if (!of_property_read_u32(node, "reg", &port)) {
+ if (port == portnum)
+ return node;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(usb_of_get_child_node);
+
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 65b6e6b84043..c953a0f1c695 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -23,10 +23,12 @@ static ssize_t field##_show(struct device *dev, \
{ \
struct usb_device *udev; \
struct usb_host_config *actconfig; \
- ssize_t rc = 0; \
+ ssize_t rc; \
\
udev = to_usb_device(dev); \
- usb_lock_device(udev); \
+ rc = usb_lock_device_interruptible(udev); \
+ if (rc < 0) \
+ return -EINTR; \
actconfig = udev->actconfig; \
if (actconfig) \
rc = sprintf(buf, format_string, \
@@ -47,10 +49,12 @@ static ssize_t bMaxPower_show(struct device *dev,
{
struct usb_device *udev;
struct usb_host_config *actconfig;
- ssize_t rc = 0;
+ ssize_t rc;
udev = to_usb_device(dev);
- usb_lock_device(udev);
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
actconfig = udev->actconfig;
if (actconfig)
rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
@@ -64,10 +68,12 @@ static ssize_t configuration_show(struct device *dev,
{
struct usb_device *udev;
struct usb_host_config *actconfig;
- ssize_t rc = 0;
+ ssize_t rc;
udev = to_usb_device(dev);
- usb_lock_device(udev);
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
actconfig = udev->actconfig;
if (actconfig && actconfig->string)
rc = sprintf(buf, "%s\n", actconfig->string);
@@ -84,11 +90,13 @@ static ssize_t bConfigurationValue_store(struct device *dev,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
- int config, value;
+ int config, value, rc;
if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255)
return -EINVAL;
- usb_lock_device(udev);
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
value = usb_set_configuration(udev, config);
usb_unlock_device(udev);
return (value < 0) ? value : count;
@@ -105,7 +113,9 @@ static ssize_t name##_show(struct device *dev, \
int retval; \
\
udev = to_usb_device(dev); \
- usb_lock_device(udev); \
+ retval = usb_lock_device_interruptible(udev); \
+ if (retval < 0) \
+ return -EINTR; \
retval = sprintf(buf, "%s\n", udev->name); \
usb_unlock_device(udev); \
return retval; \
@@ -141,6 +151,9 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
case USB_SPEED_SUPER:
speed = "5000";
break;
+ case USB_SPEED_SUPER_PLUS:
+ speed = "10000";
+ break;
default:
speed = "unknown";
}
@@ -224,11 +237,13 @@ static ssize_t avoid_reset_quirk_store(struct device *dev,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
- int val;
+ int val, rc;
if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
return -EINVAL;
- usb_lock_device(udev);
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
if (val)
udev->quirks |= USB_QUIRK_RESET;
else
@@ -294,7 +309,7 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
- int value;
+ int value, rc;
/* Hubs are always enabled for USB_PERSIST */
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
@@ -303,7 +318,9 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
if (sscanf(buf, "%d", &value) != 1)
return -EINVAL;
- usb_lock_device(udev);
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
udev->persist_enabled = !!value;
usb_unlock_device(udev);
return count;
@@ -420,13 +437,16 @@ static ssize_t level_store(struct device *dev, struct device_attribute *attr,
int len = count;
char *cp;
int rc = count;
+ int rv;
warn_level();
cp = memchr(buf, '\n', count);
if (cp)
len = cp - buf;
- usb_lock_device(udev);
+ rv = usb_lock_device_interruptible(udev);
+ if (rv < 0)
+ return -EINTR;
if (len == sizeof on_string - 1 &&
strncmp(buf, on_string, len) == 0)
@@ -466,7 +486,9 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev,
bool value;
int ret;
- usb_lock_device(udev);
+ ret = usb_lock_device_interruptible(udev);
+ if (ret < 0)
+ return -EINTR;
ret = strtobool(buf, &value);
@@ -536,8 +558,11 @@ static ssize_t usb3_hardware_lpm_u1_show(struct device *dev,
{
struct usb_device *udev = to_usb_device(dev);
const char *p;
+ int rc;
- usb_lock_device(udev);
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
if (udev->usb3_lpm_u1_enabled)
p = "enabled";
@@ -555,8 +580,11 @@ static ssize_t usb3_hardware_lpm_u2_show(struct device *dev,
{
struct usb_device *udev = to_usb_device(dev);
const char *p;
+ int rc;
- usb_lock_device(udev);
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
if (udev->usb3_lpm_u2_enabled)
p = "enabled";
@@ -822,7 +850,6 @@ read_descriptors(struct file *filp, struct kobject *kobj,
* Following that are the raw descriptor entries for all the
* configurations (config plus subsidiary descriptors).
*/
- usb_lock_device(udev);
for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations &&
nleft > 0; ++cfgno) {
if (cfgno < 0) {
@@ -843,7 +870,6 @@ read_descriptors(struct file *filp, struct kobject *kobj,
off -= srclen;
}
}
- usb_unlock_device(udev);
return count - nleft;
}
@@ -969,7 +995,9 @@ static ssize_t supports_autosuspend_show(struct device *dev,
{
int s;
- device_lock(dev);
+ s = device_lock_interruptible(dev);
+ if (s < 0)
+ return -EINTR;
/* Devices will be autosuspended even when an interface isn't claimed */
s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend);
device_unlock(dev);
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 3d274778caaf..c601e25b609f 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -401,7 +401,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* SuperSpeed isoc endpoints have up to 16 bursts of up to
* 3 packets each
*/
- if (dev->speed == USB_SPEED_SUPER) {
+ if (dev->speed >= USB_SPEED_SUPER) {
int burst = 1 + ep->ss_ep_comp.bMaxBurst;
int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes);
max *= burst;
@@ -499,6 +499,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
}
/* too big? */
switch (dev->speed) {
+ case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER: /* units are 125us */
/* Handle up to 2^(16-1) microframes */
if (urb->interval > (1 << 15))
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index ebb29caa3fe4..ffa5cf13ffe1 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
+#include <linux/usb/of.h>
#include <asm/io.h>
#include <linux/scatterlist.h>
@@ -241,7 +242,7 @@ static int __each_dev(struct device *dev, void *data)
if (!is_usb_device(dev))
return 0;
- return arg->fn(container_of(dev, struct usb_device, dev), arg->data);
+ return arg->fn(to_usb_device(dev), arg->data);
}
/**
@@ -397,7 +398,7 @@ struct device_type usb_device_type = {
/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
static unsigned usb_bus_is_wusb(struct usb_bus *bus)
{
- struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
+ struct usb_hcd *hcd = bus_to_hcd(bus);
return hcd->wireless;
}
@@ -470,6 +471,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->route = 0;
dev->dev.parent = bus->controller;
+ dev->dev.of_node = bus->controller->of_node;
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
} else {
@@ -494,6 +496,14 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->dev.parent = &parent->dev;
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
+ if (!parent->parent) {
+ /* device under root hub's port */
+ port1 = usb_hcd_find_raw_port_number(usb_hcd,
+ port1);
+ }
+ dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node,
+ port1);
+
/* hub driver sets up TT records */
}
@@ -1115,6 +1125,7 @@ static void __exit usb_exit(void)
bus_unregister(&usb_bus_type);
usb_acpi_unregister();
usb_debugfs_cleanup();
+ idr_destroy(&usb_bus_idr);
}
subsys_initcall(usb_init);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 05b5e17abf92..53318126ed91 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -45,7 +45,7 @@ static inline unsigned usb_get_max_power(struct usb_device *udev,
struct usb_host_config *c)
{
/* SuperSpeed power is in 8 mA units; others are in 2 mA units */
- unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2);
+ unsigned mul = (udev->speed >= USB_SPEED_SUPER ? 8 : 2);
return c->desc.bMaxPower * mul;
}
diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig
index fd95ba6ec317..c1f29caa8990 100644
--- a/drivers/usb/dwc2/Kconfig
+++ b/drivers/usb/dwc2/Kconfig
@@ -1,6 +1,8 @@
config USB_DWC2
tristate "DesignWare USB2 DRD Core Support"
+ depends on HAS_DMA
depends on USB || USB_GADGET
+ depends on HAS_IOMEM
help
Say Y here if your system has a Dual Role Hi-Speed USB
controller based on the DesignWare HSOTG IP Core.
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index e991d55914db..4135a5ff67ca 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -56,189 +56,6 @@
#include "core.h"
#include "hcd.h"
-#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
-/**
- * dwc2_backup_host_registers() - Backup controller host registers.
- * When suspending usb bus, registers needs to be backuped
- * if controller power is disabled once suspended.
- *
- * @hsotg: Programming view of the DWC_otg controller
- */
-static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
-{
- struct dwc2_hregs_backup *hr;
- int i;
-
- dev_dbg(hsotg->dev, "%s\n", __func__);
-
- /* Backup Host regs */
- hr = &hsotg->hr_backup;
- hr->hcfg = dwc2_readl(hsotg->regs + HCFG);
- hr->haintmsk = dwc2_readl(hsotg->regs + HAINTMSK);
- for (i = 0; i < hsotg->core_params->host_channels; ++i)
- hr->hcintmsk[i] = dwc2_readl(hsotg->regs + HCINTMSK(i));
-
- hr->hprt0 = dwc2_read_hprt0(hsotg);
- hr->hfir = dwc2_readl(hsotg->regs + HFIR);
- hr->valid = true;
-
- return 0;
-}
-
-/**
- * dwc2_restore_host_registers() - Restore controller host registers.
- * When resuming usb bus, device registers needs to be restored
- * if controller power were disabled.
- *
- * @hsotg: Programming view of the DWC_otg controller
- */
-static int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
-{
- struct dwc2_hregs_backup *hr;
- int i;
-
- dev_dbg(hsotg->dev, "%s\n", __func__);
-
- /* Restore host regs */
- hr = &hsotg->hr_backup;
- if (!hr->valid) {
- dev_err(hsotg->dev, "%s: no host registers to restore\n",
- __func__);
- return -EINVAL;
- }
- hr->valid = false;
-
- dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
- dwc2_writel(hr->haintmsk, hsotg->regs + HAINTMSK);
-
- for (i = 0; i < hsotg->core_params->host_channels; ++i)
- dwc2_writel(hr->hcintmsk[i], hsotg->regs + HCINTMSK(i));
-
- dwc2_writel(hr->hprt0, hsotg->regs + HPRT0);
- dwc2_writel(hr->hfir, hsotg->regs + HFIR);
- hsotg->frame_number = 0;
-
- return 0;
-}
-#else
-static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
-{ return 0; }
-
-static inline int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
-{ return 0; }
-#endif
-
-#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
- IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
-/**
- * dwc2_backup_device_registers() - Backup controller device registers.
- * When suspending usb bus, registers needs to be backuped
- * if controller power is disabled once suspended.
- *
- * @hsotg: Programming view of the DWC_otg controller
- */
-static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
-{
- struct dwc2_dregs_backup *dr;
- int i;
-
- dev_dbg(hsotg->dev, "%s\n", __func__);
-
- /* Backup dev regs */
- dr = &hsotg->dr_backup;
-
- dr->dcfg = dwc2_readl(hsotg->regs + DCFG);
- dr->dctl = dwc2_readl(hsotg->regs + DCTL);
- dr->daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
- dr->diepmsk = dwc2_readl(hsotg->regs + DIEPMSK);
- dr->doepmsk = dwc2_readl(hsotg->regs + DOEPMSK);
-
- for (i = 0; i < hsotg->num_of_eps; i++) {
- /* Backup IN EPs */
- dr->diepctl[i] = dwc2_readl(hsotg->regs + DIEPCTL(i));
-
- /* Ensure DATA PID is correctly configured */
- if (dr->diepctl[i] & DXEPCTL_DPID)
- dr->diepctl[i] |= DXEPCTL_SETD1PID;
- else
- dr->diepctl[i] |= DXEPCTL_SETD0PID;
-
- dr->dieptsiz[i] = dwc2_readl(hsotg->regs + DIEPTSIZ(i));
- dr->diepdma[i] = dwc2_readl(hsotg->regs + DIEPDMA(i));
-
- /* Backup OUT EPs */
- dr->doepctl[i] = dwc2_readl(hsotg->regs + DOEPCTL(i));
-
- /* Ensure DATA PID is correctly configured */
- if (dr->doepctl[i] & DXEPCTL_DPID)
- dr->doepctl[i] |= DXEPCTL_SETD1PID;
- else
- dr->doepctl[i] |= DXEPCTL_SETD0PID;
-
- dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i));
- dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i));
- }
- dr->valid = true;
- return 0;
-}
-
-/**
- * dwc2_restore_device_registers() - Restore controller device registers.
- * When resuming usb bus, device registers needs to be restored
- * if controller power were disabled.
- *
- * @hsotg: Programming view of the DWC_otg controller
- */
-static int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
-{
- struct dwc2_dregs_backup *dr;
- u32 dctl;
- int i;
-
- dev_dbg(hsotg->dev, "%s\n", __func__);
-
- /* Restore dev regs */
- dr = &hsotg->dr_backup;
- if (!dr->valid) {
- dev_err(hsotg->dev, "%s: no device registers to restore\n",
- __func__);
- return -EINVAL;
- }
- dr->valid = false;
-
- dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
- dwc2_writel(dr->dctl, hsotg->regs + DCTL);
- dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK);
- dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK);
- dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK);
-
- for (i = 0; i < hsotg->num_of_eps; i++) {
- /* Restore IN EPs */
- dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
- dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i));
- dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i));
-
- /* Restore OUT EPs */
- dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
- dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
- dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i));
- }
-
- /* Set the Power-On Programming done bit */
- dctl = dwc2_readl(hsotg->regs + DCTL);
- dctl |= DCTL_PWRONPRGDONE;
- dwc2_writel(dctl, hsotg->regs + DCTL);
-
- return 0;
-}
-#else
-static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
-{ return 0; }
-
-static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
-{ return 0; }
-#endif
-
/**
* dwc2_backup_global_registers() - Backup global controller registers.
* When suspending usb bus, registers needs to be backuped
@@ -421,62 +238,6 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
return ret;
}
-/**
- * dwc2_enable_common_interrupts() - Initializes the commmon interrupts,
- * used in both device and host modes
- *
- * @hsotg: Programming view of the DWC_otg controller
- */
-static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
-{
- u32 intmsk;
-
- /* Clear any pending OTG Interrupts */
- dwc2_writel(0xffffffff, hsotg->regs + GOTGINT);
-
- /* Clear any pending interrupts */
- dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
-
- /* Enable the interrupts in the GINTMSK */
- intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT;
-
- if (hsotg->core_params->dma_enable <= 0)
- intmsk |= GINTSTS_RXFLVL;
- if (hsotg->core_params->external_id_pin_ctl <= 0)
- intmsk |= GINTSTS_CONIDSTSCHNG;
-
- intmsk |= GINTSTS_WKUPINT | GINTSTS_USBSUSP |
- GINTSTS_SESSREQINT;
-
- dwc2_writel(intmsk, hsotg->regs + GINTMSK);
-}
-
-/*
- * Initializes the FSLSPClkSel field of the HCFG register depending on the
- * PHY type
- */
-static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
-{
- u32 hcfg, val;
-
- if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
- hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
- hsotg->core_params->ulpi_fs_ls > 0) ||
- hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
- /* Full speed PHY */
- val = HCFG_FSLSPCLKSEL_48_MHZ;
- } else {
- /* High speed PHY running at full speed or high speed */
- val = HCFG_FSLSPCLKSEL_30_60_MHZ;
- }
-
- dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
- hcfg = dwc2_readl(hsotg->regs + HCFG);
- hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
- hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT;
- dwc2_writel(hcfg, hsotg->regs + HCFG);
-}
-
/*
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
@@ -619,6 +380,12 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
__func__, hsotg->dr_mode);
break;
}
+
+ /*
+ * NOTE: This is required for some rockchip soc based
+ * platforms.
+ */
+ msleep(50);
}
/*
@@ -640,1644 +407,6 @@ int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
return 0;
}
-static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
-{
- u32 usbcfg, i2cctl;
- int retval = 0;
-
- /*
- * core_init() is now called on every switch so only call the
- * following for the first time through
- */
- if (select_phy) {
- dev_dbg(hsotg->dev, "FS PHY selected\n");
-
- usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- if (!(usbcfg & GUSBCFG_PHYSEL)) {
- usbcfg |= GUSBCFG_PHYSEL;
- dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
-
- /* Reset after a PHY select */
- retval = dwc2_core_reset_and_force_dr_mode(hsotg);
-
- if (retval) {
- dev_err(hsotg->dev,
- "%s: Reset failed, aborting", __func__);
- return retval;
- }
- }
- }
-
- /*
- * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
- * do this on HNP Dev/Host mode switches (done in dev_init and
- * host_init).
- */
- if (dwc2_is_host_mode(hsotg))
- dwc2_init_fs_ls_pclk_sel(hsotg);
-
- if (hsotg->core_params->i2c_enable > 0) {
- dev_dbg(hsotg->dev, "FS PHY enabling I2C\n");
-
- /* Program GUSBCFG.OtgUtmiFsSel to I2C */
- usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL;
- dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
-
- /* Program GI2CCTL.I2CEn */
- i2cctl = dwc2_readl(hsotg->regs + GI2CCTL);
- i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK;
- i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT;
- i2cctl &= ~GI2CCTL_I2CEN;
- dwc2_writel(i2cctl, hsotg->regs + GI2CCTL);
- i2cctl |= GI2CCTL_I2CEN;
- dwc2_writel(i2cctl, hsotg->regs + GI2CCTL);
- }
-
- return retval;
-}
-
-static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
-{
- u32 usbcfg, usbcfg_old;
- int retval = 0;
-
- if (!select_phy)
- return 0;
-
- usbcfg = usbcfg_old = dwc2_readl(hsotg->regs + GUSBCFG);
-
- /*
- * HS PHY parameters. These parameters are preserved during soft reset
- * so only program the first time. Do a soft reset immediately after
- * setting phyif.
- */
- switch (hsotg->core_params->phy_type) {
- case DWC2_PHY_TYPE_PARAM_ULPI:
- /* ULPI interface */
- dev_dbg(hsotg->dev, "HS ULPI PHY selected\n");
- usbcfg |= GUSBCFG_ULPI_UTMI_SEL;
- usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
- if (hsotg->core_params->phy_ulpi_ddr > 0)
- usbcfg |= GUSBCFG_DDRSEL;
- break;
- case DWC2_PHY_TYPE_PARAM_UTMI:
- /* UTMI+ interface */
- dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n");
- usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
- if (hsotg->core_params->phy_utmi_width == 16)
- usbcfg |= GUSBCFG_PHYIF16;
- break;
- default:
- dev_err(hsotg->dev, "FS PHY selected at HS!\n");
- break;
- }
-
- if (usbcfg != usbcfg_old) {
- dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
-
- /* Reset after setting the PHY parameters */
- retval = dwc2_core_reset_and_force_dr_mode(hsotg);
- if (retval) {
- dev_err(hsotg->dev,
- "%s: Reset failed, aborting", __func__);
- return retval;
- }
- }
-
- return retval;
-}
-
-static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
-{
- u32 usbcfg;
- int retval = 0;
-
- if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL &&
- hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
- /* If FS mode with FS PHY */
- retval = dwc2_fs_phy_init(hsotg, select_phy);
- if (retval)
- return retval;
- } else {
- /* High speed PHY */
- retval = dwc2_hs_phy_init(hsotg, select_phy);
- if (retval)
- return retval;
- }
-
- if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
- hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
- hsotg->core_params->ulpi_fs_ls > 0) {
- dev_dbg(hsotg->dev, "Setting ULPI FSLS\n");
- usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- usbcfg |= GUSBCFG_ULPI_FS_LS;
- usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M;
- dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
- } else {
- usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- usbcfg &= ~GUSBCFG_ULPI_FS_LS;
- usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
- dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
- }
-
- return retval;
-}
-
-static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
-{
- u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
-
- switch (hsotg->hw_params.arch) {
- case GHWCFG2_EXT_DMA_ARCH:
- dev_err(hsotg->dev, "External DMA Mode not supported\n");
- return -EINVAL;
-
- case GHWCFG2_INT_DMA_ARCH:
- dev_dbg(hsotg->dev, "Internal DMA Mode\n");
- if (hsotg->core_params->ahbcfg != -1) {
- ahbcfg &= GAHBCFG_CTRL_MASK;
- ahbcfg |= hsotg->core_params->ahbcfg &
- ~GAHBCFG_CTRL_MASK;
- }
- break;
-
- case GHWCFG2_SLAVE_ONLY_ARCH:
- default:
- dev_dbg(hsotg->dev, "Slave Only Mode\n");
- break;
- }
-
- dev_dbg(hsotg->dev, "dma_enable:%d dma_desc_enable:%d\n",
- hsotg->core_params->dma_enable,
- hsotg->core_params->dma_desc_enable);
-
- if (hsotg->core_params->dma_enable > 0) {
- if (hsotg->core_params->dma_desc_enable > 0)
- dev_dbg(hsotg->dev, "Using Descriptor DMA mode\n");
- else
- dev_dbg(hsotg->dev, "Using Buffer DMA mode\n");
- } else {
- dev_dbg(hsotg->dev, "Using Slave mode\n");
- hsotg->core_params->dma_desc_enable = 0;
- }
-
- if (hsotg->core_params->dma_enable > 0)
- ahbcfg |= GAHBCFG_DMA_EN;
-
- dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
-
- return 0;
-}
-
-static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
-{
- u32 usbcfg;
-
- usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
-
- switch (hsotg->hw_params.op_mode) {
- case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
- if (hsotg->core_params->otg_cap ==
- DWC2_CAP_PARAM_HNP_SRP_CAPABLE)
- usbcfg |= GUSBCFG_HNPCAP;
- if (hsotg->core_params->otg_cap !=
- DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
- usbcfg |= GUSBCFG_SRPCAP;
- break;
-
- case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
- case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
- case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
- if (hsotg->core_params->otg_cap !=
- DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
- usbcfg |= GUSBCFG_SRPCAP;
- break;
-
- case GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE:
- case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE:
- case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST:
- default:
- break;
- }
-
- dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
-}
-
-/**
- * dwc2_core_init() - Initializes the DWC_otg controller registers and
- * prepares the core for device mode or host mode operation
- *
- * @hsotg: Programming view of the DWC_otg controller
- * @initial_setup: If true then this is the first init for this instance.
- */
-int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
-{
- u32 usbcfg, otgctl;
- int retval;
-
- dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
-
- usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
-
- /* Set ULPI External VBUS bit if needed */
- usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV;
- if (hsotg->core_params->phy_ulpi_ext_vbus ==
- DWC2_PHY_ULPI_EXTERNAL_VBUS)
- usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV;
-
- /* Set external TS Dline pulsing bit if needed */
- usbcfg &= ~GUSBCFG_TERMSELDLPULSE;
- if (hsotg->core_params->ts_dline > 0)
- usbcfg |= GUSBCFG_TERMSELDLPULSE;
-
- dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
-
- /*
- * Reset the Controller
- *
- * We only need to reset the controller if this is a re-init.
- * For the first init we know for sure that earlier code reset us (it
- * needed to in order to properly detect various parameters).
- */
- if (!initial_setup) {
- retval = dwc2_core_reset_and_force_dr_mode(hsotg);
- if (retval) {
- dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
- __func__);
- return retval;
- }
- }
-
- /*
- * This needs to happen in FS mode before any other programming occurs
- */
- retval = dwc2_phy_init(hsotg, initial_setup);
- if (retval)
- return retval;
-
- /* Program the GAHBCFG Register */
- retval = dwc2_gahbcfg_init(hsotg);
- if (retval)
- return retval;
-
- /* Program the GUSBCFG register */
- dwc2_gusbcfg_init(hsotg);
-
- /* Program the GOTGCTL register */
- otgctl = dwc2_readl(hsotg->regs + GOTGCTL);
- otgctl &= ~GOTGCTL_OTGVER;
- if (hsotg->core_params->otg_ver > 0)
- otgctl |= GOTGCTL_OTGVER;
- dwc2_writel(otgctl, hsotg->regs + GOTGCTL);
- dev_dbg(hsotg->dev, "OTG VER PARAM: %d\n", hsotg->core_params->otg_ver);
-
- /* Clear the SRP success bit for FS-I2c */
- hsotg->srp_success = 0;
-
- /* Enable common interrupts */
- dwc2_enable_common_interrupts(hsotg);
-
- /*
- * Do device or host initialization based on mode during PCD and
- * HCD initialization
- */
- if (dwc2_is_host_mode(hsotg)) {
- dev_dbg(hsotg->dev, "Host Mode\n");
- hsotg->op_state = OTG_STATE_A_HOST;
- } else {
- dev_dbg(hsotg->dev, "Device Mode\n");
- hsotg->op_state = OTG_STATE_B_PERIPHERAL;
- }
-
- return 0;
-}
-
-/**
- * dwc2_enable_host_interrupts() - Enables the Host mode interrupts
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg)
-{
- u32 intmsk;
-
- dev_dbg(hsotg->dev, "%s()\n", __func__);
-
- /* Disable all interrupts */
- dwc2_writel(0, hsotg->regs + GINTMSK);
- dwc2_writel(0, hsotg->regs + HAINTMSK);
-
- /* Enable the common interrupts */
- dwc2_enable_common_interrupts(hsotg);
-
- /* Enable host mode interrupts without disturbing common interrupts */
- intmsk = dwc2_readl(hsotg->regs + GINTMSK);
- intmsk |= GINTSTS_DISCONNINT | GINTSTS_PRTINT | GINTSTS_HCHINT;
- dwc2_writel(intmsk, hsotg->regs + GINTMSK);
-}
-
-/**
- * dwc2_disable_host_interrupts() - Disables the Host Mode interrupts
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg)
-{
- u32 intmsk = dwc2_readl(hsotg->regs + GINTMSK);
-
- /* Disable host mode interrupts without disturbing common interrupts */
- intmsk &= ~(GINTSTS_SOF | GINTSTS_PRTINT | GINTSTS_HCHINT |
- GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP | GINTSTS_DISCONNINT);
- dwc2_writel(intmsk, hsotg->regs + GINTMSK);
-}
-
-/*
- * dwc2_calculate_dynamic_fifo() - Calculates the default fifo size
- * For system that have a total fifo depth that is smaller than the default
- * RX + TX fifo size.
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-static void dwc2_calculate_dynamic_fifo(struct dwc2_hsotg *hsotg)
-{
- struct dwc2_core_params *params = hsotg->core_params;
- struct dwc2_hw_params *hw = &hsotg->hw_params;
- u32 rxfsiz, nptxfsiz, ptxfsiz, total_fifo_size;
-
- total_fifo_size = hw->total_fifo_size;
- rxfsiz = params->host_rx_fifo_size;
- nptxfsiz = params->host_nperio_tx_fifo_size;
- ptxfsiz = params->host_perio_tx_fifo_size;
-
- /*
- * Will use Method 2 defined in the DWC2 spec: minimum FIFO depth
- * allocation with support for high bandwidth endpoints. Synopsys
- * defines MPS(Max Packet size) for a periodic EP=1024, and for
- * non-periodic as 512.
- */
- if (total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)) {
- /*
- * For Buffer DMA mode/Scatter Gather DMA mode
- * 2 * ((Largest Packet size / 4) + 1 + 1) + n
- * with n = number of host channel.
- * 2 * ((1024/4) + 2) = 516
- */
- rxfsiz = 516 + hw->host_channels;
-
- /*
- * min non-periodic tx fifo depth
- * 2 * (largest non-periodic USB packet used / 4)
- * 2 * (512/4) = 256
- */
- nptxfsiz = 256;
-
- /*
- * min periodic tx fifo depth
- * (largest packet size*MC)/4
- * (1024 * 3)/4 = 768
- */
- ptxfsiz = 768;
-
- params->host_rx_fifo_size = rxfsiz;
- params->host_nperio_tx_fifo_size = nptxfsiz;
- params->host_perio_tx_fifo_size = ptxfsiz;
- }
-
- /*
- * If the summation of RX, NPTX and PTX fifo sizes is still
- * bigger than the total_fifo_size, then we have a problem.
- *
- * We won't be able to allocate as many endpoints. Right now,
- * we're just printing an error message, but ideally this FIFO
- * allocation algorithm would be improved in the future.
- *
- * FIXME improve this FIFO allocation algorithm.
- */
- if (unlikely(total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)))
- dev_err(hsotg->dev, "invalid fifo sizes\n");
-}
-
-static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
-{
- struct dwc2_core_params *params = hsotg->core_params;
- u32 nptxfsiz, hptxfsiz, dfifocfg, grxfsiz;
-
- if (!params->enable_dynamic_fifo)
- return;
-
- dwc2_calculate_dynamic_fifo(hsotg);
-
- /* Rx FIFO */
- grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
- dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz);
- grxfsiz &= ~GRXFSIZ_DEPTH_MASK;
- grxfsiz |= params->host_rx_fifo_size <<
- GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
- dwc2_writel(grxfsiz, hsotg->regs + GRXFSIZ);
- dev_dbg(hsotg->dev, "new grxfsiz=%08x\n",
- dwc2_readl(hsotg->regs + GRXFSIZ));
-
- /* Non-periodic Tx FIFO */
- dev_dbg(hsotg->dev, "initial gnptxfsiz=%08x\n",
- dwc2_readl(hsotg->regs + GNPTXFSIZ));
- nptxfsiz = params->host_nperio_tx_fifo_size <<
- FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
- nptxfsiz |= params->host_rx_fifo_size <<
- FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
- dwc2_writel(nptxfsiz, hsotg->regs + GNPTXFSIZ);
- dev_dbg(hsotg->dev, "new gnptxfsiz=%08x\n",
- dwc2_readl(hsotg->regs + GNPTXFSIZ));
-
- /* Periodic Tx FIFO */
- dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n",
- dwc2_readl(hsotg->regs + HPTXFSIZ));
- hptxfsiz = params->host_perio_tx_fifo_size <<
- FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
- hptxfsiz |= (params->host_rx_fifo_size +
- params->host_nperio_tx_fifo_size) <<
- FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
- dwc2_writel(hptxfsiz, hsotg->regs + HPTXFSIZ);
- dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n",
- dwc2_readl(hsotg->regs + HPTXFSIZ));
-
- if (hsotg->core_params->en_multiple_tx_fifo > 0 &&
- hsotg->hw_params.snpsid <= DWC2_CORE_REV_2_94a) {
- /*
- * Global DFIFOCFG calculation for Host mode -
- * include RxFIFO, NPTXFIFO and HPTXFIFO
- */
- dfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG);
- dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
- dfifocfg |= (params->host_rx_fifo_size +
- params->host_nperio_tx_fifo_size +
- params->host_perio_tx_fifo_size) <<
- GDFIFOCFG_EPINFOBASE_SHIFT &
- GDFIFOCFG_EPINFOBASE_MASK;
- dwc2_writel(dfifocfg, hsotg->regs + GDFIFOCFG);
- }
-}
-
-/**
- * dwc2_core_host_init() - Initializes the DWC_otg controller registers for
- * Host mode
- *
- * @hsotg: Programming view of DWC_otg controller
- *
- * This function flushes the Tx and Rx FIFOs and flushes any entries in the
- * request queues. Host channels are reset to ensure that they are ready for
- * performing transfers.
- */
-void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
-{
- u32 hcfg, hfir, otgctl;
-
- dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
-
- /* Restart the Phy Clock */
- dwc2_writel(0, hsotg->regs + PCGCTL);
-
- /* Initialize Host Configuration Register */
- dwc2_init_fs_ls_pclk_sel(hsotg);
- if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL) {
- hcfg = dwc2_readl(hsotg->regs + HCFG);
- hcfg |= HCFG_FSLSSUPP;
- dwc2_writel(hcfg, hsotg->regs + HCFG);
- }
-
- /*
- * This bit allows dynamic reloading of the HFIR register during
- * runtime. This bit needs to be programmed during initial configuration
- * and its value must not be changed during runtime.
- */
- if (hsotg->core_params->reload_ctl > 0) {
- hfir = dwc2_readl(hsotg->regs + HFIR);
- hfir |= HFIR_RLDCTRL;
- dwc2_writel(hfir, hsotg->regs + HFIR);
- }
-
- if (hsotg->core_params->dma_desc_enable > 0) {
- u32 op_mode = hsotg->hw_params.op_mode;
- if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a ||
- !hsotg->hw_params.dma_desc_enable ||
- op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE ||
- op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE ||
- op_mode == GHWCFG2_OP_MODE_UNDEFINED) {
- dev_err(hsotg->dev,
- "Hardware does not support descriptor DMA mode -\n");
- dev_err(hsotg->dev,
- "falling back to buffer DMA mode.\n");
- hsotg->core_params->dma_desc_enable = 0;
- } else {
- hcfg = dwc2_readl(hsotg->regs + HCFG);
- hcfg |= HCFG_DESCDMA;
- dwc2_writel(hcfg, hsotg->regs + HCFG);
- }
- }
-
- /* Configure data FIFO sizes */
- dwc2_config_fifos(hsotg);
-
- /* TODO - check this */
- /* Clear Host Set HNP Enable in the OTG Control Register */
- otgctl = dwc2_readl(hsotg->regs + GOTGCTL);
- otgctl &= ~GOTGCTL_HSTSETHNPEN;
- dwc2_writel(otgctl, hsotg->regs + GOTGCTL);
-
- /* Make sure the FIFOs are flushed */
- dwc2_flush_tx_fifo(hsotg, 0x10 /* all TX FIFOs */);
- dwc2_flush_rx_fifo(hsotg);
-
- /* Clear Host Set HNP Enable in the OTG Control Register */
- otgctl = dwc2_readl(hsotg->regs + GOTGCTL);
- otgctl &= ~GOTGCTL_HSTSETHNPEN;
- dwc2_writel(otgctl, hsotg->regs + GOTGCTL);
-
- if (hsotg->core_params->dma_desc_enable <= 0) {
- int num_channels, i;
- u32 hcchar;
-
- /* Flush out any leftover queued requests */
- num_channels = hsotg->core_params->host_channels;
- for (i = 0; i < num_channels; i++) {
- hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
- hcchar &= ~HCCHAR_CHENA;
- hcchar |= HCCHAR_CHDIS;
- hcchar &= ~HCCHAR_EPDIR;
- dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
- }
-
- /* Halt all channels to put them into a known state */
- for (i = 0; i < num_channels; i++) {
- int count = 0;
-
- hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
- hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS;
- hcchar &= ~HCCHAR_EPDIR;
- dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
- dev_dbg(hsotg->dev, "%s: Halt channel %d\n",
- __func__, i);
- do {
- hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
- if (++count > 1000) {
- dev_err(hsotg->dev,
- "Unable to clear enable on channel %d\n",
- i);
- break;
- }
- udelay(1);
- } while (hcchar & HCCHAR_CHENA);
- }
- }
-
- /* Turn on the vbus power */
- dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state);
- if (hsotg->op_state == OTG_STATE_A_HOST) {
- u32 hprt0 = dwc2_read_hprt0(hsotg);
-
- dev_dbg(hsotg->dev, "Init: Power Port (%d)\n",
- !!(hprt0 & HPRT0_PWR));
- if (!(hprt0 & HPRT0_PWR)) {
- hprt0 |= HPRT0_PWR;
- dwc2_writel(hprt0, hsotg->regs + HPRT0);
- }
- }
-
- dwc2_enable_host_interrupts(hsotg);
-}
-
-static void dwc2_hc_enable_slave_ints(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan)
-{
- u32 hcintmsk = HCINTMSK_CHHLTD;
-
- switch (chan->ep_type) {
- case USB_ENDPOINT_XFER_CONTROL:
- case USB_ENDPOINT_XFER_BULK:
- dev_vdbg(hsotg->dev, "control/bulk\n");
- hcintmsk |= HCINTMSK_XFERCOMPL;
- hcintmsk |= HCINTMSK_STALL;
- hcintmsk |= HCINTMSK_XACTERR;
- hcintmsk |= HCINTMSK_DATATGLERR;
- if (chan->ep_is_in) {
- hcintmsk |= HCINTMSK_BBLERR;
- } else {
- hcintmsk |= HCINTMSK_NAK;
- hcintmsk |= HCINTMSK_NYET;
- if (chan->do_ping)
- hcintmsk |= HCINTMSK_ACK;
- }
-
- if (chan->do_split) {
- hcintmsk |= HCINTMSK_NAK;
- if (chan->complete_split)
- hcintmsk |= HCINTMSK_NYET;
- else
- hcintmsk |= HCINTMSK_ACK;
- }
-
- if (chan->error_state)
- hcintmsk |= HCINTMSK_ACK;
- break;
-
- case USB_ENDPOINT_XFER_INT:
- if (dbg_perio())
- dev_vdbg(hsotg->dev, "intr\n");
- hcintmsk |= HCINTMSK_XFERCOMPL;
- hcintmsk |= HCINTMSK_NAK;
- hcintmsk |= HCINTMSK_STALL;
- hcintmsk |= HCINTMSK_XACTERR;
- hcintmsk |= HCINTMSK_DATATGLERR;
- hcintmsk |= HCINTMSK_FRMOVRUN;
-
- if (chan->ep_is_in)
- hcintmsk |= HCINTMSK_BBLERR;
- if (chan->error_state)
- hcintmsk |= HCINTMSK_ACK;
- if (chan->do_split) {
- if (chan->complete_split)
- hcintmsk |= HCINTMSK_NYET;
- else
- hcintmsk |= HCINTMSK_ACK;
- }
- break;
-
- case USB_ENDPOINT_XFER_ISOC:
- if (dbg_perio())
- dev_vdbg(hsotg->dev, "isoc\n");
- hcintmsk |= HCINTMSK_XFERCOMPL;
- hcintmsk |= HCINTMSK_FRMOVRUN;
- hcintmsk |= HCINTMSK_ACK;
-
- if (chan->ep_is_in) {
- hcintmsk |= HCINTMSK_XACTERR;
- hcintmsk |= HCINTMSK_BBLERR;
- }
- break;
- default:
- dev_err(hsotg->dev, "## Unknown EP type ##\n");
- break;
- }
-
- dwc2_writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
-}
-
-static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan)
-{
- u32 hcintmsk = HCINTMSK_CHHLTD;
-
- /*
- * For Descriptor DMA mode core halts the channel on AHB error.
- * Interrupt is not required.
- */
- if (hsotg->core_params->dma_desc_enable <= 0) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "desc DMA disabled\n");
- hcintmsk |= HCINTMSK_AHBERR;
- } else {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "desc DMA enabled\n");
- if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
- hcintmsk |= HCINTMSK_XFERCOMPL;
- }
-
- if (chan->error_state && !chan->do_split &&
- chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "setting ACK\n");
- hcintmsk |= HCINTMSK_ACK;
- if (chan->ep_is_in) {
- hcintmsk |= HCINTMSK_DATATGLERR;
- if (chan->ep_type != USB_ENDPOINT_XFER_INT)
- hcintmsk |= HCINTMSK_NAK;
- }
- }
-
- dwc2_writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
-}
-
-static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan)
-{
- u32 intmsk;
-
- if (hsotg->core_params->dma_enable > 0) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "DMA enabled\n");
- dwc2_hc_enable_dma_ints(hsotg, chan);
- } else {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "DMA disabled\n");
- dwc2_hc_enable_slave_ints(hsotg, chan);
- }
-
- /* Enable the top level host channel interrupt */
- intmsk = dwc2_readl(hsotg->regs + HAINTMSK);
- intmsk |= 1 << chan->hc_num;
- dwc2_writel(intmsk, hsotg->regs + HAINTMSK);
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "set HAINTMSK to %08x\n", intmsk);
-
- /* Make sure host channel interrupts are enabled */
- intmsk = dwc2_readl(hsotg->regs + GINTMSK);
- intmsk |= GINTSTS_HCHINT;
- dwc2_writel(intmsk, hsotg->regs + GINTMSK);
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "set GINTMSK to %08x\n", intmsk);
-}
-
-/**
- * dwc2_hc_init() - Prepares a host channel for transferring packets to/from
- * a specific endpoint
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan: Information needed to initialize the host channel
- *
- * The HCCHARn register is set up with the characteristics specified in chan.
- * Host channel interrupts that may need to be serviced while this transfer is
- * in progress are enabled.
- */
-void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
-{
- u8 hc_num = chan->hc_num;
- u32 hcintmsk;
- u32 hcchar;
- u32 hcsplt = 0;
-
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
- /* Clear old interrupt conditions for this host channel */
- hcintmsk = 0xffffffff;
- hcintmsk &= ~HCINTMSK_RESERVED14_31;
- dwc2_writel(hcintmsk, hsotg->regs + HCINT(hc_num));
-
- /* Enable channel interrupts required for this transfer */
- dwc2_hc_enable_ints(hsotg, chan);
-
- /*
- * Program the HCCHARn register with the endpoint characteristics for
- * the current transfer
- */
- hcchar = chan->dev_addr << HCCHAR_DEVADDR_SHIFT & HCCHAR_DEVADDR_MASK;
- hcchar |= chan->ep_num << HCCHAR_EPNUM_SHIFT & HCCHAR_EPNUM_MASK;
- if (chan->ep_is_in)
- hcchar |= HCCHAR_EPDIR;
- if (chan->speed == USB_SPEED_LOW)
- hcchar |= HCCHAR_LSPDDEV;
- hcchar |= chan->ep_type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK;
- hcchar |= chan->max_packet << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK;
- dwc2_writel(hcchar, hsotg->regs + HCCHAR(hc_num));
- if (dbg_hc(chan)) {
- dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n",
- hc_num, hcchar);
-
- dev_vdbg(hsotg->dev, "%s: Channel %d\n",
- __func__, hc_num);
- dev_vdbg(hsotg->dev, " Dev Addr: %d\n",
- chan->dev_addr);
- dev_vdbg(hsotg->dev, " Ep Num: %d\n",
- chan->ep_num);
- dev_vdbg(hsotg->dev, " Is In: %d\n",
- chan->ep_is_in);
- dev_vdbg(hsotg->dev, " Is Low Speed: %d\n",
- chan->speed == USB_SPEED_LOW);
- dev_vdbg(hsotg->dev, " Ep Type: %d\n",
- chan->ep_type);
- dev_vdbg(hsotg->dev, " Max Pkt: %d\n",
- chan->max_packet);
- }
-
- /* Program the HCSPLT register for SPLITs */
- if (chan->do_split) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev,
- "Programming HC %d with split --> %s\n",
- hc_num,
- chan->complete_split ? "CSPLIT" : "SSPLIT");
- if (chan->complete_split)
- hcsplt |= HCSPLT_COMPSPLT;
- hcsplt |= chan->xact_pos << HCSPLT_XACTPOS_SHIFT &
- HCSPLT_XACTPOS_MASK;
- hcsplt |= chan->hub_addr << HCSPLT_HUBADDR_SHIFT &
- HCSPLT_HUBADDR_MASK;
- hcsplt |= chan->hub_port << HCSPLT_PRTADDR_SHIFT &
- HCSPLT_PRTADDR_MASK;
- if (dbg_hc(chan)) {
- dev_vdbg(hsotg->dev, " comp split %d\n",
- chan->complete_split);
- dev_vdbg(hsotg->dev, " xact pos %d\n",
- chan->xact_pos);
- dev_vdbg(hsotg->dev, " hub addr %d\n",
- chan->hub_addr);
- dev_vdbg(hsotg->dev, " hub port %d\n",
- chan->hub_port);
- dev_vdbg(hsotg->dev, " is_in %d\n",
- chan->ep_is_in);
- dev_vdbg(hsotg->dev, " Max Pkt %d\n",
- chan->max_packet);
- dev_vdbg(hsotg->dev, " xferlen %d\n",
- chan->xfer_len);
- }
- }
-
- dwc2_writel(hcsplt, hsotg->regs + HCSPLT(hc_num));
-}
-
-/**
- * dwc2_hc_halt() - Attempts to halt a host channel
- *
- * @hsotg: Controller register interface
- * @chan: Host channel to halt
- * @halt_status: Reason for halting the channel
- *
- * This function should only be called in Slave mode or to abort a transfer in
- * either Slave mode or DMA mode. Under normal circumstances in DMA mode, the
- * controller halts the channel when the transfer is complete or a condition
- * occurs that requires application intervention.
- *
- * In slave mode, checks for a free request queue entry, then sets the Channel
- * Enable and Channel Disable bits of the Host Channel Characteristics
- * register of the specified channel to intiate the halt. If there is no free
- * request queue entry, sets only the Channel Disable bit of the HCCHARn
- * register to flush requests for this channel. In the latter case, sets a
- * flag to indicate that the host channel needs to be halted when a request
- * queue slot is open.
- *
- * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
- * HCCHARn register. The controller ensures there is space in the request
- * queue before submitting the halt request.
- *
- * Some time may elapse before the core flushes any posted requests for this
- * host channel and halts. The Channel Halted interrupt handler completes the
- * deactivation of the host channel.
- */
-void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
- enum dwc2_halt_status halt_status)
-{
- u32 nptxsts, hptxsts, hcchar;
-
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "%s()\n", __func__);
- if (halt_status == DWC2_HC_XFER_NO_HALT_STATUS)
- dev_err(hsotg->dev, "!!! halt_status = %d !!!\n", halt_status);
-
- if (halt_status == DWC2_HC_XFER_URB_DEQUEUE ||
- halt_status == DWC2_HC_XFER_AHB_ERR) {
- /*
- * Disable all channel interrupts except Ch Halted. The QTD
- * and QH state associated with this transfer has been cleared
- * (in the case of URB_DEQUEUE), so the channel needs to be
- * shut down carefully to prevent crashes.
- */
- u32 hcintmsk = HCINTMSK_CHHLTD;
-
- dev_vdbg(hsotg->dev, "dequeue/error\n");
- dwc2_writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
-
- /*
- * Make sure no other interrupts besides halt are currently
- * pending. Handling another interrupt could cause a crash due
- * to the QTD and QH state.
- */
- dwc2_writel(~hcintmsk, hsotg->regs + HCINT(chan->hc_num));
-
- /*
- * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
- * even if the channel was already halted for some other
- * reason
- */
- chan->halt_status = halt_status;
-
- hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
- if (!(hcchar & HCCHAR_CHENA)) {
- /*
- * The channel is either already halted or it hasn't
- * started yet. In DMA mode, the transfer may halt if
- * it finishes normally or a condition occurs that
- * requires driver intervention. Don't want to halt
- * the channel again. In either Slave or DMA mode,
- * it's possible that the transfer has been assigned
- * to a channel, but not started yet when an URB is
- * dequeued. Don't want to halt a channel that hasn't
- * started yet.
- */
- return;
- }
- }
- if (chan->halt_pending) {
- /*
- * A halt has already been issued for this channel. This might
- * happen when a transfer is aborted by a higher level in
- * the stack.
- */
- dev_vdbg(hsotg->dev,
- "*** %s: Channel %d, chan->halt_pending already set ***\n",
- __func__, chan->hc_num);
- return;
- }
-
- hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
-
- /* No need to set the bit in DDMA for disabling the channel */
- /* TODO check it everywhere channel is disabled */
- if (hsotg->core_params->dma_desc_enable <= 0) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "desc DMA disabled\n");
- hcchar |= HCCHAR_CHENA;
- } else {
- if (dbg_hc(chan))
- dev_dbg(hsotg->dev, "desc DMA enabled\n");
- }
- hcchar |= HCCHAR_CHDIS;
-
- if (hsotg->core_params->dma_enable <= 0) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "DMA not enabled\n");
- hcchar |= HCCHAR_CHENA;
-
- /* Check for space in the request queue to issue the halt */
- if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
- chan->ep_type == USB_ENDPOINT_XFER_BULK) {
- dev_vdbg(hsotg->dev, "control/bulk\n");
- nptxsts = dwc2_readl(hsotg->regs + GNPTXSTS);
- if ((nptxsts & TXSTS_QSPCAVAIL_MASK) == 0) {
- dev_vdbg(hsotg->dev, "Disabling channel\n");
- hcchar &= ~HCCHAR_CHENA;
- }
- } else {
- if (dbg_perio())
- dev_vdbg(hsotg->dev, "isoc/intr\n");
- hptxsts = dwc2_readl(hsotg->regs + HPTXSTS);
- if ((hptxsts & TXSTS_QSPCAVAIL_MASK) == 0 ||
- hsotg->queuing_high_bandwidth) {
- if (dbg_perio())
- dev_vdbg(hsotg->dev, "Disabling channel\n");
- hcchar &= ~HCCHAR_CHENA;
- }
- }
- } else {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "DMA enabled\n");
- }
-
- dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
- chan->halt_status = halt_status;
-
- if (hcchar & HCCHAR_CHENA) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "Channel enabled\n");
- chan->halt_pending = 1;
- chan->halt_on_queue = 0;
- } else {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "Channel disabled\n");
- chan->halt_on_queue = 1;
- }
-
- if (dbg_hc(chan)) {
- dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
- chan->hc_num);
- dev_vdbg(hsotg->dev, " hcchar: 0x%08x\n",
- hcchar);
- dev_vdbg(hsotg->dev, " halt_pending: %d\n",
- chan->halt_pending);
- dev_vdbg(hsotg->dev, " halt_on_queue: %d\n",
- chan->halt_on_queue);
- dev_vdbg(hsotg->dev, " halt_status: %d\n",
- chan->halt_status);
- }
-}
-
-/**
- * dwc2_hc_cleanup() - Clears the transfer state for a host channel
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan: Identifies the host channel to clean up
- *
- * This function is normally called after a transfer is done and the host
- * channel is being released
- */
-void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
-{
- u32 hcintmsk;
-
- chan->xfer_started = 0;
-
- /*
- * Clear channel interrupt enables and any unhandled channel interrupt
- * conditions
- */
- dwc2_writel(0, hsotg->regs + HCINTMSK(chan->hc_num));
- hcintmsk = 0xffffffff;
- hcintmsk &= ~HCINTMSK_RESERVED14_31;
- dwc2_writel(hcintmsk, hsotg->regs + HCINT(chan->hc_num));
-}
-
-/**
- * dwc2_hc_set_even_odd_frame() - Sets the channel property that indicates in
- * which frame a periodic transfer should occur
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan: Identifies the host channel to set up and its properties
- * @hcchar: Current value of the HCCHAR register for the specified host channel
- *
- * This function has no effect on non-periodic transfers
- */
-static void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan, u32 *hcchar)
-{
- if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
- chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
- /* 1 if _next_ frame is odd, 0 if it's even */
- if (!(dwc2_hcd_get_frame_number(hsotg) & 0x1))
- *hcchar |= HCCHAR_ODDFRM;
- }
-}
-
-static void dwc2_set_pid_isoc(struct dwc2_host_chan *chan)
-{
- /* Set up the initial PID for the transfer */
- if (chan->speed == USB_SPEED_HIGH) {
- if (chan->ep_is_in) {
- if (chan->multi_count == 1)
- chan->data_pid_start = DWC2_HC_PID_DATA0;
- else if (chan->multi_count == 2)
- chan->data_pid_start = DWC2_HC_PID_DATA1;
- else
- chan->data_pid_start = DWC2_HC_PID_DATA2;
- } else {
- if (chan->multi_count == 1)
- chan->data_pid_start = DWC2_HC_PID_DATA0;
- else
- chan->data_pid_start = DWC2_HC_PID_MDATA;
- }
- } else {
- chan->data_pid_start = DWC2_HC_PID_DATA0;
- }
-}
-
-/**
- * dwc2_hc_write_packet() - Writes a packet into the Tx FIFO associated with
- * the Host Channel
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan: Information needed to initialize the host channel
- *
- * This function should only be called in Slave mode. For a channel associated
- * with a non-periodic EP, the non-periodic Tx FIFO is written. For a channel
- * associated with a periodic EP, the periodic Tx FIFO is written.
- *
- * Upon return the xfer_buf and xfer_count fields in chan are incremented by
- * the number of bytes written to the Tx FIFO.
- */
-static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan)
-{
- u32 i;
- u32 remaining_count;
- u32 byte_count;
- u32 dword_count;
- u32 __iomem *data_fifo;
- u32 *data_buf = (u32 *)chan->xfer_buf;
-
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
- data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num));
-
- remaining_count = chan->xfer_len - chan->xfer_count;
- if (remaining_count > chan->max_packet)
- byte_count = chan->max_packet;
- else
- byte_count = remaining_count;
-
- dword_count = (byte_count + 3) / 4;
-
- if (((unsigned long)data_buf & 0x3) == 0) {
- /* xfer_buf is DWORD aligned */
- for (i = 0; i < dword_count; i++, data_buf++)
- dwc2_writel(*data_buf, data_fifo);
- } else {
- /* xfer_buf is not DWORD aligned */
- for (i = 0; i < dword_count; i++, data_buf++) {
- u32 data = data_buf[0] | data_buf[1] << 8 |
- data_buf[2] << 16 | data_buf[3] << 24;
- dwc2_writel(data, data_fifo);
- }
- }
-
- chan->xfer_count += byte_count;
- chan->xfer_buf += byte_count;
-}
-
-/**
- * dwc2_hc_start_transfer() - Does the setup for a data transfer for a host
- * channel and starts the transfer
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan: Information needed to initialize the host channel. The xfer_len value
- * may be reduced to accommodate the max widths of the XferSize and
- * PktCnt fields in the HCTSIZn register. The multi_count value may be
- * changed to reflect the final xfer_len value.
- *
- * This function may be called in either Slave mode or DMA mode. In Slave mode,
- * the caller must ensure that there is sufficient space in the request queue
- * and Tx Data FIFO.
- *
- * For an OUT transfer in Slave mode, it loads a data packet into the
- * appropriate FIFO. If necessary, additional data packets are loaded in the
- * Host ISR.
- *
- * For an IN transfer in Slave mode, a data packet is requested. The data
- * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
- * additional data packets are requested in the Host ISR.
- *
- * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
- * register along with a packet count of 1 and the channel is enabled. This
- * causes a single PING transaction to occur. Other fields in HCTSIZ are
- * simply set to 0 since no data transfer occurs in this case.
- *
- * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
- * all the information required to perform the subsequent data transfer. In
- * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
- * controller performs the entire PING protocol, then starts the data
- * transfer.
- */
-void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan)
-{
- u32 max_hc_xfer_size = hsotg->core_params->max_transfer_size;
- u16 max_hc_pkt_count = hsotg->core_params->max_packet_count;
- u32 hcchar;
- u32 hctsiz = 0;
- u16 num_packets;
- u32 ec_mc;
-
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
- if (chan->do_ping) {
- if (hsotg->core_params->dma_enable <= 0) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "ping, no DMA\n");
- dwc2_hc_do_ping(hsotg, chan);
- chan->xfer_started = 1;
- return;
- } else {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "ping, DMA\n");
- hctsiz |= TSIZ_DOPNG;
- }
- }
-
- if (chan->do_split) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "split\n");
- num_packets = 1;
-
- if (chan->complete_split && !chan->ep_is_in)
- /*
- * For CSPLIT OUT Transfer, set the size to 0 so the
- * core doesn't expect any data written to the FIFO
- */
- chan->xfer_len = 0;
- else if (chan->ep_is_in || chan->xfer_len > chan->max_packet)
- chan->xfer_len = chan->max_packet;
- else if (!chan->ep_is_in && chan->xfer_len > 188)
- chan->xfer_len = 188;
-
- hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
- TSIZ_XFERSIZE_MASK;
-
- /* For split set ec_mc for immediate retries */
- if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
- chan->ep_type == USB_ENDPOINT_XFER_ISOC)
- ec_mc = 3;
- else
- ec_mc = 1;
- } else {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "no split\n");
- /*
- * Ensure that the transfer length and packet count will fit
- * in the widths allocated for them in the HCTSIZn register
- */
- if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
- chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
- /*
- * Make sure the transfer size is no larger than one
- * (micro)frame's worth of data. (A check was done
- * when the periodic transfer was accepted to ensure
- * that a (micro)frame's worth of data can be
- * programmed into a channel.)
- */
- u32 max_periodic_len =
- chan->multi_count * chan->max_packet;
-
- if (chan->xfer_len > max_periodic_len)
- chan->xfer_len = max_periodic_len;
- } else if (chan->xfer_len > max_hc_xfer_size) {
- /*
- * Make sure that xfer_len is a multiple of max packet
- * size
- */
- chan->xfer_len =
- max_hc_xfer_size - chan->max_packet + 1;
- }
-
- if (chan->xfer_len > 0) {
- num_packets = (chan->xfer_len + chan->max_packet - 1) /
- chan->max_packet;
- if (num_packets > max_hc_pkt_count) {
- num_packets = max_hc_pkt_count;
- chan->xfer_len = num_packets * chan->max_packet;
- }
- } else {
- /* Need 1 packet for transfer length of 0 */
- num_packets = 1;
- }
-
- if (chan->ep_is_in)
- /*
- * Always program an integral # of max packets for IN
- * transfers
- */
- chan->xfer_len = num_packets * chan->max_packet;
-
- if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
- chan->ep_type == USB_ENDPOINT_XFER_ISOC)
- /*
- * Make sure that the multi_count field matches the
- * actual transfer length
- */
- chan->multi_count = num_packets;
-
- if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
- dwc2_set_pid_isoc(chan);
-
- hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
- TSIZ_XFERSIZE_MASK;
-
- /* The ec_mc gets the multi_count for non-split */
- ec_mc = chan->multi_count;
- }
-
- chan->start_pkt_count = num_packets;
- hctsiz |= num_packets << TSIZ_PKTCNT_SHIFT & TSIZ_PKTCNT_MASK;
- hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
- TSIZ_SC_MC_PID_MASK;
- dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
- if (dbg_hc(chan)) {
- dev_vdbg(hsotg->dev, "Wrote %08x to HCTSIZ(%d)\n",
- hctsiz, chan->hc_num);
-
- dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
- chan->hc_num);
- dev_vdbg(hsotg->dev, " Xfer Size: %d\n",
- (hctsiz & TSIZ_XFERSIZE_MASK) >>
- TSIZ_XFERSIZE_SHIFT);
- dev_vdbg(hsotg->dev, " Num Pkts: %d\n",
- (hctsiz & TSIZ_PKTCNT_MASK) >>
- TSIZ_PKTCNT_SHIFT);
- dev_vdbg(hsotg->dev, " Start PID: %d\n",
- (hctsiz & TSIZ_SC_MC_PID_MASK) >>
- TSIZ_SC_MC_PID_SHIFT);
- }
-
- if (hsotg->core_params->dma_enable > 0) {
- dma_addr_t dma_addr;
-
- if (chan->align_buf) {
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "align_buf\n");
- dma_addr = chan->align_buf;
- } else {
- dma_addr = chan->xfer_dma;
- }
- dwc2_writel((u32)dma_addr, hsotg->regs + HCDMA(chan->hc_num));
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n",
- (unsigned long)dma_addr, chan->hc_num);
- }
-
- /* Start the split */
- if (chan->do_split) {
- u32 hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chan->hc_num));
-
- hcsplt |= HCSPLT_SPLTENA;
- dwc2_writel(hcsplt, hsotg->regs + HCSPLT(chan->hc_num));
- }
-
- hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
- hcchar &= ~HCCHAR_MULTICNT_MASK;
- hcchar |= (ec_mc << HCCHAR_MULTICNT_SHIFT) & HCCHAR_MULTICNT_MASK;
- dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
-
- if (hcchar & HCCHAR_CHDIS)
- dev_warn(hsotg->dev,
- "%s: chdis set, channel %d, hcchar 0x%08x\n",
- __func__, chan->hc_num, hcchar);
-
- /* Set host channel enable after all other setup is complete */
- hcchar |= HCCHAR_CHENA;
- hcchar &= ~HCCHAR_CHDIS;
-
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
- (hcchar & HCCHAR_MULTICNT_MASK) >>
- HCCHAR_MULTICNT_SHIFT);
-
- dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
- chan->hc_num);
-
- chan->xfer_started = 1;
- chan->requests++;
-
- if (hsotg->core_params->dma_enable <= 0 &&
- !chan->ep_is_in && chan->xfer_len > 0)
- /* Load OUT packet into the appropriate Tx FIFO */
- dwc2_hc_write_packet(hsotg, chan);
-}
-
-/**
- * dwc2_hc_start_transfer_ddma() - Does the setup for a data transfer for a
- * host channel and starts the transfer in Descriptor DMA mode
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan: Information needed to initialize the host channel
- *
- * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
- * Sets PID and NTD values. For periodic transfers initializes SCHED_INFO field
- * with micro-frame bitmap.
- *
- * Initializes HCDMA register with descriptor list address and CTD value then
- * starts the transfer via enabling the channel.
- */
-void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan)
-{
- u32 hcchar;
- u32 hctsiz = 0;
-
- if (chan->do_ping)
- hctsiz |= TSIZ_DOPNG;
-
- if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
- dwc2_set_pid_isoc(chan);
-
- /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
- hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
- TSIZ_SC_MC_PID_MASK;
-
- /* 0 - 1 descriptor, 1 - 2 descriptors, etc */
- hctsiz |= (chan->ntd - 1) << TSIZ_NTD_SHIFT & TSIZ_NTD_MASK;
-
- /* Non-zero only for high-speed interrupt endpoints */
- hctsiz |= chan->schinfo << TSIZ_SCHINFO_SHIFT & TSIZ_SCHINFO_MASK;
-
- if (dbg_hc(chan)) {
- dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
- chan->hc_num);
- dev_vdbg(hsotg->dev, " Start PID: %d\n",
- chan->data_pid_start);
- dev_vdbg(hsotg->dev, " NTD: %d\n", chan->ntd - 1);
- }
-
- dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
-
- dma_sync_single_for_device(hsotg->dev, chan->desc_list_addr,
- chan->desc_list_sz, DMA_TO_DEVICE);
-
- dwc2_writel(chan->desc_list_addr, hsotg->regs + HCDMA(chan->hc_num));
-
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "Wrote %pad to HCDMA(%d)\n",
- &chan->desc_list_addr, chan->hc_num);
-
- hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
- hcchar &= ~HCCHAR_MULTICNT_MASK;
- hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
- HCCHAR_MULTICNT_MASK;
-
- if (hcchar & HCCHAR_CHDIS)
- dev_warn(hsotg->dev,
- "%s: chdis set, channel %d, hcchar 0x%08x\n",
- __func__, chan->hc_num, hcchar);
-
- /* Set host channel enable after all other setup is complete */
- hcchar |= HCCHAR_CHENA;
- hcchar &= ~HCCHAR_CHDIS;
-
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
- (hcchar & HCCHAR_MULTICNT_MASK) >>
- HCCHAR_MULTICNT_SHIFT);
-
- dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
- chan->hc_num);
-
- chan->xfer_started = 1;
- chan->requests++;
-}
-
-/**
- * dwc2_hc_continue_transfer() - Continues a data transfer that was started by
- * a previous call to dwc2_hc_start_transfer()
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan: Information needed to initialize the host channel
- *
- * The caller must ensure there is sufficient space in the request queue and Tx
- * Data FIFO. This function should only be called in Slave mode. In DMA mode,
- * the controller acts autonomously to complete transfers programmed to a host
- * channel.
- *
- * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
- * if there is any data remaining to be queued. For an IN transfer, another
- * data packet is always requested. For the SETUP phase of a control transfer,
- * this function does nothing.
- *
- * Return: 1 if a new request is queued, 0 if no more requests are required
- * for this transfer
- */
-int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan)
-{
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
- chan->hc_num);
-
- if (chan->do_split)
- /* SPLITs always queue just once per channel */
- return 0;
-
- if (chan->data_pid_start == DWC2_HC_PID_SETUP)
- /* SETUPs are queued only once since they can't be NAK'd */
- return 0;
-
- if (chan->ep_is_in) {
- /*
- * Always queue another request for other IN transfers. If
- * back-to-back INs are issued and NAKs are received for both,
- * the driver may still be processing the first NAK when the
- * second NAK is received. When the interrupt handler clears
- * the NAK interrupt for the first NAK, the second NAK will
- * not be seen. So we can't depend on the NAK interrupt
- * handler to requeue a NAK'd request. Instead, IN requests
- * are issued each time this function is called. When the
- * transfer completes, the extra requests for the channel will
- * be flushed.
- */
- u32 hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
-
- dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
- hcchar |= HCCHAR_CHENA;
- hcchar &= ~HCCHAR_CHDIS;
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, " IN xfer: hcchar = 0x%08x\n",
- hcchar);
- dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
- chan->requests++;
- return 1;
- }
-
- /* OUT transfers */
-
- if (chan->xfer_count < chan->xfer_len) {
- if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
- chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
- u32 hcchar = dwc2_readl(hsotg->regs +
- HCCHAR(chan->hc_num));
-
- dwc2_hc_set_even_odd_frame(hsotg, chan,
- &hcchar);
- }
-
- /* Load OUT packet into the appropriate Tx FIFO */
- dwc2_hc_write_packet(hsotg, chan);
- chan->requests++;
- return 1;
- }
-
- return 0;
-}
-
-/**
- * dwc2_hc_do_ping() - Starts a PING transfer
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan: Information needed to initialize the host channel
- *
- * This function should only be called in Slave mode. The Do Ping bit is set in
- * the HCTSIZ register, then the channel is enabled.
- */
-void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
-{
- u32 hcchar;
- u32 hctsiz;
-
- if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
- chan->hc_num);
-
-
- hctsiz = TSIZ_DOPNG;
- hctsiz |= 1 << TSIZ_PKTCNT_SHIFT;
- dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
-
- hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
- hcchar |= HCCHAR_CHENA;
- hcchar &= ~HCCHAR_CHDIS;
- dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
-}
-
-/**
- * dwc2_calc_frame_interval() - Calculates the correct frame Interval value for
- * the HFIR register according to PHY type and speed
- *
- * @hsotg: Programming view of DWC_otg controller
- *
- * NOTE: The caller can modify the value of the HFIR register only after the
- * Port Enable bit of the Host Port Control and Status register (HPRT.EnaPort)
- * has been set
- */
-u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
-{
- u32 usbcfg;
- u32 hprt0;
- int clock = 60; /* default value */
-
- usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- hprt0 = dwc2_readl(hsotg->regs + HPRT0);
-
- if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) &&
- !(usbcfg & GUSBCFG_PHYIF16))
- clock = 60;
- if ((usbcfg & GUSBCFG_PHYSEL) && hsotg->hw_params.fs_phy_type ==
- GHWCFG2_FS_PHY_TYPE_SHARED_ULPI)
- clock = 48;
- if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
- !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
- clock = 30;
- if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
- !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && !(usbcfg & GUSBCFG_PHYIF16))
- clock = 60;
- if ((usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
- !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
- clock = 48;
- if ((usbcfg & GUSBCFG_PHYSEL) && !(usbcfg & GUSBCFG_PHYIF16) &&
- hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
- clock = 48;
- if ((usbcfg & GUSBCFG_PHYSEL) &&
- hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
- clock = 48;
-
- if ((hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT == HPRT0_SPD_HIGH_SPEED)
- /* High speed case */
- return 125 * clock;
- else
- /* FS/LS case */
- return 1000 * clock;
-}
-
-/**
- * dwc2_read_packet() - Reads a packet from the Rx FIFO into the destination
- * buffer
- *
- * @core_if: Programming view of DWC_otg controller
- * @dest: Destination buffer for the packet
- * @bytes: Number of bytes to copy to the destination
- */
-void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes)
-{
- u32 __iomem *fifo = hsotg->regs + HCFIFO(0);
- u32 *data_buf = (u32 *)dest;
- int word_count = (bytes + 3) / 4;
- int i;
-
- /*
- * Todo: Account for the case where dest is not dword aligned. This
- * requires reading data from the FIFO into a u32 temp buffer, then
- * moving it into the data buffer.
- */
-
- dev_vdbg(hsotg->dev, "%s(%p,%p,%d)\n", __func__, hsotg, dest, bytes);
-
- for (i = 0; i < word_count; i++, data_buf++)
- *data_buf = dwc2_readl(fifo);
-}
-
/**
* dwc2_dump_host_registers() - Prints the host registers
*
@@ -3349,13 +1478,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >>
GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
hw->max_transfer_size = (1 << (width + 11)) - 1;
- /*
- * Clip max_transfer_size to 65535. dwc2_hc_setup_align_buf() allocates
- * coherent buffers with this size, and if it's too large we can
- * exhaust the coherent DMA pool.
- */
- if (hw->max_transfer_size > 65535)
- hw->max_transfer_size = 65535;
width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >>
GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
hw->max_packet_count = (1 << (width + 4)) - 1;
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 7fb6434f4639..3c58d633ce80 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -44,6 +44,26 @@
#include <linux/usb/phy.h>
#include "hw.h"
+/*
+ * Suggested defines for tracers:
+ * - no_printk: Disable tracing
+ * - pr_info: Print this info to the console
+ * - trace_printk: Print this info to trace buffer (good for verbose logging)
+ */
+
+#define DWC2_TRACE_SCHEDULER no_printk
+#define DWC2_TRACE_SCHEDULER_VB no_printk
+
+/* Detailed scheduler tracing, but won't overwhelm console */
+#define dwc2_sch_dbg(hsotg, fmt, ...) \
+ DWC2_TRACE_SCHEDULER(pr_fmt("%s: SCH: " fmt), \
+ dev_name(hsotg->dev), ##__VA_ARGS__)
+
+/* Verbose scheduler tracing */
+#define dwc2_sch_vdbg(hsotg, fmt, ...) \
+ DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \
+ dev_name(hsotg->dev), ##__VA_ARGS__)
+
static inline u32 dwc2_readl(const void __iomem *addr)
{
u32 value = __raw_readl(addr);
@@ -572,6 +592,84 @@ struct dwc2_hregs_backup {
bool valid;
};
+/*
+ * Constants related to high speed periodic scheduling
+ *
+ * We have a periodic schedule that is DWC2_HS_SCHEDULE_UFRAMES long. From a
+ * reservation point of view it's assumed that the schedule goes right back to
+ * the beginning after the end of the schedule.
+ *
+ * What does that mean for scheduling things with a long interval? It means
+ * we'll reserve time for them in every possible microframe that they could
+ * ever be scheduled in. ...but we'll still only actually schedule them as
+ * often as they were requested.
+ *
+ * We keep our schedule in a "bitmap" structure. This simplifies having
+ * to keep track of and merge intervals: we just let the bitmap code do most
+ * of the heavy lifting. In a way scheduling is much like memory allocation.
+ *
+ * We schedule 100us per uframe or 80% of 125us (the maximum amount you're
+ * supposed to schedule for periodic transfers). That's according to spec.
+ *
+ * Note that though we only schedule 80% of each microframe, the bitmap that we
+ * keep the schedule in is tightly packed (AKA it doesn't have 100us worth of
+ * space for each uFrame).
+ *
+ * Requirements:
+ * - DWC2_HS_SCHEDULE_UFRAMES must even divide 0x4000 (HFNUM_MAX_FRNUM + 1)
+ * - DWC2_HS_SCHEDULE_UFRAMES must be 8 times DWC2_LS_SCHEDULE_FRAMES (probably
+ * could be any multiple of 8 times DWC2_LS_SCHEDULE_FRAMES, but there might
+ * be bugs). The 8 comes from the USB spec: number of microframes per frame.
+ */
+#define DWC2_US_PER_UFRAME 125
+#define DWC2_HS_PERIODIC_US_PER_UFRAME 100
+
+#define DWC2_HS_SCHEDULE_UFRAMES 8
+#define DWC2_HS_SCHEDULE_US (DWC2_HS_SCHEDULE_UFRAMES * \
+ DWC2_HS_PERIODIC_US_PER_UFRAME)
+
+/*
+ * Constants related to low speed scheduling
+ *
+ * For high speed we schedule every 1us. For low speed that's a bit overkill,
+ * so we make up a unit called a "slice" that's worth 25us. There are 40
+ * slices in a full frame and we can schedule 36 of those (90%) for periodic
+ * transfers.
+ *
+ * Our low speed schedule can be as short as 1 frame or could be longer. When
+ * we only schedule 1 frame it means that we'll need to reserve a time every
+ * frame even for things that only transfer very rarely, so something that runs
+ * every 2048 frames will get time reserved in every frame. Our low speed
+ * schedule can be longer and we'll be able to handle more overlap, but that
+ * will come at increased memory cost and increased time to schedule.
+ *
+ * Note: one other advantage of a short low speed schedule is that if we mess
+ * up and miss scheduling we can jump in and use any of the slots that we
+ * happened to reserve.
+ *
+ * With 25 us per slice and 1 frame in the schedule, we only need 4 bytes for
+ * the schedule. There will be one schedule per TT.
+ *
+ * Requirements:
+ * - DWC2_US_PER_SLICE must evenly divide DWC2_LS_PERIODIC_US_PER_FRAME.
+ */
+#define DWC2_US_PER_SLICE 25
+#define DWC2_SLICES_PER_UFRAME (DWC2_US_PER_UFRAME / DWC2_US_PER_SLICE)
+
+#define DWC2_ROUND_US_TO_SLICE(us) \
+ (DIV_ROUND_UP((us), DWC2_US_PER_SLICE) * \
+ DWC2_US_PER_SLICE)
+
+#define DWC2_LS_PERIODIC_US_PER_FRAME \
+ 900
+#define DWC2_LS_PERIODIC_SLICES_PER_FRAME \
+ (DWC2_LS_PERIODIC_US_PER_FRAME / \
+ DWC2_US_PER_SLICE)
+
+#define DWC2_LS_SCHEDULE_FRAMES 1
+#define DWC2_LS_SCHEDULE_SLICES (DWC2_LS_SCHEDULE_FRAMES * \
+ DWC2_LS_PERIODIC_SLICES_PER_FRAME)
+
/**
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
* and periodic schedules
@@ -657,11 +755,14 @@ struct dwc2_hregs_backup {
* periodic_sched_ready because it must be rescheduled for
* the next frame. Otherwise, the item moves to
* periodic_sched_inactive.
+ * @split_order: List keeping track of channels doing splits, in order.
* @periodic_usecs: Total bandwidth claimed so far for periodic transfers.
* This value is in microseconds per (micro)frame. The
* assumption is that all periodic transfers may occur in
* the same (micro)frame.
- * @frame_usecs: Internal variable used by the microframe scheduler
+ * @hs_periodic_bitmap: Bitmap used by the microframe scheduler any time the
+ * host is in high speed mode; low speed schedules are
+ * stored elsewhere since we need one per TT.
* @frame_number: Frame number read from the core at SOF. The value ranges
* from 0 to HFNUM_MAX_FRNUM.
* @periodic_qh_count: Count of periodic QHs, if using several eps. Used for
@@ -780,16 +881,19 @@ struct dwc2_hsotg {
struct list_head periodic_sched_ready;
struct list_head periodic_sched_assigned;
struct list_head periodic_sched_queued;
+ struct list_head split_order;
u16 periodic_usecs;
- u16 frame_usecs[8];
+ unsigned long hs_periodic_bitmap[
+ DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)];
u16 frame_number;
u16 periodic_qh_count;
bool bus_suspended;
bool new_connection;
+ u16 last_frame_num;
+
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
#define FRAME_NUM_ARRAY_SIZE 1000
- u16 last_frame_num;
u16 *frame_num_array;
u16 *last_frame_num_array;
int frame_num_idx;
@@ -885,34 +989,11 @@ enum dwc2_halt_status {
*/
extern int dwc2_core_reset(struct dwc2_hsotg *hsotg);
extern int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg);
-extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
-/*
- * Host core Functions.
- * The following functions support managing the DWC_otg controller in host
- * mode.
- */
-extern void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
-extern void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
- enum dwc2_halt_status halt_status);
-extern void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan);
-extern void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan);
-extern void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan);
-extern int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan);
-extern void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan);
-extern void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg);
-extern void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg);
-
-extern u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg);
extern bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg);
/*
@@ -924,7 +1005,6 @@ extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes);
extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num);
extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
-extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
@@ -1191,6 +1271,8 @@ extern void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg);
extern void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2);
extern int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
#define dwc2_is_device_connected(hsotg) (hsotg->connected)
+int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg);
+int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg);
#else
static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
{ return 0; }
@@ -1208,22 +1290,37 @@ static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
int testmode)
{ return 0; }
#define dwc2_is_device_connected(hsotg) (0)
+static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
+{ return 0; }
+static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
+{ return 0; }
#endif
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
+extern int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us);
extern void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
+int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
+int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
#else
static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
{ return 0; }
+static inline int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg,
+ int us)
+{ return 0; }
static inline void dwc2_hcd_connect(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force) {}
static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
{ return 0; }
+static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
+{ return 0; }
+static inline int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
+{ return 0; }
+
#endif
#endif /* __DWC2_CORE_H__ */
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 422ab7da4eb5..e9940dd004e4 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -3668,3 +3668,105 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg)
return 0;
}
+
+/**
+ * dwc2_backup_device_registers() - Backup controller device registers.
+ * When suspending usb bus, registers needs to be backuped
+ * if controller power is disabled once suspended.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_dregs_backup *dr;
+ int i;
+
+ dev_dbg(hsotg->dev, "%s\n", __func__);
+
+ /* Backup dev regs */
+ dr = &hsotg->dr_backup;
+
+ dr->dcfg = dwc2_readl(hsotg->regs + DCFG);
+ dr->dctl = dwc2_readl(hsotg->regs + DCTL);
+ dr->daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
+ dr->diepmsk = dwc2_readl(hsotg->regs + DIEPMSK);
+ dr->doepmsk = dwc2_readl(hsotg->regs + DOEPMSK);
+
+ for (i = 0; i < hsotg->num_of_eps; i++) {
+ /* Backup IN EPs */
+ dr->diepctl[i] = dwc2_readl(hsotg->regs + DIEPCTL(i));
+
+ /* Ensure DATA PID is correctly configured */
+ if (dr->diepctl[i] & DXEPCTL_DPID)
+ dr->diepctl[i] |= DXEPCTL_SETD1PID;
+ else
+ dr->diepctl[i] |= DXEPCTL_SETD0PID;
+
+ dr->dieptsiz[i] = dwc2_readl(hsotg->regs + DIEPTSIZ(i));
+ dr->diepdma[i] = dwc2_readl(hsotg->regs + DIEPDMA(i));
+
+ /* Backup OUT EPs */
+ dr->doepctl[i] = dwc2_readl(hsotg->regs + DOEPCTL(i));
+
+ /* Ensure DATA PID is correctly configured */
+ if (dr->doepctl[i] & DXEPCTL_DPID)
+ dr->doepctl[i] |= DXEPCTL_SETD1PID;
+ else
+ dr->doepctl[i] |= DXEPCTL_SETD0PID;
+
+ dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i));
+ dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i));
+ }
+ dr->valid = true;
+ return 0;
+}
+
+/**
+ * dwc2_restore_device_registers() - Restore controller device registers.
+ * When resuming usb bus, device registers needs to be restored
+ * if controller power were disabled.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_dregs_backup *dr;
+ u32 dctl;
+ int i;
+
+ dev_dbg(hsotg->dev, "%s\n", __func__);
+
+ /* Restore dev regs */
+ dr = &hsotg->dr_backup;
+ if (!dr->valid) {
+ dev_err(hsotg->dev, "%s: no device registers to restore\n",
+ __func__);
+ return -EINVAL;
+ }
+ dr->valid = false;
+
+ dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
+ dwc2_writel(dr->dctl, hsotg->regs + DCTL);
+ dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK);
+ dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK);
+ dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK);
+
+ for (i = 0; i < hsotg->num_of_eps; i++) {
+ /* Restore IN EPs */
+ dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
+ dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i));
+ dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i));
+
+ /* Restore OUT EPs */
+ dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
+ dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
+ dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i));
+ }
+
+ /* Set the Power-On Programming done bit */
+ dctl = dwc2_readl(hsotg->regs + DCTL);
+ dctl |= DCTL_PWRONPRGDONE;
+ dwc2_writel(dctl, hsotg->regs + DCTL);
+
+ return 0;
+}
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 8847c72e55f6..1f6255131857 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -54,6 +54,535 @@
#include "core.h"
#include "hcd.h"
+/*
+ * =========================================================================
+ * Host Core Layer Functions
+ * =========================================================================
+ */
+
+/**
+ * dwc2_enable_common_interrupts() - Initializes the commmon interrupts,
+ * used in both device and host modes
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
+{
+ u32 intmsk;
+
+ /* Clear any pending OTG Interrupts */
+ dwc2_writel(0xffffffff, hsotg->regs + GOTGINT);
+
+ /* Clear any pending interrupts */
+ dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+
+ /* Enable the interrupts in the GINTMSK */
+ intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT;
+
+ if (hsotg->core_params->dma_enable <= 0)
+ intmsk |= GINTSTS_RXFLVL;
+ if (hsotg->core_params->external_id_pin_ctl <= 0)
+ intmsk |= GINTSTS_CONIDSTSCHNG;
+
+ intmsk |= GINTSTS_WKUPINT | GINTSTS_USBSUSP |
+ GINTSTS_SESSREQINT;
+
+ dwc2_writel(intmsk, hsotg->regs + GINTMSK);
+}
+
+/*
+ * Initializes the FSLSPClkSel field of the HCFG register depending on the
+ * PHY type
+ */
+static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
+{
+ u32 hcfg, val;
+
+ if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+ hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+ hsotg->core_params->ulpi_fs_ls > 0) ||
+ hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
+ /* Full speed PHY */
+ val = HCFG_FSLSPCLKSEL_48_MHZ;
+ } else {
+ /* High speed PHY running at full speed or high speed */
+ val = HCFG_FSLSPCLKSEL_30_60_MHZ;
+ }
+
+ dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
+ hcfg = dwc2_readl(hsotg->regs + HCFG);
+ hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
+ hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT;
+ dwc2_writel(hcfg, hsotg->regs + HCFG);
+}
+
+static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+{
+ u32 usbcfg, i2cctl;
+ int retval = 0;
+
+ /*
+ * core_init() is now called on every switch so only call the
+ * following for the first time through
+ */
+ if (select_phy) {
+ dev_dbg(hsotg->dev, "FS PHY selected\n");
+
+ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ if (!(usbcfg & GUSBCFG_PHYSEL)) {
+ usbcfg |= GUSBCFG_PHYSEL;
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+
+ /* Reset after a PHY select */
+ retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+
+ if (retval) {
+ dev_err(hsotg->dev,
+ "%s: Reset failed, aborting", __func__);
+ return retval;
+ }
+ }
+ }
+
+ /*
+ * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
+ * do this on HNP Dev/Host mode switches (done in dev_init and
+ * host_init).
+ */
+ if (dwc2_is_host_mode(hsotg))
+ dwc2_init_fs_ls_pclk_sel(hsotg);
+
+ if (hsotg->core_params->i2c_enable > 0) {
+ dev_dbg(hsotg->dev, "FS PHY enabling I2C\n");
+
+ /* Program GUSBCFG.OtgUtmiFsSel to I2C */
+ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL;
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+
+ /* Program GI2CCTL.I2CEn */
+ i2cctl = dwc2_readl(hsotg->regs + GI2CCTL);
+ i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK;
+ i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT;
+ i2cctl &= ~GI2CCTL_I2CEN;
+ dwc2_writel(i2cctl, hsotg->regs + GI2CCTL);
+ i2cctl |= GI2CCTL_I2CEN;
+ dwc2_writel(i2cctl, hsotg->regs + GI2CCTL);
+ }
+
+ return retval;
+}
+
+static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+{
+ u32 usbcfg, usbcfg_old;
+ int retval = 0;
+
+ if (!select_phy)
+ return 0;
+
+ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ usbcfg_old = usbcfg;
+
+ /*
+ * HS PHY parameters. These parameters are preserved during soft reset
+ * so only program the first time. Do a soft reset immediately after
+ * setting phyif.
+ */
+ switch (hsotg->core_params->phy_type) {
+ case DWC2_PHY_TYPE_PARAM_ULPI:
+ /* ULPI interface */
+ dev_dbg(hsotg->dev, "HS ULPI PHY selected\n");
+ usbcfg |= GUSBCFG_ULPI_UTMI_SEL;
+ usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
+ if (hsotg->core_params->phy_ulpi_ddr > 0)
+ usbcfg |= GUSBCFG_DDRSEL;
+ break;
+ case DWC2_PHY_TYPE_PARAM_UTMI:
+ /* UTMI+ interface */
+ dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n");
+ usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
+ if (hsotg->core_params->phy_utmi_width == 16)
+ usbcfg |= GUSBCFG_PHYIF16;
+ break;
+ default:
+ dev_err(hsotg->dev, "FS PHY selected at HS!\n");
+ break;
+ }
+
+ if (usbcfg != usbcfg_old) {
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+
+ /* Reset after setting the PHY parameters */
+ retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+ if (retval) {
+ dev_err(hsotg->dev,
+ "%s: Reset failed, aborting", __func__);
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
+static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+{
+ u32 usbcfg;
+ int retval = 0;
+
+ if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL &&
+ hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
+ /* If FS mode with FS PHY */
+ retval = dwc2_fs_phy_init(hsotg, select_phy);
+ if (retval)
+ return retval;
+ } else {
+ /* High speed PHY */
+ retval = dwc2_hs_phy_init(hsotg, select_phy);
+ if (retval)
+ return retval;
+ }
+
+ if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+ hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+ hsotg->core_params->ulpi_fs_ls > 0) {
+ dev_dbg(hsotg->dev, "Setting ULPI FSLS\n");
+ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ usbcfg |= GUSBCFG_ULPI_FS_LS;
+ usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M;
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+ } else {
+ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ usbcfg &= ~GUSBCFG_ULPI_FS_LS;
+ usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+ }
+
+ return retval;
+}
+
+static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
+{
+ u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
+
+ switch (hsotg->hw_params.arch) {
+ case GHWCFG2_EXT_DMA_ARCH:
+ dev_err(hsotg->dev, "External DMA Mode not supported\n");
+ return -EINVAL;
+
+ case GHWCFG2_INT_DMA_ARCH:
+ dev_dbg(hsotg->dev, "Internal DMA Mode\n");
+ if (hsotg->core_params->ahbcfg != -1) {
+ ahbcfg &= GAHBCFG_CTRL_MASK;
+ ahbcfg |= hsotg->core_params->ahbcfg &
+ ~GAHBCFG_CTRL_MASK;
+ }
+ break;
+
+ case GHWCFG2_SLAVE_ONLY_ARCH:
+ default:
+ dev_dbg(hsotg->dev, "Slave Only Mode\n");
+ break;
+ }
+
+ dev_dbg(hsotg->dev, "dma_enable:%d dma_desc_enable:%d\n",
+ hsotg->core_params->dma_enable,
+ hsotg->core_params->dma_desc_enable);
+
+ if (hsotg->core_params->dma_enable > 0) {
+ if (hsotg->core_params->dma_desc_enable > 0)
+ dev_dbg(hsotg->dev, "Using Descriptor DMA mode\n");
+ else
+ dev_dbg(hsotg->dev, "Using Buffer DMA mode\n");
+ } else {
+ dev_dbg(hsotg->dev, "Using Slave mode\n");
+ hsotg->core_params->dma_desc_enable = 0;
+ }
+
+ if (hsotg->core_params->dma_enable > 0)
+ ahbcfg |= GAHBCFG_DMA_EN;
+
+ dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
+
+ return 0;
+}
+
+static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
+{
+ u32 usbcfg;
+
+ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
+
+ switch (hsotg->hw_params.op_mode) {
+ case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+ if (hsotg->core_params->otg_cap ==
+ DWC2_CAP_PARAM_HNP_SRP_CAPABLE)
+ usbcfg |= GUSBCFG_HNPCAP;
+ if (hsotg->core_params->otg_cap !=
+ DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
+ usbcfg |= GUSBCFG_SRPCAP;
+ break;
+
+ case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+ case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+ case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+ if (hsotg->core_params->otg_cap !=
+ DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
+ usbcfg |= GUSBCFG_SRPCAP;
+ break;
+
+ case GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE:
+ case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE:
+ case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST:
+ default:
+ break;
+ }
+
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+}
+
+/**
+ * dwc2_enable_host_interrupts() - Enables the Host mode interrupts
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+static void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg)
+{
+ u32 intmsk;
+
+ dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+ /* Disable all interrupts */
+ dwc2_writel(0, hsotg->regs + GINTMSK);
+ dwc2_writel(0, hsotg->regs + HAINTMSK);
+
+ /* Enable the common interrupts */
+ dwc2_enable_common_interrupts(hsotg);
+
+ /* Enable host mode interrupts without disturbing common interrupts */
+ intmsk = dwc2_readl(hsotg->regs + GINTMSK);
+ intmsk |= GINTSTS_DISCONNINT | GINTSTS_PRTINT | GINTSTS_HCHINT;
+ dwc2_writel(intmsk, hsotg->regs + GINTMSK);
+}
+
+/**
+ * dwc2_disable_host_interrupts() - Disables the Host Mode interrupts
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+static void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg)
+{
+ u32 intmsk = dwc2_readl(hsotg->regs + GINTMSK);
+
+ /* Disable host mode interrupts without disturbing common interrupts */
+ intmsk &= ~(GINTSTS_SOF | GINTSTS_PRTINT | GINTSTS_HCHINT |
+ GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP | GINTSTS_DISCONNINT);
+ dwc2_writel(intmsk, hsotg->regs + GINTMSK);
+}
+
+/*
+ * dwc2_calculate_dynamic_fifo() - Calculates the default fifo size
+ * For system that have a total fifo depth that is smaller than the default
+ * RX + TX fifo size.
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+static void dwc2_calculate_dynamic_fifo(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_core_params *params = hsotg->core_params;
+ struct dwc2_hw_params *hw = &hsotg->hw_params;
+ u32 rxfsiz, nptxfsiz, ptxfsiz, total_fifo_size;
+
+ total_fifo_size = hw->total_fifo_size;
+ rxfsiz = params->host_rx_fifo_size;
+ nptxfsiz = params->host_nperio_tx_fifo_size;
+ ptxfsiz = params->host_perio_tx_fifo_size;
+
+ /*
+ * Will use Method 2 defined in the DWC2 spec: minimum FIFO depth
+ * allocation with support for high bandwidth endpoints. Synopsys
+ * defines MPS(Max Packet size) for a periodic EP=1024, and for
+ * non-periodic as 512.
+ */
+ if (total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)) {
+ /*
+ * For Buffer DMA mode/Scatter Gather DMA mode
+ * 2 * ((Largest Packet size / 4) + 1 + 1) + n
+ * with n = number of host channel.
+ * 2 * ((1024/4) + 2) = 516
+ */
+ rxfsiz = 516 + hw->host_channels;
+
+ /*
+ * min non-periodic tx fifo depth
+ * 2 * (largest non-periodic USB packet used / 4)
+ * 2 * (512/4) = 256
+ */
+ nptxfsiz = 256;
+
+ /*
+ * min periodic tx fifo depth
+ * (largest packet size*MC)/4
+ * (1024 * 3)/4 = 768
+ */
+ ptxfsiz = 768;
+
+ params->host_rx_fifo_size = rxfsiz;
+ params->host_nperio_tx_fifo_size = nptxfsiz;
+ params->host_perio_tx_fifo_size = ptxfsiz;
+ }
+
+ /*
+ * If the summation of RX, NPTX and PTX fifo sizes is still
+ * bigger than the total_fifo_size, then we have a problem.
+ *
+ * We won't be able to allocate as many endpoints. Right now,
+ * we're just printing an error message, but ideally this FIFO
+ * allocation algorithm would be improved in the future.
+ *
+ * FIXME improve this FIFO allocation algorithm.
+ */
+ if (unlikely(total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)))
+ dev_err(hsotg->dev, "invalid fifo sizes\n");
+}
+
+static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_core_params *params = hsotg->core_params;
+ u32 nptxfsiz, hptxfsiz, dfifocfg, grxfsiz;
+
+ if (!params->enable_dynamic_fifo)
+ return;
+
+ dwc2_calculate_dynamic_fifo(hsotg);
+
+ /* Rx FIFO */
+ grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
+ dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz);
+ grxfsiz &= ~GRXFSIZ_DEPTH_MASK;
+ grxfsiz |= params->host_rx_fifo_size <<
+ GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
+ dwc2_writel(grxfsiz, hsotg->regs + GRXFSIZ);
+ dev_dbg(hsotg->dev, "new grxfsiz=%08x\n",
+ dwc2_readl(hsotg->regs + GRXFSIZ));
+
+ /* Non-periodic Tx FIFO */
+ dev_dbg(hsotg->dev, "initial gnptxfsiz=%08x\n",
+ dwc2_readl(hsotg->regs + GNPTXFSIZ));
+ nptxfsiz = params->host_nperio_tx_fifo_size <<
+ FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+ nptxfsiz |= params->host_rx_fifo_size <<
+ FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+ dwc2_writel(nptxfsiz, hsotg->regs + GNPTXFSIZ);
+ dev_dbg(hsotg->dev, "new gnptxfsiz=%08x\n",
+ dwc2_readl(hsotg->regs + GNPTXFSIZ));
+
+ /* Periodic Tx FIFO */
+ dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n",
+ dwc2_readl(hsotg->regs + HPTXFSIZ));
+ hptxfsiz = params->host_perio_tx_fifo_size <<
+ FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+ hptxfsiz |= (params->host_rx_fifo_size +
+ params->host_nperio_tx_fifo_size) <<
+ FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+ dwc2_writel(hptxfsiz, hsotg->regs + HPTXFSIZ);
+ dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n",
+ dwc2_readl(hsotg->regs + HPTXFSIZ));
+
+ if (hsotg->core_params->en_multiple_tx_fifo > 0 &&
+ hsotg->hw_params.snpsid <= DWC2_CORE_REV_2_94a) {
+ /*
+ * Global DFIFOCFG calculation for Host mode -
+ * include RxFIFO, NPTXFIFO and HPTXFIFO
+ */
+ dfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG);
+ dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
+ dfifocfg |= (params->host_rx_fifo_size +
+ params->host_nperio_tx_fifo_size +
+ params->host_perio_tx_fifo_size) <<
+ GDFIFOCFG_EPINFOBASE_SHIFT &
+ GDFIFOCFG_EPINFOBASE_MASK;
+ dwc2_writel(dfifocfg, hsotg->regs + GDFIFOCFG);
+ }
+}
+
+/**
+ * dwc2_calc_frame_interval() - Calculates the correct frame Interval value for
+ * the HFIR register according to PHY type and speed
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * NOTE: The caller can modify the value of the HFIR register only after the
+ * Port Enable bit of the Host Port Control and Status register (HPRT.EnaPort)
+ * has been set
+ */
+u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
+{
+ u32 usbcfg;
+ u32 hprt0;
+ int clock = 60; /* default value */
+
+ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+
+ if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) &&
+ !(usbcfg & GUSBCFG_PHYIF16))
+ clock = 60;
+ if ((usbcfg & GUSBCFG_PHYSEL) && hsotg->hw_params.fs_phy_type ==
+ GHWCFG2_FS_PHY_TYPE_SHARED_ULPI)
+ clock = 48;
+ if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
+ !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
+ clock = 30;
+ if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
+ !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && !(usbcfg & GUSBCFG_PHYIF16))
+ clock = 60;
+ if ((usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
+ !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
+ clock = 48;
+ if ((usbcfg & GUSBCFG_PHYSEL) && !(usbcfg & GUSBCFG_PHYIF16) &&
+ hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
+ clock = 48;
+ if ((usbcfg & GUSBCFG_PHYSEL) &&
+ hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
+ clock = 48;
+
+ if ((hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT == HPRT0_SPD_HIGH_SPEED)
+ /* High speed case */
+ return 125 * clock - 1;
+
+ /* FS/LS case */
+ return 1000 * clock - 1;
+}
+
+/**
+ * dwc2_read_packet() - Reads a packet from the Rx FIFO into the destination
+ * buffer
+ *
+ * @core_if: Programming view of DWC_otg controller
+ * @dest: Destination buffer for the packet
+ * @bytes: Number of bytes to copy to the destination
+ */
+void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes)
+{
+ u32 __iomem *fifo = hsotg->regs + HCFIFO(0);
+ u32 *data_buf = (u32 *)dest;
+ int word_count = (bytes + 3) / 4;
+ int i;
+
+ /*
+ * Todo: Account for the case where dest is not dword aligned. This
+ * requires reading data from the FIFO into a u32 temp buffer, then
+ * moving it into the data buffer.
+ */
+
+ dev_vdbg(hsotg->dev, "%s(%p,%p,%d)\n", __func__, hsotg, dest, bytes);
+
+ for (i = 0; i < word_count; i++, data_buf++)
+ *data_buf = dwc2_readl(fifo);
+}
+
/**
* dwc2_dump_channel_info() - Prints the state of a host channel
*
@@ -77,7 +606,7 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
u32 hc_dma;
int i;
- if (chan == NULL)
+ if (!chan)
return;
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
@@ -120,6 +649,1056 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
}
/*
+ * =========================================================================
+ * Low Level Host Channel Access Functions
+ * =========================================================================
+ */
+
+static void dwc2_hc_enable_slave_ints(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 hcintmsk = HCINTMSK_CHHLTD;
+
+ switch (chan->ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ dev_vdbg(hsotg->dev, "control/bulk\n");
+ hcintmsk |= HCINTMSK_XFERCOMPL;
+ hcintmsk |= HCINTMSK_STALL;
+ hcintmsk |= HCINTMSK_XACTERR;
+ hcintmsk |= HCINTMSK_DATATGLERR;
+ if (chan->ep_is_in) {
+ hcintmsk |= HCINTMSK_BBLERR;
+ } else {
+ hcintmsk |= HCINTMSK_NAK;
+ hcintmsk |= HCINTMSK_NYET;
+ if (chan->do_ping)
+ hcintmsk |= HCINTMSK_ACK;
+ }
+
+ if (chan->do_split) {
+ hcintmsk |= HCINTMSK_NAK;
+ if (chan->complete_split)
+ hcintmsk |= HCINTMSK_NYET;
+ else
+ hcintmsk |= HCINTMSK_ACK;
+ }
+
+ if (chan->error_state)
+ hcintmsk |= HCINTMSK_ACK;
+ break;
+
+ case USB_ENDPOINT_XFER_INT:
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "intr\n");
+ hcintmsk |= HCINTMSK_XFERCOMPL;
+ hcintmsk |= HCINTMSK_NAK;
+ hcintmsk |= HCINTMSK_STALL;
+ hcintmsk |= HCINTMSK_XACTERR;
+ hcintmsk |= HCINTMSK_DATATGLERR;
+ hcintmsk |= HCINTMSK_FRMOVRUN;
+
+ if (chan->ep_is_in)
+ hcintmsk |= HCINTMSK_BBLERR;
+ if (chan->error_state)
+ hcintmsk |= HCINTMSK_ACK;
+ if (chan->do_split) {
+ if (chan->complete_split)
+ hcintmsk |= HCINTMSK_NYET;
+ else
+ hcintmsk |= HCINTMSK_ACK;
+ }
+ break;
+
+ case USB_ENDPOINT_XFER_ISOC:
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "isoc\n");
+ hcintmsk |= HCINTMSK_XFERCOMPL;
+ hcintmsk |= HCINTMSK_FRMOVRUN;
+ hcintmsk |= HCINTMSK_ACK;
+
+ if (chan->ep_is_in) {
+ hcintmsk |= HCINTMSK_XACTERR;
+ hcintmsk |= HCINTMSK_BBLERR;
+ }
+ break;
+ default:
+ dev_err(hsotg->dev, "## Unknown EP type ##\n");
+ break;
+ }
+
+ dwc2_writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
+}
+
+static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 hcintmsk = HCINTMSK_CHHLTD;
+
+ /*
+ * For Descriptor DMA mode core halts the channel on AHB error.
+ * Interrupt is not required.
+ */
+ if (hsotg->core_params->dma_desc_enable <= 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "desc DMA disabled\n");
+ hcintmsk |= HCINTMSK_AHBERR;
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "desc DMA enabled\n");
+ if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ hcintmsk |= HCINTMSK_XFERCOMPL;
+ }
+
+ if (chan->error_state && !chan->do_split &&
+ chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "setting ACK\n");
+ hcintmsk |= HCINTMSK_ACK;
+ if (chan->ep_is_in) {
+ hcintmsk |= HCINTMSK_DATATGLERR;
+ if (chan->ep_type != USB_ENDPOINT_XFER_INT)
+ hcintmsk |= HCINTMSK_NAK;
+ }
+ }
+
+ dwc2_writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
+}
+
+static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 intmsk;
+
+ if (hsotg->core_params->dma_enable > 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "DMA enabled\n");
+ dwc2_hc_enable_dma_ints(hsotg, chan);
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "DMA disabled\n");
+ dwc2_hc_enable_slave_ints(hsotg, chan);
+ }
+
+ /* Enable the top level host channel interrupt */
+ intmsk = dwc2_readl(hsotg->regs + HAINTMSK);
+ intmsk |= 1 << chan->hc_num;
+ dwc2_writel(intmsk, hsotg->regs + HAINTMSK);
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "set HAINTMSK to %08x\n", intmsk);
+
+ /* Make sure host channel interrupts are enabled */
+ intmsk = dwc2_readl(hsotg->regs + GINTMSK);
+ intmsk |= GINTSTS_HCHINT;
+ dwc2_writel(intmsk, hsotg->regs + GINTMSK);
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "set GINTMSK to %08x\n", intmsk);
+}
+
+/**
+ * dwc2_hc_init() - Prepares a host channel for transferring packets to/from
+ * a specific endpoint
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * The HCCHARn register is set up with the characteristics specified in chan.
+ * Host channel interrupts that may need to be serviced while this transfer is
+ * in progress are enabled.
+ */
+static void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
+{
+ u8 hc_num = chan->hc_num;
+ u32 hcintmsk;
+ u32 hcchar;
+ u32 hcsplt = 0;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ /* Clear old interrupt conditions for this host channel */
+ hcintmsk = 0xffffffff;
+ hcintmsk &= ~HCINTMSK_RESERVED14_31;
+ dwc2_writel(hcintmsk, hsotg->regs + HCINT(hc_num));
+
+ /* Enable channel interrupts required for this transfer */
+ dwc2_hc_enable_ints(hsotg, chan);
+
+ /*
+ * Program the HCCHARn register with the endpoint characteristics for
+ * the current transfer
+ */
+ hcchar = chan->dev_addr << HCCHAR_DEVADDR_SHIFT & HCCHAR_DEVADDR_MASK;
+ hcchar |= chan->ep_num << HCCHAR_EPNUM_SHIFT & HCCHAR_EPNUM_MASK;
+ if (chan->ep_is_in)
+ hcchar |= HCCHAR_EPDIR;
+ if (chan->speed == USB_SPEED_LOW)
+ hcchar |= HCCHAR_LSPDDEV;
+ hcchar |= chan->ep_type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK;
+ hcchar |= chan->max_packet << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK;
+ dwc2_writel(hcchar, hsotg->regs + HCCHAR(hc_num));
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n",
+ hc_num, hcchar);
+
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n",
+ __func__, hc_num);
+ dev_vdbg(hsotg->dev, " Dev Addr: %d\n",
+ chan->dev_addr);
+ dev_vdbg(hsotg->dev, " Ep Num: %d\n",
+ chan->ep_num);
+ dev_vdbg(hsotg->dev, " Is In: %d\n",
+ chan->ep_is_in);
+ dev_vdbg(hsotg->dev, " Is Low Speed: %d\n",
+ chan->speed == USB_SPEED_LOW);
+ dev_vdbg(hsotg->dev, " Ep Type: %d\n",
+ chan->ep_type);
+ dev_vdbg(hsotg->dev, " Max Pkt: %d\n",
+ chan->max_packet);
+ }
+
+ /* Program the HCSPLT register for SPLITs */
+ if (chan->do_split) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev,
+ "Programming HC %d with split --> %s\n",
+ hc_num,
+ chan->complete_split ? "CSPLIT" : "SSPLIT");
+ if (chan->complete_split)
+ hcsplt |= HCSPLT_COMPSPLT;
+ hcsplt |= chan->xact_pos << HCSPLT_XACTPOS_SHIFT &
+ HCSPLT_XACTPOS_MASK;
+ hcsplt |= chan->hub_addr << HCSPLT_HUBADDR_SHIFT &
+ HCSPLT_HUBADDR_MASK;
+ hcsplt |= chan->hub_port << HCSPLT_PRTADDR_SHIFT &
+ HCSPLT_PRTADDR_MASK;
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, " comp split %d\n",
+ chan->complete_split);
+ dev_vdbg(hsotg->dev, " xact pos %d\n",
+ chan->xact_pos);
+ dev_vdbg(hsotg->dev, " hub addr %d\n",
+ chan->hub_addr);
+ dev_vdbg(hsotg->dev, " hub port %d\n",
+ chan->hub_port);
+ dev_vdbg(hsotg->dev, " is_in %d\n",
+ chan->ep_is_in);
+ dev_vdbg(hsotg->dev, " Max Pkt %d\n",
+ chan->max_packet);
+ dev_vdbg(hsotg->dev, " xferlen %d\n",
+ chan->xfer_len);
+ }
+ }
+
+ dwc2_writel(hcsplt, hsotg->regs + HCSPLT(hc_num));
+}
+
+/**
+ * dwc2_hc_halt() - Attempts to halt a host channel
+ *
+ * @hsotg: Controller register interface
+ * @chan: Host channel to halt
+ * @halt_status: Reason for halting the channel
+ *
+ * This function should only be called in Slave mode or to abort a transfer in
+ * either Slave mode or DMA mode. Under normal circumstances in DMA mode, the
+ * controller halts the channel when the transfer is complete or a condition
+ * occurs that requires application intervention.
+ *
+ * In slave mode, checks for a free request queue entry, then sets the Channel
+ * Enable and Channel Disable bits of the Host Channel Characteristics
+ * register of the specified channel to intiate the halt. If there is no free
+ * request queue entry, sets only the Channel Disable bit of the HCCHARn
+ * register to flush requests for this channel. In the latter case, sets a
+ * flag to indicate that the host channel needs to be halted when a request
+ * queue slot is open.
+ *
+ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
+ * HCCHARn register. The controller ensures there is space in the request
+ * queue before submitting the halt request.
+ *
+ * Some time may elapse before the core flushes any posted requests for this
+ * host channel and halts. The Channel Halted interrupt handler completes the
+ * deactivation of the host channel.
+ */
+void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
+ enum dwc2_halt_status halt_status)
+{
+ u32 nptxsts, hptxsts, hcchar;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+ if (halt_status == DWC2_HC_XFER_NO_HALT_STATUS)
+ dev_err(hsotg->dev, "!!! halt_status = %d !!!\n", halt_status);
+
+ if (halt_status == DWC2_HC_XFER_URB_DEQUEUE ||
+ halt_status == DWC2_HC_XFER_AHB_ERR) {
+ /*
+ * Disable all channel interrupts except Ch Halted. The QTD
+ * and QH state associated with this transfer has been cleared
+ * (in the case of URB_DEQUEUE), so the channel needs to be
+ * shut down carefully to prevent crashes.
+ */
+ u32 hcintmsk = HCINTMSK_CHHLTD;
+
+ dev_vdbg(hsotg->dev, "dequeue/error\n");
+ dwc2_writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+
+ /*
+ * Make sure no other interrupts besides halt are currently
+ * pending. Handling another interrupt could cause a crash due
+ * to the QTD and QH state.
+ */
+ dwc2_writel(~hcintmsk, hsotg->regs + HCINT(chan->hc_num));
+
+ /*
+ * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
+ * even if the channel was already halted for some other
+ * reason
+ */
+ chan->halt_status = halt_status;
+
+ hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+ if (!(hcchar & HCCHAR_CHENA)) {
+ /*
+ * The channel is either already halted or it hasn't
+ * started yet. In DMA mode, the transfer may halt if
+ * it finishes normally or a condition occurs that
+ * requires driver intervention. Don't want to halt
+ * the channel again. In either Slave or DMA mode,
+ * it's possible that the transfer has been assigned
+ * to a channel, but not started yet when an URB is
+ * dequeued. Don't want to halt a channel that hasn't
+ * started yet.
+ */
+ return;
+ }
+ }
+ if (chan->halt_pending) {
+ /*
+ * A halt has already been issued for this channel. This might
+ * happen when a transfer is aborted by a higher level in
+ * the stack.
+ */
+ dev_vdbg(hsotg->dev,
+ "*** %s: Channel %d, chan->halt_pending already set ***\n",
+ __func__, chan->hc_num);
+ return;
+ }
+
+ hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+
+ /* No need to set the bit in DDMA for disabling the channel */
+ /* TODO check it everywhere channel is disabled */
+ if (hsotg->core_params->dma_desc_enable <= 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "desc DMA disabled\n");
+ hcchar |= HCCHAR_CHENA;
+ } else {
+ if (dbg_hc(chan))
+ dev_dbg(hsotg->dev, "desc DMA enabled\n");
+ }
+ hcchar |= HCCHAR_CHDIS;
+
+ if (hsotg->core_params->dma_enable <= 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "DMA not enabled\n");
+ hcchar |= HCCHAR_CHENA;
+
+ /* Check for space in the request queue to issue the halt */
+ if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
+ chan->ep_type == USB_ENDPOINT_XFER_BULK) {
+ dev_vdbg(hsotg->dev, "control/bulk\n");
+ nptxsts = dwc2_readl(hsotg->regs + GNPTXSTS);
+ if ((nptxsts & TXSTS_QSPCAVAIL_MASK) == 0) {
+ dev_vdbg(hsotg->dev, "Disabling channel\n");
+ hcchar &= ~HCCHAR_CHENA;
+ }
+ } else {
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "isoc/intr\n");
+ hptxsts = dwc2_readl(hsotg->regs + HPTXSTS);
+ if ((hptxsts & TXSTS_QSPCAVAIL_MASK) == 0 ||
+ hsotg->queuing_high_bandwidth) {
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "Disabling channel\n");
+ hcchar &= ~HCCHAR_CHENA;
+ }
+ }
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "DMA enabled\n");
+ }
+
+ dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+ chan->halt_status = halt_status;
+
+ if (hcchar & HCCHAR_CHENA) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Channel enabled\n");
+ chan->halt_pending = 1;
+ chan->halt_on_queue = 0;
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Channel disabled\n");
+ chan->halt_on_queue = 1;
+ }
+
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+ dev_vdbg(hsotg->dev, " hcchar: 0x%08x\n",
+ hcchar);
+ dev_vdbg(hsotg->dev, " halt_pending: %d\n",
+ chan->halt_pending);
+ dev_vdbg(hsotg->dev, " halt_on_queue: %d\n",
+ chan->halt_on_queue);
+ dev_vdbg(hsotg->dev, " halt_status: %d\n",
+ chan->halt_status);
+ }
+}
+
+/**
+ * dwc2_hc_cleanup() - Clears the transfer state for a host channel
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Identifies the host channel to clean up
+ *
+ * This function is normally called after a transfer is done and the host
+ * channel is being released
+ */
+void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
+{
+ u32 hcintmsk;
+
+ chan->xfer_started = 0;
+
+ list_del_init(&chan->split_order_list_entry);
+
+ /*
+ * Clear channel interrupt enables and any unhandled channel interrupt
+ * conditions
+ */
+ dwc2_writel(0, hsotg->regs + HCINTMSK(chan->hc_num));
+ hcintmsk = 0xffffffff;
+ hcintmsk &= ~HCINTMSK_RESERVED14_31;
+ dwc2_writel(hcintmsk, hsotg->regs + HCINT(chan->hc_num));
+}
+
+/**
+ * dwc2_hc_set_even_odd_frame() - Sets the channel property that indicates in
+ * which frame a periodic transfer should occur
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Identifies the host channel to set up and its properties
+ * @hcchar: Current value of the HCCHAR register for the specified host channel
+ *
+ * This function has no effect on non-periodic transfers
+ */
+static void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, u32 *hcchar)
+{
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ int host_speed;
+ int xfer_ns;
+ int xfer_us;
+ int bytes_in_fifo;
+ u16 fifo_space;
+ u16 frame_number;
+ u16 wire_frame;
+
+ /*
+ * Try to figure out if we're an even or odd frame. If we set
+ * even and the current frame number is even the the transfer
+ * will happen immediately. Similar if both are odd. If one is
+ * even and the other is odd then the transfer will happen when
+ * the frame number ticks.
+ *
+ * There's a bit of a balancing act to get this right.
+ * Sometimes we may want to send data in the current frame (AK
+ * right away). We might want to do this if the frame number
+ * _just_ ticked, but we might also want to do this in order
+ * to continue a split transaction that happened late in a
+ * microframe (so we didn't know to queue the next transfer
+ * until the frame number had ticked). The problem is that we
+ * need a lot of knowledge to know if there's actually still
+ * time to send things or if it would be better to wait until
+ * the next frame.
+ *
+ * We can look at how much time is left in the current frame
+ * and make a guess about whether we'll have time to transfer.
+ * We'll do that.
+ */
+
+ /* Get speed host is running at */
+ host_speed = (chan->speed != USB_SPEED_HIGH &&
+ !chan->do_split) ? chan->speed : USB_SPEED_HIGH;
+
+ /* See how many bytes are in the periodic FIFO right now */
+ fifo_space = (dwc2_readl(hsotg->regs + HPTXSTS) &
+ TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT;
+ bytes_in_fifo = sizeof(u32) *
+ (hsotg->core_params->host_perio_tx_fifo_size -
+ fifo_space);
+
+ /*
+ * Roughly estimate bus time for everything in the periodic
+ * queue + our new transfer. This is "rough" because we're
+ * using a function that makes takes into account IN/OUT
+ * and INT/ISO and we're just slamming in one value for all
+ * transfers. This should be an over-estimate and that should
+ * be OK, but we can probably tighten it.
+ */
+ xfer_ns = usb_calc_bus_time(host_speed, false, false,
+ chan->xfer_len + bytes_in_fifo);
+ xfer_us = NS_TO_US(xfer_ns);
+
+ /* See what frame number we'll be at by the time we finish */
+ frame_number = dwc2_hcd_get_future_frame_number(hsotg, xfer_us);
+
+ /* This is when we were scheduled to be on the wire */
+ wire_frame = dwc2_frame_num_inc(chan->qh->next_active_frame, 1);
+
+ /*
+ * If we'd finish _after_ the frame we're scheduled in then
+ * it's hopeless. Just schedule right away and hope for the
+ * best. Note that it _might_ be wise to call back into the
+ * scheduler to pick a better frame, but this is better than
+ * nothing.
+ */
+ if (dwc2_frame_num_gt(frame_number, wire_frame)) {
+ dwc2_sch_vdbg(hsotg,
+ "QH=%p EO MISS fr=%04x=>%04x (%+d)\n",
+ chan->qh, wire_frame, frame_number,
+ dwc2_frame_num_dec(frame_number,
+ wire_frame));
+ wire_frame = frame_number;
+
+ /*
+ * We picked a different frame number; communicate this
+ * back to the scheduler so it doesn't try to schedule
+ * another in the same frame.
+ *
+ * Remember that next_active_frame is 1 before the wire
+ * frame.
+ */
+ chan->qh->next_active_frame =
+ dwc2_frame_num_dec(frame_number, 1);
+ }
+
+ if (wire_frame & 1)
+ *hcchar |= HCCHAR_ODDFRM;
+ else
+ *hcchar &= ~HCCHAR_ODDFRM;
+ }
+}
+
+static void dwc2_set_pid_isoc(struct dwc2_host_chan *chan)
+{
+ /* Set up the initial PID for the transfer */
+ if (chan->speed == USB_SPEED_HIGH) {
+ if (chan->ep_is_in) {
+ if (chan->multi_count == 1)
+ chan->data_pid_start = DWC2_HC_PID_DATA0;
+ else if (chan->multi_count == 2)
+ chan->data_pid_start = DWC2_HC_PID_DATA1;
+ else
+ chan->data_pid_start = DWC2_HC_PID_DATA2;
+ } else {
+ if (chan->multi_count == 1)
+ chan->data_pid_start = DWC2_HC_PID_DATA0;
+ else
+ chan->data_pid_start = DWC2_HC_PID_MDATA;
+ }
+ } else {
+ chan->data_pid_start = DWC2_HC_PID_DATA0;
+ }
+}
+
+/**
+ * dwc2_hc_write_packet() - Writes a packet into the Tx FIFO associated with
+ * the Host Channel
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * This function should only be called in Slave mode. For a channel associated
+ * with a non-periodic EP, the non-periodic Tx FIFO is written. For a channel
+ * associated with a periodic EP, the periodic Tx FIFO is written.
+ *
+ * Upon return the xfer_buf and xfer_count fields in chan are incremented by
+ * the number of bytes written to the Tx FIFO.
+ */
+static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 i;
+ u32 remaining_count;
+ u32 byte_count;
+ u32 dword_count;
+ u32 __iomem *data_fifo;
+ u32 *data_buf = (u32 *)chan->xfer_buf;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num));
+
+ remaining_count = chan->xfer_len - chan->xfer_count;
+ if (remaining_count > chan->max_packet)
+ byte_count = chan->max_packet;
+ else
+ byte_count = remaining_count;
+
+ dword_count = (byte_count + 3) / 4;
+
+ if (((unsigned long)data_buf & 0x3) == 0) {
+ /* xfer_buf is DWORD aligned */
+ for (i = 0; i < dword_count; i++, data_buf++)
+ dwc2_writel(*data_buf, data_fifo);
+ } else {
+ /* xfer_buf is not DWORD aligned */
+ for (i = 0; i < dword_count; i++, data_buf++) {
+ u32 data = data_buf[0] | data_buf[1] << 8 |
+ data_buf[2] << 16 | data_buf[3] << 24;
+ dwc2_writel(data, data_fifo);
+ }
+ }
+
+ chan->xfer_count += byte_count;
+ chan->xfer_buf += byte_count;
+}
+
+/**
+ * dwc2_hc_do_ping() - Starts a PING transfer
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * This function should only be called in Slave mode. The Do Ping bit is set in
+ * the HCTSIZ register, then the channel is enabled.
+ */
+static void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 hcchar;
+ u32 hctsiz;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+
+ hctsiz = TSIZ_DOPNG;
+ hctsiz |= 1 << TSIZ_PKTCNT_SHIFT;
+ dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+
+ hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+ hcchar |= HCCHAR_CHENA;
+ hcchar &= ~HCCHAR_CHDIS;
+ dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+}
+
+/**
+ * dwc2_hc_start_transfer() - Does the setup for a data transfer for a host
+ * channel and starts the transfer
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel. The xfer_len value
+ * may be reduced to accommodate the max widths of the XferSize and
+ * PktCnt fields in the HCTSIZn register. The multi_count value may be
+ * changed to reflect the final xfer_len value.
+ *
+ * This function may be called in either Slave mode or DMA mode. In Slave mode,
+ * the caller must ensure that there is sufficient space in the request queue
+ * and Tx Data FIFO.
+ *
+ * For an OUT transfer in Slave mode, it loads a data packet into the
+ * appropriate FIFO. If necessary, additional data packets are loaded in the
+ * Host ISR.
+ *
+ * For an IN transfer in Slave mode, a data packet is requested. The data
+ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
+ * additional data packets are requested in the Host ISR.
+ *
+ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
+ * register along with a packet count of 1 and the channel is enabled. This
+ * causes a single PING transaction to occur. Other fields in HCTSIZ are
+ * simply set to 0 since no data transfer occurs in this case.
+ *
+ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
+ * all the information required to perform the subsequent data transfer. In
+ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
+ * controller performs the entire PING protocol, then starts the data
+ * transfer.
+ */
+static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 max_hc_xfer_size = hsotg->core_params->max_transfer_size;
+ u16 max_hc_pkt_count = hsotg->core_params->max_packet_count;
+ u32 hcchar;
+ u32 hctsiz = 0;
+ u16 num_packets;
+ u32 ec_mc;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ if (chan->do_ping) {
+ if (hsotg->core_params->dma_enable <= 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "ping, no DMA\n");
+ dwc2_hc_do_ping(hsotg, chan);
+ chan->xfer_started = 1;
+ return;
+ }
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "ping, DMA\n");
+
+ hctsiz |= TSIZ_DOPNG;
+ }
+
+ if (chan->do_split) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "split\n");
+ num_packets = 1;
+
+ if (chan->complete_split && !chan->ep_is_in)
+ /*
+ * For CSPLIT OUT Transfer, set the size to 0 so the
+ * core doesn't expect any data written to the FIFO
+ */
+ chan->xfer_len = 0;
+ else if (chan->ep_is_in || chan->xfer_len > chan->max_packet)
+ chan->xfer_len = chan->max_packet;
+ else if (!chan->ep_is_in && chan->xfer_len > 188)
+ chan->xfer_len = 188;
+
+ hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
+ TSIZ_XFERSIZE_MASK;
+
+ /* For split set ec_mc for immediate retries */
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ ec_mc = 3;
+ else
+ ec_mc = 1;
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "no split\n");
+ /*
+ * Ensure that the transfer length and packet count will fit
+ * in the widths allocated for them in the HCTSIZn register
+ */
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ /*
+ * Make sure the transfer size is no larger than one
+ * (micro)frame's worth of data. (A check was done
+ * when the periodic transfer was accepted to ensure
+ * that a (micro)frame's worth of data can be
+ * programmed into a channel.)
+ */
+ u32 max_periodic_len =
+ chan->multi_count * chan->max_packet;
+
+ if (chan->xfer_len > max_periodic_len)
+ chan->xfer_len = max_periodic_len;
+ } else if (chan->xfer_len > max_hc_xfer_size) {
+ /*
+ * Make sure that xfer_len is a multiple of max packet
+ * size
+ */
+ chan->xfer_len =
+ max_hc_xfer_size - chan->max_packet + 1;
+ }
+
+ if (chan->xfer_len > 0) {
+ num_packets = (chan->xfer_len + chan->max_packet - 1) /
+ chan->max_packet;
+ if (num_packets > max_hc_pkt_count) {
+ num_packets = max_hc_pkt_count;
+ chan->xfer_len = num_packets * chan->max_packet;
+ }
+ } else {
+ /* Need 1 packet for transfer length of 0 */
+ num_packets = 1;
+ }
+
+ if (chan->ep_is_in)
+ /*
+ * Always program an integral # of max packets for IN
+ * transfers
+ */
+ chan->xfer_len = num_packets * chan->max_packet;
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ /*
+ * Make sure that the multi_count field matches the
+ * actual transfer length
+ */
+ chan->multi_count = num_packets;
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ dwc2_set_pid_isoc(chan);
+
+ hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
+ TSIZ_XFERSIZE_MASK;
+
+ /* The ec_mc gets the multi_count for non-split */
+ ec_mc = chan->multi_count;
+ }
+
+ chan->start_pkt_count = num_packets;
+ hctsiz |= num_packets << TSIZ_PKTCNT_SHIFT & TSIZ_PKTCNT_MASK;
+ hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
+ TSIZ_SC_MC_PID_MASK;
+ dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, "Wrote %08x to HCTSIZ(%d)\n",
+ hctsiz, chan->hc_num);
+
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+ dev_vdbg(hsotg->dev, " Xfer Size: %d\n",
+ (hctsiz & TSIZ_XFERSIZE_MASK) >>
+ TSIZ_XFERSIZE_SHIFT);
+ dev_vdbg(hsotg->dev, " Num Pkts: %d\n",
+ (hctsiz & TSIZ_PKTCNT_MASK) >>
+ TSIZ_PKTCNT_SHIFT);
+ dev_vdbg(hsotg->dev, " Start PID: %d\n",
+ (hctsiz & TSIZ_SC_MC_PID_MASK) >>
+ TSIZ_SC_MC_PID_SHIFT);
+ }
+
+ if (hsotg->core_params->dma_enable > 0) {
+ dwc2_writel((u32)chan->xfer_dma,
+ hsotg->regs + HCDMA(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n",
+ (unsigned long)chan->xfer_dma, chan->hc_num);
+ }
+
+ /* Start the split */
+ if (chan->do_split) {
+ u32 hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chan->hc_num));
+
+ hcsplt |= HCSPLT_SPLTENA;
+ dwc2_writel(hcsplt, hsotg->regs + HCSPLT(chan->hc_num));
+ }
+
+ hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+ hcchar &= ~HCCHAR_MULTICNT_MASK;
+ hcchar |= (ec_mc << HCCHAR_MULTICNT_SHIFT) & HCCHAR_MULTICNT_MASK;
+ dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
+
+ if (hcchar & HCCHAR_CHDIS)
+ dev_warn(hsotg->dev,
+ "%s: chdis set, channel %d, hcchar 0x%08x\n",
+ __func__, chan->hc_num, hcchar);
+
+ /* Set host channel enable after all other setup is complete */
+ hcchar |= HCCHAR_CHENA;
+ hcchar &= ~HCCHAR_CHDIS;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
+ (hcchar & HCCHAR_MULTICNT_MASK) >>
+ HCCHAR_MULTICNT_SHIFT);
+
+ dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
+ chan->hc_num);
+
+ chan->xfer_started = 1;
+ chan->requests++;
+
+ if (hsotg->core_params->dma_enable <= 0 &&
+ !chan->ep_is_in && chan->xfer_len > 0)
+ /* Load OUT packet into the appropriate Tx FIFO */
+ dwc2_hc_write_packet(hsotg, chan);
+}
+
+/**
+ * dwc2_hc_start_transfer_ddma() - Does the setup for a data transfer for a
+ * host channel and starts the transfer in Descriptor DMA mode
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
+ * Sets PID and NTD values. For periodic transfers initializes SCHED_INFO field
+ * with micro-frame bitmap.
+ *
+ * Initializes HCDMA register with descriptor list address and CTD value then
+ * starts the transfer via enabling the channel.
+ */
+void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 hcchar;
+ u32 hctsiz = 0;
+
+ if (chan->do_ping)
+ hctsiz |= TSIZ_DOPNG;
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ dwc2_set_pid_isoc(chan);
+
+ /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
+ hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
+ TSIZ_SC_MC_PID_MASK;
+
+ /* 0 - 1 descriptor, 1 - 2 descriptors, etc */
+ hctsiz |= (chan->ntd - 1) << TSIZ_NTD_SHIFT & TSIZ_NTD_MASK;
+
+ /* Non-zero only for high-speed interrupt endpoints */
+ hctsiz |= chan->schinfo << TSIZ_SCHINFO_SHIFT & TSIZ_SCHINFO_MASK;
+
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+ dev_vdbg(hsotg->dev, " Start PID: %d\n",
+ chan->data_pid_start);
+ dev_vdbg(hsotg->dev, " NTD: %d\n", chan->ntd - 1);
+ }
+
+ dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+
+ dma_sync_single_for_device(hsotg->dev, chan->desc_list_addr,
+ chan->desc_list_sz, DMA_TO_DEVICE);
+
+ dwc2_writel(chan->desc_list_addr, hsotg->regs + HCDMA(chan->hc_num));
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Wrote %pad to HCDMA(%d)\n",
+ &chan->desc_list_addr, chan->hc_num);
+
+ hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+ hcchar &= ~HCCHAR_MULTICNT_MASK;
+ hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
+ HCCHAR_MULTICNT_MASK;
+
+ if (hcchar & HCCHAR_CHDIS)
+ dev_warn(hsotg->dev,
+ "%s: chdis set, channel %d, hcchar 0x%08x\n",
+ __func__, chan->hc_num, hcchar);
+
+ /* Set host channel enable after all other setup is complete */
+ hcchar |= HCCHAR_CHENA;
+ hcchar &= ~HCCHAR_CHDIS;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
+ (hcchar & HCCHAR_MULTICNT_MASK) >>
+ HCCHAR_MULTICNT_SHIFT);
+
+ dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
+ chan->hc_num);
+
+ chan->xfer_started = 1;
+ chan->requests++;
+}
+
+/**
+ * dwc2_hc_continue_transfer() - Continues a data transfer that was started by
+ * a previous call to dwc2_hc_start_transfer()
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * The caller must ensure there is sufficient space in the request queue and Tx
+ * Data FIFO. This function should only be called in Slave mode. In DMA mode,
+ * the controller acts autonomously to complete transfers programmed to a host
+ * channel.
+ *
+ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
+ * if there is any data remaining to be queued. For an IN transfer, another
+ * data packet is always requested. For the SETUP phase of a control transfer,
+ * this function does nothing.
+ *
+ * Return: 1 if a new request is queued, 0 if no more requests are required
+ * for this transfer
+ */
+static int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+
+ if (chan->do_split)
+ /* SPLITs always queue just once per channel */
+ return 0;
+
+ if (chan->data_pid_start == DWC2_HC_PID_SETUP)
+ /* SETUPs are queued only once since they can't be NAK'd */
+ return 0;
+
+ if (chan->ep_is_in) {
+ /*
+ * Always queue another request for other IN transfers. If
+ * back-to-back INs are issued and NAKs are received for both,
+ * the driver may still be processing the first NAK when the
+ * second NAK is received. When the interrupt handler clears
+ * the NAK interrupt for the first NAK, the second NAK will
+ * not be seen. So we can't depend on the NAK interrupt
+ * handler to requeue a NAK'd request. Instead, IN requests
+ * are issued each time this function is called. When the
+ * transfer completes, the extra requests for the channel will
+ * be flushed.
+ */
+ u32 hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+
+ dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
+ hcchar |= HCCHAR_CHENA;
+ hcchar &= ~HCCHAR_CHDIS;
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, " IN xfer: hcchar = 0x%08x\n",
+ hcchar);
+ dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+ chan->requests++;
+ return 1;
+ }
+
+ /* OUT transfers */
+
+ if (chan->xfer_count < chan->xfer_len) {
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ u32 hcchar = dwc2_readl(hsotg->regs +
+ HCCHAR(chan->hc_num));
+
+ dwc2_hc_set_even_odd_frame(hsotg, chan,
+ &hcchar);
+ }
+
+ /* Load OUT packet into the appropriate Tx FIFO */
+ dwc2_hc_write_packet(hsotg, chan);
+ chan->requests++;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * =========================================================================
+ * HCD
+ * =========================================================================
+ */
+
+/*
* Processes all the URBs in a single list of QHs. Completes them with
* -ETIMEDOUT and frees the QTD.
*
@@ -164,6 +1743,9 @@ static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
qtd_list_entry)
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+ if (qh->channel && qh->channel->qh == qh)
+ qh->channel->qh = NULL;
+
spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hcd_qh_free(hsotg, qh);
spin_lock_irqsave(&hsotg->lock, flags);
@@ -554,7 +2136,12 @@ static int dwc2_hcd_endpoint_disable(struct dwc2_hsotg *hsotg,
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
ep->hcpriv = NULL;
+
+ if (qh->channel && qh->channel->qh == qh)
+ qh->channel->qh = NULL;
+
spin_unlock_irqrestore(&hsotg->lock, flags);
+
dwc2_hcd_qh_free(hsotg, qh);
return 0;
@@ -580,6 +2167,224 @@ static int dwc2_hcd_endpoint_reset(struct dwc2_hsotg *hsotg,
return 0;
}
+/**
+ * dwc2_core_init() - Initializes the DWC_otg controller registers and
+ * prepares the core for device mode or host mode operation
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @initial_setup: If true then this is the first init for this instance.
+ */
+static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
+{
+ u32 usbcfg, otgctl;
+ int retval;
+
+ dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
+
+ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+
+ /* Set ULPI External VBUS bit if needed */
+ usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV;
+ if (hsotg->core_params->phy_ulpi_ext_vbus ==
+ DWC2_PHY_ULPI_EXTERNAL_VBUS)
+ usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV;
+
+ /* Set external TS Dline pulsing bit if needed */
+ usbcfg &= ~GUSBCFG_TERMSELDLPULSE;
+ if (hsotg->core_params->ts_dline > 0)
+ usbcfg |= GUSBCFG_TERMSELDLPULSE;
+
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+
+ /*
+ * Reset the Controller
+ *
+ * We only need to reset the controller if this is a re-init.
+ * For the first init we know for sure that earlier code reset us (it
+ * needed to in order to properly detect various parameters).
+ */
+ if (!initial_setup) {
+ retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+ if (retval) {
+ dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
+ __func__);
+ return retval;
+ }
+ }
+
+ /*
+ * This needs to happen in FS mode before any other programming occurs
+ */
+ retval = dwc2_phy_init(hsotg, initial_setup);
+ if (retval)
+ return retval;
+
+ /* Program the GAHBCFG Register */
+ retval = dwc2_gahbcfg_init(hsotg);
+ if (retval)
+ return retval;
+
+ /* Program the GUSBCFG register */
+ dwc2_gusbcfg_init(hsotg);
+
+ /* Program the GOTGCTL register */
+ otgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+ otgctl &= ~GOTGCTL_OTGVER;
+ if (hsotg->core_params->otg_ver > 0)
+ otgctl |= GOTGCTL_OTGVER;
+ dwc2_writel(otgctl, hsotg->regs + GOTGCTL);
+ dev_dbg(hsotg->dev, "OTG VER PARAM: %d\n", hsotg->core_params->otg_ver);
+
+ /* Clear the SRP success bit for FS-I2c */
+ hsotg->srp_success = 0;
+
+ /* Enable common interrupts */
+ dwc2_enable_common_interrupts(hsotg);
+
+ /*
+ * Do device or host initialization based on mode during PCD and
+ * HCD initialization
+ */
+ if (dwc2_is_host_mode(hsotg)) {
+ dev_dbg(hsotg->dev, "Host Mode\n");
+ hsotg->op_state = OTG_STATE_A_HOST;
+ } else {
+ dev_dbg(hsotg->dev, "Device Mode\n");
+ hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+ }
+
+ return 0;
+}
+
+/**
+ * dwc2_core_host_init() - Initializes the DWC_otg controller registers for
+ * Host mode
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * This function flushes the Tx and Rx FIFOs and flushes any entries in the
+ * request queues. Host channels are reset to ensure that they are ready for
+ * performing transfers.
+ */
+static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
+{
+ u32 hcfg, hfir, otgctl;
+
+ dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
+
+ /* Restart the Phy Clock */
+ dwc2_writel(0, hsotg->regs + PCGCTL);
+
+ /* Initialize Host Configuration Register */
+ dwc2_init_fs_ls_pclk_sel(hsotg);
+ if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL) {
+ hcfg = dwc2_readl(hsotg->regs + HCFG);
+ hcfg |= HCFG_FSLSSUPP;
+ dwc2_writel(hcfg, hsotg->regs + HCFG);
+ }
+
+ /*
+ * This bit allows dynamic reloading of the HFIR register during
+ * runtime. This bit needs to be programmed during initial configuration
+ * and its value must not be changed during runtime.
+ */
+ if (hsotg->core_params->reload_ctl > 0) {
+ hfir = dwc2_readl(hsotg->regs + HFIR);
+ hfir |= HFIR_RLDCTRL;
+ dwc2_writel(hfir, hsotg->regs + HFIR);
+ }
+
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ u32 op_mode = hsotg->hw_params.op_mode;
+
+ if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a ||
+ !hsotg->hw_params.dma_desc_enable ||
+ op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE ||
+ op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE ||
+ op_mode == GHWCFG2_OP_MODE_UNDEFINED) {
+ dev_err(hsotg->dev,
+ "Hardware does not support descriptor DMA mode -\n");
+ dev_err(hsotg->dev,
+ "falling back to buffer DMA mode.\n");
+ hsotg->core_params->dma_desc_enable = 0;
+ } else {
+ hcfg = dwc2_readl(hsotg->regs + HCFG);
+ hcfg |= HCFG_DESCDMA;
+ dwc2_writel(hcfg, hsotg->regs + HCFG);
+ }
+ }
+
+ /* Configure data FIFO sizes */
+ dwc2_config_fifos(hsotg);
+
+ /* TODO - check this */
+ /* Clear Host Set HNP Enable in the OTG Control Register */
+ otgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+ otgctl &= ~GOTGCTL_HSTSETHNPEN;
+ dwc2_writel(otgctl, hsotg->regs + GOTGCTL);
+
+ /* Make sure the FIFOs are flushed */
+ dwc2_flush_tx_fifo(hsotg, 0x10 /* all TX FIFOs */);
+ dwc2_flush_rx_fifo(hsotg);
+
+ /* Clear Host Set HNP Enable in the OTG Control Register */
+ otgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+ otgctl &= ~GOTGCTL_HSTSETHNPEN;
+ dwc2_writel(otgctl, hsotg->regs + GOTGCTL);
+
+ if (hsotg->core_params->dma_desc_enable <= 0) {
+ int num_channels, i;
+ u32 hcchar;
+
+ /* Flush out any leftover queued requests */
+ num_channels = hsotg->core_params->host_channels;
+ for (i = 0; i < num_channels; i++) {
+ hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
+ hcchar &= ~HCCHAR_CHENA;
+ hcchar |= HCCHAR_CHDIS;
+ hcchar &= ~HCCHAR_EPDIR;
+ dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
+ }
+
+ /* Halt all channels to put them into a known state */
+ for (i = 0; i < num_channels; i++) {
+ int count = 0;
+
+ hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
+ hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS;
+ hcchar &= ~HCCHAR_EPDIR;
+ dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
+ dev_dbg(hsotg->dev, "%s: Halt channel %d\n",
+ __func__, i);
+ do {
+ hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
+ if (++count > 1000) {
+ dev_err(hsotg->dev,
+ "Unable to clear enable on channel %d\n",
+ i);
+ break;
+ }
+ udelay(1);
+ } while (hcchar & HCCHAR_CHENA);
+ }
+ }
+
+ /* Turn on the vbus power */
+ dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state);
+ if (hsotg->op_state == OTG_STATE_A_HOST) {
+ u32 hprt0 = dwc2_read_hprt0(hsotg);
+
+ dev_dbg(hsotg->dev, "Init: Power Port (%d)\n",
+ !!(hprt0 & HPRT0_PWR));
+ if (!(hprt0 & HPRT0_PWR)) {
+ hprt0 |= HPRT0_PWR;
+ dwc2_writel(hprt0, hsotg->regs + HPRT0);
+ }
+ }
+
+ dwc2_enable_host_interrupts(hsotg);
+}
+
/*
* Initializes dynamic portions of the DWC_otg HCD state
*
@@ -635,9 +2440,9 @@ static void dwc2_hc_init_split(struct dwc2_hsotg *hsotg,
chan->hub_port = (u8)hub_port;
}
-static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
- struct dwc2_host_chan *chan,
- struct dwc2_qtd *qtd, void *bufptr)
+static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ struct dwc2_qtd *qtd)
{
struct dwc2_hcd_urb *urb = qtd->urb;
struct dwc2_hcd_iso_packet_desc *frame_desc;
@@ -657,7 +2462,6 @@ static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
else
chan->xfer_buf = urb->setup_packet;
chan->xfer_len = 8;
- bufptr = NULL;
break;
case DWC2_CONTROL_DATA:
@@ -684,7 +2488,6 @@ static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
chan->xfer_dma = hsotg->status_buf_dma;
else
chan->xfer_buf = hsotg->status_buf;
- bufptr = NULL;
break;
}
break;
@@ -717,14 +2520,6 @@ static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
chan->xfer_len = frame_desc->length - qtd->isoc_split_offset;
- /* For non-dword aligned buffers */
- if (hsotg->core_params->dma_enable > 0 &&
- (chan->xfer_dma & 0x3))
- bufptr = (u8 *)urb->buf + frame_desc->offset +
- qtd->isoc_split_offset;
- else
- bufptr = NULL;
-
if (chan->xact_pos == DWC2_HCSPLT_XACTPOS_ALL) {
if (chan->xfer_len <= 188)
chan->xact_pos = DWC2_HCSPLT_XACTPOS_ALL;
@@ -733,63 +2528,93 @@ static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
}
break;
}
+}
+
+#define DWC2_USB_DMA_ALIGN 4
+
+struct dma_aligned_buffer {
+ void *kmalloc_ptr;
+ void *old_xfer_buffer;
+ u8 data[0];
+};
+
+static void dwc2_free_dma_aligned_buffer(struct urb *urb)
+{
+ struct dma_aligned_buffer *temp;
+
+ if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
+ return;
- return bufptr;
+ temp = container_of(urb->transfer_buffer,
+ struct dma_aligned_buffer, data);
+
+ if (usb_urb_dir_in(urb))
+ memcpy(temp->old_xfer_buffer, temp->data,
+ urb->transfer_buffer_length);
+ urb->transfer_buffer = temp->old_xfer_buffer;
+ kfree(temp->kmalloc_ptr);
+
+ urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
}
-static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
- struct dwc2_host_chan *chan,
- struct dwc2_hcd_urb *urb, void *bufptr)
+static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
{
- u32 buf_size;
- struct urb *usb_urb;
- struct usb_hcd *hcd;
+ struct dma_aligned_buffer *temp, *kmalloc_ptr;
+ size_t kmalloc_size;
- if (!qh->dw_align_buf) {
- if (chan->ep_type != USB_ENDPOINT_XFER_ISOC)
- buf_size = hsotg->core_params->max_transfer_size;
- else
- /* 3072 = 3 max-size Isoc packets */
- buf_size = 3072;
+ if (urb->num_sgs || urb->sg ||
+ urb->transfer_buffer_length == 0 ||
+ !((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1)))
+ return 0;
- qh->dw_align_buf = kmalloc(buf_size, GFP_ATOMIC | GFP_DMA);
- if (!qh->dw_align_buf)
- return -ENOMEM;
- qh->dw_align_buf_size = buf_size;
- }
+ /* Allocate a buffer with enough padding for alignment */
+ kmalloc_size = urb->transfer_buffer_length +
+ sizeof(struct dma_aligned_buffer) + DWC2_USB_DMA_ALIGN - 1;
- if (chan->xfer_len) {
- dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
- usb_urb = urb->priv;
+ kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
+ if (!kmalloc_ptr)
+ return -ENOMEM;
- if (usb_urb) {
- if (usb_urb->transfer_flags &
- (URB_SETUP_MAP_SINGLE | URB_DMA_MAP_SG |
- URB_DMA_MAP_PAGE | URB_DMA_MAP_SINGLE)) {
- hcd = dwc2_hsotg_to_hcd(hsotg);
- usb_hcd_unmap_urb_for_dma(hcd, usb_urb);
- }
- if (!chan->ep_is_in)
- memcpy(qh->dw_align_buf, bufptr,
- chan->xfer_len);
- } else {
- dev_warn(hsotg->dev, "no URB in dwc2_urb\n");
- }
- }
+ /* Position our struct dma_aligned_buffer such that data is aligned */
+ temp = PTR_ALIGN(kmalloc_ptr + 1, DWC2_USB_DMA_ALIGN) - 1;
+ temp->kmalloc_ptr = kmalloc_ptr;
+ temp->old_xfer_buffer = urb->transfer_buffer;
+ if (usb_urb_dir_out(urb))
+ memcpy(temp->data, urb->transfer_buffer,
+ urb->transfer_buffer_length);
+ urb->transfer_buffer = temp->data;
- qh->dw_align_buf_dma = dma_map_single(hsotg->dev,
- qh->dw_align_buf, qh->dw_align_buf_size,
- chan->ep_is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (dma_mapping_error(hsotg->dev, qh->dw_align_buf_dma)) {
- dev_err(hsotg->dev, "can't map align_buf\n");
- chan->align_buf = 0;
- return -EINVAL;
- }
+ urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
- chan->align_buf = qh->dw_align_buf_dma;
return 0;
}
+static int dwc2_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ int ret;
+
+ /* We assume setup_dma is always aligned; warn if not */
+ WARN_ON_ONCE(urb->setup_dma &&
+ (urb->setup_dma & (DWC2_USB_DMA_ALIGN - 1)));
+
+ ret = dwc2_alloc_dma_aligned_buffer(urb, mem_flags);
+ if (ret)
+ return ret;
+
+ ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+ if (ret)
+ dwc2_free_dma_aligned_buffer(urb);
+
+ return ret;
+}
+
+static void dwc2_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+ dwc2_free_dma_aligned_buffer(urb);
+}
+
/**
* dwc2_assign_and_init_hc() - Assigns transactions from a QTD to a free host
* channel and initializes the host channel to perform the transactions. The
@@ -804,7 +2629,6 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
struct dwc2_host_chan *chan;
struct dwc2_hcd_urb *urb;
struct dwc2_qtd *qtd;
- void *bufptr = NULL;
if (dbg_qh(qh))
dev_vdbg(hsotg->dev, "%s(%p,%p)\n", __func__, hsotg, qh);
@@ -866,16 +2690,10 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
!dwc2_hcd_is_pipe_in(&urb->pipe_info))
urb->actual_length = urb->length;
- if (hsotg->core_params->dma_enable > 0) {
+ if (hsotg->core_params->dma_enable > 0)
chan->xfer_dma = urb->dma + urb->actual_length;
-
- /* For non-dword aligned case */
- if (hsotg->core_params->dma_desc_enable <= 0 &&
- (chan->xfer_dma & 0x3))
- bufptr = (u8 *)urb->buf + urb->actual_length;
- } else {
+ else
chan->xfer_buf = (u8 *)urb->buf + urb->actual_length;
- }
chan->xfer_len = urb->length - urb->actual_length;
chan->xfer_count = 0;
@@ -887,27 +2705,7 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
chan->do_split = 0;
/* Set the transfer attributes */
- bufptr = dwc2_hc_init_xfer(hsotg, chan, qtd, bufptr);
-
- /* Non DWORD-aligned buffer case */
- if (bufptr) {
- dev_vdbg(hsotg->dev, "Non-aligned buffer\n");
- if (dwc2_hc_setup_align_buf(hsotg, qh, chan, urb, bufptr)) {
- dev_err(hsotg->dev,
- "%s: Failed to allocate memory to handle non-dword aligned buffer\n",
- __func__);
- /* Add channel back to free list */
- chan->align_buf = 0;
- chan->multi_count = 0;
- list_add_tail(&chan->hc_list_entry,
- &hsotg->free_hc_list);
- qtd->in_process = 0;
- qh->channel = NULL;
- return -ENOMEM;
- }
- } else {
- chan->align_buf = 0;
- }
+ dwc2_hc_init_xfer(hsotg, chan, qtd);
if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
chan->ep_type == USB_ENDPOINT_XFER_ISOC)
@@ -968,7 +2766,8 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions(
* periodic assigned schedule
*/
qh_ptr = qh_ptr->next;
- list_move(&qh->qh_list_entry, &hsotg->periodic_sched_assigned);
+ list_move_tail(&qh->qh_list_entry,
+ &hsotg->periodic_sched_assigned);
ret_val = DWC2_TRANSACTION_PERIODIC;
}
@@ -1001,8 +2800,8 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions(
* non-periodic active schedule
*/
qh_ptr = qh_ptr->next;
- list_move(&qh->qh_list_entry,
- &hsotg->non_periodic_sched_active);
+ list_move_tail(&qh->qh_list_entry,
+ &hsotg->non_periodic_sched_active);
if (ret_val == DWC2_TRANSACTION_NONE)
ret_val = DWC2_TRANSACTION_NON_PERIODIC;
@@ -1043,6 +2842,11 @@ static int dwc2_queue_transaction(struct dwc2_hsotg *hsotg,
{
int retval = 0;
+ if (chan->do_split)
+ /* Put ourselves on the list to keep order straight */
+ list_move_tail(&chan->split_order_list_entry,
+ &hsotg->split_order);
+
if (hsotg->core_params->dma_enable > 0) {
if (hsotg->core_params->dma_desc_enable > 0) {
if (!chan->xfer_started ||
@@ -1102,10 +2906,14 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
u32 fspcavail;
u32 gintmsk;
int status;
- int no_queue_space = 0;
- int no_fifo_space = 0;
+ bool no_queue_space = false;
+ bool no_fifo_space = false;
u32 qspcavail;
+ /* If empty list then just adjust interrupt enables */
+ if (list_empty(&hsotg->periodic_sched_assigned))
+ goto exit;
+
if (dbg_perio())
dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
@@ -1175,50 +2983,40 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
* Move the QH from the periodic assigned schedule to
* the periodic queued schedule
*/
- list_move(&qh->qh_list_entry,
- &hsotg->periodic_sched_queued);
+ list_move_tail(&qh->qh_list_entry,
+ &hsotg->periodic_sched_queued);
/* done queuing high bandwidth */
hsotg->queuing_high_bandwidth = 0;
}
}
- if (hsotg->core_params->dma_enable <= 0) {
- tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
- qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
- TXSTS_QSPCAVAIL_SHIFT;
- fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
- TXSTS_FSPCAVAIL_SHIFT;
- if (dbg_perio()) {
- dev_vdbg(hsotg->dev,
- " P Tx Req Queue Space Avail (after queue): %d\n",
- qspcavail);
- dev_vdbg(hsotg->dev,
- " P Tx FIFO Space Avail (after queue): %d\n",
- fspcavail);
- }
-
- if (!list_empty(&hsotg->periodic_sched_assigned) ||
- no_queue_space || no_fifo_space) {
- /*
- * May need to queue more transactions as the request
- * queue or Tx FIFO empties. Enable the periodic Tx
- * FIFO empty interrupt. (Always use the half-empty
- * level to ensure that new requests are loaded as
- * soon as possible.)
- */
- gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+exit:
+ if (no_queue_space || no_fifo_space ||
+ (hsotg->core_params->dma_enable <= 0 &&
+ !list_empty(&hsotg->periodic_sched_assigned))) {
+ /*
+ * May need to queue more transactions as the request
+ * queue or Tx FIFO empties. Enable the periodic Tx
+ * FIFO empty interrupt. (Always use the half-empty
+ * level to ensure that new requests are loaded as
+ * soon as possible.)
+ */
+ gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+ if (!(gintmsk & GINTSTS_PTXFEMP)) {
gintmsk |= GINTSTS_PTXFEMP;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
- } else {
- /*
- * Disable the Tx FIFO empty interrupt since there are
- * no more transactions that need to be queued right
- * now. This function is called from interrupt
- * handlers to queue more transactions as transfer
- * states change.
- */
- gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+ }
+ } else {
+ /*
+ * Disable the Tx FIFO empty interrupt since there are
+ * no more transactions that need to be queued right
+ * now. This function is called from interrupt
+ * handlers to queue more transactions as transfer
+ * states change.
+ */
+ gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+ if (gintmsk & GINTSTS_PTXFEMP) {
gintmsk &= ~GINTSTS_PTXFEMP;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
}
@@ -1365,9 +3163,8 @@ void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
dev_vdbg(hsotg->dev, "Queue Transactions\n");
#endif
/* Process host channels associated with periodic transfers */
- if ((tr_type == DWC2_TRANSACTION_PERIODIC ||
- tr_type == DWC2_TRANSACTION_ALL) &&
- !list_empty(&hsotg->periodic_sched_assigned))
+ if (tr_type == DWC2_TRANSACTION_PERIODIC ||
+ tr_type == DWC2_TRANSACTION_ALL)
dwc2_process_periodic_channels(hsotg);
/* Process host channels associated with non-periodic transfers */
@@ -1947,6 +3744,35 @@ int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
return (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
}
+int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us)
+{
+ u32 hprt = dwc2_readl(hsotg->regs + HPRT0);
+ u32 hfir = dwc2_readl(hsotg->regs + HFIR);
+ u32 hfnum = dwc2_readl(hsotg->regs + HFNUM);
+ unsigned int us_per_frame;
+ unsigned int frame_number;
+ unsigned int remaining;
+ unsigned int interval;
+ unsigned int phy_clks;
+
+ /* High speed has 125 us per (micro) frame; others are 1 ms per */
+ us_per_frame = (hprt & HPRT0_SPD_MASK) ? 1000 : 125;
+
+ /* Extract fields */
+ frame_number = (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
+ remaining = (hfnum & HFNUM_FRREM_MASK) >> HFNUM_FRREM_SHIFT;
+ interval = (hfir & HFIR_FRINT_MASK) >> HFIR_FRINT_SHIFT;
+
+ /*
+ * Number of phy clocks since the last tick of the frame number after
+ * "us" has passed.
+ */
+ phy_clks = (interval - remaining) +
+ DIV_ROUND_UP(interval * us, us_per_frame);
+
+ return dwc2_frame_num_inc(frame_number, phy_clks / interval);
+}
+
int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg)
{
return hsotg->op_state == OTG_STATE_B_HOST;
@@ -2223,6 +4049,90 @@ void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context, int *hub_addr,
*hub_port = urb->dev->ttport;
}
+/**
+ * dwc2_host_get_tt_info() - Get the dwc2_tt associated with context
+ *
+ * This will get the dwc2_tt structure (and ttport) associated with the given
+ * context (which is really just a struct urb pointer).
+ *
+ * The first time this is called for a given TT we allocate memory for our
+ * structure. When everyone is done and has called dwc2_host_put_tt_info()
+ * then the refcount for the structure will go to 0 and we'll free it.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: The QH structure.
+ * @context: The priv pointer from a struct dwc2_hcd_urb.
+ * @mem_flags: Flags for allocating memory.
+ * @ttport: We'll return this device's port number here. That's used to
+ * reference into the bitmap if we're on a multi_tt hub.
+ *
+ * Return: a pointer to a struct dwc2_tt. Don't forget to call
+ * dwc2_host_put_tt_info()! Returns NULL upon memory alloc failure.
+ */
+
+struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, void *context,
+ gfp_t mem_flags, int *ttport)
+{
+ struct urb *urb = context;
+ struct dwc2_tt *dwc_tt = NULL;
+
+ if (urb->dev->tt) {
+ *ttport = urb->dev->ttport;
+
+ dwc_tt = urb->dev->tt->hcpriv;
+ if (dwc_tt == NULL) {
+ size_t bitmap_size;
+
+ /*
+ * For single_tt we need one schedule. For multi_tt
+ * we need one per port.
+ */
+ bitmap_size = DWC2_ELEMENTS_PER_LS_BITMAP *
+ sizeof(dwc_tt->periodic_bitmaps[0]);
+ if (urb->dev->tt->multi)
+ bitmap_size *= urb->dev->tt->hub->maxchild;
+
+ dwc_tt = kzalloc(sizeof(*dwc_tt) + bitmap_size,
+ mem_flags);
+ if (dwc_tt == NULL)
+ return NULL;
+
+ dwc_tt->usb_tt = urb->dev->tt;
+ dwc_tt->usb_tt->hcpriv = dwc_tt;
+ }
+
+ dwc_tt->refcount++;
+ }
+
+ return dwc_tt;
+}
+
+/**
+ * dwc2_host_put_tt_info() - Put the dwc2_tt from dwc2_host_get_tt_info()
+ *
+ * Frees resources allocated by dwc2_host_get_tt_info() if all current holders
+ * of the structure are done.
+ *
+ * It's OK to call this with NULL.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @dwc_tt: The pointer returned by dwc2_host_get_tt_info.
+ */
+void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg, struct dwc2_tt *dwc_tt)
+{
+ /* Model kfree and make put of NULL a no-op */
+ if (dwc_tt == NULL)
+ return;
+
+ WARN_ON(dwc_tt->refcount < 1);
+
+ dwc_tt->refcount--;
+ if (!dwc_tt->refcount) {
+ dwc_tt->usb_tt->hcpriv = NULL;
+ kfree(dwc_tt);
+ }
+}
+
int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context)
{
struct urb *urb = context;
@@ -2334,9 +4244,7 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
kfree(qtd->urb);
qtd->urb = NULL;
- spin_unlock(&hsotg->lock);
usb_hcd_giveback_urb(dwc2_hsotg_to_hcd(hsotg), urb, status);
- spin_lock(&hsotg->lock);
}
/*
@@ -2789,6 +4697,8 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
fail3:
dwc2_urb->priv = NULL;
usb_hcd_unlink_urb_from_ep(hcd, urb);
+ if (qh_allocated && qh->channel && qh->channel->qh == qh)
+ qh->channel->qh = NULL;
fail2:
spin_unlock_irqrestore(&hsotg->lock, flags);
urb->hcpriv = NULL;
@@ -2955,7 +4865,7 @@ static struct hc_driver dwc2_hc_driver = {
.hcd_priv_size = sizeof(struct wrapper_priv_data),
.irq = _dwc2_hcd_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
.start = _dwc2_hcd_start,
.stop = _dwc2_hcd_stop,
@@ -2971,6 +4881,9 @@ static struct hc_driver dwc2_hc_driver = {
.bus_suspend = _dwc2_hcd_suspend,
.bus_resume = _dwc2_hcd_resume,
+
+ .map_urb_for_dma = dwc2_map_urb_for_dma,
+ .unmap_urb_for_dma = dwc2_unmap_urb_for_dma,
};
/*
@@ -3081,8 +4994,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
FRAME_NUM_ARRAY_SIZE, GFP_KERNEL);
if (!hsotg->last_frame_num_array)
goto error1;
- hsotg->last_frame_num = HFNUM_MAX_FRNUM;
#endif
+ hsotg->last_frame_num = HFNUM_MAX_FRNUM;
/* Check if the bus driver or platform code has setup a dma_mask */
if (hsotg->core_params->dma_enable > 0 &&
@@ -3146,6 +5059,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
INIT_LIST_HEAD(&hsotg->periodic_sched_assigned);
INIT_LIST_HEAD(&hsotg->periodic_sched_queued);
+ INIT_LIST_HEAD(&hsotg->split_order);
+
/*
* Create a host channel descriptor for each host channel implemented
* in the controller. Initialize the channel descriptor array.
@@ -3159,12 +5074,10 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
if (channel == NULL)
goto error3;
channel->hc_num = i;
+ INIT_LIST_HEAD(&channel->split_order_list_entry);
hsotg->hc_ptr_array[i] = channel;
}
- if (hsotg->core_params->uframe_sched > 0)
- dwc2_hcd_init_usecs(hsotg);
-
/* Initialize hsotg start work */
INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func);
@@ -3317,3 +5230,67 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
kfree(hsotg->frame_num_array);
#endif
}
+
+/**
+ * dwc2_backup_host_registers() - Backup controller host registers.
+ * When suspending usb bus, registers needs to be backuped
+ * if controller power is disabled once suspended.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_hregs_backup *hr;
+ int i;
+
+ dev_dbg(hsotg->dev, "%s\n", __func__);
+
+ /* Backup Host regs */
+ hr = &hsotg->hr_backup;
+ hr->hcfg = dwc2_readl(hsotg->regs + HCFG);
+ hr->haintmsk = dwc2_readl(hsotg->regs + HAINTMSK);
+ for (i = 0; i < hsotg->core_params->host_channels; ++i)
+ hr->hcintmsk[i] = dwc2_readl(hsotg->regs + HCINTMSK(i));
+
+ hr->hprt0 = dwc2_read_hprt0(hsotg);
+ hr->hfir = dwc2_readl(hsotg->regs + HFIR);
+ hr->valid = true;
+
+ return 0;
+}
+
+/**
+ * dwc2_restore_host_registers() - Restore controller host registers.
+ * When resuming usb bus, device registers needs to be restored
+ * if controller power were disabled.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_hregs_backup *hr;
+ int i;
+
+ dev_dbg(hsotg->dev, "%s\n", __func__);
+
+ /* Restore host regs */
+ hr = &hsotg->hr_backup;
+ if (!hr->valid) {
+ dev_err(hsotg->dev, "%s: no host registers to restore\n",
+ __func__);
+ return -EINVAL;
+ }
+ hr->valid = false;
+
+ dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
+ dwc2_writel(hr->haintmsk, hsotg->regs + HAINTMSK);
+
+ for (i = 0; i < hsotg->core_params->host_channels; ++i)
+ dwc2_writel(hr->hcintmsk[i], hsotg->regs + HCINTMSK(i));
+
+ dwc2_writel(hr->hprt0, hsotg->regs + HPRT0);
+ dwc2_writel(hr->hfir, hsotg->regs + HFIR);
+ hsotg->frame_number = 0;
+
+ return 0;
+}
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index 8f0a29cefdf7..89fa26cb25f4 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -75,8 +75,6 @@ struct dwc2_qh;
* (micro)frame
* @xfer_buf: Pointer to current transfer buffer position
* @xfer_dma: DMA address of xfer_buf
- * @align_buf: In Buffer DMA mode this will be used if xfer_buf is not
- * DWORD aligned
* @xfer_len: Total number of bytes to transfer
* @xfer_count: Number of bytes transferred so far
* @start_pkt_count: Packet count at start of transfer
@@ -108,6 +106,7 @@ struct dwc2_qh;
* @hc_list_entry: For linking to list of host channels
* @desc_list_addr: Current QH's descriptor list DMA address
* @desc_list_sz: Current QH's descriptor list size
+ * @split_order_list_entry: List entry for keeping track of the order of splits
*
* This structure represents the state of a single host channel when acting in
* host mode. It contains the data items needed to transfer packets to an
@@ -133,7 +132,6 @@ struct dwc2_host_chan {
u8 *xfer_buf;
dma_addr_t xfer_dma;
- dma_addr_t align_buf;
u32 xfer_len;
u32 xfer_count;
u16 start_pkt_count;
@@ -161,6 +159,7 @@ struct dwc2_host_chan {
struct list_head hc_list_entry;
dma_addr_t desc_list_addr;
u32 desc_list_sz;
+ struct list_head split_order_list_entry;
};
struct dwc2_hcd_pipe_info {
@@ -213,9 +212,47 @@ enum dwc2_transaction_type {
DWC2_TRANSACTION_ALL,
};
+/* The number of elements per LS bitmap (per port on multi_tt) */
+#define DWC2_ELEMENTS_PER_LS_BITMAP DIV_ROUND_UP(DWC2_LS_SCHEDULE_SLICES, \
+ BITS_PER_LONG)
+
+/**
+ * struct dwc2_tt - dwc2 data associated with a usb_tt
+ *
+ * @refcount: Number of Queue Heads (QHs) holding a reference.
+ * @usb_tt: Pointer back to the official usb_tt.
+ * @periodic_bitmaps: Bitmap for which parts of the 1ms frame are accounted
+ * for already. Each is DWC2_ELEMENTS_PER_LS_BITMAP
+ * elements (so sizeof(long) times that in bytes).
+ *
+ * This structure is stored in the hcpriv of the official usb_tt.
+ */
+struct dwc2_tt {
+ int refcount;
+ struct usb_tt *usb_tt;
+ unsigned long periodic_bitmaps[];
+};
+
+/**
+ * struct dwc2_hs_transfer_time - Info about a transfer on the high speed bus.
+ *
+ * @start_schedule_usecs: The start time on the main bus schedule. Note that
+ * the main bus schedule is tightly packed and this
+ * time should be interpreted as tightly packed (so
+ * uFrame 0 starts at 0 us, uFrame 1 starts at 100 us
+ * instead of 125 us).
+ * @duration_us: How long this transfer goes.
+ */
+
+struct dwc2_hs_transfer_time {
+ u32 start_schedule_us;
+ u16 duration_us;
+};
+
/**
* struct dwc2_qh - Software queue head structure
*
+ * @hsotg: The HCD state structure for the DWC OTG controller
* @ep_type: Endpoint type. One of the following values:
* - USB_ENDPOINT_XFER_CONTROL
* - USB_ENDPOINT_XFER_BULK
@@ -236,17 +273,35 @@ enum dwc2_transaction_type {
* @do_split: Full/low speed endpoint on high-speed hub requires split
* @td_first: Index of first activated isochronous transfer descriptor
* @td_last: Index of last activated isochronous transfer descriptor
- * @usecs: Bandwidth in microseconds per (micro)frame
- * @interval: Interval between transfers in (micro)frames
- * @sched_frame: (Micro)frame to initialize a periodic transfer.
- * The transfer executes in the following (micro)frame.
- * @frame_usecs: Internal variable used by the microframe scheduler
- * @start_split_frame: (Micro)frame at which last start split was initialized
+ * @host_us: Bandwidth in microseconds per transfer as seen by host
+ * @device_us: Bandwidth in microseconds per transfer as seen by device
+ * @host_interval: Interval between transfers as seen by the host. If
+ * the host is high speed and the device is low speed this
+ * will be 8 times device interval.
+ * @device_interval: Interval between transfers as seen by the device.
+ * interval.
+ * @next_active_frame: (Micro)frame _before_ we next need to put something on
+ * the bus. We'll move the qh to active here. If the
+ * host is in high speed mode this will be a uframe. If
+ * the host is in low speed mode this will be a full frame.
+ * @start_active_frame: If we are partway through a split transfer, this will be
+ * what next_active_frame was when we started. Otherwise
+ * it should always be the same as next_active_frame.
+ * @num_hs_transfers: Number of transfers in hs_transfers.
+ * Normally this is 1 but can be more than one for splits.
+ * Always >= 1 unless the host is in low/full speed mode.
+ * @hs_transfers: Transfers that are scheduled as seen by the high speed
+ * bus. Not used if host is in low or full speed mode (but
+ * note that it IS USED if the device is low or full speed
+ * as long as the HOST is in high speed mode).
+ * @ls_start_schedule_slice: Start time (in slices) on the low speed bus
+ * schedule that's being used by this device. This
+ * will be on the periodic_bitmap in a
+ * "struct dwc2_tt". Not used if this device is high
+ * speed. Note that this is in "schedule slice" which
+ * is tightly packed.
+ * @ls_duration_us: Duration on the low speed bus schedule.
* @ntd: Actual number of transfer descriptors in a list
- * @dw_align_buf: Used instead of original buffer if its physical address
- * is not dword-aligned
- * @dw_align_buf_size: Size of dw_align_buf
- * @dw_align_buf_dma: DMA address for dw_align_buf
* @qtd_list: List of QTDs for this QH
* @channel: Host channel currently processing transfers for this QH
* @qh_list_entry: Entry for QH in either the periodic or non-periodic
@@ -257,13 +312,20 @@ enum dwc2_transaction_type {
* @n_bytes: Xfer Bytes array. Each element corresponds to a transfer
* descriptor and indicates original XferSize value for the
* descriptor
+ * @unreserve_timer: Timer for releasing periodic reservation.
+ * @dwc2_tt: Pointer to our tt info (or NULL if no tt).
+ * @ttport: Port number within our tt.
* @tt_buffer_dirty True if clear_tt_buffer_complete is pending
+ * @unreserve_pending: True if we planned to unreserve but haven't yet.
+ * @schedule_low_speed: True if we have a low/full speed component (either the
+ * host is in low/full speed mode or do_split).
*
* A Queue Head (QH) holds the static characteristics of an endpoint and
* maintains a list of transfers (QTDs) for that endpoint. A QH structure may
* be entered in either the non-periodic or periodic schedule.
*/
struct dwc2_qh {
+ struct dwc2_hsotg *hsotg;
u8 ep_type;
u8 ep_is_in;
u16 maxp;
@@ -273,15 +335,16 @@ struct dwc2_qh {
u8 do_split;
u8 td_first;
u8 td_last;
- u16 usecs;
- u16 interval;
- u16 sched_frame;
- u16 frame_usecs[8];
- u16 start_split_frame;
+ u16 host_us;
+ u16 device_us;
+ u16 host_interval;
+ u16 device_interval;
+ u16 next_active_frame;
+ u16 start_active_frame;
+ s16 num_hs_transfers;
+ struct dwc2_hs_transfer_time hs_transfers[DWC2_HS_SCHEDULE_UFRAMES];
+ u32 ls_start_schedule_slice;
u16 ntd;
- u8 *dw_align_buf;
- int dw_align_buf_size;
- dma_addr_t dw_align_buf_dma;
struct list_head qtd_list;
struct dwc2_host_chan *channel;
struct list_head qh_list_entry;
@@ -289,7 +352,12 @@ struct dwc2_qh {
dma_addr_t desc_list_dma;
u32 desc_list_sz;
u32 *n_bytes;
+ struct timer_list unreserve_timer;
+ struct dwc2_tt *dwc_tt;
+ int ttport;
unsigned tt_buffer_dirty:1;
+ unsigned unreserve_pending:1;
+ unsigned schedule_low_speed:1;
};
/**
@@ -362,6 +430,8 @@ struct hc_xfer_info {
};
#endif
+u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg);
+
/* Gets the struct usb_hcd that contains a struct dwc2_hsotg */
static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
{
@@ -383,6 +453,12 @@ static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
dwc2_writel(mask, hsotg->regs + HCINTMSK(chnum));
}
+void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
+void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
+ enum dwc2_halt_status halt_status);
+void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan);
+
/*
* Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they
* are read as 1, they won't clear when written back.
@@ -456,7 +532,6 @@ extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
/* Schedule Queue Functions */
/* Implemented in hcd_queue.c */
-extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg);
extern struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
struct dwc2_hcd_urb *urb,
gfp_t mem_flags);
@@ -571,6 +646,11 @@ static inline u16 dwc2_frame_num_inc(u16 frame, u16 inc)
return (frame + inc) & HFNUM_MAX_FRNUM;
}
+static inline u16 dwc2_frame_num_dec(u16 frame, u16 dec)
+{
+ return (frame + HFNUM_MAX_FRNUM + 1 - dec) & HFNUM_MAX_FRNUM;
+}
+
static inline u16 dwc2_full_frame_num(u16 frame)
{
return (frame & HFNUM_MAX_FRNUM) >> 3;
@@ -648,7 +728,7 @@ static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg,
return 0;
}
- return qh->usecs;
+ return qh->host_us;
}
extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
@@ -717,6 +797,12 @@ extern void dwc2_host_start(struct dwc2_hsotg *hsotg);
extern void dwc2_host_disconnect(struct dwc2_hsotg *hsotg);
extern void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context,
int *hub_addr, int *hub_port);
+extern struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg,
+ void *context, gfp_t mem_flags,
+ int *ttport);
+
+extern void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg,
+ struct dwc2_tt *dwc_tt);
extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
int status);
@@ -739,7 +825,7 @@ do { \
_qtd_ = list_entry((_qh_)->qtd_list.next, struct dwc2_qtd, \
qtd_list_entry); \
if (usb_pipeint(_qtd_->urb->pipe) && \
- (_qh_)->start_split_frame != 0 && !_qtd_->complete_split) { \
+ (_qh_)->start_active_frame != 0 && !_qtd_->complete_split) { \
_hfnum_.d32 = dwc2_readl((_hcd_)->regs + HFNUM); \
switch (_hfnum_.b.frnum & 0x7) { \
case 7: \
diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c
index 36606fc33c0d..0e1d42b5dec5 100644
--- a/drivers/usb/dwc2/hcd_ddma.c
+++ b/drivers/usb/dwc2/hcd_ddma.c
@@ -81,7 +81,7 @@ static u16 dwc2_max_desc_num(struct dwc2_qh *qh)
static u16 dwc2_frame_incr_val(struct dwc2_qh *qh)
{
return qh->dev_speed == USB_SPEED_HIGH ?
- (qh->interval + 8 - 1) / 8 : qh->interval;
+ (qh->host_interval + 8 - 1) / 8 : qh->host_interval;
}
static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
@@ -111,7 +111,7 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
dma_unmap_single(hsotg->dev, qh->desc_list_dma,
qh->desc_list_sz,
DMA_FROM_DEVICE);
- kfree(qh->desc_list);
+ kmem_cache_free(desc_cache, qh->desc_list);
qh->desc_list = NULL;
return -ENOMEM;
}
@@ -252,7 +252,7 @@ static void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
chan = qh->channel;
inc = dwc2_frame_incr_val(qh);
if (qh->ep_type == USB_ENDPOINT_XFER_ISOC)
- i = dwc2_frame_list_idx(qh->sched_frame);
+ i = dwc2_frame_list_idx(qh->next_active_frame);
else
i = 0;
@@ -278,13 +278,13 @@ static void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
return;
chan->schinfo = 0;
- if (chan->speed == USB_SPEED_HIGH && qh->interval) {
+ if (chan->speed == USB_SPEED_HIGH && qh->host_interval) {
j = 1;
/* TODO - check this */
- inc = (8 + qh->interval - 1) / qh->interval;
+ inc = (8 + qh->host_interval - 1) / qh->host_interval;
for (i = 0; i < inc; i++) {
chan->schinfo |= j;
- j = j << qh->interval;
+ j = j << qh->host_interval;
}
} else {
chan->schinfo = 0xff;
@@ -431,7 +431,10 @@ static u16 dwc2_calc_starting_frame(struct dwc2_hsotg *hsotg,
hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
- /* sched_frame is always frame number (not uFrame) both in FS and HS! */
+ /*
+ * next_active_frame is always frame number (not uFrame) both in FS
+ * and HS!
+ */
/*
* skip_frames is used to limit activated descriptors number
@@ -514,13 +517,13 @@ static u16 dwc2_recalc_initial_desc_idx(struct dwc2_hsotg *hsotg,
*/
fr_idx_tmp = dwc2_frame_list_idx(frame);
fr_idx = (FRLISTEN_64_SIZE +
- dwc2_frame_list_idx(qh->sched_frame) - fr_idx_tmp)
- % dwc2_frame_incr_val(qh);
+ dwc2_frame_list_idx(qh->next_active_frame) -
+ fr_idx_tmp) % dwc2_frame_incr_val(qh);
fr_idx = (fr_idx + fr_idx_tmp) % FRLISTEN_64_SIZE;
} else {
- qh->sched_frame = dwc2_calc_starting_frame(hsotg, qh,
+ qh->next_active_frame = dwc2_calc_starting_frame(hsotg, qh,
&skip_frames);
- fr_idx = dwc2_frame_list_idx(qh->sched_frame);
+ fr_idx = dwc2_frame_list_idx(qh->next_active_frame);
}
qh->td_first = qh->td_last = dwc2_frame_to_desc_idx(qh, fr_idx);
@@ -583,7 +586,7 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
u16 next_idx;
idx = qh->td_last;
- inc = qh->interval;
+ inc = qh->host_interval;
hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed);
@@ -605,11 +608,11 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
}
}
- if (qh->interval) {
- ntd_max = (dwc2_max_desc_num(qh) + qh->interval - 1) /
- qh->interval;
+ if (qh->host_interval) {
+ ntd_max = (dwc2_max_desc_num(qh) + qh->host_interval - 1) /
+ qh->host_interval;
if (skip_frames && !qh->channel)
- ntd_max -= skip_frames / qh->interval;
+ ntd_max -= skip_frames / qh->host_interval;
}
max_xfer_size = qh->dev_speed == USB_SPEED_HIGH ?
@@ -1029,7 +1032,7 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
idx);
if (rc < 0)
return;
- idx = dwc2_desclist_idx_inc(idx, qh->interval,
+ idx = dwc2_desclist_idx_inc(idx, qh->host_interval,
chan->speed);
if (!rc)
continue;
@@ -1039,7 +1042,7 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
/* rc == DWC2_CMPL_STOP */
- if (qh->interval >= 32)
+ if (qh->host_interval >= 32)
goto stop_scan;
qh->td_first = idx;
@@ -1174,14 +1177,11 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc,
halt_status, n_bytes,
xfer_done);
- if (*xfer_done && urb->status != -EINPROGRESS)
- failed = 1;
-
- if (failed) {
+ if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
dwc2_host_complete(hsotg, qtd, urb->status);
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
- dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
- failed, *xfer_done, urb->status);
+ dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x\n",
+ failed, *xfer_done);
return failed;
}
@@ -1236,21 +1236,25 @@ static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
list_for_each_safe(qtd_item, qtd_tmp, &qh->qtd_list) {
int i;
+ int qtd_desc_count;
qtd = list_entry(qtd_item, struct dwc2_qtd, qtd_list_entry);
xfer_done = 0;
+ qtd_desc_count = qtd->n_desc;
- for (i = 0; i < qtd->n_desc; i++) {
+ for (i = 0; i < qtd_desc_count; i++) {
if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd,
desc_num, halt_status,
&xfer_done)) {
qtd = NULL;
- break;
+ goto stop_scan;
}
+
desc_num++;
}
}
+stop_scan:
if (qh->ep_type != USB_ENDPOINT_XFER_CONTROL) {
/*
* Resetting the data toggle for bulk and interrupt endpoints
@@ -1258,8 +1262,8 @@ static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
*/
if (halt_status == DWC2_HC_XFER_STALL)
qh->data_toggle = DWC2_HC_PID_DATA0;
- else if (qtd)
- dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+ else
+ dwc2_hcd_save_data_toggle(hsotg, chan, chnum, NULL);
}
if (halt_status == DWC2_HC_XFER_COMPLETE) {
@@ -1327,8 +1331,8 @@ void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
dwc2_hcd_qh_unlink(hsotg, qh);
} else {
/* Keep in assigned schedule to continue transfer */
- list_move(&qh->qh_list_entry,
- &hsotg->periodic_sched_assigned);
+ list_move_tail(&qh->qh_list_entry,
+ &hsotg->periodic_sched_assigned);
/*
* If channel has been halted during giveback of urb
* then prevent any new scheduling.
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index f8253803a050..906f223542ee 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -55,12 +55,16 @@
/* This function is for debug only */
static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
{
-#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
u16 curr_frame_number = hsotg->frame_number;
+ u16 expected = dwc2_frame_num_inc(hsotg->last_frame_num, 1);
+
+ if (expected != curr_frame_number)
+ dwc2_sch_vdbg(hsotg, "MISSED SOF %04x != %04x\n",
+ expected, curr_frame_number);
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
- if (((hsotg->last_frame_num + 1) & HFNUM_MAX_FRNUM) !=
- curr_frame_number) {
+ if (expected != curr_frame_number) {
hsotg->frame_num_array[hsotg->frame_num_idx] =
curr_frame_number;
hsotg->last_frame_num_array[hsotg->frame_num_idx] =
@@ -79,14 +83,15 @@ static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
}
hsotg->dumped_frame_num_array = 1;
}
- hsotg->last_frame_num = curr_frame_number;
#endif
+ hsotg->last_frame_num = curr_frame_number;
}
static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan,
struct dwc2_qtd *qtd)
{
+ struct usb_device *root_hub = dwc2_hsotg_to_hcd(hsotg)->self.root_hub;
struct urb *usb_urb;
if (!chan->qh)
@@ -102,6 +107,15 @@ static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg,
if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt)
return;
+ /*
+ * The root hub doesn't really have a TT, but Linux thinks it
+ * does because how could you have a "high speed hub" that
+ * directly talks directly to low speed devices without a TT?
+ * It's all lies. Lies, I tell you.
+ */
+ if (usb_urb->dev->tt->hub == root_hub)
+ return;
+
if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
chan->qh->tt_buffer_dirty = 1;
if (usb_hub_clear_tt_buffer(usb_urb))
@@ -138,13 +152,19 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
while (qh_entry != &hsotg->periodic_sched_inactive) {
qh = list_entry(qh_entry, struct dwc2_qh, qh_list_entry);
qh_entry = qh_entry->next;
- if (dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number))
+ if (dwc2_frame_num_le(qh->next_active_frame,
+ hsotg->frame_number)) {
+ dwc2_sch_vdbg(hsotg, "QH=%p ready fn=%04x, nxt=%04x\n",
+ qh, hsotg->frame_number,
+ qh->next_active_frame);
+
/*
* Move QH to the ready list to be executed next
* (micro)frame
*/
- list_move(&qh->qh_list_entry,
+ list_move_tail(&qh->qh_list_entry,
&hsotg->periodic_sched_ready);
+ }
}
tr_type = dwc2_hcd_select_transactions(hsotg);
if (tr_type != DWC2_TRANSACTION_NONE)
@@ -472,18 +492,6 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
xfer_length = urb->length - urb->actual_length;
}
- /* Non DWORD-aligned buffer case handling */
- if (chan->align_buf && xfer_length) {
- dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
- dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
- chan->qh->dw_align_buf_size,
- chan->ep_is_in ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (chan->ep_is_in)
- memcpy(urb->buf + urb->actual_length,
- chan->qh->dw_align_buf, xfer_length);
- }
-
dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
urb->actual_length, xfer_length);
urb->actual_length += xfer_length;
@@ -525,11 +533,19 @@ void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
+ if (WARN(!chan || !chan->qh,
+ "chan->qh must be specified for non-control eps\n"))
+ return;
+
if (pid == TSIZ_SC_MC_PID_DATA0)
chan->qh->data_toggle = DWC2_HC_PID_DATA0;
else
chan->qh->data_toggle = DWC2_HC_PID_DATA1;
} else {
+ if (WARN(!qtd,
+ "qtd must be specified for control eps\n"))
+ return;
+
if (pid == TSIZ_SC_MC_PID_DATA0)
qtd->data_toggle = DWC2_HC_PID_DATA0;
else
@@ -565,21 +581,6 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
frame_desc->status = 0;
frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
chan, chnum, qtd, halt_status, NULL);
-
- /* Non DWORD-aligned buffer case handling */
- if (chan->align_buf && frame_desc->actual_length) {
- dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
- __func__);
- dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
- chan->qh->dw_align_buf_size,
- chan->ep_is_in ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (chan->ep_is_in)
- memcpy(urb->buf + frame_desc->offset +
- qtd->isoc_split_offset,
- chan->qh->dw_align_buf,
- frame_desc->actual_length);
- }
break;
case DWC2_HC_XFER_FRAME_OVERRUN:
urb->error_count++;
@@ -600,21 +601,6 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
chan, chnum, qtd, halt_status, NULL);
- /* Non DWORD-aligned buffer case handling */
- if (chan->align_buf && frame_desc->actual_length) {
- dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
- __func__);
- dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
- chan->qh->dw_align_buf_size,
- chan->ep_is_in ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (chan->ep_is_in)
- memcpy(urb->buf + frame_desc->offset +
- qtd->isoc_split_offset,
- chan->qh->dw_align_buf,
- frame_desc->actual_length);
- }
-
/* Skip whole frame */
if (chan->qh->do_split &&
chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in &&
@@ -680,8 +666,6 @@ static void dwc2_deactivate_qh(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
}
no_qtd:
- if (qh->channel)
- qh->channel->align_buf = 0;
qh->channel = NULL;
dwc2_hcd_qh_deactivate(hsotg, qh, continue_split);
}
@@ -838,7 +822,7 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
* halt to be queued when the periodic schedule is
* processed.
*/
- list_move(&chan->qh->qh_list_entry,
+ list_move_tail(&chan->qh->qh_list_entry,
&hsotg->periodic_sched_assigned);
/*
@@ -946,14 +930,6 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
frame_desc->actual_length += len;
- if (chan->align_buf) {
- dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
- dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
- chan->qh->dw_align_buf_size, DMA_FROM_DEVICE);
- memcpy(qtd->urb->buf + frame_desc->offset +
- qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
- }
-
qtd->isoc_split_offset += len;
if (frame_desc->actual_length >= frame_desc->length) {
@@ -1176,19 +1152,6 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
xfer_length = urb->length - urb->actual_length;
}
- /* Non DWORD-aligned buffer case handling */
- if (chan->align_buf && xfer_length && chan->ep_is_in) {
- dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
- dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
- chan->qh->dw_align_buf_size,
- chan->ep_is_in ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (chan->ep_is_in)
- memcpy(urb->buf + urb->actual_length,
- chan->qh->dw_align_buf,
- xfer_length);
- }
-
urb->actual_length += xfer_length;
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
@@ -1408,14 +1371,50 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg,
if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
- int frnum = dwc2_hcd_get_frame_number(hsotg);
+ struct dwc2_qh *qh = chan->qh;
+ bool past_end;
+
+ if (hsotg->core_params->uframe_sched <= 0) {
+ int frnum = dwc2_hcd_get_frame_number(hsotg);
+
+ /* Don't have num_hs_transfers; simple logic */
+ past_end = dwc2_full_frame_num(frnum) !=
+ dwc2_full_frame_num(qh->next_active_frame);
+ } else {
+ int end_frnum;
- if (dwc2_full_frame_num(frnum) !=
- dwc2_full_frame_num(chan->qh->sched_frame)) {
/*
- * No longer in the same full speed frame.
- * Treat this as a transaction error.
- */
+ * Figure out the end frame based on schedule.
+ *
+ * We don't want to go on trying again and again
+ * forever. Let's stop when we've done all the
+ * transfers that were scheduled.
+ *
+ * We're going to be comparing start_active_frame
+ * and next_active_frame, both of which are 1
+ * before the time the packet goes on the wire,
+ * so that cancels out. Basically if had 1
+ * transfer and we saw 1 NYET then we're done.
+ * We're getting a NYET here so if next >=
+ * (start + num_transfers) we're done. The
+ * complexity is that for all but ISOC_OUT we
+ * skip one slot.
+ */
+ end_frnum = dwc2_frame_num_inc(
+ qh->start_active_frame,
+ qh->num_hs_transfers);
+
+ if (qh->ep_type != USB_ENDPOINT_XFER_ISOC ||
+ qh->ep_is_in)
+ end_frnum =
+ dwc2_frame_num_inc(end_frnum, 1);
+
+ past_end = dwc2_frame_num_le(
+ end_frnum, qh->next_active_frame);
+ }
+
+ if (past_end) {
+ /* Treat this as a transaction error. */
#if 0
/*
* Todo: Fix system performance so this can
@@ -2000,6 +1999,16 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
}
dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
+
+ /*
+ * If we got an interrupt after someone called
+ * dwc2_hcd_endpoint_disable() we don't want to crash below
+ */
+ if (!chan->qh) {
+ dev_warn(hsotg->dev, "Interrupt on disabled channel\n");
+ return;
+ }
+
chan->hcint = hcint;
hcint &= hcintmsk;
@@ -2122,6 +2131,7 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
{
u32 haint;
int i;
+ struct dwc2_host_chan *chan, *chan_tmp;
haint = dwc2_readl(hsotg->regs + HAINT);
if (dbg_perio()) {
@@ -2130,6 +2140,22 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
dev_vdbg(hsotg->dev, "HAINT=%08x\n", haint);
}
+ /*
+ * According to USB 2.0 spec section 11.18.8, a host must
+ * issue complete-split transactions in a microframe for a
+ * set of full-/low-speed endpoints in the same relative
+ * order as the start-splits were issued in a microframe for.
+ */
+ list_for_each_entry_safe(chan, chan_tmp, &hsotg->split_order,
+ split_order_list_entry) {
+ int hc_num = chan->hc_num;
+
+ if (haint & (1 << hc_num)) {
+ dwc2_hc_n_intr(hsotg, hc_num);
+ haint &= ~(1 << hc_num);
+ }
+ }
+
for (i = 0; i < hsotg->core_params->host_channels; i++) {
if (haint & (1 << i))
dwc2_hc_n_intr(hsotg, i);
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 27d402f680a3..7f634fd771c7 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -38,6 +38,7 @@
* This file contains the functions to manage Queue Heads and Queue
* Transfer Descriptors for Host mode
*/
+#include <linux/gcd.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
@@ -53,194 +54,8 @@
#include "core.h"
#include "hcd.h"
-/**
- * dwc2_qh_init() - Initializes a QH structure
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh: The QH to init
- * @urb: Holds the information about the device/endpoint needed to initialize
- * the QH
- */
-#define SCHEDULE_SLOP 10
-static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
- struct dwc2_hcd_urb *urb)
-{
- int dev_speed, hub_addr, hub_port;
- char *speed, *type;
-
- dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
- /* Initialize QH */
- qh->ep_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
- qh->ep_is_in = dwc2_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
-
- qh->data_toggle = DWC2_HC_PID_DATA0;
- qh->maxp = dwc2_hcd_get_mps(&urb->pipe_info);
- INIT_LIST_HEAD(&qh->qtd_list);
- INIT_LIST_HEAD(&qh->qh_list_entry);
-
- /* FS/LS Endpoint on HS Hub, NOT virtual root hub */
- dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
-
- dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port);
-
- if ((dev_speed == USB_SPEED_LOW || dev_speed == USB_SPEED_FULL) &&
- hub_addr != 0 && hub_addr != 1) {
- dev_vdbg(hsotg->dev,
- "QH init: EP %d: TT found at hub addr %d, for port %d\n",
- dwc2_hcd_get_ep_num(&urb->pipe_info), hub_addr,
- hub_port);
- qh->do_split = 1;
- }
-
- if (qh->ep_type == USB_ENDPOINT_XFER_INT ||
- qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
- /* Compute scheduling parameters once and save them */
- u32 hprt, prtspd;
-
- /* Todo: Account for split transfers in the bus time */
- int bytecount =
- dwc2_hb_mult(qh->maxp) * dwc2_max_packet(qh->maxp);
-
- qh->usecs = NS_TO_US(usb_calc_bus_time(qh->do_split ?
- USB_SPEED_HIGH : dev_speed, qh->ep_is_in,
- qh->ep_type == USB_ENDPOINT_XFER_ISOC,
- bytecount));
-
- /* Ensure frame_number corresponds to the reality */
- hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
- /* Start in a slightly future (micro)frame */
- qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
- SCHEDULE_SLOP);
- qh->interval = urb->interval;
-#if 0
- /* Increase interrupt polling rate for debugging */
- if (qh->ep_type == USB_ENDPOINT_XFER_INT)
- qh->interval = 8;
-#endif
- hprt = dwc2_readl(hsotg->regs + HPRT0);
- prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
- if (prtspd == HPRT0_SPD_HIGH_SPEED &&
- (dev_speed == USB_SPEED_LOW ||
- dev_speed == USB_SPEED_FULL)) {
- qh->interval *= 8;
- qh->sched_frame |= 0x7;
- qh->start_split_frame = qh->sched_frame;
- }
- dev_dbg(hsotg->dev, "interval=%d\n", qh->interval);
- }
-
- dev_vdbg(hsotg->dev, "DWC OTG HCD QH Initialized\n");
- dev_vdbg(hsotg->dev, "DWC OTG HCD QH - qh = %p\n", qh);
- dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Device Address = %d\n",
- dwc2_hcd_get_dev_addr(&urb->pipe_info));
- dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Endpoint %d, %s\n",
- dwc2_hcd_get_ep_num(&urb->pipe_info),
- dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
-
- qh->dev_speed = dev_speed;
-
- switch (dev_speed) {
- case USB_SPEED_LOW:
- speed = "low";
- break;
- case USB_SPEED_FULL:
- speed = "full";
- break;
- case USB_SPEED_HIGH:
- speed = "high";
- break;
- default:
- speed = "?";
- break;
- }
- dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Speed = %s\n", speed);
-
- switch (qh->ep_type) {
- case USB_ENDPOINT_XFER_ISOC:
- type = "isochronous";
- break;
- case USB_ENDPOINT_XFER_INT:
- type = "interrupt";
- break;
- case USB_ENDPOINT_XFER_CONTROL:
- type = "control";
- break;
- case USB_ENDPOINT_XFER_BULK:
- type = "bulk";
- break;
- default:
- type = "?";
- break;
- }
-
- dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Type = %s\n", type);
-
- if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
- dev_vdbg(hsotg->dev, "DWC OTG HCD QH - usecs = %d\n",
- qh->usecs);
- dev_vdbg(hsotg->dev, "DWC OTG HCD QH - interval = %d\n",
- qh->interval);
- }
-}
-
-/**
- * dwc2_hcd_qh_create() - Allocates and initializes a QH
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @urb: Holds the information about the device/endpoint needed
- * to initialize the QH
- * @atomic_alloc: Flag to do atomic allocation if needed
- *
- * Return: Pointer to the newly allocated QH, or NULL on error
- */
-struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
- struct dwc2_hcd_urb *urb,
- gfp_t mem_flags)
-{
- struct dwc2_qh *qh;
-
- if (!urb->priv)
- return NULL;
-
- /* Allocate memory */
- qh = kzalloc(sizeof(*qh), mem_flags);
- if (!qh)
- return NULL;
-
- dwc2_qh_init(hsotg, qh, urb);
-
- if (hsotg->core_params->dma_desc_enable > 0 &&
- dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) {
- dwc2_hcd_qh_free(hsotg, qh);
- return NULL;
- }
-
- return qh;
-}
-
-/**
- * dwc2_hcd_qh_free() - Frees the QH
- *
- * @hsotg: HCD instance
- * @qh: The QH to free
- *
- * QH should already be removed from the list. QTD list should already be empty
- * if called from URB Dequeue.
- *
- * Must NOT be called with interrupt disabled or spinlock held
- */
-void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
- if (qh->desc_list) {
- dwc2_hcd_qh_free_ddma(hsotg, qh);
- } else {
- /* kfree(NULL) is safe */
- kfree(qh->dw_align_buf);
- qh->dw_align_buf_dma = (dma_addr_t)0;
- }
- kfree(qh);
-}
+/* Wait this long before releasing periodic reservation */
+#define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
/**
* dwc2_periodic_channel_available() - Checks that a channel is available for a
@@ -301,19 +116,19 @@ static int dwc2_check_periodic_bandwidth(struct dwc2_hsotg *hsotg,
* High speed mode
* Max periodic usecs is 80% x 125 usec = 100 usec
*/
- max_claimed_usecs = 100 - qh->usecs;
+ max_claimed_usecs = 100 - qh->host_us;
} else {
/*
* Full speed mode
* Max periodic usecs is 90% x 1000 usec = 900 usec
*/
- max_claimed_usecs = 900 - qh->usecs;
+ max_claimed_usecs = 900 - qh->host_us;
}
if (hsotg->periodic_usecs > max_claimed_usecs) {
dev_err(hsotg->dev,
"%s: already claimed usecs %d, required usecs %d\n",
- __func__, hsotg->periodic_usecs, qh->usecs);
+ __func__, hsotg->periodic_usecs, qh->host_us);
status = -ENOSPC;
}
@@ -321,113 +136,1177 @@ static int dwc2_check_periodic_bandwidth(struct dwc2_hsotg *hsotg,
}
/**
- * Microframe scheduler
- * track the total use in hsotg->frame_usecs
- * keep each qh use in qh->frame_usecs
- * when surrendering the qh then donate the time back
+ * pmap_schedule() - Schedule time in a periodic bitmap (pmap).
+ *
+ * @map: The bitmap representing the schedule; will be updated
+ * upon success.
+ * @bits_per_period: The schedule represents several periods. This is how many
+ * bits are in each period. It's assumed that the beginning
+ * of the schedule will repeat after its end.
+ * @periods_in_map: The number of periods in the schedule.
+ * @num_bits: The number of bits we need per period we want to reserve
+ * in this function call.
+ * @interval: How often we need to be scheduled for the reservation this
+ * time. 1 means every period. 2 means every other period.
+ * ...you get the picture?
+ * @start: The bit number to start at. Normally 0. Must be within
+ * the interval or we return failure right away.
+ * @only_one_period: Normally we'll allow picking a start anywhere within the
+ * first interval, since we can still make all repetition
+ * requirements by doing that. However, if you pass true
+ * here then we'll return failure if we can't fit within
+ * the period that "start" is in.
+ *
+ * The idea here is that we want to schedule time for repeating events that all
+ * want the same resource. The resource is divided into fixed-sized periods
+ * and the events want to repeat every "interval" periods. The schedule
+ * granularity is one bit.
+ *
+ * To keep things "simple", we'll represent our schedule with a bitmap that
+ * contains a fixed number of periods. This gets rid of a lot of complexity
+ * but does mean that we need to handle things specially (and non-ideally) if
+ * the number of the periods in the schedule doesn't match well with the
+ * intervals that we're trying to schedule.
+ *
+ * Here's an explanation of the scheme we'll implement, assuming 8 periods.
+ * - If interval is 1, we need to take up space in each of the 8
+ * periods we're scheduling. Easy.
+ * - If interval is 2, we need to take up space in half of the
+ * periods. Again, easy.
+ * - If interval is 3, we actually need to fall back to interval 1.
+ * Why? Because we might need time in any period. AKA for the
+ * first 8 periods, we'll be in slot 0, 3, 6. Then we'll be
+ * in slot 1, 4, 7. Then we'll be in 2, 5. Then we'll be back to
+ * 0, 3, and 6. Since we could be in any frame we need to reserve
+ * for all of them. Sucks, but that's what you gotta do. Note that
+ * if we were instead scheduling 8 * 3 = 24 we'd do much better, but
+ * then we need more memory and time to do scheduling.
+ * - If interval is 4, easy.
+ * - If interval is 5, we again need interval 1. The schedule will be
+ * 0, 5, 2, 7, 4, 1, 6, 3, 0
+ * - If interval is 6, we need interval 2. 0, 6, 4, 2.
+ * - If interval is 7, we need interval 1.
+ * - If interval is 8, we need interval 8.
+ *
+ * If you do the math, you'll see that we need to pretend that interval is
+ * equal to the greatest_common_divisor(interval, periods_in_map).
+ *
+ * Note that at the moment this function tends to front-pack the schedule.
+ * In some cases that's really non-ideal (it's hard to schedule things that
+ * need to repeat every period). In other cases it's perfect (you can easily
+ * schedule bigger, less often repeating things).
+ *
+ * Here's the algorithm in action (8 periods, 5 bits per period):
+ * |** | |** | |** | |** | | OK 2 bits, intv 2 at 0
+ * |*****| ***|*****| ***|*****| ***|*****| ***| OK 3 bits, intv 3 at 2
+ * |*****|* ***|*****| ***|*****|* ***|*****| ***| OK 1 bits, intv 4 at 5
+ * |** |* |** | |** |* |** | | Remv 3 bits, intv 3 at 2
+ * |*** |* |*** | |*** |* |*** | | OK 1 bits, intv 6 at 2
+ * |**** |* * |**** | * |**** |* * |**** | * | OK 1 bits, intv 1 at 3
+ * |**** |**** |**** | *** |**** |**** |**** | *** | OK 2 bits, intv 2 at 6
+ * |*****|*****|*****| ****|*****|*****|*****| ****| OK 1 bits, intv 1 at 4
+ * |*****|*****|*****| ****|*****|*****|*****| ****| FAIL 1 bits, intv 1
+ * | ***|*****| ***| ****| ***|*****| ***| ****| Remv 2 bits, intv 2 at 0
+ * | ***| ****| ***| ****| ***| ****| ***| ****| Remv 1 bits, intv 4 at 5
+ * | **| ****| **| ****| **| ****| **| ****| Remv 1 bits, intv 6 at 2
+ * | *| ** *| *| ** *| *| ** *| *| ** *| Remv 1 bits, intv 1 at 3
+ * | *| *| *| *| *| *| *| *| Remv 2 bits, intv 2 at 6
+ * | | | | | | | | | Remv 1 bits, intv 1 at 4
+ * |** | |** | |** | |** | | OK 2 bits, intv 2 at 0
+ * |*** | |** | |*** | |** | | OK 1 bits, intv 4 at 2
+ * |*****| |** **| |*****| |** **| | OK 2 bits, intv 2 at 3
+ * |*****|* |** **| |*****|* |** **| | OK 1 bits, intv 4 at 5
+ * |*****|*** |** **| ** |*****|*** |** **| ** | OK 2 bits, intv 2 at 6
+ * |*****|*****|** **| ****|*****|*****|** **| ****| OK 2 bits, intv 2 at 8
+ * |*****|*****|*****| ****|*****|*****|*****| ****| OK 1 bits, intv 4 at 12
+ *
+ * This function is pretty generic and could be easily abstracted if anything
+ * needed similar scheduling.
+ *
+ * Returns either -ENOSPC or a >= 0 start bit which should be passed to the
+ * unschedule routine. The map bitmap will be updated on a non-error result.
*/
-static const unsigned short max_uframe_usecs[] = {
- 100, 100, 100, 100, 100, 100, 30, 0
-};
+static int pmap_schedule(unsigned long *map, int bits_per_period,
+ int periods_in_map, int num_bits,
+ int interval, int start, bool only_one_period)
+{
+ int interval_bits;
+ int to_reserve;
+ int first_end;
+ int i;
+
+ if (num_bits > bits_per_period)
+ return -ENOSPC;
+
+ /* Adjust interval as per description */
+ interval = gcd(interval, periods_in_map);
+
+ interval_bits = bits_per_period * interval;
+ to_reserve = periods_in_map / interval;
+
+ /* If start has gotten us past interval then we can't schedule */
+ if (start >= interval_bits)
+ return -ENOSPC;
+
+ if (only_one_period)
+ /* Must fit within same period as start; end at begin of next */
+ first_end = (start / bits_per_period + 1) * bits_per_period;
+ else
+ /* Can fit anywhere in the first interval */
+ first_end = interval_bits;
+
+ /*
+ * We'll try to pick the first repetition, then see if that time
+ * is free for each of the subsequent repetitions. If it's not
+ * we'll adjust the start time for the next search of the first
+ * repetition.
+ */
+ while (start + num_bits <= first_end) {
+ int end;
+
+ /* Need to stay within this period */
+ end = (start / bits_per_period + 1) * bits_per_period;
+
+ /* Look for num_bits us in this microframe starting at start */
+ start = bitmap_find_next_zero_area(map, end, start, num_bits,
+ 0);
+
+ /*
+ * We should get start >= end if we fail. We might be
+ * able to check the next microframe depending on the
+ * interval, so continue on (start already updated).
+ */
+ if (start >= end) {
+ start = end;
+ continue;
+ }
+
+ /* At this point we have a valid point for first one */
+ for (i = 1; i < to_reserve; i++) {
+ int ith_start = start + interval_bits * i;
+ int ith_end = end + interval_bits * i;
+ int ret;
+
+ /* Use this as a dumb "check if bits are 0" */
+ ret = bitmap_find_next_zero_area(
+ map, ith_start + num_bits, ith_start, num_bits,
+ 0);
+
+ /* We got the right place, continue checking */
+ if (ret == ith_start)
+ continue;
+
+ /* Move start up for next time and exit for loop */
+ ith_start = bitmap_find_next_zero_area(
+ map, ith_end, ith_start, num_bits, 0);
+ if (ith_start >= ith_end)
+ /* Need a while new period next time */
+ start = end;
+ else
+ start = ith_start - interval_bits * i;
+ break;
+ }
+
+ /* If didn't exit the for loop with a break, we have success */
+ if (i == to_reserve)
+ break;
+ }
-void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg)
+ if (start + num_bits > first_end)
+ return -ENOSPC;
+
+ for (i = 0; i < to_reserve; i++) {
+ int ith_start = start + interval_bits * i;
+
+ bitmap_set(map, ith_start, num_bits);
+ }
+
+ return start;
+}
+
+/**
+ * pmap_unschedule() - Undo work done by pmap_schedule()
+ *
+ * @map: See pmap_schedule().
+ * @bits_per_period: See pmap_schedule().
+ * @periods_in_map: See pmap_schedule().
+ * @num_bits: The number of bits that was passed to schedule.
+ * @interval: The interval that was passed to schedule.
+ * @start: The return value from pmap_schedule().
+ */
+static void pmap_unschedule(unsigned long *map, int bits_per_period,
+ int periods_in_map, int num_bits,
+ int interval, int start)
{
+ int interval_bits;
+ int to_release;
int i;
- for (i = 0; i < 8; i++)
- hsotg->frame_usecs[i] = max_uframe_usecs[i];
+ /* Adjust interval as per description in pmap_schedule() */
+ interval = gcd(interval, periods_in_map);
+
+ interval_bits = bits_per_period * interval;
+ to_release = periods_in_map / interval;
+
+ for (i = 0; i < to_release; i++) {
+ int ith_start = start + interval_bits * i;
+
+ bitmap_clear(map, ith_start, num_bits);
+ }
}
-static int dwc2_find_single_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+/*
+ * cat_printf() - A printf() + strcat() helper
+ *
+ * This is useful for concatenating a bunch of strings where each string is
+ * constructed using printf.
+ *
+ * @buf: The destination buffer; will be updated to point after the printed
+ * data.
+ * @size: The number of bytes in the buffer (includes space for '\0').
+ * @fmt: The format for printf.
+ * @...: The args for printf.
+ */
+static void cat_printf(char **buf, size_t *size, const char *fmt, ...)
{
- unsigned short utime = qh->usecs;
+ va_list args;
int i;
- for (i = 0; i < 8; i++) {
- /* At the start hsotg->frame_usecs[i] = max_uframe_usecs[i] */
- if (utime <= hsotg->frame_usecs[i]) {
- hsotg->frame_usecs[i] -= utime;
- qh->frame_usecs[i] += utime;
- return i;
- }
+ if (*size == 0)
+ return;
+
+ va_start(args, fmt);
+ i = vsnprintf(*buf, *size, fmt, args);
+ va_end(args);
+
+ if (i >= *size) {
+ (*buf)[*size - 1] = '\0';
+ *buf += *size;
+ *size = 0;
+ } else {
+ *buf += i;
+ *size -= i;
}
- return -ENOSPC;
}
/*
- * use this for FS apps that can span multiple uframes
+ * pmap_print() - Print the given periodic map
+ *
+ * Will attempt to print out the periodic schedule.
+ *
+ * @map: See pmap_schedule().
+ * @bits_per_period: See pmap_schedule().
+ * @periods_in_map: See pmap_schedule().
+ * @period_name: The name of 1 period, like "uFrame"
+ * @units: The name of the units, like "us".
+ * @print_fn: The function to call for printing.
+ * @print_data: Opaque data to pass to the print function.
+ */
+static void pmap_print(unsigned long *map, int bits_per_period,
+ int periods_in_map, const char *period_name,
+ const char *units,
+ void (*print_fn)(const char *str, void *data),
+ void *print_data)
+{
+ int period;
+
+ for (period = 0; period < periods_in_map; period++) {
+ char tmp[64];
+ char *buf = tmp;
+ size_t buf_size = sizeof(tmp);
+ int period_start = period * bits_per_period;
+ int period_end = period_start + bits_per_period;
+ int start = 0;
+ int count = 0;
+ bool printed = false;
+ int i;
+
+ for (i = period_start; i < period_end + 1; i++) {
+ /* Handle case when ith bit is set */
+ if (i < period_end &&
+ bitmap_find_next_zero_area(map, i + 1,
+ i, 1, 0) != i) {
+ if (count == 0)
+ start = i - period_start;
+ count++;
+ continue;
+ }
+
+ /* ith bit isn't set; don't care if count == 0 */
+ if (count == 0)
+ continue;
+
+ if (!printed)
+ cat_printf(&buf, &buf_size, "%s %d: ",
+ period_name, period);
+ else
+ cat_printf(&buf, &buf_size, ", ");
+ printed = true;
+
+ cat_printf(&buf, &buf_size, "%d %s -%3d %s", start,
+ units, start + count - 1, units);
+ count = 0;
+ }
+
+ if (printed)
+ print_fn(tmp, print_data);
+ }
+}
+
+/**
+ * dwc2_get_ls_map() - Get the map used for the given qh
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ *
+ * We'll always get the periodic map out of our TT. Note that even if we're
+ * running the host straight in low speed / full speed mode it appears as if
+ * a TT is allocated for us, so we'll use it. If that ever changes we can
+ * add logic here to get a map out of "hsotg" if !qh->do_split.
+ *
+ * Returns: the map or NULL if a map couldn't be found.
*/
-static int dwc2_find_multi_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+static unsigned long *dwc2_get_ls_map(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
{
- unsigned short utime = qh->usecs;
- unsigned short xtime;
- int t_left;
+ unsigned long *map;
+
+ /* Don't expect to be missing a TT and be doing low speed scheduling */
+ if (WARN_ON(!qh->dwc_tt))
+ return NULL;
+
+ /* Get the map and adjust if this is a multi_tt hub */
+ map = qh->dwc_tt->periodic_bitmaps;
+ if (qh->dwc_tt->usb_tt->multi)
+ map += DWC2_ELEMENTS_PER_LS_BITMAP * qh->ttport;
+
+ return map;
+}
+
+struct dwc2_qh_print_data {
+ struct dwc2_hsotg *hsotg;
+ struct dwc2_qh *qh;
+};
+
+/**
+ * dwc2_qh_print() - Helper function for dwc2_qh_schedule_print()
+ *
+ * @str: The string to print
+ * @data: A pointer to a struct dwc2_qh_print_data
+ */
+static void dwc2_qh_print(const char *str, void *data)
+{
+ struct dwc2_qh_print_data *print_data = data;
+
+ dwc2_sch_dbg(print_data->hsotg, "QH=%p ...%s\n", print_data->qh, str);
+}
+
+/**
+ * dwc2_qh_schedule_print() - Print the periodic schedule
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH to print.
+ */
+static void dwc2_qh_schedule_print(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ struct dwc2_qh_print_data print_data = { hsotg, qh };
int i;
- int j;
- int k;
- for (i = 0; i < 8; i++) {
- if (hsotg->frame_usecs[i] <= 0)
+ /*
+ * The printing functions are quite slow and inefficient.
+ * If we don't have tracing turned on, don't run unless the special
+ * define is turned on.
+ */
+#ifndef DWC2_PRINT_SCHEDULE
+ return;
+#endif
+
+ if (qh->schedule_low_speed) {
+ unsigned long *map = dwc2_get_ls_map(hsotg, qh);
+
+ dwc2_sch_dbg(hsotg, "QH=%p LS/FS trans: %d=>%d us @ %d us",
+ qh, qh->device_us,
+ DWC2_ROUND_US_TO_SLICE(qh->device_us),
+ DWC2_US_PER_SLICE * qh->ls_start_schedule_slice);
+
+ if (map) {
+ dwc2_sch_dbg(hsotg,
+ "QH=%p Whole low/full speed map %p now:\n",
+ qh, map);
+ pmap_print(map, DWC2_LS_PERIODIC_SLICES_PER_FRAME,
+ DWC2_LS_SCHEDULE_FRAMES, "Frame ", "slices",
+ dwc2_qh_print, &print_data);
+ }
+ }
+
+ for (i = 0; i < qh->num_hs_transfers; i++) {
+ struct dwc2_hs_transfer_time *trans_time = qh->hs_transfers + i;
+ int uframe = trans_time->start_schedule_us /
+ DWC2_HS_PERIODIC_US_PER_UFRAME;
+ int rel_us = trans_time->start_schedule_us %
+ DWC2_HS_PERIODIC_US_PER_UFRAME;
+
+ dwc2_sch_dbg(hsotg,
+ "QH=%p HS trans #%d: %d us @ uFrame %d + %d us\n",
+ qh, i, trans_time->duration_us, uframe, rel_us);
+ }
+ if (qh->num_hs_transfers) {
+ dwc2_sch_dbg(hsotg, "QH=%p Whole high speed map now:\n", qh);
+ pmap_print(hsotg->hs_periodic_bitmap,
+ DWC2_HS_PERIODIC_US_PER_UFRAME,
+ DWC2_HS_SCHEDULE_UFRAMES, "uFrame", "us",
+ dwc2_qh_print, &print_data);
+ }
+
+}
+
+/**
+ * dwc2_ls_pmap_schedule() - Schedule a low speed QH
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ * @search_slice: We'll start trying to schedule at the passed slice.
+ * Remember that slices are the units of the low speed
+ * schedule (think 25us or so).
+ *
+ * Wraps pmap_schedule() with the right parameters for low speed scheduling.
+ *
+ * Normally we schedule low speed devices on the map associated with the TT.
+ *
+ * Returns: 0 for success or an error code.
+ */
+static int dwc2_ls_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ int search_slice)
+{
+ int slices = DIV_ROUND_UP(qh->device_us, DWC2_US_PER_SLICE);
+ unsigned long *map = dwc2_get_ls_map(hsotg, qh);
+ int slice;
+
+ if (map == NULL)
+ return -EINVAL;
+
+ /*
+ * Schedule on the proper low speed map with our low speed scheduling
+ * parameters. Note that we use the "device_interval" here since
+ * we want the low speed interval and the only way we'd be in this
+ * function is if the device is low speed.
+ *
+ * If we happen to be doing low speed and high speed scheduling for the
+ * same transaction (AKA we have a split) we always do low speed first.
+ * That means we can always pass "false" for only_one_period (that
+ * parameters is only useful when we're trying to get one schedule to
+ * match what we already planned in the other schedule).
+ */
+ slice = pmap_schedule(map, DWC2_LS_PERIODIC_SLICES_PER_FRAME,
+ DWC2_LS_SCHEDULE_FRAMES, slices,
+ qh->device_interval, search_slice, false);
+
+ if (slice < 0)
+ return slice;
+
+ qh->ls_start_schedule_slice = slice;
+ return 0;
+}
+
+/**
+ * dwc2_ls_pmap_unschedule() - Undo work done by dwc2_ls_pmap_schedule()
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ */
+static void dwc2_ls_pmap_unschedule(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ int slices = DIV_ROUND_UP(qh->device_us, DWC2_US_PER_SLICE);
+ unsigned long *map = dwc2_get_ls_map(hsotg, qh);
+
+ /* Schedule should have failed, so no worries about no error code */
+ if (map == NULL)
+ return;
+
+ pmap_unschedule(map, DWC2_LS_PERIODIC_SLICES_PER_FRAME,
+ DWC2_LS_SCHEDULE_FRAMES, slices, qh->device_interval,
+ qh->ls_start_schedule_slice);
+}
+
+/**
+ * dwc2_hs_pmap_schedule - Schedule in the main high speed schedule
+ *
+ * This will schedule something on the main dwc2 schedule.
+ *
+ * We'll start looking in qh->hs_transfers[index].start_schedule_us. We'll
+ * update this with the result upon success. We also use the duration from
+ * the same structure.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ * @only_one_period: If true we will limit ourselves to just looking at
+ * one period (aka one 100us chunk). This is used if we have
+ * already scheduled something on the low speed schedule and
+ * need to find something that matches on the high speed one.
+ * @index: The index into qh->hs_transfers that we're working with.
+ *
+ * Returns: 0 for success or an error code. Upon success the
+ * dwc2_hs_transfer_time specified by "index" will be updated.
+ */
+static int dwc2_hs_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ bool only_one_period, int index)
+{
+ struct dwc2_hs_transfer_time *trans_time = qh->hs_transfers + index;
+ int us;
+
+ us = pmap_schedule(hsotg->hs_periodic_bitmap,
+ DWC2_HS_PERIODIC_US_PER_UFRAME,
+ DWC2_HS_SCHEDULE_UFRAMES, trans_time->duration_us,
+ qh->host_interval, trans_time->start_schedule_us,
+ only_one_period);
+
+ if (us < 0)
+ return us;
+
+ trans_time->start_schedule_us = us;
+ return 0;
+}
+
+/**
+ * dwc2_ls_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule()
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ */
+static void dwc2_hs_pmap_unschedule(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh, int index)
+{
+ struct dwc2_hs_transfer_time *trans_time = qh->hs_transfers + index;
+
+ pmap_unschedule(hsotg->hs_periodic_bitmap,
+ DWC2_HS_PERIODIC_US_PER_UFRAME,
+ DWC2_HS_SCHEDULE_UFRAMES, trans_time->duration_us,
+ qh->host_interval, trans_time->start_schedule_us);
+}
+
+/**
+ * dwc2_uframe_schedule_split - Schedule a QH for a periodic split xfer.
+ *
+ * This is the most complicated thing in USB. We have to find matching time
+ * in both the global high speed schedule for the port and the low speed
+ * schedule for the TT associated with the given device.
+ *
+ * Being here means that the host must be running in high speed mode and the
+ * device is in low or full speed mode (and behind a hub).
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ */
+static int dwc2_uframe_schedule_split(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ int bytecount = dwc2_hb_mult(qh->maxp) * dwc2_max_packet(qh->maxp);
+ int ls_search_slice;
+ int err = 0;
+ int host_interval_in_sched;
+
+ /*
+ * The interval (how often to repeat) in the actual host schedule.
+ * See pmap_schedule() for gcd() explanation.
+ */
+ host_interval_in_sched = gcd(qh->host_interval,
+ DWC2_HS_SCHEDULE_UFRAMES);
+
+ /*
+ * We always try to find space in the low speed schedule first, then
+ * try to find high speed time that matches. If we don't, we'll bump
+ * up the place we start searching in the low speed schedule and try
+ * again. To start we'll look right at the beginning of the low speed
+ * schedule.
+ *
+ * Note that this will tend to front-load the high speed schedule.
+ * We may eventually want to try to avoid this by either considering
+ * both schedules together or doing some sort of round robin.
+ */
+ ls_search_slice = 0;
+
+ while (ls_search_slice < DWC2_LS_SCHEDULE_SLICES) {
+ int start_s_uframe;
+ int ssplit_s_uframe;
+ int second_s_uframe;
+ int rel_uframe;
+ int first_count;
+ int middle_count;
+ int end_count;
+ int first_data_bytes;
+ int other_data_bytes;
+ int i;
+
+ if (qh->schedule_low_speed) {
+ err = dwc2_ls_pmap_schedule(hsotg, qh, ls_search_slice);
+
+ /*
+ * If we got an error here there's no other magic we
+ * can do, so bail. All the looping above is only
+ * helpful to redo things if we got a low speed slot
+ * and then couldn't find a matching high speed slot.
+ */
+ if (err)
+ return err;
+ } else {
+ /* Must be missing the tt structure? Why? */
+ WARN_ON_ONCE(1);
+ }
+
+ /*
+ * This will give us a number 0 - 7 if
+ * DWC2_LS_SCHEDULE_FRAMES == 1, or 0 - 15 if == 2, or ...
+ */
+ start_s_uframe = qh->ls_start_schedule_slice /
+ DWC2_SLICES_PER_UFRAME;
+
+ /* Get a number that's always 0 - 7 */
+ rel_uframe = (start_s_uframe % 8);
+
+ /*
+ * If we were going to start in uframe 7 then we would need to
+ * issue a start split in uframe 6, which spec says is not OK.
+ * Move on to the next full frame (assuming there is one).
+ *
+ * See 11.18.4 Host Split Transaction Scheduling Requirements
+ * bullet 1.
+ */
+ if (rel_uframe == 7) {
+ if (qh->schedule_low_speed)
+ dwc2_ls_pmap_unschedule(hsotg, qh);
+ ls_search_slice =
+ (qh->ls_start_schedule_slice /
+ DWC2_LS_PERIODIC_SLICES_PER_FRAME + 1) *
+ DWC2_LS_PERIODIC_SLICES_PER_FRAME;
continue;
+ }
/*
- * we need n consecutive slots so use j as a start slot
- * j plus j+1 must be enough time (for now)
+ * For ISOC in:
+ * - start split (frame -1)
+ * - complete split w/ data (frame +1)
+ * - complete split w/ data (frame +2)
+ * - ...
+ * - complete split w/ data (frame +num_data_packets)
+ * - complete split w/ data (frame +num_data_packets+1)
+ * - complete split w/ data (frame +num_data_packets+2, max 8)
+ * ...though if frame was "0" then max is 7...
+ *
+ * For ISOC out we might need to do:
+ * - start split w/ data (frame -1)
+ * - start split w/ data (frame +0)
+ * - ...
+ * - start split w/ data (frame +num_data_packets-2)
+ *
+ * For INTERRUPT in we might need to do:
+ * - start split (frame -1)
+ * - complete split w/ data (frame +1)
+ * - complete split w/ data (frame +2)
+ * - complete split w/ data (frame +3, max 8)
+ *
+ * For INTERRUPT out we might need to do:
+ * - start split w/ data (frame -1)
+ * - complete split (frame +1)
+ * - complete split (frame +2)
+ * - complete split (frame +3, max 8)
+ *
+ * Start adjusting!
*/
- xtime = hsotg->frame_usecs[i];
- for (j = i + 1; j < 8; j++) {
- /*
- * if we add this frame remaining time to xtime we may
- * be OK, if not we need to test j for a complete frame
- */
- if (xtime + hsotg->frame_usecs[j] < utime) {
- if (hsotg->frame_usecs[j] <
- max_uframe_usecs[j])
- continue;
+ ssplit_s_uframe = (start_s_uframe +
+ host_interval_in_sched - 1) %
+ host_interval_in_sched;
+ if (qh->ep_type == USB_ENDPOINT_XFER_ISOC && !qh->ep_is_in)
+ second_s_uframe = start_s_uframe;
+ else
+ second_s_uframe = start_s_uframe + 1;
+
+ /* First data transfer might not be all 188 bytes. */
+ first_data_bytes = 188 -
+ DIV_ROUND_UP(188 * (qh->ls_start_schedule_slice %
+ DWC2_SLICES_PER_UFRAME),
+ DWC2_SLICES_PER_UFRAME);
+ if (first_data_bytes > bytecount)
+ first_data_bytes = bytecount;
+ other_data_bytes = bytecount - first_data_bytes;
+
+ /*
+ * For now, skip OUT xfers where first xfer is partial
+ *
+ * Main dwc2 code assumes:
+ * - INT transfers never get split in two.
+ * - ISOC transfers can always transfer 188 bytes the first
+ * time.
+ *
+ * Until that code is fixed, try again if the first transfer
+ * couldn't transfer everything.
+ *
+ * This code can be removed if/when the rest of dwc2 handles
+ * the above cases. Until it's fixed we just won't be able
+ * to schedule quite as tightly.
+ */
+ if (!qh->ep_is_in &&
+ (first_data_bytes != min_t(int, 188, bytecount))) {
+ dwc2_sch_dbg(hsotg,
+ "QH=%p avoiding broken 1st xfer (%d, %d)\n",
+ qh, first_data_bytes, bytecount);
+ if (qh->schedule_low_speed)
+ dwc2_ls_pmap_unschedule(hsotg, qh);
+ ls_search_slice = (start_s_uframe + 1) *
+ DWC2_SLICES_PER_UFRAME;
+ continue;
+ }
+
+ /* Start by assuming transfers for the bytes */
+ qh->num_hs_transfers = 1 + DIV_ROUND_UP(other_data_bytes, 188);
+
+ /*
+ * Everything except ISOC OUT has extra transfers. Rules are
+ * complicated. See 11.18.4 Host Split Transaction Scheduling
+ * Requirements bullet 3.
+ */
+ if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
+ if (rel_uframe == 6)
+ qh->num_hs_transfers += 2;
+ else
+ qh->num_hs_transfers += 3;
+
+ if (qh->ep_is_in) {
+ /*
+ * First is start split, middle/end is data.
+ * Allocate full data bytes for all data.
+ */
+ first_count = 4;
+ middle_count = bytecount;
+ end_count = bytecount;
+ } else {
+ /*
+ * First is data, middle/end is complete.
+ * First transfer and second can have data.
+ * Rest should just have complete split.
+ */
+ first_count = first_data_bytes;
+ middle_count = max_t(int, 4, other_data_bytes);
+ end_count = 4;
}
- if (xtime >= utime) {
- t_left = utime;
- for (k = i; k < 8; k++) {
- t_left -= hsotg->frame_usecs[k];
- if (t_left <= 0) {
- qh->frame_usecs[k] +=
- hsotg->frame_usecs[k]
- + t_left;
- hsotg->frame_usecs[k] = -t_left;
- return i;
- } else {
- qh->frame_usecs[k] +=
- hsotg->frame_usecs[k];
- hsotg->frame_usecs[k] = 0;
- }
- }
+ } else {
+ if (qh->ep_is_in) {
+ int last;
+
+ /* Account for the start split */
+ qh->num_hs_transfers++;
+
+ /* Calculate "L" value from spec */
+ last = rel_uframe + qh->num_hs_transfers + 1;
+
+ /* Start with basic case */
+ if (last <= 6)
+ qh->num_hs_transfers += 2;
+ else
+ qh->num_hs_transfers += 1;
+
+ /* Adjust downwards */
+ if (last >= 6 && rel_uframe == 0)
+ qh->num_hs_transfers--;
+
+ /* 1st = start; rest can contain data */
+ first_count = 4;
+ middle_count = min_t(int, 188, bytecount);
+ end_count = middle_count;
+ } else {
+ /* All contain data, last might be smaller */
+ first_count = first_data_bytes;
+ middle_count = min_t(int, 188,
+ other_data_bytes);
+ end_count = other_data_bytes % 188;
}
- /* add the frame time to x time */
- xtime += hsotg->frame_usecs[j];
- /* we must have a fully available next frame or break */
- if (xtime < utime &&
- hsotg->frame_usecs[j] == max_uframe_usecs[j])
- continue;
}
+
+ /* Assign durations per uFrame */
+ qh->hs_transfers[0].duration_us = HS_USECS_ISO(first_count);
+ for (i = 1; i < qh->num_hs_transfers - 1; i++)
+ qh->hs_transfers[i].duration_us =
+ HS_USECS_ISO(middle_count);
+ if (qh->num_hs_transfers > 1)
+ qh->hs_transfers[qh->num_hs_transfers - 1].duration_us =
+ HS_USECS_ISO(end_count);
+
+ /*
+ * Assign start us. The call below to dwc2_hs_pmap_schedule()
+ * will start with these numbers but may adjust within the same
+ * microframe.
+ */
+ qh->hs_transfers[0].start_schedule_us =
+ ssplit_s_uframe * DWC2_HS_PERIODIC_US_PER_UFRAME;
+ for (i = 1; i < qh->num_hs_transfers; i++)
+ qh->hs_transfers[i].start_schedule_us =
+ ((second_s_uframe + i - 1) %
+ DWC2_HS_SCHEDULE_UFRAMES) *
+ DWC2_HS_PERIODIC_US_PER_UFRAME;
+
+ /* Try to schedule with filled in hs_transfers above */
+ for (i = 0; i < qh->num_hs_transfers; i++) {
+ err = dwc2_hs_pmap_schedule(hsotg, qh, true, i);
+ if (err)
+ break;
+ }
+
+ /* If we scheduled all w/out breaking out then we're all good */
+ if (i == qh->num_hs_transfers)
+ break;
+
+ for (; i >= 0; i--)
+ dwc2_hs_pmap_unschedule(hsotg, qh, i);
+
+ if (qh->schedule_low_speed)
+ dwc2_ls_pmap_unschedule(hsotg, qh);
+
+ /* Try again starting in the next microframe */
+ ls_search_slice = (start_s_uframe + 1) * DWC2_SLICES_PER_UFRAME;
}
- return -ENOSPC;
+
+ if (ls_search_slice >= DWC2_LS_SCHEDULE_SLICES)
+ return -ENOSPC;
+
+ return 0;
+}
+
+/**
+ * dwc2_uframe_schedule_hs - Schedule a QH for a periodic high speed xfer.
+ *
+ * Basically this just wraps dwc2_hs_pmap_schedule() to provide a clean
+ * interface.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ */
+static int dwc2_uframe_schedule_hs(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ /* In non-split host and device time are the same */
+ WARN_ON(qh->host_us != qh->device_us);
+ WARN_ON(qh->host_interval != qh->device_interval);
+ WARN_ON(qh->num_hs_transfers != 1);
+
+ /* We'll have one transfer; init start to 0 before calling scheduler */
+ qh->hs_transfers[0].start_schedule_us = 0;
+ qh->hs_transfers[0].duration_us = qh->host_us;
+
+ return dwc2_hs_pmap_schedule(hsotg, qh, false, 0);
+}
+
+/**
+ * dwc2_uframe_schedule_ls - Schedule a QH for a periodic low/full speed xfer.
+ *
+ * Basically this just wraps dwc2_ls_pmap_schedule() to provide a clean
+ * interface.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ */
+static int dwc2_uframe_schedule_ls(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ /* In non-split host and device time are the same */
+ WARN_ON(qh->host_us != qh->device_us);
+ WARN_ON(qh->host_interval != qh->device_interval);
+ WARN_ON(!qh->schedule_low_speed);
+
+ /* Run on the main low speed schedule (no split = no hub = no TT) */
+ return dwc2_ls_pmap_schedule(hsotg, qh, 0);
}
-static int dwc2_find_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+/**
+ * dwc2_uframe_schedule - Schedule a QH for a periodic xfer.
+ *
+ * Calls one of the 3 sub-function depending on what type of transfer this QH
+ * is for. Also adds some printing.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ */
+static int dwc2_uframe_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
int ret;
- if (qh->dev_speed == USB_SPEED_HIGH) {
- /* if this is a hs transaction we need a full frame */
- ret = dwc2_find_single_uframe(hsotg, qh);
+ if (qh->dev_speed == USB_SPEED_HIGH)
+ ret = dwc2_uframe_schedule_hs(hsotg, qh);
+ else if (!qh->do_split)
+ ret = dwc2_uframe_schedule_ls(hsotg, qh);
+ else
+ ret = dwc2_uframe_schedule_split(hsotg, qh);
+
+ if (ret)
+ dwc2_sch_dbg(hsotg, "QH=%p Failed to schedule %d\n", qh, ret);
+ else
+ dwc2_qh_schedule_print(hsotg, qh);
+
+ return ret;
+}
+
+/**
+ * dwc2_uframe_unschedule - Undoes dwc2_uframe_schedule().
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ */
+static void dwc2_uframe_unschedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ int i;
+
+ for (i = 0; i < qh->num_hs_transfers; i++)
+ dwc2_hs_pmap_unschedule(hsotg, qh, i);
+
+ if (qh->schedule_low_speed)
+ dwc2_ls_pmap_unschedule(hsotg, qh);
+
+ dwc2_sch_dbg(hsotg, "QH=%p Unscheduled\n", qh);
+}
+
+/**
+ * dwc2_pick_first_frame() - Choose 1st frame for qh that's already scheduled
+ *
+ * Takes a qh that has already been scheduled (which means we know we have the
+ * bandwdith reserved for us) and set the next_active_frame and the
+ * start_active_frame.
+ *
+ * This is expected to be called on qh's that weren't previously actively
+ * running. It just picks the next frame that we can fit into without any
+ * thought about the past.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: QH for a periodic endpoint
+ *
+ */
+static void dwc2_pick_first_frame(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ u16 frame_number;
+ u16 earliest_frame;
+ u16 next_active_frame;
+ u16 relative_frame;
+ u16 interval;
+
+ /*
+ * Use the real frame number rather than the cached value as of the
+ * last SOF to give us a little extra slop.
+ */
+ frame_number = dwc2_hcd_get_frame_number(hsotg);
+
+ /*
+ * We wouldn't want to start any earlier than the next frame just in
+ * case the frame number ticks as we're doing this calculation.
+ *
+ * NOTE: if we could quantify how long till we actually get scheduled
+ * we might be able to avoid the "+ 1" by looking at the upper part of
+ * HFNUM (the FRREM field). For now we'll just use the + 1 though.
+ */
+ earliest_frame = dwc2_frame_num_inc(frame_number, 1);
+ next_active_frame = earliest_frame;
+
+ /* Get the "no microframe schduler" out of the way... */
+ if (hsotg->core_params->uframe_sched <= 0) {
+ if (qh->do_split)
+ /* Splits are active at microframe 0 minus 1 */
+ next_active_frame |= 0x7;
+ goto exit;
+ }
+
+ if (qh->dev_speed == USB_SPEED_HIGH || qh->do_split) {
+ /*
+ * We're either at high speed or we're doing a split (which
+ * means we're talking high speed to a hub). In any case
+ * the first frame should be based on when the first scheduled
+ * event is.
+ */
+ WARN_ON(qh->num_hs_transfers < 1);
+
+ relative_frame = qh->hs_transfers[0].start_schedule_us /
+ DWC2_HS_PERIODIC_US_PER_UFRAME;
+
+ /* Adjust interval as per high speed schedule */
+ interval = gcd(qh->host_interval, DWC2_HS_SCHEDULE_UFRAMES);
+
} else {
/*
- * if this is a fs transaction we may need a sequence
- * of frames
+ * Low or full speed directly on dwc2. Just about the same
+ * as high speed but on a different schedule and with slightly
+ * different adjustments. Note that this works because when
+ * the host and device are both low speed then frames in the
+ * controller tick at low speed.
*/
- ret = dwc2_find_multi_uframe(hsotg, qh);
+ relative_frame = qh->ls_start_schedule_slice /
+ DWC2_LS_PERIODIC_SLICES_PER_FRAME;
+ interval = gcd(qh->host_interval, DWC2_LS_SCHEDULE_FRAMES);
}
- return ret;
+
+ /* Scheduler messed up if frame is past interval */
+ WARN_ON(relative_frame >= interval);
+
+ /*
+ * We know interval must divide (HFNUM_MAX_FRNUM + 1) now that we've
+ * done the gcd(), so it's safe to move to the beginning of the current
+ * interval like this.
+ *
+ * After this we might be before earliest_frame, but don't worry,
+ * we'll fix it...
+ */
+ next_active_frame = (next_active_frame / interval) * interval;
+
+ /*
+ * Actually choose to start at the frame number we've been
+ * scheduled for.
+ */
+ next_active_frame = dwc2_frame_num_inc(next_active_frame,
+ relative_frame);
+
+ /*
+ * We actually need 1 frame before since the next_active_frame is
+ * the frame number we'll be put on the ready list and we won't be on
+ * the bus until 1 frame later.
+ */
+ next_active_frame = dwc2_frame_num_dec(next_active_frame, 1);
+
+ /*
+ * By now we might actually be before the earliest_frame. Let's move
+ * up intervals until we're not.
+ */
+ while (dwc2_frame_num_gt(earliest_frame, next_active_frame))
+ next_active_frame = dwc2_frame_num_inc(next_active_frame,
+ interval);
+
+exit:
+ qh->next_active_frame = next_active_frame;
+ qh->start_active_frame = next_active_frame;
+
+ dwc2_sch_vdbg(hsotg, "QH=%p First fn=%04x nxt=%04x\n",
+ qh, frame_number, qh->next_active_frame);
+}
+
+/**
+ * dwc2_do_reserve() - Make a periodic reservation
+ *
+ * Try to allocate space in the periodic schedule. Depending on parameters
+ * this might use the microframe scheduler or the dumb scheduler.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: QH for the periodic transfer.
+ *
+ * Returns: 0 upon success; error upon failure.
+ */
+static int dwc2_do_reserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ int status;
+
+ if (hsotg->core_params->uframe_sched > 0) {
+ status = dwc2_uframe_schedule(hsotg, qh);
+ } else {
+ status = dwc2_periodic_channel_available(hsotg);
+ if (status) {
+ dev_info(hsotg->dev,
+ "%s: No host channel available for periodic transfer\n",
+ __func__);
+ return status;
+ }
+
+ status = dwc2_check_periodic_bandwidth(hsotg, qh);
+ }
+
+ if (status) {
+ dev_dbg(hsotg->dev,
+ "%s: Insufficient periodic bandwidth for periodic transfer\n",
+ __func__);
+ return status;
+ }
+
+ if (hsotg->core_params->uframe_sched <= 0)
+ /* Reserve periodic channel */
+ hsotg->periodic_channels++;
+
+ /* Update claimed usecs per (micro)frame */
+ hsotg->periodic_usecs += qh->host_us;
+
+ dwc2_pick_first_frame(hsotg, qh);
+
+ return 0;
+}
+
+/**
+ * dwc2_do_unreserve() - Actually release the periodic reservation
+ *
+ * This function actually releases the periodic bandwidth that was reserved
+ * by the given qh.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: QH for the periodic transfer.
+ */
+static void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ assert_spin_locked(&hsotg->lock);
+
+ WARN_ON(!qh->unreserve_pending);
+
+ /* No more unreserve pending--we're doing it */
+ qh->unreserve_pending = false;
+
+ if (WARN_ON(!list_empty(&qh->qh_list_entry)))
+ list_del_init(&qh->qh_list_entry);
+
+ /* Update claimed usecs per (micro)frame */
+ hsotg->periodic_usecs -= qh->host_us;
+
+ if (hsotg->core_params->uframe_sched > 0) {
+ dwc2_uframe_unschedule(hsotg, qh);
+ } else {
+ /* Release periodic channel reservation */
+ hsotg->periodic_channels--;
+ }
+}
+
+/**
+ * dwc2_unreserve_timer_fn() - Timer function to release periodic reservation
+ *
+ * According to the kernel doc for usb_submit_urb() (specifically the part about
+ * "Reserved Bandwidth Transfers"), we need to keep a reservation active as
+ * long as a device driver keeps submitting. Since we're using HCD_BH to give
+ * back the URB we need to give the driver a little bit of time before we
+ * release the reservation. This worker is called after the appropriate
+ * delay.
+ *
+ * @work: Pointer to a qh unreserve_work.
+ */
+static void dwc2_unreserve_timer_fn(unsigned long data)
+{
+ struct dwc2_qh *qh = (struct dwc2_qh *)data;
+ struct dwc2_hsotg *hsotg = qh->hsotg;
+ unsigned long flags;
+
+ /*
+ * Wait for the lock, or for us to be scheduled again. We
+ * could be scheduled again if:
+ * - We started executing but didn't get the lock yet.
+ * - A new reservation came in, but cancel didn't take effect
+ * because we already started executing.
+ * - The timer has been kicked again.
+ * In that case cancel and wait for the next call.
+ */
+ while (!spin_trylock_irqsave(&hsotg->lock, flags)) {
+ if (timer_pending(&qh->unreserve_timer))
+ return;
+ }
+
+ /*
+ * Might be no more unreserve pending if:
+ * - We started executing but didn't get the lock yet.
+ * - A new reservation came in, but cancel didn't take effect
+ * because we already started executing.
+ *
+ * We can't put this in the loop above because unreserve_pending needs
+ * to be accessed under lock, so we can only check it once we got the
+ * lock.
+ */
+ if (qh->unreserve_pending)
+ dwc2_do_unreserve(hsotg, qh);
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
}
/**
@@ -474,42 +1353,6 @@ static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
int status;
- if (hsotg->core_params->uframe_sched > 0) {
- int frame = -1;
-
- status = dwc2_find_uframe(hsotg, qh);
- if (status == 0)
- frame = 7;
- else if (status > 0)
- frame = status - 1;
-
- /* Set the new frame up */
- if (frame >= 0) {
- qh->sched_frame &= ~0x7;
- qh->sched_frame |= (frame & 7);
- }
-
- if (status > 0)
- status = 0;
- } else {
- status = dwc2_periodic_channel_available(hsotg);
- if (status) {
- dev_info(hsotg->dev,
- "%s: No host channel available for periodic transfer\n",
- __func__);
- return status;
- }
-
- status = dwc2_check_periodic_bandwidth(hsotg, qh);
- }
-
- if (status) {
- dev_dbg(hsotg->dev,
- "%s: Insufficient periodic bandwidth for periodic transfer\n",
- __func__);
- return status;
- }
-
status = dwc2_check_max_xfer_size(hsotg, qh);
if (status) {
dev_dbg(hsotg->dev,
@@ -518,6 +1361,35 @@ static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
return status;
}
+ /* Cancel pending unreserve; if canceled OK, unreserve was pending */
+ if (del_timer(&qh->unreserve_timer))
+ WARN_ON(!qh->unreserve_pending);
+
+ /*
+ * Only need to reserve if there's not an unreserve pending, since if an
+ * unreserve is pending then by definition our old reservation is still
+ * valid. Unreserve might still be pending even if we didn't cancel if
+ * dwc2_unreserve_timer_fn() already started. Code in the timer handles
+ * that case.
+ */
+ if (!qh->unreserve_pending) {
+ status = dwc2_do_reserve(hsotg, qh);
+ if (status)
+ return status;
+ } else {
+ /*
+ * It might have been a while, so make sure that frame_number
+ * is still good. Note: we could also try to use the similar
+ * dwc2_next_periodic_start() but that schedules much more
+ * tightly and we might need to hurry and queue things up.
+ */
+ if (dwc2_frame_num_le(qh->next_active_frame,
+ hsotg->frame_number))
+ dwc2_pick_first_frame(hsotg, qh);
+ }
+
+ qh->unreserve_pending = 0;
+
if (hsotg->core_params->dma_desc_enable > 0)
/* Don't rely on SOF and start in ready schedule */
list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
@@ -526,14 +1398,7 @@ static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
list_add_tail(&qh->qh_list_entry,
&hsotg->periodic_sched_inactive);
- if (hsotg->core_params->uframe_sched <= 0)
- /* Reserve periodic channel */
- hsotg->periodic_channels++;
-
- /* Update claimed usecs per (micro)frame */
- hsotg->periodic_usecs += qh->usecs;
-
- return status;
+ return 0;
}
/**
@@ -546,25 +1411,231 @@ static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
struct dwc2_qh *qh)
{
- int i;
+ bool did_modify;
+
+ assert_spin_locked(&hsotg->lock);
+
+ /*
+ * Schedule the unreserve to happen in a little bit. Cases here:
+ * - Unreserve worker might be sitting there waiting to grab the lock.
+ * In this case it will notice it's been schedule again and will
+ * quit.
+ * - Unreserve worker might not be scheduled.
+ *
+ * We should never already be scheduled since dwc2_schedule_periodic()
+ * should have canceled the scheduled unreserve timer (hence the
+ * warning on did_modify).
+ *
+ * We add + 1 to the timer to guarantee that at least 1 jiffy has
+ * passed (otherwise if the jiffy counter might tick right after we
+ * read it and we'll get no delay).
+ */
+ did_modify = mod_timer(&qh->unreserve_timer,
+ jiffies + DWC2_UNRESERVE_DELAY + 1);
+ WARN_ON(did_modify);
+ qh->unreserve_pending = 1;
list_del_init(&qh->qh_list_entry);
+}
- /* Update claimed usecs per (micro)frame */
- hsotg->periodic_usecs -= qh->usecs;
+/**
+ * dwc2_qh_init() - Initializes a QH structure
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: The QH to init
+ * @urb: Holds the information about the device/endpoint needed to initialize
+ * the QH
+ * @mem_flags: Flags for allocating memory.
+ */
+static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ struct dwc2_hcd_urb *urb, gfp_t mem_flags)
+{
+ int dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
+ u8 ep_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+ bool ep_is_in = !!dwc2_hcd_is_pipe_in(&urb->pipe_info);
+ bool ep_is_isoc = (ep_type == USB_ENDPOINT_XFER_ISOC);
+ bool ep_is_int = (ep_type == USB_ENDPOINT_XFER_INT);
+ u32 hprt = dwc2_readl(hsotg->regs + HPRT0);
+ u32 prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
+ bool do_split = (prtspd == HPRT0_SPD_HIGH_SPEED &&
+ dev_speed != USB_SPEED_HIGH);
+ int maxp = dwc2_hcd_get_mps(&urb->pipe_info);
+ int bytecount = dwc2_hb_mult(maxp) * dwc2_max_packet(maxp);
+ char *speed, *type;
- if (hsotg->core_params->uframe_sched > 0) {
- for (i = 0; i < 8; i++) {
- hsotg->frame_usecs[i] += qh->frame_usecs[i];
- qh->frame_usecs[i] = 0;
+ /* Initialize QH */
+ qh->hsotg = hsotg;
+ setup_timer(&qh->unreserve_timer, dwc2_unreserve_timer_fn,
+ (unsigned long)qh);
+ qh->ep_type = ep_type;
+ qh->ep_is_in = ep_is_in;
+
+ qh->data_toggle = DWC2_HC_PID_DATA0;
+ qh->maxp = maxp;
+ INIT_LIST_HEAD(&qh->qtd_list);
+ INIT_LIST_HEAD(&qh->qh_list_entry);
+
+ qh->do_split = do_split;
+ qh->dev_speed = dev_speed;
+
+ if (ep_is_int || ep_is_isoc) {
+ /* Compute scheduling parameters once and save them */
+ int host_speed = do_split ? USB_SPEED_HIGH : dev_speed;
+ struct dwc2_tt *dwc_tt = dwc2_host_get_tt_info(hsotg, urb->priv,
+ mem_flags,
+ &qh->ttport);
+ int device_ns;
+
+ qh->dwc_tt = dwc_tt;
+
+ qh->host_us = NS_TO_US(usb_calc_bus_time(host_speed, ep_is_in,
+ ep_is_isoc, bytecount));
+ device_ns = usb_calc_bus_time(dev_speed, ep_is_in,
+ ep_is_isoc, bytecount);
+
+ if (do_split && dwc_tt)
+ device_ns += dwc_tt->usb_tt->think_time;
+ qh->device_us = NS_TO_US(device_ns);
+
+
+ qh->device_interval = urb->interval;
+ qh->host_interval = urb->interval * (do_split ? 8 : 1);
+
+ /*
+ * Schedule low speed if we're running the host in low or
+ * full speed OR if we've got a "TT" to deal with to access this
+ * device.
+ */
+ qh->schedule_low_speed = prtspd != HPRT0_SPD_HIGH_SPEED ||
+ dwc_tt;
+
+ if (do_split) {
+ /* We won't know num transfers until we schedule */
+ qh->num_hs_transfers = -1;
+ } else if (dev_speed == USB_SPEED_HIGH) {
+ qh->num_hs_transfers = 1;
+ } else {
+ qh->num_hs_transfers = 0;
}
- } else {
- /* Release periodic channel reservation */
- hsotg->periodic_channels--;
+
+ /* We'll schedule later when we have something to do */
+ }
+
+ switch (dev_speed) {
+ case USB_SPEED_LOW:
+ speed = "low";
+ break;
+ case USB_SPEED_FULL:
+ speed = "full";
+ break;
+ case USB_SPEED_HIGH:
+ speed = "high";
+ break;
+ default:
+ speed = "?";
+ break;
+ }
+
+ switch (qh->ep_type) {
+ case USB_ENDPOINT_XFER_ISOC:
+ type = "isochronous";
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ type = "interrupt";
+ break;
+ case USB_ENDPOINT_XFER_CONTROL:
+ type = "control";
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ type = "bulk";
+ break;
+ default:
+ type = "?";
+ break;
+ }
+
+ dwc2_sch_dbg(hsotg, "QH=%p Init %s, %s speed, %d bytes:\n", qh, type,
+ speed, bytecount);
+ dwc2_sch_dbg(hsotg, "QH=%p ...addr=%d, ep=%d, %s\n", qh,
+ dwc2_hcd_get_dev_addr(&urb->pipe_info),
+ dwc2_hcd_get_ep_num(&urb->pipe_info),
+ ep_is_in ? "IN" : "OUT");
+ if (ep_is_int || ep_is_isoc) {
+ dwc2_sch_dbg(hsotg,
+ "QH=%p ...duration: host=%d us, device=%d us\n",
+ qh, qh->host_us, qh->device_us);
+ dwc2_sch_dbg(hsotg, "QH=%p ...interval: host=%d, device=%d\n",
+ qh, qh->host_interval, qh->device_interval);
+ if (qh->schedule_low_speed)
+ dwc2_sch_dbg(hsotg, "QH=%p ...low speed schedule=%p\n",
+ qh, dwc2_get_ls_map(hsotg, qh));
}
}
/**
+ * dwc2_hcd_qh_create() - Allocates and initializes a QH
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @urb: Holds the information about the device/endpoint needed
+ * to initialize the QH
+ * @atomic_alloc: Flag to do atomic allocation if needed
+ *
+ * Return: Pointer to the newly allocated QH, or NULL on error
+ */
+struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
+ struct dwc2_hcd_urb *urb,
+ gfp_t mem_flags)
+{
+ struct dwc2_qh *qh;
+
+ if (!urb->priv)
+ return NULL;
+
+ /* Allocate memory */
+ qh = kzalloc(sizeof(*qh), mem_flags);
+ if (!qh)
+ return NULL;
+
+ dwc2_qh_init(hsotg, qh, urb, mem_flags);
+
+ if (hsotg->core_params->dma_desc_enable > 0 &&
+ dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) {
+ dwc2_hcd_qh_free(hsotg, qh);
+ return NULL;
+ }
+
+ return qh;
+}
+
+/**
+ * dwc2_hcd_qh_free() - Frees the QH
+ *
+ * @hsotg: HCD instance
+ * @qh: The QH to free
+ *
+ * QH should already be removed from the list. QTD list should already be empty
+ * if called from URB Dequeue.
+ *
+ * Must NOT be called with interrupt disabled or spinlock held
+ */
+void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ /* Make sure any unreserve work is finished. */
+ if (del_timer_sync(&qh->unreserve_timer)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ dwc2_do_unreserve(hsotg, qh);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ }
+ dwc2_host_put_tt_info(hsotg, qh->dwc_tt);
+
+ if (qh->desc_list)
+ dwc2_hcd_qh_free_ddma(hsotg, qh);
+ kfree(qh);
+}
+
+/**
* dwc2_hcd_qh_add() - Adds a QH to either the non periodic or periodic
* schedule if it is not already in the schedule. If the QH is already in
* the schedule, no action is taken.
@@ -586,16 +1657,12 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
/* QH already in a schedule */
return 0;
- if (!dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number) &&
- !hsotg->frame_number) {
- dev_dbg(hsotg->dev,
- "reset frame number counter\n");
- qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
- SCHEDULE_SLOP);
- }
-
/* Add the new QH to the appropriate schedule */
if (dwc2_qh_is_non_per(qh)) {
+ /* Schedule right away */
+ qh->start_active_frame = hsotg->frame_number;
+ qh->next_active_frame = qh->start_active_frame;
+
/* Always start in inactive schedule */
list_add_tail(&qh->qh_list_entry,
&hsotg->non_periodic_sched_inactive);
@@ -649,39 +1716,164 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
}
}
-/*
- * Schedule the next continuing periodic split transfer
+/**
+ * dwc2_next_for_periodic_split() - Set next_active_frame midway thru a split.
+ *
+ * This is called for setting next_active_frame for periodic splits for all but
+ * the first packet of the split. Confusing? I thought so...
+ *
+ * Periodic splits are single low/full speed transfers that we end up splitting
+ * up into several high speed transfers. They always fit into one full (1 ms)
+ * frame but might be split over several microframes (125 us each). We to put
+ * each of the parts on a very specific high speed frame.
+ *
+ * This function figures out where the next active uFrame needs to be.
+ *
+ * @hsotg: The HCD state structure
+ * @qh: QH for the periodic transfer.
+ * @frame_number: The current frame number.
+ *
+ * Return: number missed by (or 0 if we didn't miss).
*/
-static void dwc2_sched_periodic_split(struct dwc2_hsotg *hsotg,
- struct dwc2_qh *qh, u16 frame_number,
- int sched_next_periodic_split)
+static int dwc2_next_for_periodic_split(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh, u16 frame_number)
{
+ u16 old_frame = qh->next_active_frame;
+ u16 prev_frame_number = dwc2_frame_num_dec(frame_number, 1);
+ int missed = 0;
u16 incr;
- if (sched_next_periodic_split) {
- qh->sched_frame = frame_number;
- incr = dwc2_frame_num_inc(qh->start_split_frame, 1);
- if (dwc2_frame_num_le(frame_number, incr)) {
- /*
- * Allow one frame to elapse after start split
- * microframe before scheduling complete split, but
- * DON'T if we are doing the next start split in the
- * same frame for an ISOC out
- */
- if (qh->ep_type != USB_ENDPOINT_XFER_ISOC ||
- qh->ep_is_in != 0) {
- qh->sched_frame =
- dwc2_frame_num_inc(qh->sched_frame, 1);
- }
- }
- } else {
- qh->sched_frame = dwc2_frame_num_inc(qh->start_split_frame,
- qh->interval);
- if (dwc2_frame_num_le(qh->sched_frame, frame_number))
- qh->sched_frame = frame_number;
- qh->sched_frame |= 0x7;
- qh->start_split_frame = qh->sched_frame;
+ /*
+ * See dwc2_uframe_schedule_split() for split scheduling.
+ *
+ * Basically: increment 1 normally, but 2 right after the start split
+ * (except for ISOC out).
+ */
+ if (old_frame == qh->start_active_frame &&
+ !(qh->ep_type == USB_ENDPOINT_XFER_ISOC && !qh->ep_is_in))
+ incr = 2;
+ else
+ incr = 1;
+
+ qh->next_active_frame = dwc2_frame_num_inc(old_frame, incr);
+
+ /*
+ * Note that it's OK for frame_number to be 1 frame past
+ * next_active_frame. Remember that next_active_frame is supposed to
+ * be 1 frame _before_ when we want to be scheduled. If we're 1 frame
+ * past it just means schedule ASAP.
+ *
+ * It's _not_ OK, however, if we're more than one frame past.
+ */
+ if (dwc2_frame_num_gt(prev_frame_number, qh->next_active_frame)) {
+ /*
+ * OOPS, we missed. That's actually pretty bad since
+ * the hub will be unhappy; try ASAP I guess.
+ */
+ missed = dwc2_frame_num_dec(prev_frame_number,
+ qh->next_active_frame);
+ qh->next_active_frame = frame_number;
}
+
+ return missed;
+}
+
+/**
+ * dwc2_next_periodic_start() - Set next_active_frame for next transfer start
+ *
+ * This is called for setting next_active_frame for a periodic transfer for
+ * all cases other than midway through a periodic split. This will also update
+ * start_active_frame.
+ *
+ * Since we _always_ keep start_active_frame as the start of the previous
+ * transfer this is normally pretty easy: we just add our interval to
+ * start_active_frame and we've got our answer.
+ *
+ * The tricks come into play if we miss. In that case we'll look for the next
+ * slot we can fit into.
+ *
+ * @hsotg: The HCD state structure
+ * @qh: QH for the periodic transfer.
+ * @frame_number: The current frame number.
+ *
+ * Return: number missed by (or 0 if we didn't miss).
+ */
+static int dwc2_next_periodic_start(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh, u16 frame_number)
+{
+ int missed = 0;
+ u16 interval = qh->host_interval;
+ u16 prev_frame_number = dwc2_frame_num_dec(frame_number, 1);
+
+ qh->start_active_frame = dwc2_frame_num_inc(qh->start_active_frame,
+ interval);
+
+ /*
+ * The dwc2_frame_num_gt() function used below won't work terribly well
+ * with if we just incremented by a really large intervals since the
+ * frame counter only goes to 0x3fff. It's terribly unlikely that we
+ * will have missed in this case anyway. Just go to exit. If we want
+ * to try to do better we'll need to keep track of a bigger counter
+ * somewhere in the driver and handle overflows.
+ */
+ if (interval >= 0x1000)
+ goto exit;
+
+ /*
+ * Test for misses, which is when it's too late to schedule.
+ *
+ * A few things to note:
+ * - We compare against prev_frame_number since start_active_frame
+ * and next_active_frame are always 1 frame before we want things
+ * to be active and we assume we can still get scheduled in the
+ * current frame number.
+ * - It's possible for start_active_frame (now incremented) to be
+ * next_active_frame if we got an EO MISS (even_odd miss) which
+ * basically means that we detected there wasn't enough time for
+ * the last packet and dwc2_hc_set_even_odd_frame() rescheduled us
+ * at the last second. We want to make sure we don't schedule
+ * another transfer for the same frame. My test webcam doesn't seem
+ * terribly upset by missing a transfer but really doesn't like when
+ * we do two transfers in the same frame.
+ * - Some misses are expected. Specifically, in order to work
+ * perfectly dwc2 really needs quite spectacular interrupt latency
+ * requirements. It needs to be able to handle its interrupts
+ * completely within 125 us of them being asserted. That not only
+ * means that the dwc2 interrupt handler needs to be fast but it
+ * means that nothing else in the system has to block dwc2 for a long
+ * time. We can help with the dwc2 parts of this, but it's hard to
+ * guarantee that a system will have interrupt latency < 125 us, so
+ * we have to be robust to some misses.
+ */
+ if (qh->start_active_frame == qh->next_active_frame ||
+ dwc2_frame_num_gt(prev_frame_number, qh->start_active_frame)) {
+ u16 ideal_start = qh->start_active_frame;
+ int periods_in_map;
+
+ /*
+ * Adjust interval as per gcd with map size.
+ * See pmap_schedule() for more details here.
+ */
+ if (qh->do_split || qh->dev_speed == USB_SPEED_HIGH)
+ periods_in_map = DWC2_HS_SCHEDULE_UFRAMES;
+ else
+ periods_in_map = DWC2_LS_SCHEDULE_FRAMES;
+ interval = gcd(interval, periods_in_map);
+
+ do {
+ qh->start_active_frame = dwc2_frame_num_inc(
+ qh->start_active_frame, interval);
+ } while (dwc2_frame_num_gt(prev_frame_number,
+ qh->start_active_frame));
+
+ missed = dwc2_frame_num_dec(qh->start_active_frame,
+ ideal_start);
+ }
+
+exit:
+ qh->next_active_frame = qh->start_active_frame;
+
+ return missed;
}
/*
@@ -700,7 +1892,9 @@ static void dwc2_sched_periodic_split(struct dwc2_hsotg *hsotg,
void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
int sched_next_periodic_split)
{
+ u16 old_frame = qh->next_active_frame;
u16 frame_number;
+ int missed;
if (dbg_qh(qh))
dev_vdbg(hsotg->dev, "%s()\n", __func__);
@@ -713,33 +1907,44 @@ void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
return;
}
+ /*
+ * Use the real frame number rather than the cached value as of the
+ * last SOF just to get us a little closer to reality. Note that
+ * means we don't actually know if we've already handled the SOF
+ * interrupt for this frame.
+ */
frame_number = dwc2_hcd_get_frame_number(hsotg);
- if (qh->do_split) {
- dwc2_sched_periodic_split(hsotg, qh, frame_number,
- sched_next_periodic_split);
- } else {
- qh->sched_frame = dwc2_frame_num_inc(qh->sched_frame,
- qh->interval);
- if (dwc2_frame_num_le(qh->sched_frame, frame_number))
- qh->sched_frame = frame_number;
- }
+ if (sched_next_periodic_split)
+ missed = dwc2_next_for_periodic_split(hsotg, qh, frame_number);
+ else
+ missed = dwc2_next_periodic_start(hsotg, qh, frame_number);
+
+ dwc2_sch_vdbg(hsotg,
+ "QH=%p next(%d) fn=%04x, sch=%04x=>%04x (%+d) miss=%d %s\n",
+ qh, sched_next_periodic_split, frame_number, old_frame,
+ qh->next_active_frame,
+ dwc2_frame_num_dec(qh->next_active_frame, old_frame),
+ missed, missed ? "MISS" : "");
if (list_empty(&qh->qtd_list)) {
dwc2_hcd_qh_unlink(hsotg, qh);
return;
}
+
/*
* Remove from periodic_sched_queued and move to
* appropriate queue
+ *
+ * Note: we purposely use the frame_number from the "hsotg" structure
+ * since we know SOF interrupt will handle future frames.
*/
- if ((hsotg->core_params->uframe_sched > 0 &&
- dwc2_frame_num_le(qh->sched_frame, frame_number)) ||
- (hsotg->core_params->uframe_sched <= 0 &&
- qh->sched_frame == frame_number))
- list_move(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
+ if (dwc2_frame_num_le(qh->next_active_frame, hsotg->frame_number))
+ list_move_tail(&qh->qh_list_entry,
+ &hsotg->periodic_sched_ready);
else
- list_move(&qh->qh_list_entry, &hsotg->periodic_sched_inactive);
+ list_move_tail(&qh->qh_list_entry,
+ &hsotg->periodic_sched_inactive);
}
/**
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 690b9fd98b55..88629bed6614 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -126,10 +126,10 @@ static const struct dwc2_core_params params_rk3066 = {
.speed = -1,
.enable_dynamic_fifo = 1,
.en_multiple_tx_fifo = -1,
- .host_rx_fifo_size = 520, /* 520 DWORDs */
+ .host_rx_fifo_size = 525, /* 525 DWORDs */
.host_nperio_tx_fifo_size = 128, /* 128 DWORDs */
.host_perio_tx_fifo_size = 256, /* 256 DWORDs */
- .max_transfer_size = 65535,
+ .max_transfer_size = -1,
.max_packet_count = -1,
.host_channels = -1,
.phy_type = -1,
@@ -149,6 +149,38 @@ static const struct dwc2_core_params params_rk3066 = {
.hibernation = -1,
};
+static const struct dwc2_core_params params_ltq = {
+ .otg_cap = 2, /* non-HNP/non-SRP */
+ .otg_ver = -1,
+ .dma_enable = -1,
+ .dma_desc_enable = -1,
+ .dma_desc_fs_enable = -1,
+ .speed = -1,
+ .enable_dynamic_fifo = -1,
+ .en_multiple_tx_fifo = -1,
+ .host_rx_fifo_size = 288, /* 288 DWORDs */
+ .host_nperio_tx_fifo_size = 128, /* 128 DWORDs */
+ .host_perio_tx_fifo_size = 96, /* 96 DWORDs */
+ .max_transfer_size = 65535,
+ .max_packet_count = 511,
+ .host_channels = -1,
+ .phy_type = -1,
+ .phy_utmi_width = -1,
+ .phy_ulpi_ddr = -1,
+ .phy_ulpi_ext_vbus = -1,
+ .i2c_enable = -1,
+ .ulpi_fs_ls = -1,
+ .host_support_fs_ls_low_power = -1,
+ .host_ls_low_power_phy_clk = -1,
+ .ts_dline = -1,
+ .reload_ctl = -1,
+ .ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
+ GAHBCFG_HBSTLEN_SHIFT,
+ .uframe_sched = -1,
+ .external_id_pin_ctl = -1,
+ .hibernation = -1,
+};
+
/*
* Check the dr_mode against the module configuration and hardware
* capabilities.
@@ -428,6 +460,8 @@ static const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "brcm,bcm2835-usb", .data = &params_bcm2835 },
{ .compatible = "hisilicon,hi6220-usb", .data = &params_hi6220 },
{ .compatible = "rockchip,rk3066-usb", .data = &params_rk3066 },
+ { .compatible = "lantiq,arx100-usb", .data = &params_ltq },
+ { .compatible = "lantiq,xrx200-usb", .data = &params_ltq },
{ .compatible = "snps,dwc2", .data = NULL },
{ .compatible = "samsung,s3c6400-hsotg", .data = NULL},
{},
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index de5e01f41bc2..17fd81447c9f 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -962,10 +962,6 @@ static int dwc3_probe(struct platform_device *pdev)
fladj = pdata->fladj_value;
}
- /* default to superspeed if no maximum_speed passed */
- if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
- dwc->maximum_speed = USB_SPEED_SUPER;
-
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
dwc->tx_de_emphasis = tx_de_emphasis;
@@ -1016,6 +1012,33 @@ static int dwc3_probe(struct platform_device *pdev)
goto err1;
}
+ /* Check the maximum_speed parameter */
+ switch (dwc->maximum_speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
+ break;
+ default:
+ dev_err(dev, "invalid maximum_speed parameter %d\n",
+ dwc->maximum_speed);
+ /* fall through */
+ case USB_SPEED_UNKNOWN:
+ /* default to superspeed */
+ dwc->maximum_speed = USB_SPEED_SUPER;
+
+ /*
+ * default to superspeed plus if we are capable.
+ */
+ if (dwc3_is_usb31(dwc) &&
+ (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
+ DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
+ dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
+
+ break;
+ }
+
/* Adjust Frame Length */
dwc3_frame_length_adjustment(dwc, fladj);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 29130682e547..6254b2ff9080 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -223,7 +223,8 @@
/* Global HWPARAMS3 Register */
#define DWC3_GHWPARAMS3_SSPHY_IFC(n) ((n) & 3)
#define DWC3_GHWPARAMS3_SSPHY_IFC_DIS 0
-#define DWC3_GHWPARAMS3_SSPHY_IFC_ENA 1
+#define DWC3_GHWPARAMS3_SSPHY_IFC_GEN1 1
+#define DWC3_GHWPARAMS3_SSPHY_IFC_GEN2 2 /* DWC_usb31 only */
#define DWC3_GHWPARAMS3_HSPHY_IFC(n) (((n) & (3 << 2)) >> 2)
#define DWC3_GHWPARAMS3_HSPHY_IFC_DIS 0
#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI 1
@@ -249,6 +250,7 @@
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
#define DWC3_DCFG_SPEED_MASK (7 << 0)
+#define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
#define DWC3_DCFG_SUPERSPEED (4 << 0)
#define DWC3_DCFG_HIGHSPEED (0 << 0)
#define DWC3_DCFG_FULLSPEED2 (1 << 0)
@@ -339,6 +341,7 @@
#define DWC3_DSTS_CONNECTSPD (7 << 0)
+#define DWC3_DSTS_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
#define DWC3_DSTS_SUPERSPEED (4 << 0)
#define DWC3_DSTS_HIGHSPEED (0 << 0)
#define DWC3_DSTS_FULLSPEED2 (1 << 0)
@@ -856,7 +859,6 @@ struct dwc3 {
unsigned pullups_connected:1;
unsigned resize_fifos:1;
unsigned setup_packet_pending:1;
- unsigned start_config_issued:1;
unsigned three_stage_setup:1;
unsigned usb3_lpm_capable:1;
@@ -1025,6 +1027,12 @@ 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_usb31 core */
+static inline bool dwc3_is_usb31(struct dwc3 *dwc)
+{
+ return !!(dwc->revision & DWC3_REVISION_IS_DWC31);
+}
+
#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/ep0.c b/drivers/usb/dwc3/ep0.c
index 3a9354abcb68..eca2e6d8e041 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -356,7 +356,8 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
*/
usb_status |= dwc->gadget.is_selfpowered;
- if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
+ if ((dwc->speed == DWC3_DSTS_SUPERSPEED) ||
+ (dwc->speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (reg & DWC3_DCTL_INITU1ENA)
usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
@@ -426,7 +427,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
case USB_DEVICE_U1_ENABLE:
if (state != USB_STATE_CONFIGURED)
return -EINVAL;
- if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+ if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
+ (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
@@ -440,7 +442,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
case USB_DEVICE_U2_ENABLE:
if (state != USB_STATE_CONFIGURED)
return -EINVAL;
- if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+ if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
+ (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
@@ -555,7 +558,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
int ret;
u32 reg;
- dwc->start_config_issued = false;
cfg = le16_to_cpu(ctrl->wValue);
switch (state) {
@@ -737,10 +739,6 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
break;
- case USB_REQ_SET_INTERFACE:
- dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE");
- dwc->start_config_issued = false;
- /* Fall through */
default:
dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
ret = dwc3_ep0_delegate_req(dwc, ctrl);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 7d1dd82a95ac..3ac170f9d94d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -385,24 +385,66 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep)
dep->trb_pool_dma = 0;
}
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep);
+
+/**
+ * dwc3_gadget_start_config - Configure EP resources
+ * @dwc: pointer to our controller context structure
+ * @dep: endpoint that is being enabled
+ *
+ * The assignment of transfer resources cannot perfectly follow the
+ * data book due to the fact that the controller driver does not have
+ * all knowledge of the configuration in advance. It is given this
+ * information piecemeal by the composite gadget framework after every
+ * SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook
+ * programming model in this scenario can cause errors. For two
+ * reasons:
+ *
+ * 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION
+ * and SET_INTERFACE (8.1.5). This is incorrect in the scenario of
+ * multiple interfaces.
+ *
+ * 2) The databook does not mention doing more DEPXFERCFG for new
+ * endpoint on alt setting (8.1.6).
+ *
+ * The following simplified method is used instead:
+ *
+ * All hardware endpoints can be assigned a transfer resource and this
+ * setting will stay persistent until either a core reset or
+ * hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and
+ * do DEPXFERCFG for every hardware endpoint as well. We are
+ * guaranteed that there are as many transfer resources as endpoints.
+ *
+ * This function is called for each endpoint when it is being enabled
+ * but is triggered only when called for EP0-out, which always happens
+ * first, and which should only happen in one of the above conditions.
+ */
static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
{
struct dwc3_gadget_ep_cmd_params params;
u32 cmd;
+ int i;
+ int ret;
+
+ if (dep->number)
+ return 0;
memset(&params, 0x00, sizeof(params));
+ cmd = DWC3_DEPCMD_DEPSTARTCFG;
- if (dep->number != 1) {
- cmd = DWC3_DEPCMD_DEPSTARTCFG;
- /* XferRscIdx == 0 for ep0 and 2 for the remaining */
- if (dep->number > 1) {
- if (dwc->start_config_issued)
- return 0;
- dwc->start_config_issued = true;
- cmd |= DWC3_DEPCMD_PARAM(2);
- }
+ ret = dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
+ struct dwc3_ep *dep = dwc->eps[i];
- return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+ if (!dep)
+ continue;
+
+ ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+ if (ret)
+ return ret;
}
return 0;
@@ -421,7 +463,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc));
/* Burst size is only needed in SuperSpeed mode */
- if (dwc->gadget.speed == USB_SPEED_SUPER) {
+ if (dwc->gadget.speed >= USB_SPEED_SUPER) {
u32 burst = dep->endpoint.maxburst - 1;
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
@@ -516,10 +558,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
struct dwc3_trb *trb_st_hw;
struct dwc3_trb *trb_link;
- ret = dwc3_gadget_set_xfer_resource(dwc, dep);
- if (ret)
- return ret;
-
dep->endpoint.desc = desc;
dep->comp_desc = comp_desc;
dep->type = usb_endpoint_type(desc);
@@ -1403,7 +1441,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
speed = reg & DWC3_DSTS_CONNECTSPD;
- if (speed == DWC3_DSTS_SUPERSPEED) {
+ if ((speed == DWC3_DSTS_SUPERSPEED) ||
+ (speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n");
ret = -EINVAL;
goto out;
@@ -1628,16 +1667,20 @@ static int dwc3_gadget_start(struct usb_gadget *g,
case USB_SPEED_HIGH:
reg |= DWC3_DSTS_HIGHSPEED;
break;
- case USB_SPEED_SUPER: /* FALLTHROUGH */
- case USB_SPEED_UNKNOWN: /* FALTHROUGH */
+ case USB_SPEED_SUPER_PLUS:
+ reg |= DWC3_DSTS_SUPERSPEED_PLUS;
+ break;
default:
- reg |= DWC3_DSTS_SUPERSPEED;
+ dev_err(dwc->dev, "invalid dwc->maximum_speed (%d)\n",
+ dwc->maximum_speed);
+ /* fall through */
+ case USB_SPEED_SUPER:
+ reg |= DWC3_DCFG_SUPERSPEED;
+ break;
}
}
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
- dwc->start_config_issued = false;
-
/* Start with SuperSpeed Default */
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
@@ -2237,7 +2280,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc3_disconnect_gadget(dwc);
- dwc->start_config_issued = false;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->setup_packet_pending = false;
@@ -2288,7 +2330,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
dwc3_stop_active_transfers(dwc);
dwc3_clear_stall_all_ep(dwc);
- dwc->start_config_issued = false;
/* Reset device address to zero */
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
@@ -2306,7 +2347,8 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
* this. Maybe it becomes part of the power saving plan.
*/
- if (speed != DWC3_DSTS_SUPERSPEED)
+ if ((speed != DWC3_DSTS_SUPERSPEED) &&
+ (speed != DWC3_DSTS_SUPERSPEED_PLUS))
return;
/*
@@ -2335,6 +2377,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
dwc3_update_ram_clk_sel(dwc, speed);
switch (speed) {
+ case DWC3_DCFG_SUPERSPEED_PLUS:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+ dwc->gadget.ep0->maxpacket = 512;
+ dwc->gadget.speed = USB_SPEED_SUPER_PLUS;
+ break;
case DWC3_DCFG_SUPERSPEED:
/*
* WORKAROUND: DWC3 revisions <1.90a have an issue which
@@ -2376,8 +2423,9 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
/* Enable USB2 LPM Capability */
- if ((dwc->revision > DWC3_REVISION_194A)
- && (speed != DWC3_DCFG_SUPERSPEED)) {
+ if ((dwc->revision > DWC3_REVISION_194A) &&
+ (speed != DWC3_DCFG_SUPERSPEED) &&
+ (speed != DWC3_DCFG_SUPERSPEED_PLUS)) {
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg |= DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 8b14c2a13ac5..a5c62093c26c 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -54,6 +54,36 @@ static struct usb_gadget_strings **get_containers_gs(
}
/**
+ * function_descriptors() - get function descriptors for speed
+ * @f: the function
+ * @speed: the speed
+ *
+ * Returns the descriptors or NULL if not set.
+ */
+static struct usb_descriptor_header **
+function_descriptors(struct usb_function *f,
+ enum usb_device_speed speed)
+{
+ struct usb_descriptor_header **descriptors;
+
+ switch (speed) {
+ case USB_SPEED_SUPER_PLUS:
+ descriptors = f->ssp_descriptors;
+ break;
+ case USB_SPEED_SUPER:
+ descriptors = f->ss_descriptors;
+ break;
+ case USB_SPEED_HIGH:
+ descriptors = f->hs_descriptors;
+ break;
+ default:
+ descriptors = f->fs_descriptors;
+ }
+
+ return descriptors;
+}
+
+/**
* next_ep_desc() - advance to the next EP descriptor
* @t: currect pointer within descriptor array
*
@@ -118,6 +148,13 @@ int config_ep_by_speed(struct usb_gadget *g,
/* select desired speed */
switch (g->speed) {
+ case USB_SPEED_SUPER_PLUS:
+ if (gadget_is_superspeed_plus(g)) {
+ speed_desc = f->ssp_descriptors;
+ want_comp_desc = 1;
+ break;
+ }
+ /* else: Fall trough */
case USB_SPEED_SUPER:
if (gadget_is_superspeed(g)) {
speed_desc = f->ss_descriptors;
@@ -161,7 +198,7 @@ ep_found:
(comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
return -EIO;
_ep->comp_desc = comp_desc;
- if (g->speed == USB_SPEED_SUPER) {
+ if (g->speed >= USB_SPEED_SUPER) {
switch (usb_endpoint_type(_ep->desc)) {
case USB_ENDPOINT_XFER_ISOC:
/* mult: bits 1:0 of bmAttributes */
@@ -237,6 +274,8 @@ int usb_add_function(struct usb_configuration *config,
config->highspeed = true;
if (!config->superspeed && function->ss_descriptors)
config->superspeed = true;
+ if (!config->superspeed_plus && function->ssp_descriptors)
+ config->superspeed_plus = true;
done:
if (value)
@@ -417,17 +456,7 @@ static int config_buf(struct usb_configuration *config,
list_for_each_entry(f, &config->functions, list) {
struct usb_descriptor_header **descriptors;
- switch (speed) {
- case USB_SPEED_SUPER:
- descriptors = f->ss_descriptors;
- break;
- case USB_SPEED_HIGH:
- descriptors = f->hs_descriptors;
- break;
- default:
- descriptors = f->fs_descriptors;
- }
-
+ descriptors = function_descriptors(f, speed);
if (!descriptors)
continue;
status = usb_descriptor_fillbuf(next, len,
@@ -451,7 +480,7 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
u8 type = w_value >> 8;
enum usb_device_speed speed = USB_SPEED_UNKNOWN;
- if (gadget->speed == USB_SPEED_SUPER)
+ if (gadget->speed >= USB_SPEED_SUPER)
speed = gadget->speed;
else if (gadget_is_dualspeed(gadget)) {
int hs = 0;
@@ -482,6 +511,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
check_config:
/* ignore configs that won't work at this speed */
switch (speed) {
+ case USB_SPEED_SUPER_PLUS:
+ if (!c->superspeed_plus)
+ continue;
+ break;
case USB_SPEED_SUPER:
if (!c->superspeed)
continue;
@@ -509,18 +542,24 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
unsigned count = 0;
int hs = 0;
int ss = 0;
+ int ssp = 0;
if (gadget_is_dualspeed(gadget)) {
if (gadget->speed == USB_SPEED_HIGH)
hs = 1;
if (gadget->speed == USB_SPEED_SUPER)
ss = 1;
+ if (gadget->speed == USB_SPEED_SUPER_PLUS)
+ ssp = 1;
if (type == USB_DT_DEVICE_QUALIFIER)
hs = !hs;
}
list_for_each_entry(c, &cdev->configs, list) {
/* ignore configs that won't work at this speed */
- if (ss) {
+ if (ssp) {
+ if (!c->superspeed_plus)
+ continue;
+ } else if (ss) {
if (!c->superspeed)
continue;
} else if (hs) {
@@ -597,6 +636,48 @@ static int bos_desc(struct usb_composite_dev *cdev)
ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
+ /* The SuperSpeedPlus USB Device Capability descriptor */
+ if (gadget_is_superspeed_plus(cdev->gadget)) {
+ struct usb_ssp_cap_descriptor *ssp_cap;
+
+ ssp_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+ bos->bNumDeviceCaps++;
+
+ /*
+ * Report typical values.
+ */
+
+ le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(1));
+ ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(1);
+ ssp_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+ ssp_cap->bDevCapabilityType = USB_SSP_CAP_TYPE;
+
+ /* SSAC = 1 (2 attributes) */
+ ssp_cap->bmAttributes = cpu_to_le32(1);
+
+ /* Min RX/TX Lane Count = 1 */
+ ssp_cap->wFunctionalitySupport = (1 << 8) | (1 << 12);
+
+ /*
+ * bmSublinkSpeedAttr[0]:
+ * ST = Symmetric, RX
+ * LSE = 3 (Gbps)
+ * LP = 1 (SuperSpeedPlus)
+ * LSM = 10 (10 Gbps)
+ */
+ ssp_cap->bmSublinkSpeedAttr[0] =
+ (3 << 4) | (1 << 14) | (0xa << 16);
+ /*
+ * bmSublinkSpeedAttr[1] =
+ * ST = Symmetric, TX
+ * LSE = 3 (Gbps)
+ * LP = 1 (SuperSpeedPlus)
+ * LSM = 10 (10 Gbps)
+ */
+ ssp_cap->bmSublinkSpeedAttr[1] =
+ (3 << 4) | (1 << 14) | (0xa << 16) | (1 << 7);
+ }
+
return le16_to_cpu(bos->wTotalLength);
}
@@ -690,16 +771,7 @@ static int set_config(struct usb_composite_dev *cdev,
* function's setup callback instead of the current
* configuration's setup callback.
*/
- switch (gadget->speed) {
- case USB_SPEED_SUPER:
- descriptors = f->ss_descriptors;
- break;
- case USB_SPEED_HIGH:
- descriptors = f->hs_descriptors;
- break;
- default:
- descriptors = f->fs_descriptors;
- }
+ descriptors = function_descriptors(f, gadget->speed);
for (; *descriptors; ++descriptors) {
struct usb_endpoint_descriptor *ep;
@@ -819,8 +891,9 @@ int usb_add_config(struct usb_composite_dev *cdev,
} else {
unsigned i;
- DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
+ DBG(cdev, "cfg %d/%p speeds:%s%s%s%s\n",
config->bConfigurationValue, config,
+ config->superspeed_plus ? " superplus" : "",
config->superspeed ? " super" : "",
config->highspeed ? " high" : "",
config->fullspeed
@@ -1499,7 +1572,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
cdev->gadget->ep0->maxpacket;
if (gadget_is_superspeed(gadget)) {
if (gadget->speed >= USB_SPEED_SUPER) {
- cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+ cdev->desc.bcdUSB = cpu_to_le16(0x0310);
cdev->desc.bMaxPacketSize0 = 9;
} else {
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
@@ -1634,15 +1707,24 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
*((u8 *)req->buf) = value;
value = min(w_length, (u16) 1);
break;
-
- /*
- * USB 3.0 additions:
- * Function driver should handle get_status request. If such cb
- * wasn't supplied we respond with default value = 0
- * Note: function driver should supply such cb only for the first
- * interface of the function
- */
case USB_REQ_GET_STATUS:
+ if (gadget_is_otg(gadget) && gadget->hnp_polling_support &&
+ (w_index == OTG_STS_SELECTOR)) {
+ if (ctrl->bRequestType != (USB_DIR_IN |
+ USB_RECIP_DEVICE))
+ goto unknown;
+ *((u8 *)req->buf) = gadget->host_request_flag;
+ value = 1;
+ break;
+ }
+
+ /*
+ * USB 3.0 additions:
+ * Function driver should handle get_status request. If such cb
+ * wasn't supplied we respond with default value = 0
+ * Note: function driver should supply such cb only for the
+ * first interface of the function
+ */
if (!gadget_is_superspeed(gadget))
goto unknown;
if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 0fafa7a1b6f6..e6c0542a063b 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -163,7 +163,8 @@ EXPORT_SYMBOL_GPL(usb_copy_descriptors);
int usb_assign_descriptors(struct usb_function *f,
struct usb_descriptor_header **fs,
struct usb_descriptor_header **hs,
- struct usb_descriptor_header **ss)
+ struct usb_descriptor_header **ss,
+ struct usb_descriptor_header **ssp)
{
struct usb_gadget *g = f->config->cdev->gadget;
@@ -182,6 +183,11 @@ int usb_assign_descriptors(struct usb_function *f,
if (!f->ss_descriptors)
goto err;
}
+ if (ssp && gadget_is_superspeed_plus(g)) {
+ f->ssp_descriptors = usb_copy_descriptors(ssp);
+ if (!f->ssp_descriptors)
+ goto err;
+ }
return 0;
err:
usb_free_all_descriptors(f);
@@ -194,6 +200,7 @@ void usb_free_all_descriptors(struct usb_function *f)
usb_free_descriptors(f->fs_descriptors);
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->ss_descriptors);
+ usb_free_descriptors(f->ssp_descriptors);
}
EXPORT_SYMBOL_GPL(usb_free_all_descriptors);
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 590c44989e5e..b6f60ca8a035 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -49,7 +49,6 @@ struct gadget_info {
struct config_group configs_group;
struct config_group strings_group;
struct config_group os_desc_group;
- struct config_group *default_groups[5];
struct mutex lock;
struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
@@ -71,7 +70,6 @@ static inline struct gadget_info *to_gadget_info(struct config_item *item)
struct config_usb_cfg {
struct config_group group;
struct config_group strings_group;
- struct config_group *default_groups[2];
struct list_head string_list;
struct usb_configuration c;
struct list_head func_list;
@@ -666,13 +664,12 @@ static struct config_group *config_desc_make(
INIT_LIST_HEAD(&cfg->string_list);
INIT_LIST_HEAD(&cfg->func_list);
- cfg->group.default_groups = cfg->default_groups;
- cfg->default_groups[0] = &cfg->strings_group;
-
config_group_init_type_name(&cfg->group, name,
&gadget_config_type);
+
config_group_init_type_name(&cfg->strings_group, "strings",
&gadget_config_name_strings_type);
+ configfs_add_default_group(&cfg->strings_group, &cfg->group);
ret = usb_add_config_only(&gi->cdev, &cfg->c);
if (ret)
@@ -1149,15 +1146,11 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
char **names,
struct module *owner)
{
- struct config_group **f_default_groups, *os_desc_group,
- **interface_groups;
+ struct config_group *os_desc_group;
struct config_item_type *os_desc_type, *interface_type;
vla_group(data_chunk);
- vla_item(data_chunk, struct config_group *, f_default_groups, 2);
vla_item(data_chunk, struct config_group, os_desc_group, 1);
- vla_item(data_chunk, struct config_group *, interface_groups,
- n_interf + 1);
vla_item(data_chunk, struct config_item_type, os_desc_type, 1);
vla_item(data_chunk, struct config_item_type, interface_type, 1);
@@ -1165,18 +1158,14 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
if (!vlabuf)
return -ENOMEM;
- f_default_groups = vla_ptr(vlabuf, data_chunk, f_default_groups);
os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group);
os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type);
- interface_groups = vla_ptr(vlabuf, data_chunk, interface_groups);
interface_type = vla_ptr(vlabuf, data_chunk, interface_type);
- parent->default_groups = f_default_groups;
os_desc_type->ct_owner = owner;
config_group_init_type_name(os_desc_group, "os_desc", os_desc_type);
- f_default_groups[0] = os_desc_group;
+ configfs_add_default_group(os_desc_group, parent);
- os_desc_group->default_groups = interface_groups;
interface_type->ct_group_ops = &interf_grp_ops;
interface_type->ct_attrs = interf_grp_attrs;
interface_type->ct_owner = owner;
@@ -1189,7 +1178,7 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
config_group_init_type_name(&d->group, "", interface_type);
config_item_set_name(&d->group.cg_item, "interface.%s",
names[n_interf]);
- interface_groups[n_interf] = &d->group;
+ configfs_add_default_group(&d->group, os_desc_group);
}
return 0;
@@ -1229,6 +1218,7 @@ static void purge_configs_funcs(struct gadget_info *gi)
}
c->next_interface_id = 0;
memset(c->interface, 0, sizeof(c->interface));
+ c->superspeed_plus = 0;
c->superspeed = 0;
c->highspeed = 0;
c->fullspeed = 0;
@@ -1423,20 +1413,23 @@ static struct config_group *gadgets_make(
if (!gi)
return ERR_PTR(-ENOMEM);
- gi->group.default_groups = gi->default_groups;
- gi->group.default_groups[0] = &gi->functions_group;
- gi->group.default_groups[1] = &gi->configs_group;
- gi->group.default_groups[2] = &gi->strings_group;
- gi->group.default_groups[3] = &gi->os_desc_group;
+ config_group_init_type_name(&gi->group, name, &gadget_root_type);
config_group_init_type_name(&gi->functions_group, "functions",
&functions_type);
+ configfs_add_default_group(&gi->functions_group, &gi->group);
+
config_group_init_type_name(&gi->configs_group, "configs",
&config_desc_type);
+ configfs_add_default_group(&gi->configs_group, &gi->group);
+
config_group_init_type_name(&gi->strings_group, "strings",
&gadget_strings_strings_type);
+ configfs_add_default_group(&gi->strings_group, &gi->group);
+
config_group_init_type_name(&gi->os_desc_group, "os_desc",
&os_desc_type);
+ configfs_add_default_group(&gi->os_desc_group, &gi->group);
gi->composite.bind = configfs_do_nothing;
gi->composite.unbind = configfs_do_nothing;
@@ -1461,8 +1454,6 @@ static struct config_group *gadgets_make(
if (!gi->composite.gadget_driver.function)
goto err;
- config_group_init_type_name(&gi->group, name,
- &gadget_root_type);
return &gi->group;
err:
kfree(gi);
diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c
index 2fa1e80a3ce7..a30766ca4226 100644
--- a/drivers/usb/gadget/function/f_acm.c
+++ b/drivers/usb/gadget/function/f_acm.c
@@ -685,7 +685,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
- acm_ss_function);
+ acm_ss_function, NULL);
if (status)
goto fail;
@@ -777,10 +777,10 @@ static ssize_t f_acm_port_num_show(struct config_item *item, char *page)
return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
}
-CONFIGFS_ATTR_RO(f_acm_port_, num);
+CONFIGFS_ATTR_RO(f_acm_, port_num);
static struct configfs_attribute *acm_attrs[] = {
- &f_acm_port_attr_num,
+ &f_acm_attr_port_num,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c
index 7ad60ee41914..4c488d15b6f6 100644
--- a/drivers/usb/gadget/function/f_ecm.c
+++ b/drivers/usb/gadget/function/f_ecm.c
@@ -786,7 +786,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
fs_ecm_notify_desc.bEndpointAddress;
status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function,
- ecm_ss_function);
+ ecm_ss_function, NULL);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index cad35a502d3f..d58bfc32be9e 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -309,7 +309,7 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
eem_ss_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress;
status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function,
- eem_ss_function);
+ eem_ss_function, NULL);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index cf43e9e18368..8cfce105c7ee 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -684,44 +684,38 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
{
struct ffs_epfile *epfile = file->private_data;
+ struct usb_request *req;
struct ffs_ep *ep;
char *data = NULL;
ssize_t ret, data_len = -EINVAL;
int halt;
/* Are we still active? */
- if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) {
- ret = -ENODEV;
- goto error;
- }
+ if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+ return -ENODEV;
/* Wait for endpoint to be enabled */
ep = epfile->ep;
if (!ep) {
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- goto error;
- }
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep));
- if (ret) {
- ret = -EINTR;
- goto error;
- }
+ if (ret)
+ return -EINTR;
}
/* Do we halt? */
halt = (!io_data->read == !epfile->in);
- if (halt && epfile->isoc) {
- ret = -EINVAL;
- goto error;
- }
+ if (halt && epfile->isoc)
+ return -EINVAL;
/* Allocate & copy */
if (!halt) {
/*
* if we _do_ wait above, the epfile->ffs->gadget might be NULL
- * before the waiting completes, so do not assign to 'gadget' earlier
+ * before the waiting completes, so do not assign to 'gadget'
+ * earlier
*/
struct usb_gadget *gadget = epfile->ffs->gadget;
size_t copied;
@@ -763,17 +757,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
if (epfile->ep != ep) {
/* In the meantime, endpoint got disabled or changed. */
ret = -ESHUTDOWN;
- spin_unlock_irq(&epfile->ffs->eps_lock);
} else if (halt) {
/* Halt */
if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))
usb_ep_set_halt(ep->ep);
- spin_unlock_irq(&epfile->ffs->eps_lock);
ret = -EBADMSG;
- } else {
- /* Fire the request */
- struct usb_request *req;
-
+ } else if (unlikely(data_len == -EINVAL)) {
/*
* Sanity Check: even though data_len can't be used
* uninitialized at the time I write this comment, some
@@ -785,80 +774,80 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
* For such reason, we're adding this redundant sanity check
* here.
*/
- if (unlikely(data_len == -EINVAL)) {
- WARN(1, "%s: data_len == -EINVAL\n", __func__);
- ret = -EINVAL;
- goto error_lock;
- }
-
- if (io_data->aio) {
- req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
- if (unlikely(!req))
- goto error_lock;
-
- req->buf = data;
- req->length = data_len;
+ WARN(1, "%s: data_len == -EINVAL\n", __func__);
+ ret = -EINVAL;
+ } else if (!io_data->aio) {
+ DECLARE_COMPLETION_ONSTACK(done);
+ bool interrupted = false;
- io_data->buf = data;
- io_data->ep = ep->ep;
- io_data->req = req;
- io_data->ffs = epfile->ffs;
+ req = ep->req;
+ req->buf = data;
+ req->length = data_len;
- req->context = io_data;
- req->complete = ffs_epfile_async_io_complete;
+ req->context = &done;
+ req->complete = ffs_epfile_io_complete;
- ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
- if (unlikely(ret)) {
- usb_ep_free_request(ep->ep, req);
- goto error_lock;
- }
- ret = -EIOCBQUEUED;
+ ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+ if (unlikely(ret < 0))
+ goto error_lock;
- spin_unlock_irq(&epfile->ffs->eps_lock);
- } else {
- DECLARE_COMPLETION_ONSTACK(done);
+ spin_unlock_irq(&epfile->ffs->eps_lock);
- req = ep->req;
- req->buf = data;
- req->length = data_len;
+ if (unlikely(wait_for_completion_interruptible(&done))) {
+ /*
+ * To avoid race condition with ffs_epfile_io_complete,
+ * dequeue the request first then check
+ * status. usb_ep_dequeue API should guarantee no race
+ * condition with req->complete callback.
+ */
+ usb_ep_dequeue(ep->ep, req);
+ interrupted = ep->status < 0;
+ }
- req->context = &done;
- req->complete = ffs_epfile_io_complete;
+ /*
+ * XXX We may end up silently droping data here. Since data_len
+ * (i.e. req->length) may be bigger than len (after being
+ * rounded up to maxpacketsize), we may end up with more data
+ * then user space has space for.
+ */
+ ret = interrupted ? -EINTR : ep->status;
+ if (io_data->read && ret > 0) {
+ ret = copy_to_iter(data, ret, &io_data->data);
+ if (!ret)
+ ret = -EFAULT;
+ }
+ goto error_mutex;
+ } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ } else {
+ req->buf = data;
+ req->length = data_len;
- ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+ io_data->buf = data;
+ io_data->ep = ep->ep;
+ io_data->req = req;
+ io_data->ffs = epfile->ffs;
- spin_unlock_irq(&epfile->ffs->eps_lock);
+ req->context = io_data;
+ req->complete = ffs_epfile_async_io_complete;
- if (unlikely(ret < 0)) {
- /* nop */
- } else if (unlikely(
- wait_for_completion_interruptible(&done))) {
- ret = -EINTR;
- usb_ep_dequeue(ep->ep, req);
- } else {
- /*
- * XXX We may end up silently droping data
- * here. Since data_len (i.e. req->length) may
- * be bigger than len (after being rounded up
- * to maxpacketsize), we may end up with more
- * data then user space has space for.
- */
- ret = ep->status;
- if (io_data->read && ret > 0) {
- ret = copy_to_iter(data, ret, &io_data->data);
- if (!ret)
- ret = -EFAULT;
- }
- }
- kfree(data);
+ ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+ if (unlikely(ret)) {
+ usb_ep_free_request(ep->ep, req);
+ goto error_lock;
}
- }
- mutex_unlock(&epfile->mutex);
- return ret;
+ ret = -EIOCBQUEUED;
+ /*
+ * Do not kfree the buffer in this function. It will be freed
+ * by ffs_user_copy_worker.
+ */
+ data = NULL;
+ }
error_lock:
spin_unlock_irq(&epfile->ffs->eps_lock);
+error_mutex:
mutex_unlock(&epfile->mutex);
error:
kfree(data);
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 99285b416308..51980c50546d 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -646,7 +646,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
hidg_fs_out_ep_desc.bEndpointAddress;
status = usb_assign_descriptors(f, hidg_fs_descriptors,
- hidg_hs_descriptors, NULL);
+ hidg_hs_descriptors, NULL, NULL);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c
index ddc3aad886b7..3a9f8f9c77bd 100644
--- a/drivers/usb/gadget/function/f_loopback.c
+++ b/drivers/usb/gadget/function/f_loopback.c
@@ -211,7 +211,7 @@ autoconf_fail:
ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs,
- ss_loopback_descs);
+ ss_loopback_descs, NULL);
if (ret)
return ret;
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 223ccf89d226..acf210f16328 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -3093,7 +3093,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
ret = usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function,
- fsg_ss_function);
+ fsg_ss_function, fsg_ss_function);
if (ret)
goto autoconf_fail;
@@ -3484,12 +3484,12 @@ static struct usb_function_instance *fsg_alloc_inst(void)
opts->lun0.lun = opts->common->luns[0];
opts->lun0.lun_id = 0;
- config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
- opts->default_groups[0] = &opts->lun0.group;
- opts->func_inst.group.default_groups = opts->default_groups;
config_group_init_type_name(&opts->func_inst.group, "", &fsg_func_type);
+ config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
+ configfs_add_default_group(&opts->lun0.group, &opts->func_inst.group);
+
return &opts->func_inst;
release_buffers:
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index fb1fe96d3215..84c0ee5ebd1e 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -56,7 +56,7 @@ static const char f_midi_longname[] = "MIDI Gadget";
* USB <- IN endpoint <- rawmidi
*/
struct gmidi_in_port {
- struct f_midi *midi;
+ struct snd_rawmidi_substream *substream;
int active;
uint8_t cable;
uint8_t state;
@@ -78,9 +78,7 @@ struct f_midi {
struct snd_rawmidi *rmidi;
u8 ms_id;
- struct snd_rawmidi_substream *in_substream[MAX_PORTS];
struct snd_rawmidi_substream *out_substream[MAX_PORTS];
- struct gmidi_in_port *in_port[MAX_PORTS];
unsigned long out_triggered;
struct tasklet_struct tasklet;
@@ -92,6 +90,8 @@ struct f_midi {
/* This fifo is used as a buffer ring for pre-allocated IN usb_requests */
DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *);
unsigned int in_last_port;
+
+ struct gmidi_in_port in_ports_array[/* in_ports */];
};
static inline struct f_midi *func_to_midi(struct usb_function *f)
@@ -518,98 +518,95 @@ static void f_midi_drop_out_substreams(struct f_midi *midi)
{
unsigned int i;
- for (i = 0; i < MAX_PORTS; i++) {
- struct gmidi_in_port *port = midi->in_port[i];
- struct snd_rawmidi_substream *substream = midi->in_substream[i];
-
- if (!port)
- break;
-
- if (!port->active || !substream)
- continue;
-
- snd_rawmidi_drop_output(substream);
+ for (i = 0; i < midi->in_ports; i++) {
+ struct gmidi_in_port *port = midi->in_ports_array + i;
+ struct snd_rawmidi_substream *substream = port->substream;
+ if (port->active && substream)
+ snd_rawmidi_drop_output(substream);
}
}
-static void f_midi_transmit(struct f_midi *midi)
+static int f_midi_do_transmit(struct f_midi *midi, struct usb_ep *ep)
{
- struct usb_ep *ep = midi->in_ep;
- bool active;
-
- /* We only care about USB requests if IN endpoint is enabled */
- if (!ep || !ep->enabled)
- goto drop_out;
+ struct usb_request *req = NULL;
+ unsigned int len, i;
+ bool active = false;
+ int err;
- do {
- struct usb_request *req = NULL;
- unsigned int len, i;
+ /*
+ * We peek the request in order to reuse it if it fails to enqueue on
+ * its endpoint
+ */
+ len = kfifo_peek(&midi->in_req_fifo, &req);
+ if (len != 1) {
+ ERROR(midi, "%s: Couldn't get usb request\n", __func__);
+ return -1;
+ }
- active = false;
+ /*
+ * If buffer overrun, then we ignore this transmission.
+ * IMPORTANT: This will cause the user-space rawmidi device to block
+ * until a) usb requests have been completed or b) snd_rawmidi_write()
+ * times out.
+ */
+ if (req->length > 0)
+ return 0;
- /* We peek the request in order to reuse it if it fails
- * to enqueue on its endpoint */
- len = kfifo_peek(&midi->in_req_fifo, &req);
- if (len != 1) {
- ERROR(midi, "%s: Couldn't get usb request\n", __func__);
- goto drop_out;
- }
+ for (i = midi->in_last_port; i < midi->in_ports; ++i) {
+ struct gmidi_in_port *port = midi->in_ports_array + i;
+ struct snd_rawmidi_substream *substream = port->substream;
- /* If buffer overrun, then we ignore this transmission.
- * IMPORTANT: This will cause the user-space rawmidi device to block until a) usb
- * requests have been completed or b) snd_rawmidi_write() times out. */
- if (req->length > 0)
- return;
+ if (!port->active || !substream)
+ continue;
- for (i = midi->in_last_port; i < MAX_PORTS; i++) {
- struct gmidi_in_port *port = midi->in_port[i];
- struct snd_rawmidi_substream *substream = midi->in_substream[i];
+ while (req->length + 3 < midi->buflen) {
+ uint8_t b;
- if (!port) {
- /* Reset counter when we reach the last available port */
- midi->in_last_port = 0;
+ if (snd_rawmidi_transmit(substream, &b, 1) != 1) {
+ port->active = 0;
break;
}
+ f_midi_transmit_byte(req, port, b);
+ }
- if (!port->active || !substream)
- continue;
+ active = !!port->active;
+ if (active)
+ break;
+ }
+ midi->in_last_port = active ? i : 0;
- while (req->length + 3 < midi->buflen) {
- uint8_t b;
+ if (req->length <= 0)
+ goto done;
- if (snd_rawmidi_transmit(substream, &b, 1) != 1) {
- port->active = 0;
- break;
- }
- f_midi_transmit_byte(req, port, b);
- }
+ err = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (err < 0) {
+ ERROR(midi, "%s failed to queue req: %d\n",
+ midi->in_ep->name, err);
+ req->length = 0; /* Re-use request next time. */
+ } else {
+ /* Upon success, put request at the back of the queue. */
+ kfifo_skip(&midi->in_req_fifo);
+ kfifo_put(&midi->in_req_fifo, req);
+ }
- active = !!port->active;
- /* Check if last port is still active, which means that
- * there is still data on that substream but this current
- * request run out of space. */
- if (active) {
- midi->in_last_port = i;
- /* There is no need to re-iterate though midi ports. */
- break;
- }
- }
+done:
+ return active;
+}
- if (req->length > 0) {
- int err;
+static void f_midi_transmit(struct f_midi *midi)
+{
+ struct usb_ep *ep = midi->in_ep;
+ int ret;
- err = usb_ep_queue(ep, req, GFP_ATOMIC);
- if (err < 0) {
- ERROR(midi, "%s failed to queue req: %d\n",
- midi->in_ep->name, err);
- req->length = 0; /* Re-use request next time. */
- } else {
- /* Upon success, put request at the back of the queue. */
- kfifo_skip(&midi->in_req_fifo);
- kfifo_put(&midi->in_req_fifo, req);
- }
- }
- } while (active);
+ /* We only care about USB requests if IN endpoint is enabled */
+ if (!ep || !ep->enabled)
+ goto drop_out;
+
+ do {
+ ret = f_midi_do_transmit(midi, ep);
+ if (ret < 0)
+ goto drop_out;
+ } while (ret);
return;
@@ -626,13 +623,15 @@ static void f_midi_in_tasklet(unsigned long data)
static int f_midi_in_open(struct snd_rawmidi_substream *substream)
{
struct f_midi *midi = substream->rmidi->private_data;
+ struct gmidi_in_port *port;
- if (!midi->in_port[substream->number])
+ if (substream->number >= midi->in_ports)
return -EINVAL;
VDBG(midi, "%s()\n", __func__);
- midi->in_substream[substream->number] = substream;
- midi->in_port[substream->number]->state = STATE_UNKNOWN;
+ port = midi->in_ports_array + substream->number;
+ port->substream = substream;
+ port->state = STATE_UNKNOWN;
return 0;
}
@@ -648,11 +647,11 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct f_midi *midi = substream->rmidi->private_data;
- if (!midi->in_port[substream->number])
+ if (substream->number >= midi->in_ports)
return;
VDBG(midi, "%s() %d\n", __func__, up);
- midi->in_port[substream->number]->active = up;
+ midi->in_ports_array[substream->number].active = up;
if (up)
tasklet_hi_schedule(&midi->tasklet);
}
@@ -1128,14 +1127,11 @@ static void f_midi_free(struct usb_function *f)
{
struct f_midi *midi;
struct f_midi_opts *opts;
- int i;
midi = func_to_midi(f);
opts = container_of(f->fi, struct f_midi_opts, func_inst);
kfree(midi->id);
mutex_lock(&opts->lock);
- for (i = opts->in_ports - 1; i >= 0; --i)
- kfree(midi->in_port[i]);
kfifo_free(&midi->in_req_fifo);
kfree(midi);
--opts->refcnt;
@@ -1163,7 +1159,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
{
- struct f_midi *midi;
+ struct f_midi *midi = NULL;
struct f_midi_opts *opts;
int status, i;
@@ -1172,37 +1168,26 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
mutex_lock(&opts->lock);
/* sanity check */
if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) {
- mutex_unlock(&opts->lock);
- return ERR_PTR(-EINVAL);
+ status = -EINVAL;
+ goto setup_fail;
}
/* allocate and initialize one new instance */
- midi = kzalloc(sizeof(*midi), GFP_KERNEL);
+ midi = kzalloc(
+ sizeof(*midi) + opts->in_ports * sizeof(*midi->in_ports_array),
+ GFP_KERNEL);
if (!midi) {
- mutex_unlock(&opts->lock);
- return ERR_PTR(-ENOMEM);
+ status = -ENOMEM;
+ goto setup_fail;
}
- for (i = 0; i < opts->in_ports; i++) {
- struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL);
-
- if (!port) {
- status = -ENOMEM;
- mutex_unlock(&opts->lock);
- goto setup_fail;
- }
-
- port->midi = midi;
- port->active = 0;
- port->cable = i;
- midi->in_port[i] = port;
- }
+ for (i = 0; i < opts->in_ports; i++)
+ midi->in_ports_array[i].cable = i;
/* set up ALSA midi devices */
midi->id = kstrdup(opts->id, GFP_KERNEL);
if (opts->id && !midi->id) {
status = -ENOMEM;
- mutex_unlock(&opts->lock);
goto setup_fail;
}
midi->in_ports = opts->in_ports;
@@ -1229,8 +1214,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
return &midi->func;
setup_fail:
- for (--i; i >= 0; i--)
- kfree(midi->in_port[i]);
+ mutex_unlock(&opts->lock);
kfree(midi);
return ERR_PTR(status);
}
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 7ad798ace1e5..97f0a9bc84df 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1432,7 +1432,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
fs_ncm_notify_desc.bEndpointAddress;
status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
- NULL);
+ NULL, NULL);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c
index d6396e0909ee..d43e86cea74f 100644
--- a/drivers/usb/gadget/function/f_obex.c
+++ b/drivers/usb/gadget/function/f_obex.c
@@ -364,7 +364,8 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
obex_hs_ep_out_desc.bEndpointAddress =
obex_fs_ep_out_desc.bEndpointAddress;
- status = usb_assign_descriptors(f, fs_function, hs_function, NULL);
+ status = usb_assign_descriptors(f, fs_function, hs_function, NULL,
+ NULL);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c
index 157441dbfeba..0473d619d5bf 100644
--- a/drivers/usb/gadget/function/f_phonet.c
+++ b/drivers/usb/gadget/function/f_phonet.c
@@ -541,7 +541,7 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
/* Do not try to bind Phonet twice... */
status = usb_assign_descriptors(f, fs_pn_function, hs_pn_function,
- NULL);
+ NULL, NULL);
if (status)
goto err;
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 26ccad5d8680..c45104e3a64b 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -1051,7 +1051,7 @@ autoconf_fail:
ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
ret = usb_assign_descriptors(f, fs_printer_function,
- hs_printer_function, ss_printer_function);
+ hs_printer_function, ss_printer_function, NULL);
if (ret)
return ret;
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index e587767e374c..c8005823b190 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -783,7 +783,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function,
- eth_ss_function);
+ eth_ss_function, NULL);
if (status)
goto fail;
@@ -889,7 +889,6 @@ static void rndis_free_inst(struct usb_function_instance *f)
free_netdev(opts->net);
}
- kfree(opts->rndis_os_desc.group.default_groups); /* single VLA chunk */
kfree(opts);
}
@@ -916,10 +915,10 @@ static struct usb_function_instance *rndis_alloc_inst(void)
descs[0] = &opts->rndis_os_desc;
names[0] = "rndis";
- usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
- names, THIS_MODULE);
config_group_init_type_name(&opts->func_inst.group, "",
&rndis_func_type);
+ usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
+ names, THIS_MODULE);
return &opts->func_inst;
}
diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c
index 6bb44d613bab..cb00ada21d9c 100644
--- a/drivers/usb/gadget/function/f_serial.c
+++ b/drivers/usb/gadget/function/f_serial.c
@@ -236,7 +236,7 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
- gser_ss_function);
+ gser_ss_function, NULL);
if (status)
goto fail;
dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index 242ba5caffe5..df0189ddfdd5 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -437,7 +437,7 @@ no_iso:
ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
ret = usb_assign_descriptors(f, fs_source_sink_descs,
- hs_source_sink_descs, ss_source_sink_descs);
+ hs_source_sink_descs, ss_source_sink_descs, NULL);
if (ret)
return ret;
diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c
index 829c78de9eba..434b983f3b4c 100644
--- a/drivers/usb/gadget/function/f_subset.c
+++ b/drivers/usb/gadget/function/f_subset.c
@@ -362,7 +362,7 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
fs_subset_out_desc.bEndpointAddress;
status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function,
- ss_eth_function);
+ ss_eth_function, NULL);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index bad007b5a190..dfb733047a4c 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -2098,7 +2098,7 @@ static int tcm_bind(struct usb_configuration *c, struct usb_function *f)
uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
ret = usb_assign_descriptors(f, uasp_fs_function_desc,
- uasp_hs_function_desc, uasp_ss_function_desc);
+ uasp_hs_function_desc, uasp_ss_function_desc, NULL);
if (ret)
goto ep_fail;
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index 6a2346b99f55..f2ac0cbc29a4 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -721,7 +721,8 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
status = -ENOMEM;
/* copy descriptors, and track endpoint copies */
- status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL);
+ status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL,
+ NULL);
if (status)
goto fail;
return 0;
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 044ca79d3cb5..186d4b162524 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -1100,7 +1100,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
- ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
+ ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL,
+ NULL);
if (ret)
goto err;
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 70d3917cc003..943c21aafd3b 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -914,7 +914,7 @@ struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
params->resp_avail = resp_avail;
params->v = v;
- INIT_LIST_HEAD(&(params->resp_queue));
+ INIT_LIST_HEAD(&params->resp_queue);
pr_debug("%s: configNr = %d\n", __func__, i);
return params;
@@ -1006,13 +1006,10 @@ EXPORT_SYMBOL_GPL(rndis_add_hdr);
void rndis_free_response(struct rndis_params *params, u8 *buf)
{
- rndis_resp_t *r;
- struct list_head *act, *tmp;
+ rndis_resp_t *r, *n;
- list_for_each_safe(act, tmp, &(params->resp_queue))
- {
- r = list_entry(act, rndis_resp_t, list);
- if (r && r->buf == buf) {
+ list_for_each_entry_safe(r, n, &params->resp_queue, list) {
+ if (r->buf == buf) {
list_del(&r->list);
kfree(r);
}
@@ -1022,14 +1019,11 @@ EXPORT_SYMBOL_GPL(rndis_free_response);
u8 *rndis_get_next_response(struct rndis_params *params, u32 *length)
{
- rndis_resp_t *r;
- struct list_head *act, *tmp;
+ rndis_resp_t *r, *n;
if (!length) return NULL;
- list_for_each_safe(act, tmp, &(params->resp_queue))
- {
- r = list_entry(act, rndis_resp_t, list);
+ list_for_each_entry_safe(r, n, &params->resp_queue, list) {
if (!r->send) {
r->send = 1;
*length = r->length;
@@ -1053,7 +1047,7 @@ static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length)
r->length = length;
r->send = 0;
- list_add_tail(&r->list, &(params->resp_queue));
+ list_add_tail(&r->list, &params->resp_queue);
return r;
}
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index ad8c9b05572d..66753ba7a42e 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -272,11 +272,6 @@ static struct config_item_type uvcg_default_processing_type = {
/* struct uvcg_processing {}; */
-static struct config_group *uvcg_processing_default_groups[] = {
- &uvcg_default_processing.group,
- NULL,
-};
-
/* control/processing */
static struct uvcg_processing_grp {
struct config_group group;
@@ -394,11 +389,6 @@ static struct config_item_type uvcg_default_camera_type = {
/* struct uvcg_camera {}; */
-static struct config_group *uvcg_camera_default_groups[] = {
- &uvcg_default_camera.group,
- NULL,
-};
-
/* control/terminal/camera */
static struct uvcg_camera_grp {
struct config_group group;
@@ -477,11 +467,6 @@ static struct config_item_type uvcg_default_output_type = {
/* struct uvcg_output {}; */
-static struct config_group *uvcg_output_default_groups[] = {
- &uvcg_default_output.group,
- NULL,
-};
-
/* control/terminal/output */
static struct uvcg_output_grp {
struct config_group group;
@@ -491,12 +476,6 @@ static struct config_item_type uvcg_output_grp_type = {
.ct_owner = THIS_MODULE,
};
-static struct config_group *uvcg_terminal_default_groups[] = {
- &uvcg_camera_grp.group,
- &uvcg_output_grp.group,
- NULL,
-};
-
/* control/terminal */
static struct uvcg_terminal_grp {
struct config_group group;
@@ -619,12 +598,6 @@ static struct config_item_type uvcg_control_class_type = {
.ct_owner = THIS_MODULE,
};
-static struct config_group *uvcg_control_class_default_groups[] = {
- &uvcg_control_class_fs.group,
- &uvcg_control_class_ss.group,
- NULL,
-};
-
/* control/class */
static struct uvcg_control_class_grp {
struct config_group group;
@@ -634,14 +607,6 @@ static struct config_item_type uvcg_control_class_grp_type = {
.ct_owner = THIS_MODULE,
};
-static struct config_group *uvcg_control_default_groups[] = {
- &uvcg_control_header_grp.group,
- &uvcg_processing_grp.group,
- &uvcg_terminal_grp.group,
- &uvcg_control_class_grp.group,
- NULL,
-};
-
/* control */
static struct uvcg_control_grp {
struct config_group group;
@@ -1780,11 +1745,6 @@ static struct config_item_type uvcg_default_color_matching_type = {
/* struct uvcg_color_matching {}; */
-static struct config_group *uvcg_color_matching_default_groups[] = {
- &uvcg_default_color_matching.group,
- NULL,
-};
-
/* streaming/color_matching */
static struct uvcg_color_matching_grp {
struct config_group group;
@@ -2145,13 +2105,6 @@ static struct config_item_type uvcg_streaming_class_type = {
.ct_owner = THIS_MODULE,
};
-static struct config_group *uvcg_streaming_class_default_groups[] = {
- &uvcg_streaming_class_fs.group,
- &uvcg_streaming_class_hs.group,
- &uvcg_streaming_class_ss.group,
- NULL,
-};
-
/* streaming/class */
static struct uvcg_streaming_class_grp {
struct config_group group;
@@ -2161,15 +2114,6 @@ static struct config_item_type uvcg_streaming_class_grp_type = {
.ct_owner = THIS_MODULE,
};
-static struct config_group *uvcg_streaming_default_groups[] = {
- &uvcg_streaming_header_grp.group,
- &uvcg_uncompressed_grp.group,
- &uvcg_mjpeg_grp.group,
- &uvcg_color_matching_grp.group,
- &uvcg_streaming_class_grp.group,
- NULL,
-};
-
/* streaming */
static struct uvcg_streaming_grp {
struct config_group group;
@@ -2179,12 +2123,6 @@ static struct config_item_type uvcg_streaming_grp_type = {
.ct_owner = THIS_MODULE,
};
-static struct config_group *uvcg_default_groups[] = {
- &uvcg_control_grp.group,
- &uvcg_streaming_grp.group,
- NULL,
-};
-
static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_uvc_opts,
@@ -2273,59 +2211,64 @@ static struct config_item_type uvc_func_type = {
.ct_owner = THIS_MODULE,
};
-static inline void uvcg_init_group(struct config_group *g,
- struct config_group **default_groups,
- const char *name,
- struct config_item_type *type)
-{
- g->default_groups = default_groups;
- config_group_init_type_name(g, name, type);
-}
-
int uvcg_attach_configfs(struct f_uvc_opts *opts)
{
config_group_init_type_name(&uvcg_control_header_grp.group,
"header",
&uvcg_control_header_grp_type);
+
config_group_init_type_name(&uvcg_default_processing.group,
- "default",
- &uvcg_default_processing_type);
- uvcg_init_group(&uvcg_processing_grp.group,
- uvcg_processing_default_groups,
- "processing",
- &uvcg_processing_grp_type);
+ "default", &uvcg_default_processing_type);
+ config_group_init_type_name(&uvcg_processing_grp.group,
+ "processing", &uvcg_processing_grp_type);
+ configfs_add_default_group(&uvcg_default_processing.group,
+ &uvcg_processing_grp.group);
+
config_group_init_type_name(&uvcg_default_camera.group,
- "default",
- &uvcg_default_camera_type);
- uvcg_init_group(&uvcg_camera_grp.group,
- uvcg_camera_default_groups,
- "camera",
- &uvcg_camera_grp_type);
+ "default", &uvcg_default_camera_type);
+ config_group_init_type_name(&uvcg_camera_grp.group,
+ "camera", &uvcg_camera_grp_type);
+ configfs_add_default_group(&uvcg_default_camera.group,
+ &uvcg_camera_grp.group);
+
config_group_init_type_name(&uvcg_default_output.group,
- "default",
- &uvcg_default_output_type);
- uvcg_init_group(&uvcg_output_grp.group,
- uvcg_output_default_groups,
- "output",
- &uvcg_output_grp_type);
- uvcg_init_group(&uvcg_terminal_grp.group,
- uvcg_terminal_default_groups,
- "terminal",
- &uvcg_terminal_grp_type);
+ "default", &uvcg_default_output_type);
+ config_group_init_type_name(&uvcg_output_grp.group,
+ "output", &uvcg_output_grp_type);
+ configfs_add_default_group(&uvcg_default_output.group,
+ &uvcg_output_grp.group);
+
+ config_group_init_type_name(&uvcg_terminal_grp.group,
+ "terminal", &uvcg_terminal_grp_type);
+ configfs_add_default_group(&uvcg_camera_grp.group,
+ &uvcg_terminal_grp.group);
+ configfs_add_default_group(&uvcg_output_grp.group,
+ &uvcg_terminal_grp.group);
+
config_group_init_type_name(&uvcg_control_class_fs.group,
- "fs",
- &uvcg_control_class_type);
+ "fs", &uvcg_control_class_type);
config_group_init_type_name(&uvcg_control_class_ss.group,
- "ss",
- &uvcg_control_class_type);
- uvcg_init_group(&uvcg_control_class_grp.group,
- uvcg_control_class_default_groups,
+ "ss", &uvcg_control_class_type);
+ config_group_init_type_name(&uvcg_control_class_grp.group,
"class",
&uvcg_control_class_grp_type);
- uvcg_init_group(&uvcg_control_grp.group,
- uvcg_control_default_groups,
+ configfs_add_default_group(&uvcg_control_class_fs.group,
+ &uvcg_control_class_grp.group);
+ configfs_add_default_group(&uvcg_control_class_ss.group,
+ &uvcg_control_class_grp.group);
+
+ config_group_init_type_name(&uvcg_control_grp.group,
"control",
&uvcg_control_grp_type);
+ configfs_add_default_group(&uvcg_control_header_grp.group,
+ &uvcg_control_grp.group);
+ configfs_add_default_group(&uvcg_processing_grp.group,
+ &uvcg_control_grp.group);
+ configfs_add_default_group(&uvcg_terminal_grp.group,
+ &uvcg_control_grp.group);
+ configfs_add_default_group(&uvcg_control_class_grp.group,
+ &uvcg_control_grp.group);
+
config_group_init_type_name(&uvcg_streaming_header_grp.group,
"header",
&uvcg_streaming_header_grp_type);
@@ -2338,30 +2281,47 @@ int uvcg_attach_configfs(struct f_uvc_opts *opts)
config_group_init_type_name(&uvcg_default_color_matching.group,
"default",
&uvcg_default_color_matching_type);
- uvcg_init_group(&uvcg_color_matching_grp.group,
- uvcg_color_matching_default_groups,
+ config_group_init_type_name(&uvcg_color_matching_grp.group,
"color_matching",
&uvcg_color_matching_grp_type);
+ configfs_add_default_group(&uvcg_default_color_matching.group,
+ &uvcg_color_matching_grp.group);
+
config_group_init_type_name(&uvcg_streaming_class_fs.group,
- "fs",
- &uvcg_streaming_class_type);
+ "fs", &uvcg_streaming_class_type);
config_group_init_type_name(&uvcg_streaming_class_hs.group,
- "hs",
- &uvcg_streaming_class_type);
+ "hs", &uvcg_streaming_class_type);
config_group_init_type_name(&uvcg_streaming_class_ss.group,
- "ss",
- &uvcg_streaming_class_type);
- uvcg_init_group(&uvcg_streaming_class_grp.group,
- uvcg_streaming_class_default_groups,
- "class",
- &uvcg_streaming_class_grp_type);
- uvcg_init_group(&uvcg_streaming_grp.group,
- uvcg_streaming_default_groups,
- "streaming",
- &uvcg_streaming_grp_type);
- uvcg_init_group(&opts->func_inst.group,
- uvcg_default_groups,
+ "ss", &uvcg_streaming_class_type);
+ config_group_init_type_name(&uvcg_streaming_class_grp.group,
+ "class", &uvcg_streaming_class_grp_type);
+ configfs_add_default_group(&uvcg_streaming_class_fs.group,
+ &uvcg_streaming_class_grp.group);
+ configfs_add_default_group(&uvcg_streaming_class_hs.group,
+ &uvcg_streaming_class_grp.group);
+ configfs_add_default_group(&uvcg_streaming_class_ss.group,
+ &uvcg_streaming_class_grp.group);
+
+ config_group_init_type_name(&uvcg_streaming_grp.group,
+ "streaming", &uvcg_streaming_grp_type);
+ configfs_add_default_group(&uvcg_streaming_header_grp.group,
+ &uvcg_streaming_grp.group);
+ configfs_add_default_group(&uvcg_uncompressed_grp.group,
+ &uvcg_streaming_grp.group);
+ configfs_add_default_group(&uvcg_mjpeg_grp.group,
+ &uvcg_streaming_grp.group);
+ configfs_add_default_group(&uvcg_color_matching_grp.group,
+ &uvcg_streaming_grp.group);
+ configfs_add_default_group(&uvcg_streaming_class_grp.group,
+ &uvcg_streaming_grp.group);
+
+ config_group_init_type_name(&opts->func_inst.group,
"",
&uvc_func_type);
+ configfs_add_default_group(&uvcg_control_grp.group,
+ &opts->func_inst.group);
+ configfs_add_default_group(&uvcg_streaming_grp.group,
+ &opts->func_inst.group);
+
return 0;
}
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index 7e179f81d05c..5cdaf0150a4e 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -130,7 +130,8 @@ struct dev_data {
setup_can_stall : 1,
setup_out_ready : 1,
setup_out_error : 1,
- setup_abort : 1;
+ setup_abort : 1,
+ gadget_registered : 1;
unsigned setup_wLength;
/* the rest is basically write-once */
@@ -1179,7 +1180,8 @@ dev_release (struct inode *inode, struct file *fd)
/* closing ep0 === shutdown all */
- usb_gadget_unregister_driver (&gadgetfs_driver);
+ if (dev->gadget_registered)
+ usb_gadget_unregister_driver (&gadgetfs_driver);
/* at this point "good" hardware has disconnected the
* device from USB; the host won't see it any more.
@@ -1697,28 +1699,6 @@ static struct usb_gadget_driver gadgetfs_driver = {
};
/*----------------------------------------------------------------------*/
-
-static void gadgetfs_nop(struct usb_gadget *arg) { }
-
-static int gadgetfs_probe(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
-{
- CHIP = gadget->name;
- return -EISNAM;
-}
-
-static struct usb_gadget_driver probe_driver = {
- .max_speed = USB_SPEED_HIGH,
- .bind = gadgetfs_probe,
- .unbind = gadgetfs_nop,
- .setup = (void *)gadgetfs_nop,
- .disconnect = gadgetfs_nop,
- .driver = {
- .name = "nop",
- },
-};
-
-
/* DEVICE INITIALIZATION
*
* fd = open ("/dev/gadget/$CHIP", O_RDWR)
@@ -1847,6 +1827,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
* kick in after the ep0 descriptor is closed.
*/
value = len;
+ dev->gadget_registered = true;
}
return value;
@@ -1968,9 +1949,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
if (the_device)
return -ESRCH;
- /* fake probe to determine $CHIP */
- CHIP = NULL;
- usb_gadget_probe_driver(&probe_driver);
+ CHIP = usb_get_gadget_udc_name();
if (!CHIP)
return -ENODEV;
@@ -2031,6 +2010,8 @@ gadgetfs_kill_sb (struct super_block *sb)
put_dev (the_device);
the_device = NULL;
}
+ kfree(CHIP);
+ CHIP = NULL;
}
/*----------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 753c29bd11ad..7c289416f87d 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -74,7 +74,6 @@ config USB_BCM63XX_UDC
config USB_FSL_USB2
tristate "Freescale Highspeed USB DR Peripheral Controller"
depends on FSL_SOC || ARCH_MXC
- select USB_FSL_MPH_DR_OF if OF
help
Some of Freescale PowerPC and i.MX processors have a High Speed
Dual-Role(DR) USB controller, which supports device mode.
@@ -128,6 +127,7 @@ config USB_OMAP
config USB_PXA25X
tristate "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
+ depends on HAS_IOMEM
help
Intel's PXA 25x series XScale ARM-5TE processors include
an integrated full speed USB 1.1 device controller. The
@@ -176,7 +176,7 @@ config USB_RENESAS_USBHS_UDC
config USB_RENESAS_USB3
tristate 'Renesas USB3.0 Peripheral controller'
- depends on ARCH_SHMOBILE || COMPILE_TEST
+ depends on ARCH_RENESAS || COMPILE_TEST
help
Renesas USB3.0 Peripheral controller is a USB peripheral controller
that supports super, high, and full speed USB 3.0 data transfers.
@@ -187,6 +187,7 @@ config USB_RENESAS_USB3
config USB_PXA27X
tristate "PXA 27x"
+ depends on HAS_IOMEM
help
Intel's PXA 27x series XScale ARM v5TE processors include
an integrated full speed USB 1.1 device controller.
@@ -244,6 +245,7 @@ config USB_MV_U3D
config USB_M66592
tristate "Renesas M66592 USB Peripheral Controller"
+ depends on HAS_IOMEM
help
M66592 is a discrete USB peripheral controller chip that
supports both full and high speed USB 2.0 data transfers.
@@ -287,6 +289,7 @@ config USB_FSL_QE
dynamically linked module called "fsl_qe_udc".
config USB_NET2272
+ depends on HAS_IOMEM
tristate "PLX NET2272"
help
PLX NET2272 is a USB peripheral controller which supports
diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c
index cd8764150861..39d70b4a8958 100644
--- a/drivers/usb/gadget/udc/amd5536udc.c
+++ b/drivers/usb/gadget/udc/amd5536udc.c
@@ -3397,7 +3397,7 @@ err_pcidev:
static const struct pci_device_id pci_id[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
- .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = 0xffffffff,
},
{},
diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c
index 7f77db5d1278..aae7458d8986 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_udc.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c
@@ -581,8 +581,13 @@ err0:
void bdc_udc_exit(struct bdc *bdc)
{
+ unsigned long flags;
+
dev_dbg(bdc->dev, "%s()\n", __func__);
+ spin_lock_irqsave(&bdc->lock, flags);
bdc_ep_disable(bdc->bdc_ep_array[1]);
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
usb_del_gadget_udc(&bdc->gadget);
bdc_free_ep(bdc);
}
diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c
index 53c0692f1b09..93d28cb00b76 100644
--- a/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -2340,7 +2340,7 @@ static struct qe_udc *qe_udc_config(struct platform_device *ofdev)
{
struct qe_udc *udc;
struct device_node *np = ofdev->dev.of_node;
- unsigned int tmp_addr = 0;
+ unsigned long tmp_addr = 0;
struct usb_device_para __iomem *usbpram;
unsigned int i;
u64 size;
diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c
index 1fdfec14a3ba..d2205d9e0c8b 100644
--- a/drivers/usb/gadget/udc/goku_udc.c
+++ b/drivers/usb/gadget/udc/goku_udc.c
@@ -1846,7 +1846,7 @@ err:
/*-------------------------------------------------------------------------*/
static const struct pci_device_id pci_ids[] = { {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = ~0,
.vendor = 0x102f, /* Toshiba */
.device = 0x0107, /* this UDC */
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 79fe6b77ee44..8f32b5ee7734 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -49,7 +49,6 @@
#endif
#include <mach/hardware.h>
-#include <mach/platform.h>
/*
* USB device configuration structure
@@ -147,9 +146,7 @@ struct lpc32xx_udc {
u32 io_p_size;
void __iomem *udp_baseaddr;
int udp_irq[4];
- struct clk *usb_pll_clk;
struct clk *usb_slv_clk;
- struct clk *usb_otg_clk;
/* DMA support */
u32 *udca_v_base;
@@ -210,16 +207,6 @@ static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g)
#define UDCA_BUFF_SIZE (128)
-/* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will
- * be replaced with an inremap()ed pointer
- * */
-#define USB_CTRL IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64)
-
-/* USB_CTRL bit defines */
-#define USB_SLAVE_HCLK_EN (1 << 24)
-#define USB_HOST_NEED_CLK_EN (1 << 21)
-#define USB_DEV_NEED_CLK_EN (1 << 22)
-
/**********************************************************************
* USB device controller register offsets
**********************************************************************/
@@ -639,9 +626,6 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc)
i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD);
- /* Enable usb_need_clk clock after transceiver is initialized */
- writel((readl(USB_CTRL) | USB_DEV_NEED_CLK_EN), USB_CTRL);
-
dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n",
i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00));
dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n",
@@ -980,31 +964,13 @@ static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
return;
udc->clocked = 1;
-
- /* 48MHz PLL up */
- clk_enable(udc->usb_pll_clk);
-
- /* Enable the USB device clock */
- writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN,
- USB_CTRL);
-
- clk_enable(udc->usb_otg_clk);
+ clk_prepare_enable(udc->usb_slv_clk);
} else {
if (!udc->clocked)
return;
udc->clocked = 0;
-
- /* Never disable the USB_HCLK during normal operation */
-
- /* 48MHz PLL dpwn */
- clk_disable(udc->usb_pll_clk);
-
- /* Disable the USB device clock */
- writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN,
- USB_CTRL);
-
- clk_disable(udc->usb_otg_clk);
+ clk_disable_unprepare(udc->usb_slv_clk);
}
}
@@ -3125,58 +3091,21 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
goto io_map_fail;
}
- /* Enable AHB slave USB clock, needed for further USB clock control */
- writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
-
- /* Get required clocks */
- udc->usb_pll_clk = clk_get(&pdev->dev, "ck_pll5");
- if (IS_ERR(udc->usb_pll_clk)) {
- dev_err(udc->dev, "failed to acquire USB PLL\n");
- retval = PTR_ERR(udc->usb_pll_clk);
- goto pll_get_fail;
- }
- udc->usb_slv_clk = clk_get(&pdev->dev, "ck_usbd");
+ /* Get USB device clock */
+ udc->usb_slv_clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(udc->usb_slv_clk)) {
dev_err(udc->dev, "failed to acquire USB device clock\n");
retval = PTR_ERR(udc->usb_slv_clk);
goto usb_clk_get_fail;
}
- udc->usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
- if (IS_ERR(udc->usb_otg_clk)) {
- dev_err(udc->dev, "failed to acquire USB otg clock\n");
- retval = PTR_ERR(udc->usb_otg_clk);
- goto usb_otg_clk_get_fail;
- }
-
- /* Setup PLL clock to 48MHz */
- retval = clk_enable(udc->usb_pll_clk);
- if (retval < 0) {
- dev_err(udc->dev, "failed to start USB PLL\n");
- goto pll_enable_fail;
- }
-
- retval = clk_set_rate(udc->usb_pll_clk, 48000);
- if (retval < 0) {
- dev_err(udc->dev, "failed to set USB clock rate\n");
- goto pll_set_fail;
- }
-
- writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN, USB_CTRL);
/* Enable USB device clock */
- retval = clk_enable(udc->usb_slv_clk);
+ retval = clk_prepare_enable(udc->usb_slv_clk);
if (retval < 0) {
dev_err(udc->dev, "failed to start USB device clock\n");
goto usb_clk_enable_fail;
}
- /* Enable USB OTG clock */
- retval = clk_enable(udc->usb_otg_clk);
- if (retval < 0) {
- dev_err(udc->dev, "failed to start USB otg clock\n");
- goto usb_otg_clk_enable_fail;
- }
-
/* Setup deferred workqueue data */
udc->poweron = udc->pullup = 0;
INIT_WORK(&udc->pullup_job, pullup_work);
@@ -3287,19 +3216,10 @@ dma_alloc_fail:
dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
udc->udca_v_base, udc->udca_p_base);
i2c_fail:
- clk_disable(udc->usb_otg_clk);
-usb_otg_clk_enable_fail:
- clk_disable(udc->usb_slv_clk);
+ clk_disable_unprepare(udc->usb_slv_clk);
usb_clk_enable_fail:
-pll_set_fail:
- clk_disable(udc->usb_pll_clk);
-pll_enable_fail:
- clk_put(udc->usb_otg_clk);
-usb_otg_clk_get_fail:
clk_put(udc->usb_slv_clk);
usb_clk_get_fail:
- clk_put(udc->usb_pll_clk);
-pll_get_fail:
iounmap(udc->udp_baseaddr);
io_map_fail:
release_mem_region(udc->io_p_start, udc->io_p_size);
@@ -3336,12 +3256,9 @@ static int lpc32xx_udc_remove(struct platform_device *pdev)
free_irq(udc->udp_irq[IRQ_USB_HP], udc);
free_irq(udc->udp_irq[IRQ_USB_LP], udc);
- clk_disable(udc->usb_otg_clk);
- clk_put(udc->usb_otg_clk);
- clk_disable(udc->usb_slv_clk);
+ clk_disable_unprepare(udc->usb_slv_clk);
clk_put(udc->usb_slv_clk);
- clk_disable(udc->usb_pll_clk);
- clk_put(udc->usb_pll_clk);
+
iounmap(udc->udp_baseaddr);
release_mem_region(udc->io_p_start, udc->io_p_size);
kfree(udc);
@@ -3367,7 +3284,7 @@ static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
udc->clocked = 1;
/* Kill global USB clock */
- clk_disable(udc->usb_slv_clk);
+ clk_disable_unprepare(udc->usb_slv_clk);
}
return 0;
@@ -3379,7 +3296,7 @@ static int lpc32xx_udc_resume(struct platform_device *pdev)
if (udc->clocked) {
/* Enable global USB clock */
- clk_enable(udc->usb_slv_clk);
+ clk_prepare_enable(udc->usb_slv_clk);
/* Enable clocking */
udc_clk_set(udc, 1);
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index 6706aef907f4..c894b94b234b 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -3735,7 +3735,7 @@ static void net2280_shutdown(struct pci_dev *pdev)
/*-------------------------------------------------------------------------*/
static const struct pci_device_id pci_ids[] = { {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX_LEGACY,
.device = 0x2280,
@@ -3743,7 +3743,7 @@ static const struct pci_device_id pci_ids[] = { {
.subdevice = PCI_ANY_ID,
.driver_data = PLX_LEGACY | PLX_2280,
}, {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX_LEGACY,
.device = 0x2282,
@@ -3752,7 +3752,7 @@ static const struct pci_device_id pci_ids[] = { {
.driver_data = PLX_LEGACY,
},
{
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX,
.device = 0x3380,
@@ -3761,7 +3761,7 @@ static const struct pci_device_id pci_ids[] = { {
.driver_data = PLX_SUPERSPEED,
},
{
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX,
.device = 0x3382,
diff --git a/drivers/usb/gadget/udc/net2280.h b/drivers/usb/gadget/udc/net2280.h
index 4dff60d34f73..0d32052bf16f 100644
--- a/drivers/usb/gadget/udc/net2280.h
+++ b/drivers/usb/gadget/udc/net2280.h
@@ -369,9 +369,20 @@ static inline void set_max_speed(struct net2280_ep *ep, u32 max)
static const u32 ep_enhanced[9] = { 0x10, 0x60, 0x30, 0x80,
0x50, 0x20, 0x70, 0x40, 0x90 };
- if (ep->dev->enhanced_mode)
+ if (ep->dev->enhanced_mode) {
reg = ep_enhanced[ep->num];
- else{
+ switch (ep->dev->gadget.speed) {
+ case USB_SPEED_SUPER:
+ reg += 2;
+ break;
+ case USB_SPEED_FULL:
+ reg += 1;
+ break;
+ case USB_SPEED_HIGH:
+ default:
+ break;
+ }
+ } else {
reg = (ep->num + 1) * 0x10;
if (ep->dev->gadget.speed != USB_SPEED_HIGH)
reg += 1;
diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c
index 7a04157ff579..9571ef54b86b 100644
--- a/drivers/usb/gadget/udc/pch_udc.c
+++ b/drivers/usb/gadget/udc/pch_udc.c
@@ -3234,22 +3234,22 @@ static const struct pci_device_id pch_udc_pcidev_id[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC),
- .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = 0xffffffff,
},
{
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC),
- .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = 0xffffffff,
},
{
PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7213_IOH_UDC),
- .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = 0xffffffff,
},
{
PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7831_IOH_UDC),
- .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = 0xffffffff,
},
{ 0 },
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index b82cb14850b6..a238da906115 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -48,18 +48,157 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
-/*
- * This driver is PXA25x only. Grab the right register definitions.
- */
-#ifdef CONFIG_ARCH_PXA
-#include <mach/pxa25x-udc.h>
-#include <mach/hardware.h>
-#endif
-
#ifdef CONFIG_ARCH_LUBBOCK
#include <mach/lubbock.h>
#endif
+#define UDCCR 0x0000 /* UDC Control Register */
+#define UDC_RES1 0x0004 /* UDC Undocumented - Reserved1 */
+#define UDC_RES2 0x0008 /* UDC Undocumented - Reserved2 */
+#define UDC_RES3 0x000C /* UDC Undocumented - Reserved3 */
+#define UDCCS0 0x0010 /* UDC Endpoint 0 Control/Status Register */
+#define UDCCS1 0x0014 /* UDC Endpoint 1 (IN) Control/Status Register */
+#define UDCCS2 0x0018 /* UDC Endpoint 2 (OUT) Control/Status Register */
+#define UDCCS3 0x001C /* UDC Endpoint 3 (IN) Control/Status Register */
+#define UDCCS4 0x0020 /* UDC Endpoint 4 (OUT) Control/Status Register */
+#define UDCCS5 0x0024 /* UDC Endpoint 5 (Interrupt) Control/Status Register */
+#define UDCCS6 0x0028 /* UDC Endpoint 6 (IN) Control/Status Register */
+#define UDCCS7 0x002C /* UDC Endpoint 7 (OUT) Control/Status Register */
+#define UDCCS8 0x0030 /* UDC Endpoint 8 (IN) Control/Status Register */
+#define UDCCS9 0x0034 /* UDC Endpoint 9 (OUT) Control/Status Register */
+#define UDCCS10 0x0038 /* UDC Endpoint 10 (Interrupt) Control/Status Register */
+#define UDCCS11 0x003C /* UDC Endpoint 11 (IN) Control/Status Register */
+#define UDCCS12 0x0040 /* UDC Endpoint 12 (OUT) Control/Status Register */
+#define UDCCS13 0x0044 /* UDC Endpoint 13 (IN) Control/Status Register */
+#define UDCCS14 0x0048 /* UDC Endpoint 14 (OUT) Control/Status Register */
+#define UDCCS15 0x004C /* UDC Endpoint 15 (Interrupt) Control/Status Register */
+#define UFNRH 0x0060 /* UDC Frame Number Register High */
+#define UFNRL 0x0064 /* UDC Frame Number Register Low */
+#define UBCR2 0x0068 /* UDC Byte Count Reg 2 */
+#define UBCR4 0x006c /* UDC Byte Count Reg 4 */
+#define UBCR7 0x0070 /* UDC Byte Count Reg 7 */
+#define UBCR9 0x0074 /* UDC Byte Count Reg 9 */
+#define UBCR12 0x0078 /* UDC Byte Count Reg 12 */
+#define UBCR14 0x007c /* UDC Byte Count Reg 14 */
+#define UDDR0 0x0080 /* UDC Endpoint 0 Data Register */
+#define UDDR1 0x0100 /* UDC Endpoint 1 Data Register */
+#define UDDR2 0x0180 /* UDC Endpoint 2 Data Register */
+#define UDDR3 0x0200 /* UDC Endpoint 3 Data Register */
+#define UDDR4 0x0400 /* UDC Endpoint 4 Data Register */
+#define UDDR5 0x00A0 /* UDC Endpoint 5 Data Register */
+#define UDDR6 0x0600 /* UDC Endpoint 6 Data Register */
+#define UDDR7 0x0680 /* UDC Endpoint 7 Data Register */
+#define UDDR8 0x0700 /* UDC Endpoint 8 Data Register */
+#define UDDR9 0x0900 /* UDC Endpoint 9 Data Register */
+#define UDDR10 0x00C0 /* UDC Endpoint 10 Data Register */
+#define UDDR11 0x0B00 /* UDC Endpoint 11 Data Register */
+#define UDDR12 0x0B80 /* UDC Endpoint 12 Data Register */
+#define UDDR13 0x0C00 /* UDC Endpoint 13 Data Register */
+#define UDDR14 0x0E00 /* UDC Endpoint 14 Data Register */
+#define UDDR15 0x00E0 /* UDC Endpoint 15 Data Register */
+
+#define UICR0 0x0050 /* UDC Interrupt Control Register 0 */
+#define UICR1 0x0054 /* UDC Interrupt Control Register 1 */
+
+#define USIR0 0x0058 /* UDC Status Interrupt Register 0 */
+#define USIR1 0x005C /* UDC Status Interrupt Register 1 */
+
+#define UDCCR_UDE (1 << 0) /* UDC enable */
+#define UDCCR_UDA (1 << 1) /* UDC active */
+#define UDCCR_RSM (1 << 2) /* Device resume */
+#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */
+#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */
+#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */
+#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */
+#define UDCCR_REM (1 << 7) /* Reset interrupt mask */
+
+#define UDCCS0_OPR (1 << 0) /* OUT packet ready */
+#define UDCCS0_IPR (1 << 1) /* IN packet ready */
+#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */
+#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */
+#define UDCCS0_SST (1 << 4) /* Sent stall */
+#define UDCCS0_FST (1 << 5) /* Force stall */
+#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */
+#define UDCCS0_SA (1 << 7) /* Setup active */
+
+#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */
+#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */
+#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */
+#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */
+#define UDCCS_BI_SST (1 << 4) /* Sent stall */
+#define UDCCS_BI_FST (1 << 5) /* Force stall */
+#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */
+
+#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */
+#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */
+#define UDCCS_BO_DME (1 << 3) /* DMA enable */
+#define UDCCS_BO_SST (1 << 4) /* Sent stall */
+#define UDCCS_BO_FST (1 << 5) /* Force stall */
+#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */
+#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */
+
+#define UDCCS_II_TFS (1 << 0) /* Transmit FIFO service */
+#define UDCCS_II_TPC (1 << 1) /* Transmit packet complete */
+#define UDCCS_II_FTF (1 << 2) /* Flush Tx FIFO */
+#define UDCCS_II_TUR (1 << 3) /* Transmit FIFO underrun */
+#define UDCCS_II_TSP (1 << 7) /* Transmit short packet */
+
+#define UDCCS_IO_RFS (1 << 0) /* Receive FIFO service */
+#define UDCCS_IO_RPC (1 << 1) /* Receive packet complete */
+#ifdef CONFIG_ARCH_IXP4XX /* FIXME: is this right?, datasheed says '2' */
+#define UDCCS_IO_ROF (1 << 3) /* Receive overflow */
+#endif
+#ifdef CONFIG_ARCH_PXA
+#define UDCCS_IO_ROF (1 << 2) /* Receive overflow */
+#endif
+#define UDCCS_IO_DME (1 << 3) /* DMA enable */
+#define UDCCS_IO_RNE (1 << 6) /* Receive FIFO not empty */
+#define UDCCS_IO_RSP (1 << 7) /* Receive short packet */
+
+#define UDCCS_INT_TFS (1 << 0) /* Transmit FIFO service */
+#define UDCCS_INT_TPC (1 << 1) /* Transmit packet complete */
+#define UDCCS_INT_FTF (1 << 2) /* Flush Tx FIFO */
+#define UDCCS_INT_TUR (1 << 3) /* Transmit FIFO underrun */
+#define UDCCS_INT_SST (1 << 4) /* Sent stall */
+#define UDCCS_INT_FST (1 << 5) /* Force stall */
+#define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */
+
+#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */
+#define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */
+#define UICR0_IM2 (1 << 2) /* Interrupt mask ep 2 */
+#define UICR0_IM3 (1 << 3) /* Interrupt mask ep 3 */
+#define UICR0_IM4 (1 << 4) /* Interrupt mask ep 4 */
+#define UICR0_IM5 (1 << 5) /* Interrupt mask ep 5 */
+#define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */
+#define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */
+
+#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */
+#define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */
+#define UICR1_IM10 (1 << 2) /* Interrupt mask ep 10 */
+#define UICR1_IM11 (1 << 3) /* Interrupt mask ep 11 */
+#define UICR1_IM12 (1 << 4) /* Interrupt mask ep 12 */
+#define UICR1_IM13 (1 << 5) /* Interrupt mask ep 13 */
+#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */
+#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */
+
+#define USIR0_IR0 (1 << 0) /* Interrupt request ep 0 */
+#define USIR0_IR1 (1 << 1) /* Interrupt request ep 1 */
+#define USIR0_IR2 (1 << 2) /* Interrupt request ep 2 */
+#define USIR0_IR3 (1 << 3) /* Interrupt request ep 3 */
+#define USIR0_IR4 (1 << 4) /* Interrupt request ep 4 */
+#define USIR0_IR5 (1 << 5) /* Interrupt request ep 5 */
+#define USIR0_IR6 (1 << 6) /* Interrupt request ep 6 */
+#define USIR0_IR7 (1 << 7) /* Interrupt request ep 7 */
+
+#define USIR1_IR8 (1 << 0) /* Interrupt request ep 8 */
+#define USIR1_IR9 (1 << 1) /* Interrupt request ep 9 */
+#define USIR1_IR10 (1 << 2) /* Interrupt request ep 10 */
+#define USIR1_IR11 (1 << 3) /* Interrupt request ep 11 */
+#define USIR1_IR12 (1 << 4) /* Interrupt request ep 12 */
+#define USIR1_IR13 (1 << 5) /* Interrupt request ep 13 */
+#define USIR1_IR14 (1 << 6) /* Interrupt request ep 14 */
+#define USIR1_IR15 (1 << 7) /* Interrupt request ep 15 */
+
/*
* This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
* series processors. The UDC for the IXP 4xx series is very similar.
@@ -150,25 +289,61 @@ static void pullup_on(void)
mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}
-static void pio_irq_enable(int bEndpointAddress)
+#if defined(CONFIG_CPU_BIG_ENDIAN)
+/*
+ * IXP4xx has its buses wired up in a way that relies on never doing any
+ * byte swaps, independent of whether it runs in big-endian or little-endian
+ * mode, as explained by Krzysztof Hałasa.
+ *
+ * We only support pxa25x in little-endian mode, but it is very likely
+ * that it works the same way.
+ */
+static inline void udc_set_reg(struct pxa25x_udc *dev, u32 reg, u32 val)
+{
+ iowrite32be(val, dev->regs + reg);
+}
+
+static inline u32 udc_get_reg(struct pxa25x_udc *dev, u32 reg)
{
- bEndpointAddress &= 0xf;
+ return ioread32be(dev->regs + reg);
+}
+#else
+static inline void udc_set_reg(struct pxa25x_udc *dev, u32 reg, u32 val)
+{
+ writel(val, dev->regs + reg);
+}
+
+static inline u32 udc_get_reg(struct pxa25x_udc *dev, u32 reg)
+{
+ return readl(dev->regs + reg);
+}
+#endif
+
+static void pio_irq_enable(struct pxa25x_ep *ep)
+{
+ u32 bEndpointAddress = ep->bEndpointAddress & 0xf;
+
if (bEndpointAddress < 8)
- UICR0 &= ~(1 << bEndpointAddress);
+ udc_set_reg(ep->dev, UICR0, udc_get_reg(ep->dev, UICR0) &
+ ~(1 << bEndpointAddress));
else {
bEndpointAddress -= 8;
- UICR1 &= ~(1 << bEndpointAddress);
+ udc_set_reg(ep->dev, UICR1, udc_get_reg(ep->dev, UICR1) &
+ ~(1 << bEndpointAddress));
}
}
-static void pio_irq_disable(int bEndpointAddress)
+static void pio_irq_disable(struct pxa25x_ep *ep)
{
- bEndpointAddress &= 0xf;
+ u32 bEndpointAddress = ep->bEndpointAddress & 0xf;
+
if (bEndpointAddress < 8)
- UICR0 |= 1 << bEndpointAddress;
+ udc_set_reg(ep->dev, UICR0, udc_get_reg(ep->dev, UICR0) |
+ (1 << bEndpointAddress));
else {
bEndpointAddress -= 8;
- UICR1 |= 1 << bEndpointAddress;
+ udc_set_reg(ep->dev, UICR1, udc_get_reg(ep->dev, UICR1) |
+ (1 << bEndpointAddress));
}
}
@@ -177,22 +352,61 @@ static void pio_irq_disable(int bEndpointAddress)
*/
#define UDCCR_MASK_BITS (UDCCR_REM | UDCCR_SRM | UDCCR_UDE)
-static inline void udc_set_mask_UDCCR(int mask)
+static inline void udc_set_mask_UDCCR(struct pxa25x_udc *dev, int mask)
{
- UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);
+ u32 udccr = udc_get_reg(dev, UDCCR);
+
+ udc_set_reg(dev, (udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS), UDCCR);
}
-static inline void udc_clear_mask_UDCCR(int mask)
+static inline void udc_clear_mask_UDCCR(struct pxa25x_udc *dev, int mask)
{
- UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);
+ u32 udccr = udc_get_reg(dev, UDCCR);
+
+ udc_set_reg(dev, (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS), UDCCR);
}
-static inline void udc_ack_int_UDCCR(int mask)
+static inline void udc_ack_int_UDCCR(struct pxa25x_udc *dev, int mask)
{
/* udccr contains the bits we dont want to change */
- __u32 udccr = UDCCR & UDCCR_MASK_BITS;
+ u32 udccr = udc_get_reg(dev, UDCCR) & UDCCR_MASK_BITS;
- UDCCR = udccr | (mask & ~UDCCR_MASK_BITS);
+ udc_set_reg(dev, udccr | (mask & ~UDCCR_MASK_BITS), UDCCR);
+}
+
+static inline u32 udc_ep_get_UDCCS(struct pxa25x_ep *ep)
+{
+ return udc_get_reg(ep->dev, ep->regoff_udccs);
+}
+
+static inline void udc_ep_set_UDCCS(struct pxa25x_ep *ep, u32 data)
+{
+ udc_set_reg(ep->dev, data, ep->regoff_udccs);
+}
+
+static inline u32 udc_ep0_get_UDCCS(struct pxa25x_udc *dev)
+{
+ return udc_get_reg(dev, UDCCS0);
+}
+
+static inline void udc_ep0_set_UDCCS(struct pxa25x_udc *dev, u32 data)
+{
+ udc_set_reg(dev, data, UDCCS0);
+}
+
+static inline u32 udc_ep_get_UDDR(struct pxa25x_ep *ep)
+{
+ return udc_get_reg(ep->dev, ep->regoff_uddr);
+}
+
+static inline void udc_ep_set_UDDR(struct pxa25x_ep *ep, u32 data)
+{
+ udc_set_reg(ep->dev, data, ep->regoff_uddr);
+}
+
+static inline u32 udc_ep_get_UBCR(struct pxa25x_ep *ep)
+{
+ return udc_get_reg(ep->dev, ep->regoff_ubcr);
}
/*
@@ -358,7 +572,7 @@ static inline void ep0_idle (struct pxa25x_udc *dev)
}
static int
-write_packet(volatile u32 *uddr, struct pxa25x_request *req, unsigned max)
+write_packet(struct pxa25x_ep *ep, struct pxa25x_request *req, unsigned max)
{
u8 *buf;
unsigned length, count;
@@ -372,7 +586,7 @@ write_packet(volatile u32 *uddr, struct pxa25x_request *req, unsigned max)
count = length;
while (likely(count--))
- *uddr = *buf++;
+ udc_ep_set_UDDR(ep, *buf++);
return length;
}
@@ -392,7 +606,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
unsigned count;
int is_last, is_short;
- count = write_packet(ep->reg_uddr, req, max);
+ count = write_packet(ep, req, max);
/* last packet is usually short (or a zlp) */
if (unlikely (count != max))
@@ -416,15 +630,15 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
* double buffering might work. TSP, TPC, and TFS
* bit values are the same for all normal IN endpoints.
*/
- *ep->reg_udccs = UDCCS_BI_TPC;
+ udc_ep_set_UDCCS(ep, UDCCS_BI_TPC);
if (is_short)
- *ep->reg_udccs = UDCCS_BI_TSP;
+ udc_ep_set_UDCCS(ep, UDCCS_BI_TSP);
/* requests complete when all IN data is in the FIFO */
if (is_last) {
done (ep, req, 0);
if (list_empty(&ep->queue))
- pio_irq_disable (ep->bEndpointAddress);
+ pio_irq_disable(ep);
return 1;
}
@@ -432,7 +646,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
// double buffering is off in the default fifo mode, which
// prevents TFS from being set here.
- } while (*ep->reg_udccs & UDCCS_BI_TFS);
+ } while (udc_ep_get_UDCCS(ep) & UDCCS_BI_TFS);
return 0;
}
@@ -442,20 +656,21 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
static inline
void ep0start(struct pxa25x_udc *dev, u32 flags, const char *tag)
{
- UDCCS0 = flags|UDCCS0_SA|UDCCS0_OPR;
- USIR0 = USIR0_IR0;
+ udc_ep0_set_UDCCS(dev, flags|UDCCS0_SA|UDCCS0_OPR);
+ udc_set_reg(dev, USIR0, USIR0_IR0);
dev->req_pending = 0;
DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n",
- __func__, tag, UDCCS0, flags);
+ __func__, tag, udc_ep0_get_UDCCS(dev), flags);
}
static int
write_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
{
+ struct pxa25x_udc *dev = ep->dev;
unsigned count;
int is_short;
- count = write_packet(&UDDR0, req, EP0_FIFO_SIZE);
+ count = write_packet(&dev->ep[0], req, EP0_FIFO_SIZE);
ep->dev->stats.write.bytes += count;
/* last packet "must be" short (or a zlp) */
@@ -468,7 +683,7 @@ write_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
if (ep->dev->req_pending)
ep0start(ep->dev, UDCCS0_IPR, "short IN");
else
- UDCCS0 = UDCCS0_IPR;
+ udc_ep0_set_UDCCS(dev, UDCCS0_IPR);
count = req->req.length;
done (ep, req, 0);
@@ -484,9 +699,9 @@ write_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
if (count >= EP0_FIFO_SIZE) {
count = 100;
do {
- if ((UDCCS0 & UDCCS0_OPR) != 0) {
+ if ((udc_ep0_get_UDCCS(dev) & UDCCS0_OPR) != 0) {
/* clear OPR, generate ack */
- UDCCS0 = UDCCS0_OPR;
+ udc_ep0_set_UDCCS(dev, UDCCS0_OPR);
break;
}
count--;
@@ -521,7 +736,7 @@ read_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
* UDCCS_{BO,IO}_RPC are all the same bit value.
* UDCCS_{BO,IO}_RNE are all the same bit value.
*/
- udccs = *ep->reg_udccs;
+ udccs = udc_ep_get_UDCCS(ep);
if (unlikely ((udccs & UDCCS_BO_RPC) == 0))
break;
buf = req->req.buf + req->req.actual;
@@ -530,7 +745,7 @@ read_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
/* read all bytes from this packet */
if (likely (udccs & UDCCS_BO_RNE)) {
- count = 1 + (0x0ff & *ep->reg_ubcr);
+ count = 1 + (0x0ff & udc_ep_get_UBCR(ep));
req->req.actual += min (count, bufferspace);
} else /* zlp */
count = 0;
@@ -540,7 +755,7 @@ read_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
is_short ? "/S" : "",
req, req->req.actual, req->req.length);
while (likely (count-- != 0)) {
- u8 byte = (u8) *ep->reg_uddr;
+ u8 byte = (u8) udc_ep_get_UDDR(ep);
if (unlikely (bufferspace == 0)) {
/* this happens when the driver's buffer
@@ -556,7 +771,7 @@ read_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
bufferspace--;
}
}
- *ep->reg_udccs = UDCCS_BO_RPC;
+ udc_ep_set_UDCCS(ep, UDCCS_BO_RPC);
/* RPC/RSP/RNE could now reflect the other packet buffer */
/* iso is one request per packet */
@@ -571,7 +786,7 @@ read_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
if (is_short || req->req.actual == req->req.length) {
done (ep, req, 0);
if (list_empty(&ep->queue))
- pio_irq_disable (ep->bEndpointAddress);
+ pio_irq_disable(ep);
return 1;
}
@@ -595,7 +810,7 @@ read_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
buf = req->req.buf + req->req.actual;
bufferspace = req->req.length - req->req.actual;
- while (UDCCS0 & UDCCS0_RNE) {
+ while (udc_ep_get_UDCCS(ep) & UDCCS0_RNE) {
byte = (u8) UDDR0;
if (unlikely (bufferspace == 0)) {
@@ -613,7 +828,7 @@ read_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
}
}
- UDCCS0 = UDCCS0_OPR | UDCCS0_IPR;
+ udc_ep_set_UDCCS(ep, UDCCS0_OPR | UDCCS0_IPR);
/* completion */
if (req->req.actual >= req->req.length)
@@ -687,8 +902,8 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
DBG(DBG_VERBOSE, "ep0 config ack%s\n",
dev->has_cfr ? "" : " raced");
if (dev->has_cfr)
- UDCCFR = UDCCFR_AREN|UDCCFR_ACM
- |UDCCFR_MB1;
+ udc_set_reg(dev, UDCCFR, UDCCFR_AREN |
+ UDCCFR_ACM | UDCCFR_MB1);
done(ep, req, 0);
dev->ep0state = EP0_END_XFER;
local_irq_restore (flags);
@@ -696,7 +911,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
}
if (dev->req_pending)
ep0start(dev, UDCCS0_IPR, "OUT");
- if (length == 0 || ((UDCCS0 & UDCCS0_RNE) != 0
+ if (length == 0 || ((udc_ep0_get_UDCCS(dev) & UDCCS0_RNE) != 0
&& read_ep0_fifo(ep, req))) {
ep0_idle(dev);
done(ep, req, 0);
@@ -711,16 +926,16 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
}
/* can the FIFO can satisfy the request immediately? */
} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
- if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
+ if ((udc_ep_get_UDCCS(ep) & UDCCS_BI_TFS) != 0
&& write_fifo(ep, req))
req = NULL;
- } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
+ } else if ((udc_ep_get_UDCCS(ep) & UDCCS_BO_RFS) != 0
&& read_fifo(ep, req)) {
req = NULL;
}
if (likely(req && ep->ep.desc))
- pio_irq_enable(ep->bEndpointAddress);
+ pio_irq_enable(ep);
}
/* pio or dma irq handler advances the queue. */
@@ -747,7 +962,7 @@ static void nuke(struct pxa25x_ep *ep, int status)
done(ep, req, status);
}
if (ep->ep.desc)
- pio_irq_disable (ep->bEndpointAddress);
+ pio_irq_disable(ep);
}
@@ -807,14 +1022,14 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
local_irq_save(flags);
if ((ep->bEndpointAddress & USB_DIR_IN) != 0
- && ((*ep->reg_udccs & UDCCS_BI_TFS) == 0
+ && ((udc_ep_get_UDCCS(ep) & UDCCS_BI_TFS) == 0
|| !list_empty(&ep->queue))) {
local_irq_restore(flags);
return -EAGAIN;
}
/* FST bit is the same for control, bulk in, bulk out, interrupt in */
- *ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF;
+ udc_ep_set_UDCCS(ep, UDCCS_BI_FST|UDCCS_BI_FTF);
/* ep0 needs special care */
if (!ep->ep.desc) {
@@ -826,7 +1041,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
} else {
unsigned i;
for (i = 0; i < 1000; i += 20) {
- if (*ep->reg_udccs & UDCCS_BI_SST)
+ if (udc_ep_get_UDCCS(ep) & UDCCS_BI_SST)
break;
udelay(20);
}
@@ -850,10 +1065,10 @@ static int pxa25x_ep_fifo_status(struct usb_ep *_ep)
if ((ep->bEndpointAddress & USB_DIR_IN) != 0)
return -EOPNOTSUPP;
if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN
- || (*ep->reg_udccs & UDCCS_BO_RFS) == 0)
+ || (udc_ep_get_UDCCS(ep) & UDCCS_BO_RFS) == 0)
return 0;
else
- return (*ep->reg_ubcr & 0xfff) + 1;
+ return (udc_ep_get_UBCR(ep) & 0xfff) + 1;
}
static void pxa25x_ep_fifo_flush(struct usb_ep *_ep)
@@ -870,15 +1085,15 @@ static void pxa25x_ep_fifo_flush(struct usb_ep *_ep)
/* for OUT, just read and discard the FIFO contents. */
if ((ep->bEndpointAddress & USB_DIR_IN) == 0) {
- while (((*ep->reg_udccs) & UDCCS_BO_RNE) != 0)
- (void) *ep->reg_uddr;
+ while (((udc_ep_get_UDCCS(ep)) & UDCCS_BO_RNE) != 0)
+ (void)udc_ep_get_UDDR(ep);
return;
}
/* most IN status is the same, but ISO can't stall */
- *ep->reg_udccs = UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR
+ udc_ep_set_UDCCS(ep, UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR
| (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
- ? 0 : UDCCS_BI_SST);
+ ? 0 : UDCCS_BI_SST));
}
@@ -905,15 +1120,23 @@ static struct usb_ep_ops pxa25x_ep_ops = {
static int pxa25x_udc_get_frame(struct usb_gadget *_gadget)
{
- return ((UFNRH & 0x07) << 8) | (UFNRL & 0xff);
+ struct pxa25x_udc *dev;
+
+ dev = container_of(_gadget, struct pxa25x_udc, gadget);
+ return ((udc_get_reg(dev, UFNRH) & 0x07) << 8) |
+ (udc_get_reg(dev, UFNRL) & 0xff);
}
static int pxa25x_udc_wakeup(struct usb_gadget *_gadget)
{
+ struct pxa25x_udc *udc;
+
+ udc = container_of(_gadget, struct pxa25x_udc, gadget);
+
/* host may not have enabled remote wakeup */
- if ((UDCCS0 & UDCCS0_DRWF) == 0)
+ if ((udc_ep0_get_UDCCS(udc) & UDCCS0_DRWF) == 0)
return -EHOSTUNREACH;
- udc_set_mask_UDCCR(UDCCR_RSM);
+ udc_set_mask_UDCCR(udc, UDCCR_RSM);
return 0;
}
@@ -1034,9 +1257,11 @@ udc_seq_show(struct seq_file *m, void *_d)
/* registers for device and ep0 */
seq_printf(m,
"uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
- UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
+ udc_get_reg(dev, UICR1), udc_get_reg(dev, UICR0),
+ udc_get_reg(dev, USIR1), udc_get_reg(dev, USIR0),
+ udc_get_reg(dev, UFNRH), udc_get_reg(dev, UFNRL));
- tmp = UDCCR;
+ tmp = udc_get_reg(dev, UDCCR);
seq_printf(m,
"udccr %02X =%s%s%s%s%s%s%s%s\n", tmp,
(tmp & UDCCR_REM) ? " rem" : "",
@@ -1048,7 +1273,7 @@ udc_seq_show(struct seq_file *m, void *_d)
(tmp & UDCCR_UDA) ? " uda" : "",
(tmp & UDCCR_UDE) ? " ude" : "");
- tmp = UDCCS0;
+ tmp = udc_ep0_get_UDCCS(dev);
seq_printf(m,
"udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp,
(tmp & UDCCS0_SA) ? " sa" : "",
@@ -1061,7 +1286,7 @@ udc_seq_show(struct seq_file *m, void *_d)
(tmp & UDCCS0_OPR) ? " opr" : "");
if (dev->has_cfr) {
- tmp = UDCCFR;
+ tmp = udc_get_reg(dev, UDCCFR);
seq_printf(m,
"udccfr %02X =%s%s\n", tmp,
(tmp & UDCCFR_AREN) ? " aren" : "",
@@ -1087,7 +1312,7 @@ udc_seq_show(struct seq_file *m, void *_d)
desc = ep->ep.desc;
if (!desc)
continue;
- tmp = *dev->ep [i].reg_udccs;
+ tmp = udc_ep_get_UDCCS(&dev->ep[i]);
seq_printf(m,
"%s max %d %s udccs %02x irqs %lu\n",
ep->ep.name, usb_endpoint_maxp(desc),
@@ -1151,14 +1376,15 @@ static const struct file_operations debug_fops = {
static void udc_disable(struct pxa25x_udc *dev)
{
/* block all irqs */
- udc_set_mask_UDCCR(UDCCR_SRM|UDCCR_REM);
- UICR0 = UICR1 = 0xff;
- UFNRH = UFNRH_SIM;
+ udc_set_mask_UDCCR(dev, UDCCR_SRM|UDCCR_REM);
+ udc_set_reg(dev, UICR0, 0xff);
+ udc_set_reg(dev, UICR1, 0xff);
+ udc_set_reg(dev, UFNRH, UFNRH_SIM);
/* if hardware supports it, disconnect from usb */
pullup_off();
- udc_clear_mask_UDCCR(UDCCR_UDE);
+ udc_clear_mask_UDCCR(dev, UDCCR_UDE);
ep0_idle (dev);
dev->gadget.speed = USB_SPEED_UNKNOWN;
@@ -1200,10 +1426,10 @@ static void udc_reinit(struct pxa25x_udc *dev)
*/
static void udc_enable (struct pxa25x_udc *dev)
{
- udc_clear_mask_UDCCR(UDCCR_UDE);
+ udc_clear_mask_UDCCR(dev, UDCCR_UDE);
/* try to clear these bits before we enable the udc */
- udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);
+ udc_ack_int_UDCCR(dev, UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);
ep0_idle(dev);
dev->gadget.speed = USB_SPEED_UNKNOWN;
@@ -1215,15 +1441,15 @@ static void udc_enable (struct pxa25x_udc *dev)
* - if RESET is already in progress, ack interrupt
* - unmask reset interrupt
*/
- udc_set_mask_UDCCR(UDCCR_UDE);
- if (!(UDCCR & UDCCR_UDA))
- udc_ack_int_UDCCR(UDCCR_RSTIR);
+ udc_set_mask_UDCCR(dev, UDCCR_UDE);
+ if (!(udc_get_reg(dev, UDCCR) & UDCCR_UDA))
+ udc_ack_int_UDCCR(dev, UDCCR_RSTIR);
if (dev->has_cfr /* UDC_RES2 is defined */) {
/* pxa255 (a0+) can avoid a set_config race that could
* prevent gadget drivers from configuring correctly
*/
- UDCCFR = UDCCFR_ACM | UDCCFR_MB1;
+ udc_set_reg(dev, UDCCFR, UDCCFR_ACM | UDCCFR_MB1);
} else {
/* "USB test mode" for pxa250 errata 40-42 (stepping a0, a1)
* which could result in missing packets and interrupts.
@@ -1231,15 +1457,15 @@ static void udc_enable (struct pxa25x_udc *dev)
* double buffers or not; ACM/AREN bits fit into the holes.
* zero bits (like USIR0_IRx) disable double buffering.
*/
- UDC_RES1 = 0x00;
- UDC_RES2 = 0x00;
+ udc_set_reg(dev, UDC_RES1, 0x00);
+ udc_set_reg(dev, UDC_RES2, 0x00);
}
/* enable suspend/resume and reset irqs */
- udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM);
+ udc_clear_mask_UDCCR(dev, UDCCR_SRM | UDCCR_REM);
/* enable ep0 irqs */
- UICR0 &= ~UICR0_IM0;
+ udc_set_reg(dev, UICR0, udc_get_reg(dev, UICR0) & ~UICR0_IM0);
/* if hardware supports it, pullup D+ and wait for reset */
pullup_on();
@@ -1408,9 +1634,9 @@ static void udc_watchdog(unsigned long _dev)
local_irq_disable();
if (dev->ep0state == EP0_STALL
- && (UDCCS0 & UDCCS0_FST) == 0
- && (UDCCS0 & UDCCS0_SST) == 0) {
- UDCCS0 = UDCCS0_FST|UDCCS0_FTF;
+ && (udc_ep0_get_UDCCS(dev) & UDCCS0_FST) == 0
+ && (udc_ep0_get_UDCCS(dev) & UDCCS0_SST) == 0) {
+ udc_ep0_set_UDCCS(dev, UDCCS0_FST|UDCCS0_FTF);
DBG(DBG_VERBOSE, "ep0 re-stall\n");
start_watchdog(dev);
}
@@ -1419,7 +1645,7 @@ static void udc_watchdog(unsigned long _dev)
static void handle_ep0 (struct pxa25x_udc *dev)
{
- u32 udccs0 = UDCCS0;
+ u32 udccs0 = udc_ep0_get_UDCCS(dev);
struct pxa25x_ep *ep = &dev->ep [0];
struct pxa25x_request *req;
union {
@@ -1436,7 +1662,7 @@ static void handle_ep0 (struct pxa25x_udc *dev)
/* clear stall status */
if (udccs0 & UDCCS0_SST) {
nuke(ep, -EPIPE);
- UDCCS0 = UDCCS0_SST;
+ udc_ep0_set_UDCCS(dev, UDCCS0_SST);
del_timer(&dev->timer);
ep0_idle(dev);
}
@@ -1451,7 +1677,7 @@ static void handle_ep0 (struct pxa25x_udc *dev)
switch (dev->ep0state) {
case EP0_IDLE:
/* late-breaking status? */
- udccs0 = UDCCS0;
+ udccs0 = udc_ep0_get_UDCCS(dev);
/* start control request? */
if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))
@@ -1462,14 +1688,14 @@ static void handle_ep0 (struct pxa25x_udc *dev)
/* read SETUP packet */
for (i = 0; i < 8; i++) {
- if (unlikely(!(UDCCS0 & UDCCS0_RNE))) {
+ if (unlikely(!(udc_ep0_get_UDCCS(dev) & UDCCS0_RNE))) {
bad_setup:
DMSG("SETUP %d!\n", i);
goto stall;
}
u.raw [i] = (u8) UDDR0;
}
- if (unlikely((UDCCS0 & UDCCS0_RNE) != 0))
+ if (unlikely((udc_ep0_get_UDCCS(dev) & UDCCS0_RNE) != 0))
goto bad_setup;
got_setup:
@@ -1545,7 +1771,7 @@ config_change:
*/
}
DBG(DBG_VERBOSE, "protocol STALL, "
- "%02x err %d\n", UDCCS0, i);
+ "%02x err %d\n", udc_ep0_get_UDCCS(dev), i);
stall:
/* the watchdog timer helps deal with cases
* where udc seems to clear FST wrongly, and
@@ -1592,12 +1818,12 @@ stall:
* - IPR cleared
* - OPR got set, without SA (likely status stage)
*/
- UDCCS0 = udccs0 & (UDCCS0_SA|UDCCS0_OPR);
+ udc_ep0_set_UDCCS(dev, udccs0 & (UDCCS0_SA|UDCCS0_OPR));
}
break;
case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */
if (udccs0 & UDCCS0_OPR) {
- UDCCS0 = UDCCS0_OPR|UDCCS0_FTF;
+ udc_ep0_set_UDCCS(dev, UDCCS0_OPR|UDCCS0_FTF);
DBG(DBG_VERBOSE, "ep0in premature status\n");
if (req)
done(ep, req, 0);
@@ -1631,14 +1857,14 @@ stall:
* also appears after some config change events.
*/
if (udccs0 & UDCCS0_OPR)
- UDCCS0 = UDCCS0_OPR;
+ udc_ep0_set_UDCCS(dev, UDCCS0_OPR);
ep0_idle(dev);
break;
case EP0_STALL:
- UDCCS0 = UDCCS0_FST;
+ udc_ep0_set_UDCCS(dev, UDCCS0_FST);
break;
}
- USIR0 = USIR0_IR0;
+ udc_set_reg(dev, USIR0, USIR0_IR0);
}
static void handle_ep(struct pxa25x_ep *ep)
@@ -1658,14 +1884,14 @@ static void handle_ep(struct pxa25x_ep *ep)
// TODO check FST handling
- udccs = *ep->reg_udccs;
+ udccs = udc_ep_get_UDCCS(ep);
if (unlikely(is_in)) { /* irq from TPC, SST, or (ISO) TUR */
tmp = UDCCS_BI_TUR;
if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))
tmp |= UDCCS_BI_SST;
tmp &= udccs;
if (likely (tmp))
- *ep->reg_udccs = tmp;
+ udc_ep_set_UDCCS(ep, tmp);
if (req && likely ((udccs & UDCCS_BI_TFS) != 0))
completed = write_fifo(ep, req);
@@ -1676,13 +1902,13 @@ static void handle_ep(struct pxa25x_ep *ep)
tmp = UDCCS_IO_ROF | UDCCS_IO_DME;
tmp &= udccs;
if (likely(tmp))
- *ep->reg_udccs = tmp;
+ udc_ep_set_UDCCS(ep, tmp);
/* fifos can hold packets, ready for reading... */
if (likely(req)) {
completed = read_fifo(ep, req);
} else
- pio_irq_disable (ep->bEndpointAddress);
+ pio_irq_disable(ep);
}
ep->pio_irqs++;
} while (completed);
@@ -1703,13 +1929,13 @@ pxa25x_udc_irq(int irq, void *_dev)
dev->stats.irqs++;
do {
- u32 udccr = UDCCR;
+ u32 udccr = udc_get_reg(dev, UDCCR);
handled = 0;
/* SUSpend Interrupt Request */
if (unlikely(udccr & UDCCR_SUSIR)) {
- udc_ack_int_UDCCR(UDCCR_SUSIR);
+ udc_ack_int_UDCCR(dev, UDCCR_SUSIR);
handled = 1;
DBG(DBG_VERBOSE, "USB suspend\n");
@@ -1722,7 +1948,7 @@ pxa25x_udc_irq(int irq, void *_dev)
/* RESume Interrupt Request */
if (unlikely(udccr & UDCCR_RESIR)) {
- udc_ack_int_UDCCR(UDCCR_RESIR);
+ udc_ack_int_UDCCR(dev, UDCCR_RESIR);
handled = 1;
DBG(DBG_VERBOSE, "USB resume\n");
@@ -1734,10 +1960,10 @@ pxa25x_udc_irq(int irq, void *_dev)
/* ReSeT Interrupt Request - USB reset */
if (unlikely(udccr & UDCCR_RSTIR)) {
- udc_ack_int_UDCCR(UDCCR_RSTIR);
+ udc_ack_int_UDCCR(dev, UDCCR_RSTIR);
handled = 1;
- if ((UDCCR & UDCCR_UDA) == 0) {
+ if ((udc_get_reg(dev, UDCCR) & UDCCR_UDA) == 0) {
DBG(DBG_VERBOSE, "USB reset start\n");
/* reset driver and endpoints,
@@ -1753,8 +1979,10 @@ pxa25x_udc_irq(int irq, void *_dev)
}
} else {
- u32 usir0 = USIR0 & ~UICR0;
- u32 usir1 = USIR1 & ~UICR1;
+ u32 usir0 = udc_get_reg(dev, USIR0) &
+ ~udc_get_reg(dev, UICR0);
+ u32 usir1 = udc_get_reg(dev, USIR1) &
+ ~udc_get_reg(dev, UICR1);
int i;
if (unlikely (!usir0 && !usir1))
@@ -1775,13 +2003,15 @@ pxa25x_udc_irq(int irq, void *_dev)
if (i && (usir0 & tmp)) {
handle_ep(&dev->ep[i]);
- USIR0 |= tmp;
+ udc_set_reg(dev, USIR0,
+ udc_get_reg(dev, USIR0) | tmp);
handled = 1;
}
#ifndef CONFIG_USB_PXA25X_SMALL
if (usir1 & tmp) {
handle_ep(&dev->ep[i+8]);
- USIR1 |= tmp;
+ udc_set_reg(dev, USIR1,
+ udc_get_reg(dev, USIR1) | tmp);
handled = 1;
}
#endif
@@ -1826,8 +2056,8 @@ static struct pxa25x_udc memory = {
USB_EP_CAPS_DIR_ALL),
},
.dev = &memory,
- .reg_udccs = &UDCCS0,
- .reg_uddr = &UDDR0,
+ .regoff_udccs = UDCCS0,
+ .regoff_uddr = UDDR0,
},
/* first group of endpoints */
@@ -1843,8 +2073,8 @@ static struct pxa25x_udc memory = {
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 1,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .reg_udccs = &UDCCS1,
- .reg_uddr = &UDDR1,
+ .regoff_udccs = UDCCS1,
+ .regoff_uddr = UDDR1,
},
.ep[2] = {
.ep = {
@@ -1858,9 +2088,9 @@ static struct pxa25x_udc memory = {
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 2,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .reg_udccs = &UDCCS2,
- .reg_ubcr = &UBCR2,
- .reg_uddr = &UDDR2,
+ .regoff_udccs = UDCCS2,
+ .regoff_ubcr = UBCR2,
+ .regoff_uddr = UDDR2,
},
#ifndef CONFIG_USB_PXA25X_SMALL
.ep[3] = {
@@ -1875,8 +2105,8 @@ static struct pxa25x_udc memory = {
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 3,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .reg_udccs = &UDCCS3,
- .reg_uddr = &UDDR3,
+ .regoff_udccs = UDCCS3,
+ .regoff_uddr = UDDR3,
},
.ep[4] = {
.ep = {
@@ -1890,9 +2120,9 @@ static struct pxa25x_udc memory = {
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 4,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .reg_udccs = &UDCCS4,
- .reg_ubcr = &UBCR4,
- .reg_uddr = &UDDR4,
+ .regoff_udccs = UDCCS4,
+ .regoff_ubcr = UBCR4,
+ .regoff_uddr = UDDR4,
},
.ep[5] = {
.ep = {
@@ -1905,8 +2135,8 @@ static struct pxa25x_udc memory = {
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 5,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .reg_udccs = &UDCCS5,
- .reg_uddr = &UDDR5,
+ .regoff_udccs = UDCCS5,
+ .regoff_uddr = UDDR5,
},
/* second group of endpoints */
@@ -1922,8 +2152,8 @@ static struct pxa25x_udc memory = {
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 6,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .reg_udccs = &UDCCS6,
- .reg_uddr = &UDDR6,
+ .regoff_udccs = UDCCS6,
+ .regoff_uddr = UDDR6,
},
.ep[7] = {
.ep = {
@@ -1937,9 +2167,9 @@ static struct pxa25x_udc memory = {
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 7,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .reg_udccs = &UDCCS7,
- .reg_ubcr = &UBCR7,
- .reg_uddr = &UDDR7,
+ .regoff_udccs = UDCCS7,
+ .regoff_ubcr = UBCR7,
+ .regoff_uddr = UDDR7,
},
.ep[8] = {
.ep = {
@@ -1953,8 +2183,8 @@ static struct pxa25x_udc memory = {
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 8,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .reg_udccs = &UDCCS8,
- .reg_uddr = &UDDR8,
+ .regoff_udccs = UDCCS8,
+ .regoff_uddr = UDDR8,
},
.ep[9] = {
.ep = {
@@ -1968,9 +2198,9 @@ static struct pxa25x_udc memory = {
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 9,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .reg_udccs = &UDCCS9,
- .reg_ubcr = &UBCR9,
- .reg_uddr = &UDDR9,
+ .regoff_udccs = UDCCS9,
+ .regoff_ubcr = UBCR9,
+ .regoff_uddr = UDDR9,
},
.ep[10] = {
.ep = {
@@ -1983,8 +2213,8 @@ static struct pxa25x_udc memory = {
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 10,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .reg_udccs = &UDCCS10,
- .reg_uddr = &UDDR10,
+ .regoff_udccs = UDCCS10,
+ .regoff_uddr = UDDR10,
},
/* third group of endpoints */
@@ -2000,8 +2230,8 @@ static struct pxa25x_udc memory = {
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 11,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .reg_udccs = &UDCCS11,
- .reg_uddr = &UDDR11,
+ .regoff_udccs = UDCCS11,
+ .regoff_uddr = UDDR11,
},
.ep[12] = {
.ep = {
@@ -2015,9 +2245,9 @@ static struct pxa25x_udc memory = {
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 12,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .reg_udccs = &UDCCS12,
- .reg_ubcr = &UBCR12,
- .reg_uddr = &UDDR12,
+ .regoff_udccs = UDCCS12,
+ .regoff_ubcr = UBCR12,
+ .regoff_uddr = UDDR12,
},
.ep[13] = {
.ep = {
@@ -2031,8 +2261,8 @@ static struct pxa25x_udc memory = {
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 13,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .reg_udccs = &UDCCS13,
- .reg_uddr = &UDDR13,
+ .regoff_udccs = UDCCS13,
+ .regoff_uddr = UDDR13,
},
.ep[14] = {
.ep = {
@@ -2046,9 +2276,9 @@ static struct pxa25x_udc memory = {
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 14,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .reg_udccs = &UDCCS14,
- .reg_ubcr = &UBCR14,
- .reg_uddr = &UDDR14,
+ .regoff_udccs = UDCCS14,
+ .regoff_ubcr = UBCR14,
+ .regoff_uddr = UDDR14,
},
.ep[15] = {
.ep = {
@@ -2061,8 +2291,8 @@ static struct pxa25x_udc memory = {
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 15,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .reg_udccs = &UDCCS15,
- .reg_uddr = &UDDR15,
+ .regoff_udccs = UDCCS15,
+ .regoff_uddr = UDDR15,
},
#endif /* !CONFIG_USB_PXA25X_SMALL */
};
@@ -2109,6 +2339,7 @@ static int pxa25x_udc_probe(struct platform_device *pdev)
struct pxa25x_udc *dev = &memory;
int retval, irq;
u32 chiprev;
+ struct resource *res;
pr_info("%s: version %s\n", driver_name, DRIVER_VERSION);
@@ -2154,6 +2385,11 @@ static int pxa25x_udc_probe(struct platform_device *pdev)
if (irq < 0)
return -ENODEV;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->regs))
+ return PTR_ERR(dev->regs);
+
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk);
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.h b/drivers/usb/gadget/udc/pxa25x_udc.h
index 3fe5931dc21a..4b8b72d7ab37 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.h
+++ b/drivers/usb/gadget/udc/pxa25x_udc.h
@@ -56,9 +56,9 @@ struct pxa25x_ep {
* UDDR = UDC Endpoint Data Register (the fifo)
* DRCM = DMA Request Channel Map
*/
- volatile u32 *reg_udccs;
- volatile u32 *reg_ubcr;
- volatile u32 *reg_uddr;
+ u32 regoff_udccs;
+ u32 regoff_ubcr;
+ u32 regoff_uddr;
};
struct pxa25x_request {
@@ -125,6 +125,7 @@ struct pxa25x_udc {
#ifdef CONFIG_USB_GADGET_DEBUG_FS
struct dentry *debugfs_udc;
#endif
+ void __iomem *regs;
};
#define to_pxa25x(g) (container_of((g), struct pxa25x_udc, gadget))
@@ -197,6 +198,8 @@ dump_udccs0(const char *label)
(udccs0 & UDCCS0_OPR) ? " opr" : "");
}
+static inline u32 udc_ep_get_UDCCS(struct pxa25x_ep *);
+
static void __maybe_unused
dump_state(struct pxa25x_udc *dev)
{
@@ -228,7 +231,7 @@ dump_state(struct pxa25x_udc *dev)
for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
if (dev->ep[i].ep.desc == NULL)
continue;
- DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
+ DMSG ("udccs%d = %02x\n", i, udc_ep_get_UDCCS(&dev->ep[i]));
}
}
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index fd73a3ea07c2..4151597e9d28 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -413,9 +413,10 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
if (!driver->udc_name || strcmp(driver->udc_name,
dev_name(&udc->dev)) == 0) {
ret = udc_bind_to_driver(udc, driver);
+ if (ret != -EPROBE_DEFER)
+ list_del(&driver->pending);
if (ret)
goto err4;
- list_del(&driver->pending);
break;
}
}
@@ -442,6 +443,36 @@ err1:
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
/**
+ * usb_get_gadget_udc_name - get the name of the first UDC controller
+ * This functions returns the name of the first UDC controller in the system.
+ * Please note that this interface is usefull only for legacy drivers which
+ * assume that there is only one UDC controller in the system and they need to
+ * get its name before initialization. There is no guarantee that the UDC
+ * of the returned name will be still available, when gadget driver registers
+ * itself.
+ *
+ * Returns pointer to string with UDC controller name on success, NULL
+ * otherwise. Caller should kfree() returned string.
+ */
+char *usb_get_gadget_udc_name(void)
+{
+ struct usb_udc *udc;
+ char *name = NULL;
+
+ /* For now we take the first available UDC */
+ mutex_lock(&udc_lock);
+ list_for_each_entry(udc, &udc_list, list) {
+ if (!udc->driver) {
+ name = kstrdup(udc->gadget->name, GFP_KERNEL);
+ break;
+ }
+ }
+ mutex_unlock(&udc_lock);
+ return name;
+}
+EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name);
+
+/**
* usb_add_gadget_udc - adds a new gadget to the udc class driver list
* @parent: the parent device to this udc. Usually the controller
* driver's device.
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1f117c360ebb..3050b18b2447 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -5,6 +5,7 @@ comment "USB Host Controller Drivers"
config USB_C67X00_HCD
tristate "Cypress C67x00 HCD support"
+ depends on HAS_IOMEM
help
The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
host/peripheral/OTG USB controllers.
@@ -17,6 +18,7 @@ config USB_C67X00_HCD
config USB_XHCI_HCD
tristate "xHCI HCD (USB 3.0) support"
+ depends on HAS_DMA && HAS_IOMEM
---help---
The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
"SuperSpeed" host controller hardware.
@@ -53,6 +55,7 @@ config USB_XHCI_MTK
config USB_XHCI_MVEBU
tristate "xHCI support for Marvell Armada 375/38x"
select USB_XHCI_PLATFORM
+ depends on HAS_IOMEM
depends on ARCH_MVEBU || COMPILE_TEST
---help---
Say 'Y' to enable the support for the xHCI host controller
@@ -61,7 +64,7 @@ config USB_XHCI_MVEBU
config USB_XHCI_RCAR
tristate "xHCI support for Renesas R-Car SoCs"
select USB_XHCI_PLATFORM
- depends on ARCH_SHMOBILE || COMPILE_TEST
+ depends on ARCH_RENESAS || COMPILE_TEST
---help---
Say 'Y' to enable the support for the xHCI host controller
found in Renesas R-Car ARM SoCs.
@@ -70,6 +73,7 @@ endif # USB_XHCI_HCD
config USB_EHCI_HCD
tristate "EHCI HCD (USB 2.0) support"
+ depends on HAS_DMA && HAS_IOMEM
---help---
The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
"high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
@@ -121,9 +125,6 @@ config USB_EHCI_TT_NEWSCHED
If unsure, say Y.
-config USB_FSL_MPH_DR_OF
- tristate
-
if USB_EHCI_HCD
config USB_EHCI_PCI
@@ -156,7 +157,6 @@ config USB_EHCI_FSL
tristate "Support for Freescale PPC on-chip EHCI USB controller"
depends on FSL_SOC
select USB_EHCI_ROOT_HUB_TT
- select USB_FSL_MPH_DR_OF if OF
---help---
Variation of ARC USB block used in some Freescale chips.
@@ -328,6 +328,7 @@ endif # USB_EHCI_HCD
config USB_OXU210HP_HCD
tristate "OXU210HP HCD support"
+ depends on HAS_IOMEM
---help---
The OXU210HP is an USB host/OTG/device controller. Enable this
option if your board has this chip. If unsure, say N.
@@ -340,6 +341,7 @@ config USB_OXU210HP_HCD
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
+ depends on HAS_IOMEM
---help---
The ISP1160 and ISP1161 chips are USB host controllers. Enable this
option if your board has this chip. If unsure, say N.
@@ -351,6 +353,7 @@ config USB_ISP116X_HCD
config USB_ISP1362_HCD
tristate "ISP1362 HCD support"
+ depends on HAS_IOMEM
---help---
Supports the Philips ISP1362 chip as a host controller
@@ -361,7 +364,7 @@ config USB_ISP1362_HCD
config USB_FOTG210_HCD
tristate "FOTG210 HCD support"
- depends on USB
+ depends on USB && HAS_DMA && HAS_IOMEM
---help---
Faraday FOTG210 is an OTG controller which can be configured as
an USB2.0 host. It is designed to meet USB2.0 EHCI specification
@@ -383,6 +386,7 @@ config USB_MAX3421_HCD
config USB_OHCI_HCD
tristate "OHCI HCD (USB 1.1) support"
+ depends on HAS_DMA && HAS_IOMEM
---help---
The Open Host Controller Interface (OHCI) is a standard for accessing
USB 1.1 host controller hardware. It does more in hardware than Intel's
@@ -668,6 +672,7 @@ config USB_U132_HCD
config USB_SL811_HCD
tristate "SL811HS HCD support"
+ depends on HAS_IOMEM
help
The SL811HS is a single-port USB controller that supports either
host side or peripheral side roles. Enable this option if your
@@ -699,6 +704,7 @@ config USB_SL811_CS
config USB_R8A66597_HCD
tristate "R8A66597 HCD support"
+ depends on HAS_IOMEM
help
The R8A66597 is a USB 2.0 host and peripheral controller.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 65a06b4382bf..a9ddd3c9ec94 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -74,7 +74,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
-obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
+obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o
+obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
index 291aaa2baed8..963e2d0e8f92 100644
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c
@@ -35,6 +35,7 @@ MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
MODULE_LICENSE("GPL");
struct bcma_hcd_device {
+ struct bcma_device *core;
struct platform_device *ehci_dev;
struct platform_device *ohci_dev;
struct gpio_desc *gpio_desc;
@@ -244,7 +245,10 @@ static const struct usb_ehci_pdata ehci_pdata = {
static const struct usb_ohci_pdata ohci_pdata = {
};
-static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr)
+static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev,
+ const char *name, u32 addr,
+ const void *data,
+ size_t size)
{
struct platform_device *hci_dev;
struct resource hci_res[2];
@@ -259,8 +263,7 @@ static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, boo
hci_res[1].start = dev->irq;
hci_res[1].flags = IORESOURCE_IRQ;
- hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
- "ehci-platform" , 0);
+ hci_dev = platform_device_alloc(name, 0);
if (!hci_dev)
return ERR_PTR(-ENOMEM);
@@ -271,12 +274,8 @@ static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, boo
ARRAY_SIZE(hci_res));
if (ret)
goto err_alloc;
- if (ohci)
- ret = platform_device_add_data(hci_dev, &ohci_pdata,
- sizeof(ohci_pdata));
- else
- ret = platform_device_add_data(hci_dev, &ehci_pdata,
- sizeof(ehci_pdata));
+ if (data)
+ ret = platform_device_add_data(hci_dev, data, size);
if (ret)
goto err_alloc;
ret = platform_device_add(hci_dev);
@@ -290,31 +289,16 @@ err_alloc:
return ERR_PTR(ret);
}
-static int bcma_hcd_probe(struct bcma_device *dev)
+static int bcma_hcd_usb20_init(struct bcma_hcd_device *usb_dev)
{
- int err;
+ struct bcma_device *dev = usb_dev->core;
+ struct bcma_chipinfo *chipinfo = &dev->bus->chipinfo;
u32 ohci_addr;
- struct bcma_hcd_device *usb_dev;
- struct bcma_chipinfo *chipinfo;
-
- chipinfo = &dev->bus->chipinfo;
-
- /* TODO: Probably need checks here; is the core connected? */
+ int err;
if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
return -EOPNOTSUPP;
- usb_dev = devm_kzalloc(&dev->dev, sizeof(struct bcma_hcd_device),
- GFP_KERNEL);
- if (!usb_dev)
- return -ENOMEM;
-
- if (dev->dev.of_node)
- usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc",
- &dev->dev.of_node->fwnode);
- if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
- gpiod_direction_output(usb_dev->gpio_desc, 1);
-
switch (dev->id.id) {
case BCMA_CORE_NS_USB20:
bcma_hcd_init_chip_arm(dev);
@@ -333,17 +317,20 @@ static int bcma_hcd_probe(struct bcma_device *dev)
&& chipinfo->rev == 0)
ohci_addr = 0x18009000;
- usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr);
+ usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, "ohci-platform",
+ ohci_addr, &ohci_pdata,
+ sizeof(ohci_pdata));
if (IS_ERR(usb_dev->ohci_dev))
return PTR_ERR(usb_dev->ohci_dev);
- usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr);
+ usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, "ehci-platform",
+ dev->addr, &ehci_pdata,
+ sizeof(ehci_pdata));
if (IS_ERR(usb_dev->ehci_dev)) {
err = PTR_ERR(usb_dev->ehci_dev);
goto err_unregister_ohci_dev;
}
- bcma_set_drvdata(dev, usb_dev);
return 0;
err_unregister_ohci_dev:
@@ -351,6 +338,40 @@ err_unregister_ohci_dev:
return err;
}
+static int bcma_hcd_probe(struct bcma_device *core)
+{
+ int err;
+ struct bcma_hcd_device *usb_dev;
+
+ /* TODO: Probably need checks here; is the core connected? */
+
+ usb_dev = devm_kzalloc(&core->dev, sizeof(struct bcma_hcd_device),
+ GFP_KERNEL);
+ if (!usb_dev)
+ return -ENOMEM;
+ usb_dev->core = core;
+
+ if (core->dev.of_node)
+ usb_dev->gpio_desc = devm_get_gpiod_from_child(&core->dev, "vcc",
+ &core->dev.of_node->fwnode);
+ if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
+ gpiod_direction_output(usb_dev->gpio_desc, 1);
+
+ switch (core->id.id) {
+ case BCMA_CORE_USB20_HOST:
+ case BCMA_CORE_NS_USB20:
+ err = bcma_hcd_usb20_init(usb_dev);
+ if (err)
+ return err;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ bcma_set_drvdata(core, usb_dev);
+ return 0;
+}
+
static void bcma_hcd_remove(struct bcma_device *dev)
{
struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index be0964a801e8..7440722bfbf0 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -185,8 +185,7 @@ static int ehci_atmel_drv_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int ehci_atmel_drv_suspend(struct device *dev)
+static int __maybe_unused ehci_atmel_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
@@ -200,7 +199,7 @@ static int ehci_atmel_drv_suspend(struct device *dev)
return 0;
}
-static int ehci_atmel_drv_resume(struct device *dev)
+static int __maybe_unused ehci_atmel_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
@@ -208,7 +207,6 @@ static int ehci_atmel_drv_resume(struct device *dev)
atmel_start_clock(atmel_ehci);
return ehci_resume(hcd, false);
}
-#endif
#ifdef CONFIG_OF
static const struct of_device_id atmel_ehci_dt_ids[] = {
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index b7d623f1523c..79d12b2ba3c4 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -11,76 +11,73 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* this file is part of ehci-hcd.c */
#ifdef CONFIG_DYNAMIC_DEBUG
-/* check the values in the HCSPARAMS register
+/*
+ * check the values in the HCSPARAMS register
* (host controller _Structural_ parameters)
* see EHCI spec, Table 2-4 for each value
*/
-static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
+static void dbg_hcs_params(struct ehci_hcd *ehci, char *label)
{
u32 params = ehci_readl(ehci, &ehci->caps->hcs_params);
- ehci_dbg (ehci,
+ ehci_dbg(ehci,
"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
label, params,
- HCS_DEBUG_PORT (params),
- HCS_INDICATOR (params) ? " ind" : "",
- HCS_N_CC (params),
- HCS_N_PCC (params),
- HCS_PORTROUTED (params) ? "" : " ordered",
- HCS_PPC (params) ? "" : " !ppc",
- HCS_N_PORTS (params)
- );
+ HCS_DEBUG_PORT(params),
+ HCS_INDICATOR(params) ? " ind" : "",
+ HCS_N_CC(params),
+ HCS_N_PCC(params),
+ HCS_PORTROUTED(params) ? "" : " ordered",
+ HCS_PPC(params) ? "" : " !ppc",
+ HCS_N_PORTS(params));
/* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */
- if (HCS_PORTROUTED (params)) {
+ if (HCS_PORTROUTED(params)) {
int i;
- char buf [46], tmp [7], byte;
+ char buf[46], tmp[7], byte;
buf[0] = 0;
- for (i = 0; i < HCS_N_PORTS (params); i++) {
- // FIXME MIPS won't readb() ...
- byte = readb (&ehci->caps->portroute[(i>>1)]);
+ for (i = 0; i < HCS_N_PORTS(params); i++) {
+ /* FIXME MIPS won't readb() ... */
+ byte = readb(&ehci->caps->portroute[(i >> 1)]);
sprintf(tmp, "%d ",
- ((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
+ (i & 0x1) ? byte & 0xf : (byte >> 4) & 0xf);
strcat(buf, tmp);
}
- ehci_dbg (ehci, "%s portroute %s\n",
- label, buf);
+ ehci_dbg(ehci, "%s portroute %s\n", label, buf);
}
}
#else
-static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
+static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) {}
#endif
#ifdef CONFIG_DYNAMIC_DEBUG
-/* check the values in the HCCPARAMS register
+/*
+ * check the values in the HCCPARAMS register
* (host controller _Capability_ parameters)
* see EHCI Spec, Table 2-5 for each value
- * */
-static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
+ */
+static void dbg_hcc_params(struct ehci_hcd *ehci, char *label)
{
u32 params = ehci_readl(ehci, &ehci->caps->hcc_params);
- if (HCC_ISOC_CACHE (params)) {
- ehci_dbg (ehci,
+ if (HCC_ISOC_CACHE(params)) {
+ ehci_dbg(ehci,
"%s hcc_params %04x caching frame %s%s%s\n",
label, params,
HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
HCC_CANPARK(params) ? " park" : "",
HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
} else {
- ehci_dbg (ehci,
+ ehci_dbg(ehci,
"%s hcc_params %04x thresh %d uframes %s%s%s%s%s%s%s\n",
label,
params,
@@ -97,21 +94,21 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
}
#else
-static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
+static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) {}
#endif
#ifdef CONFIG_DYNAMIC_DEBUG
static void __maybe_unused
-dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+dbg_qtd(const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
{
ehci_dbg(ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
hc32_to_cpup(ehci, &qtd->hw_next),
hc32_to_cpup(ehci, &qtd->hw_alt_next),
hc32_to_cpup(ehci, &qtd->hw_token),
- hc32_to_cpup(ehci, &qtd->hw_buf [0]));
- if (qtd->hw_buf [1])
+ hc32_to_cpup(ehci, &qtd->hw_buf[0]));
+ if (qtd->hw_buf[1])
ehci_dbg(ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
hc32_to_cpup(ehci, &qtd->hw_buf[1]),
hc32_to_cpup(ehci, &qtd->hw_buf[2]),
@@ -120,22 +117,22 @@ dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
}
static void __maybe_unused
-dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+dbg_qh(const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qh_hw *hw = qh->hw;
- ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
+ ehci_dbg(ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
dbg_qtd("overlay", ehci, (struct ehci_qtd *) &hw->hw_qtd_next);
}
static void __maybe_unused
-dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
+dbg_itd(const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
{
- ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
+ ehci_dbg(ehci, "%s [%d] itd %p, next %08x, urb %p\n",
label, itd->frame, itd, hc32_to_cpu(ehci, itd->hw_next),
itd->urb);
- ehci_dbg (ehci,
+ ehci_dbg(ehci,
" trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
hc32_to_cpu(ehci, itd->hw_transaction[0]),
hc32_to_cpu(ehci, itd->hw_transaction[1]),
@@ -145,7 +142,7 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
hc32_to_cpu(ehci, itd->hw_transaction[5]),
hc32_to_cpu(ehci, itd->hw_transaction[6]),
hc32_to_cpu(ehci, itd->hw_transaction[7]));
- ehci_dbg (ehci,
+ ehci_dbg(ehci,
" buf: %08x %08x %08x %08x %08x %08x %08x\n",
hc32_to_cpu(ehci, itd->hw_bufp[0]),
hc32_to_cpu(ehci, itd->hw_bufp[1]),
@@ -154,19 +151,19 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
hc32_to_cpu(ehci, itd->hw_bufp[4]),
hc32_to_cpu(ehci, itd->hw_bufp[5]),
hc32_to_cpu(ehci, itd->hw_bufp[6]));
- ehci_dbg (ehci, " index: %d %d %d %d %d %d %d %d\n",
+ ehci_dbg(ehci, " index: %d %d %d %d %d %d %d %d\n",
itd->index[0], itd->index[1], itd->index[2],
itd->index[3], itd->index[4], itd->index[5],
itd->index[6], itd->index[7]);
}
static void __maybe_unused
-dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+dbg_sitd(const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
- ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
+ ehci_dbg(ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
label, sitd->frame, sitd, hc32_to_cpu(ehci, sitd->hw_next),
sitd->urb);
- ehci_dbg (ehci,
+ ehci_dbg(ehci,
" addr %08x sched %04x result %08x buf %08x %08x\n",
hc32_to_cpu(ehci, sitd->hw_fullspeed_ep),
hc32_to_cpu(ehci, sitd->hw_uframe),
@@ -176,11 +173,11 @@ dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
}
static int __maybe_unused
-dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
{
- return scnprintf (buf, len,
+ return scnprintf(buf, len,
"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s%s",
- label, label [0] ? " " : "", status,
+ label, label[0] ? " " : "", status,
(status & STS_PPCE_MASK) ? " PPCE" : "",
(status & STS_ASS) ? " Async" : "",
(status & STS_PSS) ? " Periodic" : "",
@@ -191,79 +188,83 @@ dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
(status & STS_FLR) ? " FLR" : "",
(status & STS_PCD) ? " PCD" : "",
(status & STS_ERR) ? " ERR" : "",
- (status & STS_INT) ? " INT" : ""
- );
+ (status & STS_INT) ? " INT" : "");
}
static int __maybe_unused
-dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
{
- return scnprintf (buf, len,
+ return scnprintf(buf, len,
"%s%sintrenable %02x%s%s%s%s%s%s%s",
- label, label [0] ? " " : "", enable,
+ label, label[0] ? " " : "", enable,
(enable & STS_PPCE_MASK) ? " PPCE" : "",
(enable & STS_IAA) ? " IAA" : "",
(enable & STS_FATAL) ? " FATAL" : "",
(enable & STS_FLR) ? " FLR" : "",
(enable & STS_PCD) ? " PCD" : "",
(enable & STS_ERR) ? " ERR" : "",
- (enable & STS_INT) ? " INT" : ""
- );
+ (enable & STS_INT) ? " INT" : "");
}
-static const char *const fls_strings [] =
- { "1024", "512", "256", "??" };
+static const char *const fls_strings[] = { "1024", "512", "256", "??" };
static int
-dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
+dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
{
- return scnprintf (buf, len,
+ return scnprintf(buf, len,
"%s%scommand %07x %s%s%s%s%s%s=%d ithresh=%d%s%s%s%s "
"period=%s%s %s",
- label, label [0] ? " " : "", command,
+ label, label[0] ? " " : "", command,
(command & CMD_HIRD) ? " HIRD" : "",
(command & CMD_PPCEE) ? " PPCEE" : "",
(command & CMD_FSP) ? " FSP" : "",
(command & CMD_ASPE) ? " ASPE" : "",
(command & CMD_PSPE) ? " PSPE" : "",
(command & CMD_PARK) ? " park" : "(park)",
- CMD_PARK_CNT (command),
+ CMD_PARK_CNT(command),
(command >> 16) & 0x3f,
(command & CMD_LRESET) ? " LReset" : "",
(command & CMD_IAAD) ? " IAAD" : "",
(command & CMD_ASE) ? " Async" : "",
(command & CMD_PSE) ? " Periodic" : "",
- fls_strings [(command >> 2) & 0x3],
+ fls_strings[(command >> 2) & 0x3],
(command & CMD_RESET) ? " Reset" : "",
- (command & CMD_RUN) ? "RUN" : "HALT"
- );
+ (command & CMD_RUN) ? "RUN" : "HALT");
}
static int
-dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
+dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
{
char *sig;
/* signaling state */
switch (status & (3 << 10)) {
- case 0 << 10: sig = "se0"; break;
- case 1 << 10: sig = "k"; break; /* low speed */
- case 2 << 10: sig = "j"; break;
- default: sig = "?"; break;
+ case 0 << 10:
+ sig = "se0";
+ break;
+ case 1 << 10: /* low speed */
+ sig = "k";
+ break;
+ case 2 << 10:
+ sig = "j";
+ break;
+ default:
+ sig = "?";
+ break;
}
- return scnprintf (buf, len,
+ return scnprintf(buf, len,
"%s%sport:%d status %06x %d %s%s%s%s%s%s "
"sig=%s%s%s%s%s%s%s%s%s%s%s",
- label, label [0] ? " " : "", port, status,
- status>>25,/*device address */
- (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ACK ?
+ label, label[0] ? " " : "", port, status,
+ status >> 25, /*device address */
+ (status & PORT_SSTS) >> 23 == PORTSC_SUSPEND_STS_ACK ?
" ACK" : "",
- (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_NYET ?
+ (status & PORT_SSTS) >> 23 == PORTSC_SUSPEND_STS_NYET ?
" NYET" : "",
- (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_STALL ?
+ (status & PORT_SSTS) >> 23 == PORTSC_SUSPEND_STS_STALL ?
" STALL" : "",
- (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ERR ?
+ (status & PORT_SSTS) >> 23 == PORTSC_SUSPEND_STS_ERR ?
" ERR" : "",
(status & PORT_POWER) ? " POWER" : "",
(status & PORT_OWNER) ? " OWNER" : "",
@@ -282,52 +283,68 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
#else
static inline void __maybe_unused
-dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+dbg_qh(char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{}
static inline int __maybe_unused
-dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
-{ return 0; }
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
+{
+ return 0;
+}
static inline int __maybe_unused
-dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
-{ return 0; }
+dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
+{
+ return 0;
+}
static inline int __maybe_unused
-dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
-{ return 0; }
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
+{
+ return 0;
+}
static inline int __maybe_unused
-dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
-{ return 0; }
+dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
+{
+ return 0;
+}
#endif /* CONFIG_DYNAMIC_DEBUG */
-/* functions have the "wrong" filename when they're output... */
-#define dbg_status(ehci, label, status) { \
- char _buf [80]; \
- dbg_status_buf (_buf, sizeof _buf, label, status); \
- ehci_dbg (ehci, "%s\n", _buf); \
+static inline void
+dbg_status(struct ehci_hcd *ehci, const char *label, u32 status)
+{
+ char buf[80];
+
+ dbg_status_buf(buf, sizeof(buf), label, status);
+ ehci_dbg(ehci, "%s\n", buf);
}
-#define dbg_cmd(ehci, label, command) { \
- char _buf [80]; \
- dbg_command_buf (_buf, sizeof _buf, label, command); \
- ehci_dbg (ehci, "%s\n", _buf); \
+static inline void
+dbg_cmd(struct ehci_hcd *ehci, const char *label, u32 command)
+{
+ char buf[80];
+
+ dbg_command_buf(buf, sizeof(buf), label, command);
+ ehci_dbg(ehci, "%s\n", buf);
}
-#define dbg_port(ehci, label, port, status) { \
- char _buf [80]; \
- dbg_port_buf (_buf, sizeof _buf, label, port, status); \
- ehci_dbg (ehci, "%s\n", _buf); \
+static inline void
+dbg_port(struct ehci_hcd *ehci, const char *label, int port, u32 status)
+{
+ char buf[80];
+
+ dbg_port_buf(buf, sizeof(buf), label, port, status);
+ ehci_dbg(ehci, "%s\n", buf);
}
/*-------------------------------------------------------------------------*/
-#ifdef STUB_DEBUG_FILES
+#ifndef CONFIG_DYNAMIC_DEBUG
-static inline void create_debug_files (struct ehci_hcd *bus) { }
-static inline void remove_debug_files (struct ehci_hcd *bus) { }
+static inline void create_debug_files(struct ehci_hcd *bus) { }
+static inline void remove_debug_files(struct ehci_hcd *bus) { }
#else
@@ -348,6 +365,7 @@ static const struct file_operations debug_async_fops = {
.release = debug_close,
.llseek = default_llseek,
};
+
static const struct file_operations debug_bandwidth_fops = {
.owner = THIS_MODULE,
.open = debug_bandwidth_open,
@@ -355,6 +373,7 @@ static const struct file_operations debug_bandwidth_fops = {
.release = debug_close,
.llseek = default_llseek,
};
+
static const struct file_operations debug_periodic_fops = {
.owner = THIS_MODULE,
.open = debug_periodic_open,
@@ -362,6 +381,7 @@ static const struct file_operations debug_periodic_fops = {
.release = debug_close,
.llseek = default_llseek,
};
+
static const struct file_operations debug_registers_fops = {
.owner = THIS_MODULE,
.open = debug_registers_open,
@@ -381,13 +401,19 @@ struct debug_buffer {
size_t alloc_size;
};
-#define speed_char(info1) ({ char tmp; \
- switch (info1 & (3 << 12)) { \
- case QH_FULL_SPEED: tmp = 'f'; break; \
- case QH_LOW_SPEED: tmp = 'l'; break; \
- case QH_HIGH_SPEED: tmp = 'h'; break; \
- default: tmp = '?'; break; \
- } tmp; })
+static inline char speed_char(u32 info1)
+{
+ switch (info1 & (3 << 12)) {
+ case QH_FULL_SPEED:
+ return 'f';
+ case QH_LOW_SPEED:
+ return 'l';
+ case QH_HIGH_SPEED:
+ return 'h';
+ default:
+ return '?';
+ }
+}
static inline char token_mark(struct ehci_hcd *ehci, __hc32 token)
{
@@ -397,18 +423,14 @@ static inline char token_mark(struct ehci_hcd *ehci, __hc32 token)
return '*';
if (v & QTD_STS_HALT)
return '-';
- if (!IS_SHORT_READ (v))
+ if (!IS_SHORT_READ(v))
return ' ';
/* tries to advance through hw_alt_next */
return '/';
}
-static void qh_lines (
- struct ehci_hcd *ehci,
- struct ehci_qh *qh,
- char **nextp,
- unsigned *sizep
-)
+static void qh_lines(struct ehci_hcd *ehci, struct ehci_qh *qh,
+ char **nextp, unsigned *sizep)
{
u32 scratch;
u32 hw_curr;
@@ -435,7 +457,7 @@ static void qh_lines (
}
scratch = hc32_to_cpup(ehci, &hw->hw_info1);
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &hw->hw_current) : 0;
- temp = scnprintf (next, size,
+ temp = scnprintf(next, size,
"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)"
" [cur %08x next %08x buf[0] %08x]",
qh, scratch & 0x007f,
@@ -453,46 +475,52 @@ static void qh_lines (
next += temp;
/* hc may be modifying the list as we read it ... */
- list_for_each (entry, &qh->qtd_list) {
- td = list_entry (entry, struct ehci_qtd, qtd_list);
+ list_for_each(entry, &qh->qtd_list) {
+ char *type;
+
+ td = list_entry(entry, struct ehci_qtd, qtd_list);
scratch = hc32_to_cpup(ehci, &td->hw_token);
mark = ' ';
- if (hw_curr == td->qtd_dma)
+ if (hw_curr == td->qtd_dma) {
mark = '*';
- else if (hw->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
+ } else if (hw->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma)) {
mark = '+';
- else if (QTD_LENGTH (scratch)) {
+ } else if (QTD_LENGTH(scratch)) {
if (td->hw_alt_next == ehci->async->hw->hw_alt_next)
mark = '#';
else if (td->hw_alt_next != list_end)
mark = '/';
}
- temp = snprintf (next, size,
+ switch ((scratch >> 8) & 0x03) {
+ case 0:
+ type = "out";
+ break;
+ case 1:
+ type = "in";
+ break;
+ case 2:
+ type = "setup";
+ break;
+ default:
+ type = "?";
+ break;
+ }
+ temp = scnprintf(next, size,
"\n\t%p%c%s len=%d %08x urb %p"
" [td %08x buf[0] %08x]",
- td, mark, ({ char *tmp;
- switch ((scratch>>8)&0x03) {
- case 0: tmp = "out"; break;
- case 1: tmp = "in"; break;
- case 2: tmp = "setup"; break;
- default: tmp = "?"; break;
- } tmp;}),
+ td, mark, type,
(scratch >> 16) & 0x7fff,
scratch,
td->urb,
(u32) td->qtd_dma,
hc32_to_cpup(ehci, &td->hw_buf[0]));
- if (size < temp)
- temp = size;
size -= temp;
next += temp;
if (temp == size)
goto done;
}
- temp = snprintf (next, size, "\n");
- if (size < temp)
- temp = size;
+ temp = scnprintf(next, size, "\n");
size -= temp;
next += temp;
@@ -511,19 +539,20 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
struct ehci_qh *qh;
hcd = bus_to_hcd(buf->bus);
- ehci = hcd_to_ehci (hcd);
+ ehci = hcd_to_ehci(hcd);
next = buf->output_buf;
size = buf->alloc_size;
*next = 0;
- /* dumps a snapshot of the async schedule.
+ /*
+ * dumps a snapshot of the async schedule.
* usually empty except for long-term bulk reads, or head.
* one QH per line, and TDs we know about
*/
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
- qh_lines (ehci, qh, &next, &size);
+ qh_lines(ehci, qh, &next, &size);
if (!list_empty(&ehci->async_unlink) && size > 0) {
temp = scnprintf(next, size, "\nunlink =\n");
size -= temp;
@@ -535,7 +564,7 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
qh_lines(ehci, qh, &next, &size);
}
}
- spin_unlock_irqrestore (&ehci->lock, flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
return strlen(buf->output_buf);
}
@@ -623,6 +652,33 @@ static ssize_t fill_bandwidth_buffer(struct debug_buffer *buf)
return next - buf->output_buf;
}
+static unsigned output_buf_tds_dir(char *buf, struct ehci_hcd *ehci,
+ struct ehci_qh_hw *hw, struct ehci_qh *qh, unsigned size)
+{
+ u32 scratch = hc32_to_cpup(ehci, &hw->hw_info1);
+ struct ehci_qtd *qtd;
+ char *type = "";
+ unsigned temp = 0;
+
+ /* count tds, get ep direction */
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
+ temp++;
+ switch ((hc32_to_cpu(ehci, qtd->hw_token) >> 8) & 0x03) {
+ case 0:
+ type = "out";
+ continue;
+ case 1:
+ type = "in";
+ continue;
+ }
+ }
+
+ return scnprintf(buf, size, " (%c%d ep%d%s [%d/%d] q%d p%d)",
+ speed_char(scratch), scratch & 0x007f,
+ (scratch >> 8) & 0x000f, type, qh->ps.usecs,
+ qh->ps.c_usecs, temp, 0x7ff & (scratch >> 16));
+}
+
#define DBG_SCHED_LIMIT 64
static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
{
@@ -635,31 +691,32 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
unsigned i;
__hc32 tag;
- seen = kmalloc(DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC);
+ seen = kmalloc_array(DBG_SCHED_LIMIT, sizeof(*seen), GFP_ATOMIC);
if (!seen)
return 0;
seen_count = 0;
hcd = bus_to_hcd(buf->bus);
- ehci = hcd_to_ehci (hcd);
+ ehci = hcd_to_ehci(hcd);
next = buf->output_buf;
size = buf->alloc_size;
- temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size);
+ temp = scnprintf(next, size, "size = %d\n", ehci->periodic_size);
size -= temp;
next += temp;
- /* dump a snapshot of the periodic schedule.
+ /*
+ * dump a snapshot of the periodic schedule.
* iso changes, interrupt usually doesn't.
*/
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
for (i = 0; i < ehci->periodic_size; i++) {
- p = ehci->pshadow [i];
- if (likely (!p.ptr))
+ p = ehci->pshadow[i];
+ if (likely(!p.ptr))
continue;
- tag = Q_NEXT_TYPE(ehci, ehci->periodic [i]);
+ tag = Q_NEXT_TYPE(ehci, ehci->periodic[i]);
- temp = scnprintf (next, size, "%4d: ", i);
+ temp = scnprintf(next, size, "%4d: ", i);
size -= temp;
next += temp;
@@ -669,7 +726,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
switch (hc32_to_cpu(ehci, tag)) {
case Q_TYPE_QH:
hw = p.qh->hw;
- temp = scnprintf (next, size, " qh%d-%04x/%p",
+ temp = scnprintf(next, size, " qh%d-%04x/%p",
p.qh->ps.period,
hc32_to_cpup(ehci,
&hw->hw_info2)
@@ -680,10 +737,10 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
next += temp;
/* don't repeat what follows this qh */
for (temp = 0; temp < seen_count; temp++) {
- if (seen [temp].ptr != p.ptr)
+ if (seen[temp].ptr != p.ptr)
continue;
if (p.qh->qh_next.ptr) {
- temp = scnprintf (next, size,
+ temp = scnprintf(next, size,
" ...");
size -= temp;
next += temp;
@@ -692,58 +749,32 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
}
/* show more info the first time around */
if (temp == seen_count) {
- u32 scratch = hc32_to_cpup(ehci,
- &hw->hw_info1);
- struct ehci_qtd *qtd;
- char *type = "";
-
- /* count tds, get ep direction */
- temp = 0;
- list_for_each_entry (qtd,
- &p.qh->qtd_list,
- qtd_list) {
- temp++;
- switch (0x03 & (hc32_to_cpu(
- ehci,
- qtd->hw_token) >> 8)) {
- case 0: type = "out"; continue;
- case 1: type = "in"; continue;
- }
- }
-
- temp = scnprintf (next, size,
- " (%c%d ep%d%s "
- "[%d/%d] q%d p%d)",
- speed_char (scratch),
- scratch & 0x007f,
- (scratch >> 8) & 0x000f, type,
- p.qh->ps.usecs,
- p.qh->ps.c_usecs,
- temp,
- 0x7ff & (scratch >> 16));
+ temp = output_buf_tds_dir(next, ehci,
+ hw, p.qh, size);
if (seen_count < DBG_SCHED_LIMIT)
- seen [seen_count++].qh = p.qh;
- } else
+ seen[seen_count++].qh = p.qh;
+ } else {
temp = 0;
+ }
tag = Q_NEXT_TYPE(ehci, hw->hw_next);
p = p.qh->qh_next;
break;
case Q_TYPE_FSTN:
- temp = scnprintf (next, size,
+ temp = scnprintf(next, size,
" fstn-%8x/%p", p.fstn->hw_prev,
p.fstn);
tag = Q_NEXT_TYPE(ehci, p.fstn->hw_next);
p = p.fstn->fstn_next;
break;
case Q_TYPE_ITD:
- temp = scnprintf (next, size,
+ temp = scnprintf(next, size,
" itd/%p", p.itd);
tag = Q_NEXT_TYPE(ehci, p.itd->hw_next);
p = p.itd->itd_next;
break;
case Q_TYPE_SITD:
- temp = scnprintf (next, size,
+ temp = scnprintf(next, size,
" sitd%d-%04x/%p",
p.sitd->stream->ps.period,
hc32_to_cpup(ehci, &p.sitd->hw_uframe)
@@ -757,12 +788,12 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
next += temp;
} while (p.ptr);
- temp = scnprintf (next, size, "\n");
+ temp = scnprintf(next, size, "\n");
size -= temp;
next += temp;
}
- spin_unlock_irqrestore (&ehci->lock, flags);
- kfree (seen);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ kfree(seen);
return buf->alloc_size - size;
}
@@ -789,19 +820,19 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
struct ehci_hcd *ehci;
unsigned long flags;
unsigned temp, size, i;
- char *next, scratch [80];
- static char fmt [] = "%*s\n";
- static char label [] = "";
+ char *next, scratch[80];
+ static char fmt[] = "%*s\n";
+ static char label[] = "";
hcd = bus_to_hcd(buf->bus);
- ehci = hcd_to_ehci (hcd);
+ ehci = hcd_to_ehci(hcd);
next = buf->output_buf;
size = buf->alloc_size;
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
if (!HCD_HW_ACCESSIBLE(hcd)) {
- size = scnprintf (next, size,
+ size = scnprintf(next, size,
"bus %s, device %s\n"
"%s\n"
"SUSPENDED (no register access)\n",
@@ -813,7 +844,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
/* Capability Registers */
i = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
- temp = scnprintf (next, size,
+ temp = scnprintf(next, size,
"bus %s, device %s\n"
"%s\n"
"EHCI %x.%02x, rh state %s\n",
@@ -829,16 +860,16 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
if (dev_is_pci(hcd->self.controller)) {
struct pci_dev *pdev;
u32 offset, cap, cap2;
- unsigned count = 256/4;
+ unsigned count = 256 / 4;
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
offset = HCC_EXT_CAPS(ehci_readl(ehci,
&ehci->caps->hcc_params));
while (offset && count--) {
- pci_read_config_dword (pdev, offset, &cap);
+ pci_read_config_dword(pdev, offset, &cap);
switch (cap & 0xff) {
case 1:
- temp = scnprintf (next, size,
+ temp = scnprintf(next, size,
"ownership %08x%s%s\n", cap,
(cap & (1 << 24)) ? " linux" : "",
(cap & (1 << 16)) ? " firmware" : "");
@@ -846,8 +877,8 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
next += temp;
offset += 4;
- pci_read_config_dword (pdev, offset, &cap2);
- temp = scnprintf (next, size,
+ pci_read_config_dword(pdev, offset, &cap2);
+ temp = scnprintf(next, size,
"SMI sts/enable 0x%08x\n", cap2);
size -= temp;
next += temp;
@@ -863,50 +894,50 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
}
#endif
- // FIXME interpret both types of params
+ /* FIXME interpret both types of params */
i = ehci_readl(ehci, &ehci->caps->hcs_params);
- temp = scnprintf (next, size, "structural params 0x%08x\n", i);
+ temp = scnprintf(next, size, "structural params 0x%08x\n", i);
size -= temp;
next += temp;
i = ehci_readl(ehci, &ehci->caps->hcc_params);
- temp = scnprintf (next, size, "capability params 0x%08x\n", i);
+ temp = scnprintf(next, size, "capability params 0x%08x\n", i);
size -= temp;
next += temp;
/* Operational Registers */
- temp = dbg_status_buf (scratch, sizeof scratch, label,
+ temp = dbg_status_buf(scratch, sizeof(scratch), label,
ehci_readl(ehci, &ehci->regs->status));
- temp = scnprintf (next, size, fmt, temp, scratch);
+ temp = scnprintf(next, size, fmt, temp, scratch);
size -= temp;
next += temp;
- temp = dbg_command_buf (scratch, sizeof scratch, label,
+ temp = dbg_command_buf(scratch, sizeof(scratch), label,
ehci_readl(ehci, &ehci->regs->command));
- temp = scnprintf (next, size, fmt, temp, scratch);
+ temp = scnprintf(next, size, fmt, temp, scratch);
size -= temp;
next += temp;
- temp = dbg_intr_buf (scratch, sizeof scratch, label,
+ temp = dbg_intr_buf(scratch, sizeof(scratch), label,
ehci_readl(ehci, &ehci->regs->intr_enable));
- temp = scnprintf (next, size, fmt, temp, scratch);
+ temp = scnprintf(next, size, fmt, temp, scratch);
size -= temp;
next += temp;
- temp = scnprintf (next, size, "uframe %04x\n",
+ temp = scnprintf(next, size, "uframe %04x\n",
ehci_read_frame_index(ehci));
size -= temp;
next += temp;
- for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
- temp = dbg_port_buf (scratch, sizeof scratch, label, i,
+ for (i = 1; i <= HCS_N_PORTS(ehci->hcs_params); i++) {
+ temp = dbg_port_buf(scratch, sizeof(scratch), label, i,
ehci_readl(ehci,
&ehci->regs->port_status[i - 1]));
- temp = scnprintf (next, size, fmt, temp, scratch);
+ temp = scnprintf(next, size, fmt, temp, scratch);
size -= temp;
next += temp;
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
- temp = scnprintf (next, size,
+ temp = scnprintf(next, size,
" debug control %08x\n",
ehci_readl(ehci,
&ehci->debug->control));
@@ -924,31 +955,31 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
}
#ifdef EHCI_STATS
- temp = scnprintf (next, size,
+ temp = scnprintf(next, size,
"irq normal %ld err %ld iaa %ld (lost %ld)\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.iaa,
ehci->stats.lost_iaa);
size -= temp;
next += temp;
- temp = scnprintf (next, size, "complete %ld unlink %ld\n",
+ temp = scnprintf(next, size, "complete %ld unlink %ld\n",
ehci->stats.complete, ehci->stats.unlink);
size -= temp;
next += temp;
#endif
done:
- spin_unlock_irqrestore (&ehci->lock, flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
return buf->alloc_size - size;
}
static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
- ssize_t (*fill_func)(struct debug_buffer *))
+ ssize_t (*fill_func)(struct debug_buffer *))
{
struct debug_buffer *buf;
- buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (buf) {
buf->bus = bus;
@@ -984,7 +1015,7 @@ out:
}
static ssize_t debug_output(struct file *file, char __user *user_buf,
- size_t len, loff_t *offset)
+ size_t len, loff_t *offset)
{
struct debug_buffer *buf = file->private_data;
int ret = 0;
@@ -1004,7 +1035,6 @@ static ssize_t debug_output(struct file *file, char __user *user_buf,
out:
return ret;
-
}
static int debug_close(struct inode *inode, struct file *file)
@@ -1037,11 +1067,12 @@ static int debug_bandwidth_open(struct inode *inode, struct file *file)
static int debug_periodic_open(struct inode *inode, struct file *file)
{
struct debug_buffer *buf;
+
buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
if (!buf)
return -ENOMEM;
- buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
+ buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8) * PAGE_SIZE;
file->private_data = buf;
return 0;
}
@@ -1054,7 +1085,7 @@ static int debug_registers_open(struct inode *inode, struct file *file)
return file->private_data ? 0 : -ENOMEM;
}
-static inline void create_debug_files (struct ehci_hcd *ehci)
+static inline void create_debug_files(struct ehci_hcd *ehci)
{
struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
@@ -1084,9 +1115,9 @@ file_error:
debugfs_remove_recursive(ehci->debug_dir);
}
-static inline void remove_debug_files (struct ehci_hcd *ehci)
+static inline void remove_debug_files(struct ehci_hcd *ehci)
{
debugfs_remove_recursive(ehci->debug_dir);
}
-#endif /* STUB_DEBUG_FILES */
+#endif /* CONFIG_DYNAMIC_DEBUG */
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 3b6eb219de1a..9f5ffb629973 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -35,6 +35,7 @@
#include <linux/usb/otg.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
+#include <linux/of_platform.h>
#include "ehci.h"
#include "ehci-fsl.h"
@@ -241,7 +242,8 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
* to portsc
*/
if (pdata->check_phy_clk_valid) {
- if (!(in_be32(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID)) {
+ if (!(ioread32be(non_ehci + FSL_SOC_USB_CTRL) &
+ PHY_CLK_VALID)) {
dev_warn(hcd->self.controller,
"USB PHY clock invalid\n");
return -EINVAL;
@@ -273,9 +275,11 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
/* Setup Snooping for all the 4GB space */
/* SNOOP1 starts from 0x0, size 2G */
- out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB);
+ iowrite32be(0x0 | SNOOP_SIZE_2GB,
+ non_ehci + FSL_SOC_USB_SNOOP1);
/* SNOOP2 starts from 0x80000000, size 2G */
- out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
+ iowrite32be(0x80000000 | SNOOP_SIZE_2GB,
+ non_ehci + FSL_SOC_USB_SNOOP2);
}
/* Deal with USB erratum A-005275 */
@@ -309,13 +313,13 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
if (pdata->have_sysif_regs) {
#ifdef CONFIG_FSL_SOC_BOOKE
- out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
- out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
+ iowrite32be(0x00000008, non_ehci + FSL_SOC_USB_PRICTRL);
+ iowrite32be(0x00000080, non_ehci + FSL_SOC_USB_AGECNTTHRSH);
#else
- out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
- out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
+ iowrite32be(0x0000000c, non_ehci + FSL_SOC_USB_PRICTRL);
+ iowrite32be(0x00000040, non_ehci + FSL_SOC_USB_AGECNTTHRSH);
#endif
- out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+ iowrite32be(0x00000001, non_ehci + FSL_SOC_USB_SICTRL);
}
return 0;
@@ -554,7 +558,7 @@ static int ehci_fsl_drv_suspend(struct device *dev)
if (!fsl_deep_sleep())
return 0;
- ehci_fsl->usb_ctrl = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+ ehci_fsl->usb_ctrl = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
return 0;
}
@@ -577,7 +581,7 @@ static int ehci_fsl_drv_resume(struct device *dev)
usb_root_hub_lost_power(hcd->self.root_hub);
/* Restore USB PHY settings and enable the controller. */
- out_be32(non_ehci + FSL_SOC_USB_CTRL, ehci_fsl->usb_ctrl);
+ iowrite32be(ehci_fsl->usb_ctrl, non_ehci + FSL_SOC_USB_CTRL);
ehci_reset(ehci);
ehci_fsl_reinit(ehci);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 14178bbf0694..ae1b6e69eb96 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -306,9 +306,9 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
/*-------------------------------------------------------------------------*/
+static void end_iaa_cycle(struct ehci_hcd *ehci);
static void end_unlink_async(struct ehci_hcd *ehci);
static void unlink_empty_async(struct ehci_hcd *ehci);
-static void unlink_empty_async_suspended(struct ehci_hcd *ehci);
static void ehci_work(struct ehci_hcd *ehci);
static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
@@ -565,6 +565,9 @@ static int ehci_init(struct usb_hcd *hcd)
/* Accept arbitrarily long scatter-gather lists */
if (!(hcd->driver->flags & HCD_LOCAL_MEM))
hcd->self.sg_tablesize = ~0;
+
+ /* Prepare for unlinking active QHs */
+ ehci->old_current = ~0;
return 0;
}
@@ -675,8 +678,10 @@ int ehci_setup(struct usb_hcd *hcd)
return retval;
retval = ehci_halt(ehci);
- if (retval)
+ if (retval) {
+ ehci_mem_cleanup(ehci);
return retval;
+ }
ehci_reset(ehci);
@@ -756,7 +761,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
ehci_dbg(ehci, "IAA with IAAD still set?\n");
if (ehci->iaa_in_progress)
COUNT(ehci->stats.iaa);
- end_unlink_async(ehci);
+ end_iaa_cycle(ehci);
}
/* remote wakeup [4.3.1] */
@@ -909,7 +914,7 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
*/
} else {
qh = (struct ehci_qh *) urb->hcpriv;
- qh->exception = 1;
+ qh->unlink_reason |= QH_UNLINK_REQUESTED;
switch (qh->qh_state) {
case QH_STATE_LINKED:
if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
@@ -970,10 +975,13 @@ rescan:
goto done;
}
- qh->exception = 1;
+ qh->unlink_reason |= QH_UNLINK_REQUESTED;
switch (qh->qh_state) {
case QH_STATE_LINKED:
- WARN_ON(!list_empty(&qh->qtd_list));
+ if (list_empty(&qh->qtd_list))
+ qh->unlink_reason |= QH_UNLINK_QUEUE_EMPTY;
+ else
+ WARN_ON(1);
if (usb_endpoint_type(&ep->desc) != USB_ENDPOINT_XFER_INT)
start_unlink_async(ehci, qh);
else
@@ -1040,7 +1048,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
* re-linking will call qh_refresh().
*/
usb_settoggle(qh->ps.udev, epnum, is_out, 0);
- qh->exception = 1;
+ qh->unlink_reason |= QH_UNLINK_REQUESTED;
if (eptype == USB_ENDPOINT_XFER_BULK)
start_unlink_async(ehci, qh);
else
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 086a7115d263..ffc90295a95f 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -33,6 +33,8 @@
#ifdef CONFIG_PM
+static void unlink_empty_async_suspended(struct ehci_hcd *ehci);
+
static int persist_enabled_on_companion(struct usb_device *udev, void *unused)
{
return !udev->maxchild && udev->persist_enabled &&
@@ -347,8 +349,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
goto done;
ehci->rh_state = EHCI_RH_SUSPENDED;
- end_unlink_async(ehci);
unlink_empty_async_suspended(ehci);
+
+ /* Any IAA cycle that started before the suspend is now invalid */
+ end_iaa_cycle(ehci);
ehci_handle_start_intr_unlinks(ehci);
ehci_handle_intr_unlinks(ehci);
end_free_itds(ehci);
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index c23e2858c815..3e226ef6ca62 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -33,6 +33,7 @@
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
+#include <linux/acpi.h>
#include "ehci.h"
@@ -55,12 +56,16 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
if (retval)
return retval;
+ /* select ULPI phy and clear other status/control bits in PORTSC */
+ writel(PORTSC_PTS_ULPI, USB_PORTSC);
/* bursts of unspecified length. */
writel(0, USB_AHBBURST);
/* Use the AHB transactor, allow posted data writes */
writel(0x8, USB_AHBMODE);
/* Disable streaming mode and select host mode */
writel(0x13, USB_USBMODE);
+ /* Disable ULPI_TX_PKT_EN_CLR_FIX which is valid only for HSIC */
+ writel(readl(USB_GENCONFIG_2) & ~ULPI_TX_PKT_EN_CLR_FIX, USB_GENCONFIG_2);
return 0;
}
@@ -104,9 +109,9 @@ static int ehci_msm_probe(struct platform_device *pdev)
}
/*
- * OTG driver takes care of PHY initialization, clock management,
- * powering up VBUS, mapping of registers address space and power
- * management.
+ * If there is an OTG driver, let it take care of PHY initialization,
+ * clock management, powering up VBUS, mapping of registers address
+ * space and power management.
*/
if (pdev->dev.of_node)
phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
@@ -114,27 +119,35 @@ static int ehci_msm_probe(struct platform_device *pdev)
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR(phy)) {
- dev_err(&pdev->dev, "unable to find transceiver\n");
- ret = -EPROBE_DEFER;
- goto put_hcd;
- }
-
- ret = otg_set_host(phy->otg, &hcd->self);
- if (ret < 0) {
- dev_err(&pdev->dev, "unable to register with transceiver\n");
- goto put_hcd;
+ if (PTR_ERR(phy) == -EPROBE_DEFER) {
+ dev_err(&pdev->dev, "unable to find transceiver\n");
+ ret = -EPROBE_DEFER;
+ goto put_hcd;
+ }
+ phy = NULL;
}
hcd->usb_phy = phy;
device_init_wakeup(&pdev->dev, 1);
- /*
- * OTG device parent of HCD takes care of putting
- * hardware into low power mode.
- */
- pm_runtime_no_callbacks(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- /* FIXME: need to call usb_add_hcd() here? */
+ if (phy && phy->otg) {
+ /*
+ * MSM OTG driver takes care of adding the HCD and
+ * placing hardware into low power mode via runtime PM.
+ */
+ ret = otg_set_host(phy->otg, &hcd->self);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register with transceiver\n");
+ goto put_hcd;
+ }
+
+ pm_runtime_no_callbacks(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ } else {
+ ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+ if (ret)
+ goto put_hcd;
+ }
return 0;
@@ -152,9 +165,10 @@ static int ehci_msm_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
- otg_set_host(hcd->usb_phy->otg, NULL);
-
- /* FIXME: need to call usb_remove_hcd() here? */
+ if (hcd->usb_phy && hcd->usb_phy->otg)
+ otg_set_host(hcd->usb_phy->otg, NULL);
+ else
+ usb_remove_hcd(hcd);
usb_put_hcd(hcd);
@@ -191,6 +205,12 @@ static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
.resume = ehci_msm_pm_resume,
};
+static const struct acpi_device_id msm_ehci_acpi_ids[] = {
+ { "QCOM8040", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, msm_ehci_acpi_ids);
+
static const struct of_device_id msm_ehci_dt_match[] = {
{ .compatible = "qcom,ehci-host", },
{}
@@ -200,10 +220,12 @@ MODULE_DEVICE_TABLE(of, msm_ehci_dt_match);
static struct platform_driver ehci_msm_driver = {
.probe = ehci_msm_probe,
.remove = ehci_msm_remove,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "msm_hsusb_host",
.pm = &ehci_msm_dev_pm_ops,
.of_match_table = msm_ehci_dt_match,
+ .acpi_match_table = ACPI_PTR(msm_ehci_acpi_ids),
},
};
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 2a5d2fd76040..3b3649d88c5f 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -377,6 +377,12 @@ static int ehci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return usb_hcd_pci_probe(pdev, id);
}
+static void ehci_pci_remove(struct pci_dev *pdev)
+{
+ pci_clear_mwi(pdev);
+ usb_hcd_pci_remove(pdev);
+}
+
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids [] = { {
/* handle any USB 2.0 EHCI controller */
@@ -396,7 +402,7 @@ static struct pci_driver ehci_pci_driver = {
.id_table = pci_ids,
.probe = ehci_pci_probe,
- .remove = usb_hcd_pci_remove,
+ .remove = ehci_pci_remove,
.shutdown = usb_hcd_pci_shutdown,
#ifdef CONFIG_PM
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index bd7082f297bb..1757ebb471b6 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -345,8 +345,7 @@ static int ehci_platform_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
bool do_wakeup = device_may_wakeup(dev);
int ret;
@@ -364,8 +363,7 @@ static int ehci_platform_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
if (pdata->power_on) {
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index aad0777240d3..eca3710d8fc4 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -394,6 +394,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
goto retry_xacterr;
}
stopped = 1;
+ qh->unlink_reason |= QH_UNLINK_HALTED;
/* magic dummy for some short reads; qh won't advance.
* that silicon quirk can kick in with this dummy too.
@@ -408,6 +409,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
&& !(qtd->hw_alt_next
& EHCI_LIST_END(ehci))) {
stopped = 1;
+ qh->unlink_reason |= QH_UNLINK_SHORT_READ;
}
/* stop scanning when we reach qtds the hc is using */
@@ -420,8 +422,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
stopped = 1;
/* cancel everything if we halt, suspend, etc */
- if (ehci->rh_state < EHCI_RH_RUNNING)
+ if (ehci->rh_state < EHCI_RH_RUNNING) {
last_status = -ESHUTDOWN;
+ qh->unlink_reason |= QH_UNLINK_SHUTDOWN;
+ }
/* this qtd is active; skip it unless a previous qtd
* for its urb faulted, or its urb was canceled.
@@ -538,10 +542,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* except maybe high bandwidth ...
*/
if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci))
- qh->exception = 1;
+ qh->unlink_reason |= QH_UNLINK_DUMMY_OVERLAY;
/* Let the caller know if the QH needs to be unlinked. */
- return qh->exception;
+ return qh->unlink_reason;
}
/*-------------------------------------------------------------------------*/
@@ -1003,7 +1007,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->qh_state = QH_STATE_LINKED;
qh->xacterrs = 0;
- qh->exception = 0;
+ qh->unlink_reason = 0;
/* qtd completions reported later by interrupt */
enable_async(ehci);
@@ -1279,17 +1283,13 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
static void start_iaa_cycle(struct ehci_hcd *ehci)
{
- /* Do nothing if an IAA cycle is already running */
- if (ehci->iaa_in_progress)
- return;
- ehci->iaa_in_progress = true;
-
/* If the controller isn't running, we don't have to wait for it */
if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
end_unlink_async(ehci);
- /* Otherwise start a new IAA cycle */
- } else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) {
+ /* Otherwise start a new IAA cycle if one isn't already running */
+ } else if (ehci->rh_state == EHCI_RH_RUNNING &&
+ !ehci->iaa_in_progress) {
/* Make sure the unlinks are all visible to the hardware */
wmb();
@@ -1297,17 +1297,13 @@ static void start_iaa_cycle(struct ehci_hcd *ehci)
ehci_writel(ehci, ehci->command | CMD_IAAD,
&ehci->regs->command);
ehci_readl(ehci, &ehci->regs->command);
+ ehci->iaa_in_progress = true;
ehci_enable_event(ehci, EHCI_HRTIMER_IAA_WATCHDOG, true);
}
}
-/* the async qh for the qtds being unlinked are now gone from the HC */
-
-static void end_unlink_async(struct ehci_hcd *ehci)
+static void end_iaa_cycle(struct ehci_hcd *ehci)
{
- struct ehci_qh *qh;
- bool early_exit;
-
if (ehci->has_synopsys_hc_bug)
ehci_writel(ehci, (u32) ehci->async->qh_dma,
&ehci->regs->async_next);
@@ -1315,6 +1311,16 @@ static void end_unlink_async(struct ehci_hcd *ehci)
/* The current IAA cycle has ended */
ehci->iaa_in_progress = false;
+ end_unlink_async(ehci);
+}
+
+/* See if the async qh for the qtds being unlinked are now gone from the HC */
+
+static void end_unlink_async(struct ehci_hcd *ehci)
+{
+ struct ehci_qh *qh;
+ bool early_exit;
+
if (list_empty(&ehci->async_unlink))
return;
qh = list_first_entry(&ehci->async_unlink, struct ehci_qh,
@@ -1335,14 +1341,60 @@ static void end_unlink_async(struct ehci_hcd *ehci)
* after the IAA interrupt occurs. In self-defense, always go
* through two IAA cycles for each QH.
*/
- else if (qh->qh_state == QH_STATE_UNLINK_WAIT) {
+ else if (qh->qh_state == QH_STATE_UNLINK) {
+ /*
+ * Second IAA cycle has finished. Process only the first
+ * waiting QH (NVIDIA (?) bug).
+ */
+ list_move_tail(&qh->unlink_node, &ehci->async_idle);
+ }
+
+ /*
+ * AMD/ATI (?) bug: The HC can continue to use an active QH long
+ * after the IAA interrupt occurs. To prevent problems, QHs that
+ * may still be active will wait until 2 ms have passed with no
+ * change to the hw_current and hw_token fields (this delay occurs
+ * between the two IAA cycles).
+ *
+ * The EHCI spec (4.8.2) says that active QHs must not be removed
+ * from the async schedule and recommends waiting until the QH
+ * goes inactive. This is ridiculous because the QH will _never_
+ * become inactive if the endpoint NAKs indefinitely.
+ */
+
+ /* Some reasons for unlinking guarantee the QH can't be active */
+ else if (qh->unlink_reason & (QH_UNLINK_HALTED |
+ QH_UNLINK_SHORT_READ | QH_UNLINK_DUMMY_OVERLAY))
+ goto DelayDone;
+
+ /* The QH can't be active if the queue was and still is empty... */
+ else if ((qh->unlink_reason & QH_UNLINK_QUEUE_EMPTY) &&
+ list_empty(&qh->qtd_list))
+ goto DelayDone;
+
+ /* ... or if the QH has halted */
+ else if (qh->hw->hw_token & cpu_to_hc32(ehci, QTD_STS_HALT))
+ goto DelayDone;
+
+ /* Otherwise we have to wait until the QH stops changing */
+ else {
+ __hc32 qh_current, qh_token;
+
+ qh_current = qh->hw->hw_current;
+ qh_token = qh->hw->hw_token;
+ if (qh_current != ehci->old_current ||
+ qh_token != ehci->old_token) {
+ ehci->old_current = qh_current;
+ ehci->old_token = qh_token;
+ ehci_enable_event(ehci,
+ EHCI_HRTIMER_ACTIVE_UNLINK, true);
+ return;
+ }
+ DelayDone:
qh->qh_state = QH_STATE_UNLINK;
early_exit = true;
}
-
- /* Otherwise process only the first waiting QH (NVIDIA bug?) */
- else
- list_move_tail(&qh->unlink_node, &ehci->async_idle);
+ ehci->old_current = ~0; /* Prepare for next QH */
/* Start a new IAA cycle if any QHs are waiting for it */
if (!list_empty(&ehci->async_unlink))
@@ -1395,6 +1447,7 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
/* If nothing else is being unlinked, unlink the last empty QH */
if (list_empty(&ehci->async_unlink) && qh_to_unlink) {
+ qh_to_unlink->unlink_reason |= QH_UNLINK_QUEUE_EMPTY;
start_unlink_async(ehci, qh_to_unlink);
--count;
}
@@ -1406,8 +1459,10 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
}
}
+#ifdef CONFIG_PM
+
/* The root hub is suspended; unlink all the async QHs */
-static void __maybe_unused unlink_empty_async_suspended(struct ehci_hcd *ehci)
+static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
@@ -1416,9 +1471,10 @@ static void __maybe_unused unlink_empty_async_suspended(struct ehci_hcd *ehci)
WARN_ON(!list_empty(&qh->qtd_list));
single_unlink_async(ehci, qh);
}
- start_iaa_cycle(ehci);
}
+#endif
+
/* makes sure the async qh will become idle */
/* caller must own ehci->lock */
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index f9a332775c47..1dfe54f14737 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -34,7 +34,7 @@
* pre-calculated schedule data to make appending to the queue be quick.
*/
-static int ehci_get_frame (struct usb_hcd *hcd);
+static int ehci_get_frame(struct usb_hcd *hcd);
/*
* periodic_next_shadow - return "next" pointer on shadow list
@@ -52,7 +52,7 @@ periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic,
return &periodic->fstn->fstn_next;
case Q_TYPE_ITD:
return &periodic->itd->itd_next;
- // case Q_TYPE_SITD:
+ /* case Q_TYPE_SITD: */
default:
return &periodic->sitd->sitd_next;
}
@@ -73,7 +73,7 @@ shadow_next_periodic(struct ehci_hcd *ehci, union ehci_shadow *periodic,
}
/* caller must hold ehci->lock */
-static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
+static void periodic_unlink(struct ehci_hcd *ehci, unsigned frame, void *ptr)
{
union ehci_shadow *prev_p = &ehci->pshadow[frame];
__hc32 *hw_p = &ehci->periodic[frame];
@@ -296,10 +296,9 @@ static void compute_tt_budget(u8 budget_table[EHCI_BANDWIDTH_SIZE],
if (x <= 125) {
budget_line[uf] = x;
break;
- } else {
- budget_line[uf] = 125;
- x -= 125;
}
+ budget_line[uf] = 125;
+ x -= 125;
}
}
}
@@ -330,7 +329,8 @@ static int __maybe_unused same_tt(struct usb_device *dev1,
*/
static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask)
{
- unsigned char smask = QH_SMASK & hc32_to_cpu(ehci, mask);
+ unsigned char smask = hc32_to_cpu(ehci, mask) & QH_SMASK;
+
if (!smask) {
ehci_err(ehci, "invalid empty smask!\n");
/* uframe 7 can't have bw so this will indicate failure */
@@ -346,7 +346,8 @@ max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 };
static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8])
{
int i;
- for (i=0; i<7; i++) {
+
+ for (i = 0; i < 7; i++) {
if (max_tt_usecs[i] < tt_usecs[i]) {
tt_usecs[i+1] += tt_usecs[i] - max_tt_usecs[i];
tt_usecs[i] = max_tt_usecs[i];
@@ -375,7 +376,7 @@ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8])
* limit of 16, specified in USB 2.0 spec section 11.18.4 requirement #4,
* since proper scheduling limits ssplits to less than 16 per uframe.
*/
-static int tt_available (
+static int tt_available(
struct ehci_hcd *ehci,
struct ehci_per_sched *ps,
struct ehci_tt *tt,
@@ -409,11 +410,11 @@ static int tt_available (
* must be empty, so as to not illegally delay
* already scheduled transactions
*/
- if (125 < usecs) {
+ if (usecs > 125) {
int ufs = (usecs / 125);
for (i = uframe; i < (uframe + ufs) && i < 8; i++)
- if (0 < tt_usecs[i])
+ if (tt_usecs[i] > 0)
return 0;
}
@@ -435,7 +436,7 @@ static int tt_available (
* for a periodic transfer starting at the specified frame, using
* all the uframes in the mask.
*/
-static int tt_no_collision (
+static int tt_no_collision(
struct ehci_hcd *ehci,
unsigned period,
struct usb_device *dev,
@@ -455,8 +456,8 @@ static int tt_no_collision (
__hc32 type;
struct ehci_qh_hw *hw;
- here = ehci->pshadow [frame];
- type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]);
+ here = ehci->pshadow[frame];
+ type = Q_NEXT_TYPE(ehci, ehci->periodic[frame]);
while (here.ptr) {
switch (hc32_to_cpu(ehci, type)) {
case Q_TYPE_ITD:
@@ -479,7 +480,7 @@ static int tt_no_collision (
here = here.qh->qh_next;
continue;
case Q_TYPE_SITD:
- if (same_tt (dev, here.sitd->urb->dev)) {
+ if (same_tt(dev, here.sitd->urb->dev)) {
u16 mask;
mask = hc32_to_cpu(ehci, here.sitd
@@ -492,9 +493,9 @@ static int tt_no_collision (
type = Q_NEXT_TYPE(ehci, here.sitd->hw_next);
here = here.sitd->sitd_next;
continue;
- // case Q_TYPE_FSTN:
+ /* case Q_TYPE_FSTN: */
default:
- ehci_dbg (ehci,
+ ehci_dbg(ehci,
"periodic frame %d bogus type %d\n",
frame, type);
}
@@ -588,14 +589,14 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->qh_next = here;
if (here.qh)
qh->hw->hw_next = *hw_p;
- wmb ();
+ wmb();
prev->qh = qh;
- *hw_p = QH_NEXT (ehci, qh->qh_dma);
+ *hw_p = QH_NEXT(ehci, qh->qh_dma);
}
}
qh->qh_state = QH_STATE_LINKED;
qh->xacterrs = 0;
- qh->exception = 0;
+ qh->unlink_reason = 0;
/* update per-qh bandwidth for debugfs */
ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->ps.bw_period
@@ -633,7 +634,7 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
period = qh->ps.period ? : 1;
for (i = qh->ps.phase; i < ehci->periodic_size; i += period)
- periodic_unlink (ehci, i, qh);
+ periodic_unlink(ehci, i, qh);
/* update per-qh bandwidth for debugfs */
ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->ps.bw_period
@@ -679,7 +680,7 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
/* if the qh is waiting for unlink, cancel it now */
cancel_unlink_wait_intr(ehci, qh);
- qh_unlink_periodic (ehci, qh);
+ qh_unlink_periodic(ehci, qh);
/* Make sure the unlinks are visible before starting the timer */
wmb();
@@ -763,7 +764,7 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
-static int check_period (
+static int check_period(
struct ehci_hcd *ehci,
unsigned frame,
unsigned uframe,
@@ -785,11 +786,11 @@ static int check_period (
return 0;
}
- // success!
+ /* success! */
return 1;
}
-static int check_intr_schedule (
+static int check_intr_schedule(
struct ehci_hcd *ehci,
unsigned frame,
unsigned uframe,
@@ -925,7 +926,7 @@ done:
return status;
}
-static int intr_submit (
+static int intr_submit(
struct ehci_hcd *ehci,
struct urb *urb,
struct list_head *qtd_list,
@@ -940,7 +941,7 @@ static int intr_submit (
/* get endpoint and transfer/schedule data */
epnum = urb->ep->desc.bEndpointAddress;
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
status = -ESHUTDOWN;
@@ -951,20 +952,21 @@ static int intr_submit (
goto done_not_linked;
/* get qh and force any scheduling errors */
- INIT_LIST_HEAD (&empty);
+ INIT_LIST_HEAD(&empty);
qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
if (qh == NULL) {
status = -ENOMEM;
goto done;
}
if (qh->qh_state == QH_STATE_IDLE) {
- if ((status = qh_schedule (ehci, qh)) != 0)
+ status = qh_schedule(ehci, qh);
+ if (status)
goto done;
}
/* then queue the urb's tds to the qh */
qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
- BUG_ON (qh == NULL);
+ BUG_ON(qh == NULL);
/* stuff into the periodic schedule */
if (qh->qh_state == QH_STATE_IDLE) {
@@ -982,9 +984,9 @@ done:
if (unlikely(status))
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
done_not_linked:
- spin_unlock_irqrestore (&ehci->lock, flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
if (status)
- qtd_list_free (ehci, urb, qtd_list);
+ qtd_list_free(ehci, urb, qtd_list);
return status;
}
@@ -1022,12 +1024,12 @@ static void scan_intr(struct ehci_hcd *ehci)
/* ehci_iso_stream ops work with both ITD and SITD */
static struct ehci_iso_stream *
-iso_stream_alloc (gfp_t mem_flags)
+iso_stream_alloc(gfp_t mem_flags)
{
struct ehci_iso_stream *stream;
- stream = kzalloc(sizeof *stream, mem_flags);
- if (likely (stream != NULL)) {
+ stream = kzalloc(sizeof(*stream), mem_flags);
+ if (likely(stream != NULL)) {
INIT_LIST_HEAD(&stream->td_list);
INIT_LIST_HEAD(&stream->free_list);
stream->next_uframe = NO_FRAME;
@@ -1037,13 +1039,13 @@ iso_stream_alloc (gfp_t mem_flags)
}
static void
-iso_stream_init (
+iso_stream_init(
struct ehci_hcd *ehci,
struct ehci_iso_stream *stream,
struct urb *urb
)
{
- static const u8 smask_out [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
+ static const u8 smask_out[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
struct usb_device *dev = urb->dev;
u32 buf1;
@@ -1058,11 +1060,7 @@ iso_stream_init (
epnum = usb_pipeendpoint(urb->pipe);
is_input = usb_pipein(urb->pipe) ? USB_DIR_IN : 0;
maxp = usb_endpoint_maxp(&urb->ep->desc);
- if (is_input) {
- buf1 = (1 << 11);
- } else {
- buf1 = 0;
- }
+ buf1 = is_input ? 1 << 11 : 0;
/* knows about ITD vs SITD */
if (dev->speed == USB_SPEED_HIGH) {
@@ -1111,7 +1109,7 @@ iso_stream_init (
think_time = dev->tt ? dev->tt->think_time : 0;
stream->ps.tt_usecs = NS_TO_US(think_time + usb_calc_bus_time(
dev->speed, is_input, 1, maxp));
- hs_transfers = max (1u, (maxp + 187) / 188);
+ hs_transfers = max(1u, (maxp + 187) / 188);
if (is_input) {
u32 tmp;
@@ -1151,7 +1149,7 @@ iso_stream_init (
}
static struct ehci_iso_stream *
-iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
+iso_stream_find(struct ehci_hcd *ehci, struct urb *urb)
{
unsigned epnum;
struct ehci_iso_stream *stream;
@@ -1164,25 +1162,25 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
else
ep = urb->dev->ep_out[epnum];
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
stream = ep->hcpriv;
- if (unlikely (stream == NULL)) {
+ if (unlikely(stream == NULL)) {
stream = iso_stream_alloc(GFP_ATOMIC);
- if (likely (stream != NULL)) {
+ if (likely(stream != NULL)) {
ep->hcpriv = stream;
iso_stream_init(ehci, stream, urb);
}
/* if dev->ep [epnum] is a QH, hw is set */
- } else if (unlikely (stream->hw != NULL)) {
- ehci_dbg (ehci, "dev %s ep%d%s, not iso??\n",
+ } else if (unlikely(stream->hw != NULL)) {
+ ehci_dbg(ehci, "dev %s ep%d%s, not iso??\n",
urb->dev->devpath, epnum,
usb_pipein(urb->pipe) ? "in" : "out");
stream = NULL;
}
- spin_unlock_irqrestore (&ehci->lock, flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
return stream;
}
@@ -1191,16 +1189,16 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
/* ehci_iso_sched ops can be ITD-only or SITD-only */
static struct ehci_iso_sched *
-iso_sched_alloc (unsigned packets, gfp_t mem_flags)
+iso_sched_alloc(unsigned packets, gfp_t mem_flags)
{
struct ehci_iso_sched *iso_sched;
- int size = sizeof *iso_sched;
+ int size = sizeof(*iso_sched);
- size += packets * sizeof (struct ehci_iso_packet);
+ size += packets * sizeof(struct ehci_iso_packet);
iso_sched = kzalloc(size, mem_flags);
- if (likely (iso_sched != NULL)) {
- INIT_LIST_HEAD (&iso_sched->td_list);
- }
+ if (likely(iso_sched != NULL))
+ INIT_LIST_HEAD(&iso_sched->td_list);
+
return iso_sched;
}
@@ -1222,17 +1220,17 @@ itd_sched_init(
* when we fit new itds into the schedule.
*/
for (i = 0; i < urb->number_of_packets; i++) {
- struct ehci_iso_packet *uframe = &iso_sched->packet [i];
+ struct ehci_iso_packet *uframe = &iso_sched->packet[i];
unsigned length;
dma_addr_t buf;
u32 trans;
- length = urb->iso_frame_desc [i].length;
- buf = dma + urb->iso_frame_desc [i].offset;
+ length = urb->iso_frame_desc[i].length;
+ buf = dma + urb->iso_frame_desc[i].offset;
trans = EHCI_ISOC_ACTIVE;
trans |= buf & 0x0fff;
- if (unlikely (((i + 1) == urb->number_of_packets))
+ if (unlikely(((i + 1) == urb->number_of_packets))
&& !(urb->transfer_flags & URB_NO_INTERRUPT))
trans |= EHCI_ITD_IOC;
trans |= length << 16;
@@ -1241,26 +1239,26 @@ itd_sched_init(
/* might need to cross a buffer page within a uframe */
uframe->bufp = (buf & ~(u64)0x0fff);
buf += length;
- if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
+ if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff))))
uframe->cross = 1;
}
}
static void
-iso_sched_free (
+iso_sched_free(
struct ehci_iso_stream *stream,
struct ehci_iso_sched *iso_sched
)
{
if (!iso_sched)
return;
- // caller must hold ehci->lock!
- list_splice (&iso_sched->td_list, &stream->free_list);
- kfree (iso_sched);
+ /* caller must hold ehci->lock! */
+ list_splice(&iso_sched->td_list, &stream->free_list);
+ kfree(iso_sched);
}
static int
-itd_urb_transaction (
+itd_urb_transaction(
struct ehci_iso_stream *stream,
struct ehci_hcd *ehci,
struct urb *urb,
@@ -1274,8 +1272,8 @@ itd_urb_transaction (
struct ehci_iso_sched *sched;
unsigned long flags;
- sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
- if (unlikely (sched == NULL))
+ sched = iso_sched_alloc(urb->number_of_packets, mem_flags);
+ if (unlikely(sched == NULL))
return -ENOMEM;
itd_sched_init(ehci, sched, stream, urb);
@@ -1286,7 +1284,7 @@ itd_urb_transaction (
num_itds = urb->number_of_packets;
/* allocate/init ITDs */
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
for (i = 0; i < num_itds; i++) {
/*
@@ -1298,14 +1296,14 @@ itd_urb_transaction (
struct ehci_itd, itd_list);
if (itd->frame == ehci->now_frame)
goto alloc_itd;
- list_del (&itd->itd_list);
+ list_del(&itd->itd_list);
itd_dma = itd->itd_dma;
} else {
alloc_itd:
- spin_unlock_irqrestore (&ehci->lock, flags);
- itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ itd = dma_pool_alloc(ehci->itd_pool, mem_flags,
&itd_dma);
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
if (!itd) {
iso_sched_free(stream, sched);
spin_unlock_irqrestore(&ehci->lock, flags);
@@ -1313,12 +1311,12 @@ itd_urb_transaction (
}
}
- memset (itd, 0, sizeof *itd);
+ memset(itd, 0, sizeof(*itd));
itd->itd_dma = itd_dma;
itd->frame = NO_FRAME;
- list_add (&itd->itd_list, &sched->td_list);
+ list_add(&itd->itd_list, &sched->td_list);
}
- spin_unlock_irqrestore (&ehci->lock, flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
/* temporarily store schedule info in hcpriv */
urb->hcpriv = sched;
@@ -1385,7 +1383,7 @@ static void reserve_release_iso_bandwidth(struct ehci_hcd *ehci,
}
static inline int
-itd_slot_ok (
+itd_slot_ok(
struct ehci_hcd *ehci,
struct ehci_iso_stream *stream,
unsigned uframe
@@ -1405,7 +1403,7 @@ itd_slot_ok (
}
static inline int
-sitd_slot_ok (
+sitd_slot_ok(
struct ehci_hcd *ehci,
struct ehci_iso_stream *stream,
unsigned uframe,
@@ -1492,7 +1490,7 @@ sitd_slot_ok (
*/
static int
-iso_stream_schedule (
+iso_stream_schedule(
struct ehci_hcd *ehci,
struct urb *urb,
struct ehci_iso_stream *stream
@@ -1693,9 +1691,9 @@ itd_init(struct ehci_hcd *ehci, struct ehci_iso_stream *stream,
/* it's been recently zeroed */
itd->hw_next = EHCI_LIST_END(ehci);
- itd->hw_bufp [0] = stream->buf0;
- itd->hw_bufp [1] = stream->buf1;
- itd->hw_bufp [2] = stream->buf2;
+ itd->hw_bufp[0] = stream->buf0;
+ itd->hw_bufp[1] = stream->buf1;
+ itd->hw_bufp[2] = stream->buf2;
for (i = 0; i < 8; i++)
itd->index[i] = -1;
@@ -1712,13 +1710,13 @@ itd_patch(
u16 uframe
)
{
- struct ehci_iso_packet *uf = &iso_sched->packet [index];
+ struct ehci_iso_packet *uf = &iso_sched->packet[index];
unsigned pg = itd->pg;
- // BUG_ON (pg == 6 && uf->cross);
+ /* BUG_ON(pg == 6 && uf->cross); */
uframe &= 0x07;
- itd->index [uframe] = index;
+ itd->index[uframe] = index;
itd->hw_transaction[uframe] = uf->transaction;
itd->hw_transaction[uframe] |= cpu_to_hc32(ehci, pg << 12);
@@ -1726,7 +1724,7 @@ itd_patch(
itd->hw_bufp_hi[pg] |= cpu_to_hc32(ehci, (u32)(uf->bufp >> 32));
/* iso_frame_desc[].offset must be strictly increasing */
- if (unlikely (uf->cross)) {
+ if (unlikely(uf->cross)) {
u64 bufp = uf->bufp + 4096;
itd->pg = ++pg;
@@ -1736,7 +1734,7 @@ itd_patch(
}
static inline void
-itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
+itd_link(struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
{
union ehci_shadow *prev = &ehci->pshadow[frame];
__hc32 *hw_p = &ehci->periodic[frame];
@@ -1757,7 +1755,7 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
itd->hw_next = *hw_p;
prev->itd = itd;
itd->frame = frame;
- wmb ();
+ wmb();
*hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
}
@@ -1776,7 +1774,7 @@ static void itd_link_urb(
next_uframe = stream->next_uframe & (mod - 1);
- if (unlikely (list_empty(&stream->td_list)))
+ if (unlikely(list_empty(&stream->td_list)))
ehci_to_hcd(ehci)->self.bandwidth_allocated
+= stream->bandwidth;
@@ -1792,16 +1790,16 @@ static void itd_link_urb(
packet < urb->number_of_packets;) {
if (itd == NULL) {
/* ASSERT: we have all necessary itds */
- // BUG_ON (list_empty (&iso_sched->td_list));
+ /* BUG_ON(list_empty(&iso_sched->td_list)); */
/* ASSERT: no itds for this endpoint in this uframe */
- itd = list_entry (iso_sched->td_list.next,
+ itd = list_entry(iso_sched->td_list.next,
struct ehci_itd, itd_list);
- list_move_tail (&itd->itd_list, &stream->td_list);
+ list_move_tail(&itd->itd_list, &stream->td_list);
itd->stream = stream;
itd->urb = urb;
- itd_init (ehci, stream, itd);
+ itd_init(ehci, stream, itd);
}
uframe = next_uframe & 0x07;
@@ -1823,7 +1821,7 @@ static void itd_link_urb(
stream->next_uframe = next_uframe;
/* don't need that schedule data any more */
- iso_sched_free (stream, iso_sched);
+ iso_sched_free(stream, iso_sched);
urb->hcpriv = stream;
++ehci->isoc_count;
@@ -1855,19 +1853,19 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
/* for each uframe with a packet */
for (uframe = 0; uframe < 8; uframe++) {
- if (likely (itd->index[uframe] == -1))
+ if (likely(itd->index[uframe] == -1))
continue;
urb_index = itd->index[uframe];
- desc = &urb->iso_frame_desc [urb_index];
+ desc = &urb->iso_frame_desc[urb_index];
- t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]);
- itd->hw_transaction [uframe] = 0;
+ t = hc32_to_cpup(ehci, &itd->hw_transaction[uframe]);
+ itd->hw_transaction[uframe] = 0;
/* report transfer status */
- if (unlikely (t & ISO_ERRS)) {
+ if (unlikely(t & ISO_ERRS)) {
urb->error_count++;
if (t & EHCI_ISOC_BUF_ERR)
- desc->status = usb_pipein (urb->pipe)
+ desc->status = usb_pipein(urb->pipe)
? -ENOSR /* hc couldn't read */
: -ECOMM; /* hc couldn't write */
else if (t & EHCI_ISOC_BABBLE)
@@ -1880,7 +1878,7 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
desc->actual_length = EHCI_ITD_LENGTH(t);
urb->actual_length += desc->actual_length;
}
- } else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) {
+ } else if (likely((t & EHCI_ISOC_ACTIVE) == 0)) {
desc->status = 0;
desc->actual_length = EHCI_ITD_LENGTH(t);
urb->actual_length += desc->actual_length;
@@ -1891,12 +1889,13 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
}
/* handle completion now? */
- if (likely ((urb_index + 1) != urb->number_of_packets))
+ if (likely((urb_index + 1) != urb->number_of_packets))
goto done;
- /* ASSERT: it's really the last itd for this urb
- list_for_each_entry (itd, &stream->td_list, itd_list)
- BUG_ON (itd->urb == urb);
+ /*
+ * ASSERT: it's really the last itd for this urb
+ * list_for_each_entry (itd, &stream->td_list, itd_list)
+ * BUG_ON(itd->urb == urb);
*/
/* give urb back to the driver; completion often (re)submits */
@@ -1936,7 +1935,7 @@ done:
/*-------------------------------------------------------------------------*/
-static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
+static int itd_submit(struct ehci_hcd *ehci, struct urb *urb,
gfp_t mem_flags)
{
int status = -EINVAL;
@@ -1944,37 +1943,37 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
struct ehci_iso_stream *stream;
/* Get iso_stream head */
- stream = iso_stream_find (ehci, urb);
- if (unlikely (stream == NULL)) {
- ehci_dbg (ehci, "can't get iso stream\n");
+ stream = iso_stream_find(ehci, urb);
+ if (unlikely(stream == NULL)) {
+ ehci_dbg(ehci, "can't get iso stream\n");
return -ENOMEM;
}
if (unlikely(urb->interval != stream->uperiod)) {
- ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
+ ehci_dbg(ehci, "can't change iso interval %d --> %d\n",
stream->uperiod, urb->interval);
goto done;
}
#ifdef EHCI_URB_TRACE
- ehci_dbg (ehci,
+ ehci_dbg(ehci,
"%s %s urb %p ep%d%s len %d, %d pkts %d uframes [%p]\n",
__func__, urb->dev->devpath, urb,
- usb_pipeendpoint (urb->pipe),
- usb_pipein (urb->pipe) ? "in" : "out",
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
urb->transfer_buffer_length,
urb->number_of_packets, urb->interval,
stream);
#endif
/* allocate ITDs w/o locking anything */
- status = itd_urb_transaction (stream, ehci, urb, mem_flags);
- if (unlikely (status < 0)) {
- ehci_dbg (ehci, "can't init itds\n");
+ status = itd_urb_transaction(stream, ehci, urb, mem_flags);
+ if (unlikely(status < 0)) {
+ ehci_dbg(ehci, "can't init itds\n");
goto done;
}
/* schedule ... need to lock */
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
status = -ESHUTDOWN;
goto done_not_linked;
@@ -1984,7 +1983,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
goto done_not_linked;
status = iso_stream_schedule(ehci, urb, stream);
if (likely(status == 0)) {
- itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ itd_link_urb(ehci, urb, ehci->periodic_size << 3, stream);
} else if (status > 0) {
status = 0;
ehci_urb_done(ehci, urb, 0);
@@ -1992,7 +1991,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
}
done_not_linked:
- spin_unlock_irqrestore (&ehci->lock, flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
done:
return status;
}
@@ -2022,13 +2021,13 @@ sitd_sched_init(
* when we fit new sitds into the schedule.
*/
for (i = 0; i < urb->number_of_packets; i++) {
- struct ehci_iso_packet *packet = &iso_sched->packet [i];
+ struct ehci_iso_packet *packet = &iso_sched->packet[i];
unsigned length;
dma_addr_t buf;
u32 trans;
- length = urb->iso_frame_desc [i].length & 0x03ff;
- buf = dma + urb->iso_frame_desc [i].offset;
+ length = urb->iso_frame_desc[i].length & 0x03ff;
+ buf = dma + urb->iso_frame_desc[i].offset;
trans = SITD_STS_ACTIVE;
if (((i + 1) == urb->number_of_packets)
@@ -2054,7 +2053,7 @@ sitd_sched_init(
}
static int
-sitd_urb_transaction (
+sitd_urb_transaction(
struct ehci_iso_stream *stream,
struct ehci_hcd *ehci,
struct urb *urb,
@@ -2067,14 +2066,14 @@ sitd_urb_transaction (
struct ehci_iso_sched *iso_sched;
unsigned long flags;
- iso_sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
+ iso_sched = iso_sched_alloc(urb->number_of_packets, mem_flags);
if (iso_sched == NULL)
return -ENOMEM;
sitd_sched_init(ehci, iso_sched, stream, urb);
/* allocate/init sITDs */
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
for (i = 0; i < urb->number_of_packets; i++) {
/* NOTE: for now, we don't try to handle wraparound cases
@@ -2091,14 +2090,14 @@ sitd_urb_transaction (
struct ehci_sitd, sitd_list);
if (sitd->frame == ehci->now_frame)
goto alloc_sitd;
- list_del (&sitd->sitd_list);
+ list_del(&sitd->sitd_list);
sitd_dma = sitd->sitd_dma;
} else {
alloc_sitd:
- spin_unlock_irqrestore (&ehci->lock, flags);
- sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags,
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ sitd = dma_pool_alloc(ehci->sitd_pool, mem_flags,
&sitd_dma);
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
if (!sitd) {
iso_sched_free(stream, iso_sched);
spin_unlock_irqrestore(&ehci->lock, flags);
@@ -2106,17 +2105,17 @@ sitd_urb_transaction (
}
}
- memset (sitd, 0, sizeof *sitd);
+ memset(sitd, 0, sizeof(*sitd));
sitd->sitd_dma = sitd_dma;
sitd->frame = NO_FRAME;
- list_add (&sitd->sitd_list, &iso_sched->td_list);
+ list_add(&sitd->sitd_list, &iso_sched->td_list);
}
/* temporarily store schedule info in hcpriv */
urb->hcpriv = iso_sched;
urb->error_count = 0;
- spin_unlock_irqrestore (&ehci->lock, flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
return 0;
}
@@ -2131,8 +2130,8 @@ sitd_patch(
unsigned index
)
{
- struct ehci_iso_packet *uf = &iso_sched->packet [index];
- u64 bufp = uf->bufp;
+ struct ehci_iso_packet *uf = &iso_sched->packet[index];
+ u64 bufp;
sitd->hw_next = EHCI_LIST_END(ehci);
sitd->hw_fullspeed_ep = stream->address;
@@ -2152,14 +2151,14 @@ sitd_patch(
}
static inline void
-sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
+sitd_link(struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
{
/* note: sitd ordering could matter (CSPLIT then SSPLIT) */
- sitd->sitd_next = ehci->pshadow [frame];
- sitd->hw_next = ehci->periodic [frame];
- ehci->pshadow [frame].sitd = sitd;
+ sitd->sitd_next = ehci->pshadow[frame];
+ sitd->hw_next = ehci->periodic[frame];
+ ehci->pshadow[frame].sitd = sitd;
sitd->frame = frame;
- wmb ();
+ wmb();
ehci->periodic[frame] = cpu_to_hc32(ehci, sitd->sitd_dma | Q_TYPE_SITD);
}
@@ -2196,13 +2195,13 @@ static void sitd_link_urb(
packet++) {
/* ASSERT: we have all necessary sitds */
- BUG_ON (list_empty (&sched->td_list));
+ BUG_ON(list_empty(&sched->td_list));
/* ASSERT: no itds for this endpoint in this frame */
- sitd = list_entry (sched->td_list.next,
+ sitd = list_entry(sched->td_list.next,
struct ehci_sitd, sitd_list);
- list_move_tail (&sitd->sitd_list, &stream->td_list);
+ list_move_tail(&sitd->sitd_list, &stream->td_list);
sitd->stream = stream;
sitd->urb = urb;
@@ -2215,7 +2214,7 @@ static void sitd_link_urb(
stream->next_uframe = next_uframe & (mod - 1);
/* don't need that schedule data any more */
- iso_sched_free (stream, sched);
+ iso_sched_free(stream, sched);
urb->hcpriv = stream;
++ehci->isoc_count;
@@ -2242,20 +2241,20 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
struct urb *urb = sitd->urb;
struct usb_iso_packet_descriptor *desc;
u32 t;
- int urb_index = -1;
+ int urb_index;
struct ehci_iso_stream *stream = sitd->stream;
struct usb_device *dev;
bool retval = false;
urb_index = sitd->index;
- desc = &urb->iso_frame_desc [urb_index];
+ desc = &urb->iso_frame_desc[urb_index];
t = hc32_to_cpup(ehci, &sitd->hw_results);
/* report transfer status */
if (unlikely(t & SITD_ERRS)) {
urb->error_count++;
if (t & SITD_STS_DBE)
- desc->status = usb_pipein (urb->pipe)
+ desc->status = usb_pipein(urb->pipe)
? -ENOSR /* hc couldn't read */
: -ECOMM; /* hc couldn't write */
else if (t & SITD_STS_BABBLE)
@@ -2275,9 +2274,10 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
if ((urb_index + 1) != urb->number_of_packets)
goto done;
- /* ASSERT: it's really the last sitd for this urb
- list_for_each_entry (sitd, &stream->td_list, sitd_list)
- BUG_ON (sitd->urb == urb);
+ /*
+ * ASSERT: it's really the last sitd for this urb
+ * list_for_each_entry (sitd, &stream->td_list, sitd_list)
+ * BUG_ON(sitd->urb == urb);
*/
/* give urb back to the driver; completion often (re)submits */
@@ -2316,7 +2316,7 @@ done:
}
-static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
+static int sitd_submit(struct ehci_hcd *ehci, struct urb *urb,
gfp_t mem_flags)
{
int status = -EINVAL;
@@ -2324,35 +2324,35 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
struct ehci_iso_stream *stream;
/* Get iso_stream head */
- stream = iso_stream_find (ehci, urb);
+ stream = iso_stream_find(ehci, urb);
if (stream == NULL) {
- ehci_dbg (ehci, "can't get iso stream\n");
+ ehci_dbg(ehci, "can't get iso stream\n");
return -ENOMEM;
}
if (urb->interval != stream->ps.period) {
- ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
+ ehci_dbg(ehci, "can't change iso interval %d --> %d\n",
stream->ps.period, urb->interval);
goto done;
}
#ifdef EHCI_URB_TRACE
- ehci_dbg (ehci,
+ ehci_dbg(ehci,
"submit %p dev%s ep%d%s-iso len %d\n",
urb, urb->dev->devpath,
- usb_pipeendpoint (urb->pipe),
- usb_pipein (urb->pipe) ? "in" : "out",
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
urb->transfer_buffer_length);
#endif
/* allocate SITDs */
- status = sitd_urb_transaction (stream, ehci, urb, mem_flags);
+ status = sitd_urb_transaction(stream, ehci, urb, mem_flags);
if (status < 0) {
- ehci_dbg (ehci, "can't init sitds\n");
+ ehci_dbg(ehci, "can't init sitds\n");
goto done;
}
/* schedule ... need to lock */
- spin_lock_irqsave (&ehci->lock, flags);
+ spin_lock_irqsave(&ehci->lock, flags);
if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
status = -ESHUTDOWN;
goto done_not_linked;
@@ -2362,7 +2362,7 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
goto done_not_linked;
status = iso_stream_schedule(ehci, urb, stream);
if (likely(status == 0)) {
- sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ sitd_link_urb(ehci, urb, ehci->periodic_size << 3, stream);
} else if (status > 0) {
status = 0;
ehci_urb_done(ehci, urb, 0);
@@ -2370,7 +2370,7 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
}
done_not_linked:
- spin_unlock_irqrestore (&ehci->lock, flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
done:
return status;
}
@@ -2379,9 +2379,11 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
static void scan_isoc(struct ehci_hcd *ehci)
{
- unsigned uf, now_frame, frame;
- unsigned fmask = ehci->periodic_size - 1;
- bool modified, live;
+ unsigned uf, now_frame, frame;
+ unsigned fmask = ehci->periodic_size - 1;
+ bool modified, live;
+ union ehci_shadow q, *q_p;
+ __hc32 type, *hw_p;
/*
* When running, scan from last scan point up to "now"
@@ -2399,119 +2401,117 @@ static void scan_isoc(struct ehci_hcd *ehci)
ehci->now_frame = now_frame;
frame = ehci->last_iso_frame;
- for (;;) {
- union ehci_shadow q, *q_p;
- __hc32 type, *hw_p;
restart:
- /* scan each element in frame's queue for completions */
- q_p = &ehci->pshadow [frame];
- hw_p = &ehci->periodic [frame];
- q.ptr = q_p->ptr;
- type = Q_NEXT_TYPE(ehci, *hw_p);
- modified = false;
-
- while (q.ptr != NULL) {
- switch (hc32_to_cpu(ehci, type)) {
- case Q_TYPE_ITD:
- /* If this ITD is still active, leave it for
- * later processing ... check the next entry.
- * No need to check for activity unless the
- * frame is current.
- */
- if (frame == now_frame && live) {
- rmb();
- for (uf = 0; uf < 8; uf++) {
- if (q.itd->hw_transaction[uf] &
- ITD_ACTIVE(ehci))
- break;
- }
- if (uf < 8) {
- q_p = &q.itd->itd_next;
- hw_p = &q.itd->hw_next;
- type = Q_NEXT_TYPE(ehci,
- q.itd->hw_next);
- q = *q_p;
+ /* Scan each element in frame's queue for completions */
+ q_p = &ehci->pshadow[frame];
+ hw_p = &ehci->periodic[frame];
+ q.ptr = q_p->ptr;
+ type = Q_NEXT_TYPE(ehci, *hw_p);
+ modified = false;
+
+ while (q.ptr != NULL) {
+ switch (hc32_to_cpu(ehci, type)) {
+ case Q_TYPE_ITD:
+ /*
+ * If this ITD is still active, leave it for
+ * later processing ... check the next entry.
+ * No need to check for activity unless the
+ * frame is current.
+ */
+ if (frame == now_frame && live) {
+ rmb();
+ for (uf = 0; uf < 8; uf++) {
+ if (q.itd->hw_transaction[uf] &
+ ITD_ACTIVE(ehci))
break;
- }
}
-
- /* Take finished ITDs out of the schedule
- * and process them: recycle, maybe report
- * URB completion. HC won't cache the
- * pointer for much longer, if at all.
- */
- *q_p = q.itd->itd_next;
- if (!ehci->use_dummy_qh ||
- q.itd->hw_next != EHCI_LIST_END(ehci))
- *hw_p = q.itd->hw_next;
- else
- *hw_p = cpu_to_hc32(ehci,
- ehci->dummy->qh_dma);
- type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
- wmb();
- modified = itd_complete (ehci, q.itd);
- q = *q_p;
- break;
- case Q_TYPE_SITD:
- /* If this SITD is still active, leave it for
- * later processing ... check the next entry.
- * No need to check for activity unless the
- * frame is current.
- */
- if (((frame == now_frame) ||
- (((frame + 1) & fmask) == now_frame))
- && live
- && (q.sitd->hw_results &
- SITD_ACTIVE(ehci))) {
-
- q_p = &q.sitd->sitd_next;
- hw_p = &q.sitd->hw_next;
+ if (uf < 8) {
+ q_p = &q.itd->itd_next;
+ hw_p = &q.itd->hw_next;
type = Q_NEXT_TYPE(ehci,
- q.sitd->hw_next);
+ q.itd->hw_next);
q = *q_p;
break;
}
+ }
+
+ /*
+ * Take finished ITDs out of the schedule
+ * and process them: recycle, maybe report
+ * URB completion. HC won't cache the
+ * pointer for much longer, if at all.
+ */
+ *q_p = q.itd->itd_next;
+ if (!ehci->use_dummy_qh ||
+ q.itd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.itd->hw_next;
+ else
+ *hw_p = cpu_to_hc32(ehci, ehci->dummy->qh_dma);
+ type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
+ wmb();
+ modified = itd_complete(ehci, q.itd);
+ q = *q_p;
+ break;
+ case Q_TYPE_SITD:
+ /*
+ * If this SITD is still active, leave it for
+ * later processing ... check the next entry.
+ * No need to check for activity unless the
+ * frame is current.
+ */
+ if (((frame == now_frame) ||
+ (((frame + 1) & fmask) == now_frame))
+ && live
+ && (q.sitd->hw_results & SITD_ACTIVE(ehci))) {
- /* Take finished SITDs out of the schedule
- * and process them: recycle, maybe report
- * URB completion.
- */
- *q_p = q.sitd->sitd_next;
- if (!ehci->use_dummy_qh ||
- q.sitd->hw_next != EHCI_LIST_END(ehci))
- *hw_p = q.sitd->hw_next;
- else
- *hw_p = cpu_to_hc32(ehci,
- ehci->dummy->qh_dma);
+ q_p = &q.sitd->sitd_next;
+ hw_p = &q.sitd->hw_next;
type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
- wmb();
- modified = sitd_complete (ehci, q.sitd);
q = *q_p;
break;
- default:
- ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n",
- type, frame, q.ptr);
- // BUG ();
- /* FALL THROUGH */
- case Q_TYPE_QH:
- case Q_TYPE_FSTN:
- /* End of the iTDs and siTDs */
- q.ptr = NULL;
- break;
}
- /* assume completion callbacks modify the queue */
- if (unlikely(modified && ehci->isoc_count > 0))
- goto restart;
- }
-
- /* Stop when we have reached the current frame */
- if (frame == now_frame)
+ /*
+ * Take finished SITDs out of the schedule
+ * and process them: recycle, maybe report
+ * URB completion.
+ */
+ *q_p = q.sitd->sitd_next;
+ if (!ehci->use_dummy_qh ||
+ q.sitd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.sitd->hw_next;
+ else
+ *hw_p = cpu_to_hc32(ehci, ehci->dummy->qh_dma);
+ type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
+ wmb();
+ modified = sitd_complete(ehci, q.sitd);
+ q = *q_p;
+ break;
+ default:
+ ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n",
+ type, frame, q.ptr);
+ /* BUG(); */
+ /* FALL THROUGH */
+ case Q_TYPE_QH:
+ case Q_TYPE_FSTN:
+ /* End of the iTDs and siTDs */
+ q.ptr = NULL;
break;
+ }
- /* The last frame may still have active siTDs */
- ehci->last_iso_frame = frame;
- frame = (frame + 1) & fmask;
+ /* Assume completion callbacks modify the queue */
+ if (unlikely(modified && ehci->isoc_count > 0))
+ goto restart;
}
+
+ /* Stop when we have reached the current frame */
+ if (frame == now_frame)
+ return;
+
+ /* The last frame may still have active siTDs */
+ ehci->last_iso_frame = frame;
+ frame = (frame + 1) & fmask;
+
+ goto restart;
}
diff --git a/drivers/usb/host/ehci-st.c b/drivers/usb/host/ehci-st.c
index b7c5cfa37a83..a94ed677d937 100644
--- a/drivers/usb/host/ehci-st.c
+++ b/drivers/usb/host/ehci-st.c
@@ -287,8 +287,7 @@ static int st_ehci_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
bool do_wakeup = device_may_wakeup(dev);
int ret;
@@ -308,8 +307,7 @@ static int st_ehci_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
int err;
pinctrl_pm_select_default_state(dev);
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index 424ac5d83714..69f50e6533a6 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = {
1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */
1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */
2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */
+ 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ACTIVE_UNLINK */
5 * NSEC_PER_MSEC, /* EHCI_HRTIMER_START_UNLINK_INTR */
6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */
10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */
@@ -237,6 +238,7 @@ static void ehci_handle_start_intr_unlinks(struct ehci_hcd *ehci)
ehci->intr_unlink_wait_cycle))
break;
list_del_init(&qh->unlink_node);
+ qh->unlink_reason |= QH_UNLINK_QUEUE_EMPTY;
start_unlink_intr(ehci, qh);
}
@@ -360,7 +362,7 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
}
ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
- end_unlink_async(ehci);
+ end_iaa_cycle(ehci);
}
@@ -394,6 +396,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = {
ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */
ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */
end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */
+ end_unlink_async, /* EHCI_HRTIMER_ACTIVE_UNLINK */
ehci_handle_start_intr_unlinks, /* EHCI_HRTIMER_START_UNLINK_INTR */
unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */
ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index ec61aedb0067..3f3b74aeca97 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -110,6 +110,7 @@ enum ehci_hrtimer_event {
EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
+ EHCI_HRTIMER_ACTIVE_UNLINK, /* Wait while unlinking an active QH */
EHCI_HRTIMER_START_UNLINK_INTR, /* Unlink empty interrupt QHs */
EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
@@ -156,6 +157,8 @@ struct ehci_hcd { /* one per controller */
struct list_head async_idle;
unsigned async_unlink_cycle;
unsigned async_count; /* async activity count */
+ __hc32 old_current; /* Test for QH becoming */
+ __hc32 old_token; /* inactive during unlink */
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
@@ -185,7 +188,7 @@ struct ehci_hcd { /* one per controller */
struct ehci_sitd *last_sitd_to_free;
/* per root hub port */
- unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
+ unsigned long reset_done[EHCI_MAX_ROOT_PORTS];
/* bit vectors (one bit per port) */
unsigned long bus_suspended; /* which ports were
@@ -244,9 +247,9 @@ struct ehci_hcd { /* one per controller */
/* irq statistics */
#ifdef EHCI_STATS
struct ehci_stats stats;
-# define COUNT(x) do { (x)++; } while (0)
+# define COUNT(x) ((x)++)
#else
-# define COUNT(x) do {} while (0)
+# define COUNT(x)
#endif
/* debug files */
@@ -268,13 +271,13 @@ struct ehci_hcd { /* one per controller */
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
-static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd)
+static inline struct ehci_hcd *hcd_to_ehci(struct usb_hcd *hcd)
{
return (struct ehci_hcd *) (hcd->hcd_priv);
}
-static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
+static inline struct usb_hcd *ehci_to_hcd(struct ehci_hcd *ehci)
{
- return container_of ((void *) ehci, struct usb_hcd, hcd_priv);
+ return container_of((void *) ehci, struct usb_hcd, hcd_priv);
}
/*-------------------------------------------------------------------------*/
@@ -316,25 +319,25 @@ struct ehci_qtd {
#define HALT_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_HALT)
#define STATUS_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_STS)
- __hc32 hw_buf [5]; /* see EHCI 3.5.4 */
- __hc32 hw_buf_hi [5]; /* Appendix B */
+ __hc32 hw_buf[5]; /* see EHCI 3.5.4 */
+ __hc32 hw_buf_hi[5]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t qtd_dma; /* qtd address */
struct list_head qtd_list; /* sw qtd list */
struct urb *urb; /* qtd's urb */
size_t length; /* length of buffer */
-} __attribute__ ((aligned (32)));
+} __aligned(32);
/* mask NakCnt+T in qh->hw_alt_next */
-#define QTD_MASK(ehci) cpu_to_hc32 (ehci, ~0x1f)
+#define QTD_MASK(ehci) cpu_to_hc32(ehci, ~0x1f)
-#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
+#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
/*-------------------------------------------------------------------------*/
/* type tag from {qh,itd,sitd,fstn}->hw_next */
-#define Q_NEXT_TYPE(ehci,dma) ((dma) & cpu_to_hc32(ehci, 3 << 1))
+#define Q_NEXT_TYPE(ehci, dma) ((dma) & cpu_to_hc32(ehci, 3 << 1))
/*
* Now the following defines are not converted using the
@@ -350,7 +353,8 @@ struct ehci_qtd {
#define Q_TYPE_FSTN (3 << 1)
/* next async queue entry, or pointer to interrupt/periodic QH */
-#define QH_NEXT(ehci,dma) (cpu_to_hc32(ehci, (((u32)dma)&~0x01f)|Q_TYPE_QH))
+#define QH_NEXT(ehci, dma) \
+ (cpu_to_hc32(ehci, (((u32) dma) & ~0x01f) | Q_TYPE_QH))
/* for periodic/async schedules and qtd lists, mark end of list */
#define EHCI_LIST_END(ehci) cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
@@ -405,9 +409,9 @@ struct ehci_qh_hw {
__hc32 hw_qtd_next;
__hc32 hw_alt_next;
__hc32 hw_token;
- __hc32 hw_buf [5];
- __hc32 hw_buf_hi [5];
-} __attribute__ ((aligned(32)));
+ __hc32 hw_buf[5];
+ __hc32 hw_buf_hi[5];
+} __aligned(32);
struct ehci_qh {
struct ehci_qh_hw *hw; /* Must come first */
@@ -432,13 +436,19 @@ struct ehci_qh {
u8 xacterrs; /* XactErr retry counter */
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
+ u8 unlink_reason;
+#define QH_UNLINK_HALTED 0x01 /* Halt flag is set */
+#define QH_UNLINK_SHORT_READ 0x02 /* Recover from a short read */
+#define QH_UNLINK_DUMMY_OVERLAY 0x04 /* QH overlayed the dummy TD */
+#define QH_UNLINK_SHUTDOWN 0x08 /* The HC isn't running */
+#define QH_UNLINK_QUEUE_EMPTY 0x10 /* Reached end of the queue */
+#define QH_UNLINK_REQUESTED 0x20 /* Disable, reset, or dequeue */
+
u8 gap_uf; /* uframes split/csplit gap */
unsigned is_out:1; /* bulk or intr OUT */
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
unsigned dequeue_during_giveback:1;
- unsigned exception:1; /* got a fault, or an unlink
- was requested */
unsigned should_be_inactive:1;
};
@@ -462,7 +472,7 @@ struct ehci_iso_sched {
struct list_head td_list;
unsigned span;
unsigned first_packet;
- struct ehci_iso_packet packet [0];
+ struct ehci_iso_packet packet[0];
};
/*
@@ -510,7 +520,7 @@ struct ehci_iso_stream {
struct ehci_itd {
/* first part defined by EHCI spec */
__hc32 hw_next; /* see EHCI 3.3.1 */
- __hc32 hw_transaction [8]; /* see EHCI 3.3.2 */
+ __hc32 hw_transaction[8]; /* see EHCI 3.3.2 */
#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
@@ -520,8 +530,8 @@ struct ehci_itd {
#define ITD_ACTIVE(ehci) cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
- __hc32 hw_bufp [7]; /* see EHCI 3.3.3 */
- __hc32 hw_bufp_hi [7]; /* Appendix B */
+ __hc32 hw_bufp[7]; /* see EHCI 3.3.3 */
+ __hc32 hw_bufp_hi[7]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t itd_dma; /* for this itd */
@@ -535,7 +545,7 @@ struct ehci_itd {
unsigned frame; /* where scheduled */
unsigned pg;
unsigned index[8]; /* in urb->iso_frame_desc */
-} __attribute__ ((aligned (32)));
+} __aligned(32);
/*-------------------------------------------------------------------------*/
@@ -554,7 +564,7 @@ struct ehci_sitd {
__hc32 hw_results; /* EHCI table 3-11 */
#define SITD_IOC (1 << 31) /* interrupt on completion */
#define SITD_PAGE (1 << 30) /* buffer 0/1 */
-#define SITD_LENGTH(x) (0x3ff & ((x)>>16))
+#define SITD_LENGTH(x) (((x) >> 16) & 0x3ff)
#define SITD_STS_ACTIVE (1 << 7) /* HC may execute this */
#define SITD_STS_ERR (1 << 6) /* error from TT */
#define SITD_STS_DBE (1 << 5) /* data buffer error (in HC) */
@@ -565,9 +575,9 @@ struct ehci_sitd {
#define SITD_ACTIVE(ehci) cpu_to_hc32(ehci, SITD_STS_ACTIVE)
- __hc32 hw_buf [2]; /* EHCI table 3-12 */
+ __hc32 hw_buf[2]; /* EHCI table 3-12 */
__hc32 hw_backpointer; /* EHCI table 3-13 */
- __hc32 hw_buf_hi [2]; /* Appendix B */
+ __hc32 hw_buf_hi[2]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t sitd_dma;
@@ -578,7 +588,7 @@ struct ehci_sitd {
struct list_head sitd_list; /* list of stream's sitds */
unsigned frame;
unsigned index;
-} __attribute__ ((aligned (32)));
+} __aligned(32);
/*-------------------------------------------------------------------------*/
@@ -598,7 +608,7 @@ struct ehci_fstn {
/* the rest is HCD-private */
dma_addr_t fstn_dma;
union ehci_shadow fstn_next; /* ptr to periodic q entry */
-} __attribute__ ((aligned (32)));
+} __aligned(32);
/*-------------------------------------------------------------------------*/
@@ -634,10 +644,10 @@ struct ehci_tt {
/* Prepare the PORTSC wakeup flags during controller suspend/resume */
#define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup) \
- ehci_adjust_port_wakeup_flags(ehci, true, do_wakeup);
+ ehci_adjust_port_wakeup_flags(ehci, true, do_wakeup)
#define ehci_prepare_ports_for_controller_resume(ehci) \
- ehci_adjust_port_wakeup_flags(ehci, false, false);
+ ehci_adjust_port_wakeup_flags(ehci, false, false)
/*-------------------------------------------------------------------------*/
@@ -731,7 +741,7 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#endif
static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
- __u32 __iomem * regs)
+ __u32 __iomem *regs)
{
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
return ehci_big_endian_mmio(ehci) ?
@@ -806,7 +816,7 @@ static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
#define ehci_big_endian_desc(e) ((e)->big_endian_desc)
/* cpu to ehci */
-static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
+static inline __hc32 cpu_to_hc32(const struct ehci_hcd *ehci, const u32 x)
{
return ehci_big_endian_desc(ehci)
? (__force __hc32)cpu_to_be32(x)
@@ -814,14 +824,14 @@ static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
}
/* ehci to cpu */
-static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
+static inline u32 hc32_to_cpu(const struct ehci_hcd *ehci, const __hc32 x)
{
return ehci_big_endian_desc(ehci)
? be32_to_cpu((__force __be32)x)
: le32_to_cpu((__force __le32)x);
}
-static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
+static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 *x)
{
return ehci_big_endian_desc(ehci)
? be32_to_cpup((__force __be32 *)x)
@@ -831,18 +841,18 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
#else
/* cpu to ehci */
-static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
+static inline __hc32 cpu_to_hc32(const struct ehci_hcd *ehci, const u32 x)
{
return cpu_to_le32(x);
}
/* ehci to cpu */
-static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
+static inline u32 hc32_to_cpu(const struct ehci_hcd *ehci, const __hc32 x)
{
return le32_to_cpu(x);
}
-static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
+static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 *x)
{
return le32_to_cpup(x);
}
@@ -852,18 +862,13 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
/*-------------------------------------------------------------------------*/
#define ehci_dbg(ehci, fmt, args...) \
- dev_dbg(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
+ dev_dbg(ehci_to_hcd(ehci)->self.controller, fmt, ## args)
#define ehci_err(ehci, fmt, args...) \
- dev_err(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
+ dev_err(ehci_to_hcd(ehci)->self.controller, fmt, ## args)
#define ehci_info(ehci, fmt, args...) \
- dev_info(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
+ dev_info(ehci_to_hcd(ehci)->self.controller, fmt, ## args)
#define ehci_warn(ehci, fmt, args...) \
- dev_warn(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
-
-
-#ifndef CONFIG_DYNAMIC_DEBUG
-#define STUB_DEBUG_FILES
-#endif
+ dev_warn(ehci_to_hcd(ehci)->self.controller, fmt, ## args)
/*-------------------------------------------------------------------------*/
@@ -883,12 +888,10 @@ extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr,
u32 mask, u32 done, int usec);
extern int ehci_reset(struct ehci_hcd *ehci);
-#ifdef CONFIG_PM
extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
extern int ehci_resume(struct usb_hcd *hcd, bool force_reset);
extern void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
bool suspending, bool do_wakeup);
-#endif /* CONFIG_PM */
extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength);
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index 2341af4f3490..360a5e95abca 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -2267,7 +2267,7 @@ static unsigned qh_completions(struct fotg210_hcd *fotg210,
struct fotg210_qh *qh)
{
struct fotg210_qtd *last, *end = qh->dummy;
- struct list_head *entry, *tmp;
+ struct fotg210_qtd *qtd, *tmp;
int last_status;
int stopped;
unsigned count = 0;
@@ -2301,12 +2301,10 @@ rescan:
* then let the queue advance.
* if queue is stopped, handles unlinks.
*/
- list_for_each_safe(entry, tmp, &qh->qtd_list) {
- struct fotg210_qtd *qtd;
+ list_for_each_entry_safe(qtd, tmp, &qh->qtd_list, qtd_list) {
struct urb *urb;
u32 token = 0;
- qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
urb = qtd->urb;
/* clean up any state from previous QTD ...*/
@@ -2544,14 +2542,11 @@ retry_xacterr:
* used for cleanup after errors, before HC sees an URB's TDs.
*/
static void qtd_list_free(struct fotg210_hcd *fotg210, struct urb *urb,
- struct list_head *qtd_list)
+ struct list_head *head)
{
- struct list_head *entry, *temp;
-
- list_for_each_safe(entry, temp, qtd_list) {
- struct fotg210_qtd *qtd;
+ struct fotg210_qtd *qtd, *temp;
- qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
+ list_for_each_entry_safe(qtd, temp, head, qtd_list) {
list_del(&qtd->qtd_list);
fotg210_qtd_free(fotg210, qtd);
}
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 0c382652a399..1044b0f9d656 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -17,6 +17,7 @@
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/module.h>
+#include <linux/dma-mapping.h>
struct fsl_usb2_dev_data {
char *dr_mode; /* controller mode */
@@ -96,7 +97,11 @@ static struct platform_device *fsl_usb2_device_register(
pdev->dev.parent = &ofdev->dev;
pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
- *pdev->dev.dma_mask = *ofdev->dev.dma_mask;
+
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &ofdev->dev.coherent_dma_mask;
+ else
+ dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
if (retval)
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index bd98706d1ce9..c369c29e496d 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -797,19 +797,16 @@ max3421_check_unlink(struct usb_hcd *hcd)
{
struct spi_device *spi = to_spi_device(hcd->self.controller);
struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
- struct list_head *pos, *upos, *next_upos;
struct max3421_ep *max3421_ep;
struct usb_host_endpoint *ep;
- struct urb *urb;
+ struct urb *urb, *next;
unsigned long flags;
int retval = 0;
spin_lock_irqsave(&max3421_hcd->lock, flags);
- list_for_each(pos, &max3421_hcd->ep_list) {
- max3421_ep = container_of(pos, struct max3421_ep, ep_list);
+ list_for_each_entry(max3421_ep, &max3421_hcd->ep_list, ep_list) {
ep = max3421_ep->ep;
- list_for_each_safe(upos, next_upos, &ep->urb_list) {
- urb = container_of(upos, struct urb, urb_list);
+ list_for_each_entry_safe(urb, next, &ep->urb_list, urb_list) {
if (urb->unlinked) {
retval = 1;
dev_dbg(&spi->dev, "%s: URB %p unlinked=%d",
@@ -1184,22 +1181,19 @@ dump_eps(struct usb_hcd *hcd)
struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
struct max3421_ep *max3421_ep;
struct usb_host_endpoint *ep;
- struct list_head *pos, *upos;
char ubuf[512], *dp, *end;
unsigned long flags;
struct urb *urb;
int epnum, ret;
spin_lock_irqsave(&max3421_hcd->lock, flags);
- list_for_each(pos, &max3421_hcd->ep_list) {
- max3421_ep = container_of(pos, struct max3421_ep, ep_list);
+ list_for_each_entry(max3421_ep, &max3421_hcd->ep_list, ep_list) {
ep = max3421_ep->ep;
dp = ubuf;
end = dp + sizeof(ubuf);
*dp = '\0';
- list_for_each(upos, &ep->urb_list) {
- urb = container_of(upos, struct urb, urb_list);
+ list_for_each_entry(urb, &ep->urb_list, urb_list) {
ret = snprintf(dp, end - dp, " %p(%d.%s %d/%d)", urb,
usb_pipetype(urb->pipe),
usb_urb_dir_in(urb) ? "IN" : "OUT",
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 8c6e15bd6ff0..f789d2954c5d 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -583,9 +583,7 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-
-static int
+static int __maybe_unused
ohci_hcd_at91_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -630,7 +628,8 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
return ret;
}
-static int ohci_hcd_at91_drv_resume(struct device *dev)
+static int __maybe_unused
+ohci_hcd_at91_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
@@ -643,7 +642,6 @@ static int ohci_hcd_at91_drv_resume(struct device *dev)
ohci_resume(hcd, false);
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend,
ohci_hcd_at91_drv_resume);
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index cfa94275c52c..b7d4756232ae 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -22,7 +22,6 @@
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/i2c.h>
-#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -32,25 +31,9 @@
#include "ohci.h"
-
#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/io.h>
-
-#include <mach/platform.h>
-#include <mach/irqs.h>
#define USB_CONFIG_BASE 0x31020000
-#define PWRMAN_BASE 0x40004000
-
-#define USB_CTRL IO_ADDRESS(PWRMAN_BASE + 0x64)
-
-/* USB_CTRL bit defines */
-#define USB_SLAVE_HCLK_EN (1 << 24)
-#define USB_DEV_NEED_CLK_EN (1 << 22)
-#define USB_HOST_NEED_CLK_EN (1 << 21)
-#define PAD_CONTROL_LAST_DRIVEN (1 << 19)
-
#define USB_OTG_STAT_CONTROL IO_ADDRESS(USB_CONFIG_BASE + 0x110)
/* USB_OTG_STAT_CONTROL bit defines */
@@ -75,9 +58,7 @@ static struct i2c_client *isp1301_i2c_client;
extern int usb_disabled(void);
-static struct clk *usb_pll_clk;
-static struct clk *usb_dev_clk;
-static struct clk *usb_otg_clk;
+static struct clk *usb_host_clk;
static void isp1301_configure_lpc32xx(void)
{
@@ -117,9 +98,6 @@ static void isp1301_configure_lpc32xx(void)
i2c_smbus_write_byte_data(isp1301_i2c_client,
ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
- /* Enable usb_need_clk clock after transceiver is initialized */
- __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
-
printk(KERN_INFO "ISP1301 Vendor ID : 0x%04x\n",
i2c_smbus_read_word_data(isp1301_i2c_client, 0x00));
printk(KERN_INFO "ISP1301 Product ID : 0x%04x\n",
@@ -192,59 +170,20 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
goto fail_disable;
}
- /* Enable AHB slave USB clock, needed for further USB clock control */
- __raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL);
-
- /* Enable USB PLL */
- usb_pll_clk = devm_clk_get(&pdev->dev, "ck_pll5");
- if (IS_ERR(usb_pll_clk)) {
- dev_err(&pdev->dev, "failed to acquire USB PLL\n");
- ret = PTR_ERR(usb_pll_clk);
+ /* Enable USB host clock */
+ usb_host_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(usb_host_clk)) {
+ dev_err(&pdev->dev, "failed to acquire USB OHCI clock\n");
+ ret = PTR_ERR(usb_host_clk);
goto fail_disable;
}
- ret = clk_prepare_enable(usb_pll_clk);
+ ret = clk_prepare_enable(usb_host_clk);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to start USB PLL\n");
+ dev_err(&pdev->dev, "failed to start USB OHCI clock\n");
goto fail_disable;
}
- ret = clk_set_rate(usb_pll_clk, 48000);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to set USB clock rate\n");
- goto fail_rate;
- }
-
- /* Enable USB device clock */
- usb_dev_clk = devm_clk_get(&pdev->dev, "ck_usbd");
- if (IS_ERR(usb_dev_clk)) {
- dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
- ret = PTR_ERR(usb_dev_clk);
- goto fail_rate;
- }
-
- ret = clk_prepare_enable(usb_dev_clk);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
- goto fail_rate;
- }
-
- /* Enable USB otg clocks */
- usb_otg_clk = devm_clk_get(&pdev->dev, "ck_usb_otg");
- if (IS_ERR(usb_otg_clk)) {
- dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
- ret = PTR_ERR(usb_otg_clk);
- goto fail_otg;
- }
-
- __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
-
- ret = clk_prepare_enable(usb_otg_clk);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
- goto fail_otg;
- }
-
isp1301_configure();
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
@@ -283,11 +222,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
fail_resource:
usb_put_hcd(hcd);
fail_hcd:
- clk_disable_unprepare(usb_otg_clk);
-fail_otg:
- clk_disable_unprepare(usb_dev_clk);
-fail_rate:
- clk_disable_unprepare(usb_pll_clk);
+ clk_disable_unprepare(usb_host_clk);
fail_disable:
isp1301_i2c_client = NULL;
return ret;
@@ -300,9 +235,7 @@ static int ohci_hcd_nxp_remove(struct platform_device *pdev)
usb_remove_hcd(hcd);
ohci_nxp_stop_hc();
usb_put_hcd(hcd);
- clk_disable_unprepare(usb_otg_clk);
- clk_disable_unprepare(usb_dev_clk);
- clk_disable_unprepare(usb_pll_clk);
+ clk_disable_unprepare(usb_host_clk);
isp1301_i2c_client = NULL;
return 0;
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index c2669f185f65..ae1c988da146 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -310,8 +310,7 @@ static int ohci_platform_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev->platform_data;
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
bool do_wakeup = device_may_wakeup(dev);
int ret;
@@ -329,8 +328,7 @@ static int ohci_platform_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
if (pdata->power_on) {
int err = pdata->power_on(pdev);
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index e8c006e7a960..a667cf2d5788 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -435,7 +435,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
pr_err("no resource of IORESOURCE_IRQ");
- return -ENXIO;
+ return irq;
}
usb_clk = devm_clk_get(&pdev->dev, NULL);
diff --git a/drivers/usb/host/ohci-st.c b/drivers/usb/host/ohci-st.c
index df9028e0d9b4..acf2eb2a5676 100644
--- a/drivers/usb/host/ohci-st.c
+++ b/drivers/usb/host/ohci-st.c
@@ -270,8 +270,7 @@ static int st_ohci_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev->platform_data;
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
bool do_wakeup = device_may_wakeup(dev);
int ret;
@@ -289,8 +288,7 @@ static int st_ohci_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
int err;
if (pdata->power_on) {
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index bc462288cfb0..37f1725e7a46 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -735,10 +735,8 @@ extern void ohci_init_driver(struct hc_driver *drv,
const struct ohci_driver_overrides *over);
extern int ohci_restart(struct ohci_hcd *ohci);
extern int ohci_setup(struct usb_hcd *hcd);
-#ifdef CONFIG_PM
extern int ohci_suspend(struct usb_hcd *hcd, bool do_wakeup);
extern int ohci_resume(struct usb_hcd *hcd, bool hibernated);
-#endif
extern int ohci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength);
extern int ohci_hub_status_data(struct usb_hcd *hcd, char *buf);
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index bc74aca8a54c..4e4d601af35c 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -981,7 +981,7 @@ static int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh);
static unsigned qh_completions(struct oxu_hcd *oxu, struct ehci_qh *qh)
{
struct ehci_qtd *last = NULL, *end = qh->dummy;
- struct list_head *entry, *tmp;
+ struct ehci_qtd *qtd, *tmp;
int stopped;
unsigned count = 0;
int do_status = 0;
@@ -1006,12 +1006,10 @@ static unsigned qh_completions(struct oxu_hcd *oxu, struct ehci_qh *qh)
* then let the queue advance.
* if queue is stopped, handles unlinks.
*/
- list_for_each_safe(entry, tmp, &qh->qtd_list) {
- struct ehci_qtd *qtd;
+ list_for_each_entry_safe(qtd, tmp, &qh->qtd_list, qtd_list) {
struct urb *urb;
u32 token = 0;
- qtd = list_entry(entry, struct ehci_qtd, qtd_list);
urb = qtd->urb;
/* Clean up any state from previous QTD ...*/
@@ -1174,14 +1172,11 @@ halt:
* used for cleanup after errors, before HC sees an URB's TDs.
*/
static void qtd_list_free(struct oxu_hcd *oxu,
- struct urb *urb, struct list_head *qtd_list)
+ struct urb *urb, struct list_head *head)
{
- struct list_head *entry, *temp;
-
- list_for_each_safe(entry, temp, qtd_list) {
- struct ehci_qtd *qtd;
+ struct ehci_qtd *qtd, *temp;
- qtd = list_entry(entry, struct ehci_qtd, qtd_list);
+ list_for_each_entry_safe(qtd, temp, head, qtd_list) {
list_del(&qtd->qtd_list);
oxu_qtd_free(oxu, qtd);
}
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 26cb8c861e6e..35af36253440 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -992,7 +992,7 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
if ((ext_cap_offset + sizeof(val)) > len) {
/* We're reading garbage from the controller */
dev_warn(&pdev->dev, "xHCI controller failing to respond");
- return;
+ goto iounmap;
}
val = readl(base + ext_cap_offset);
@@ -1055,6 +1055,7 @@ hc_init:
XHCI_MAX_HALT_USEC, val);
}
+iounmap:
iounmap(base);
}
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 4cbd0633c5c2..bfa7fa3d2eea 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2099,16 +2099,13 @@ static void r8a66597_check_detect_child(struct r8a66597 *r8a66597,
memset(now_map, 0, sizeof(now_map));
- list_for_each_entry(bus, &usb_bus_list, bus_list) {
- if (!bus->root_hub)
- continue;
-
- if (bus->busnum != hcd->self.busnum)
- continue;
-
+ mutex_lock(&usb_bus_idr_lock);
+ bus = idr_find(&usb_bus_idr, hcd->self.busnum);
+ if (bus && bus->root_hub) {
collect_usb_address_map(bus->root_hub, now_map);
update_usb_address_map(r8a66597, bus->root_hub, now_map);
}
+ mutex_unlock(&usb_bus_idr_lock);
}
static int r8a66597_hub_status_data(struct usb_hcd *hcd, char *buf)
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 05c85c7baf84..43d52931b5bf 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -1309,13 +1309,9 @@ static void u132_hcd_ring_work_scheduler(struct work_struct *work)
u132_ring_put_kref(u132, ring);
return;
} else if (ring->curr_endp) {
- struct u132_endp *last_endp = ring->curr_endp;
- struct list_head *scan;
- struct list_head *head = &last_endp->endp_ring;
+ struct u132_endp *endp, *last_endp = ring->curr_endp;
unsigned long wakeup = 0;
- list_for_each(scan, head) {
- struct u132_endp *endp = list_entry(scan,
- struct u132_endp, endp_ring);
+ list_for_each_entry(endp, &last_endp->endp_ring, endp_ring) {
if (endp->queue_next == endp->queue_last) {
} else if ((endp->delayed == 0)
|| time_after_eq(jiffies, endp->jiffies)) {
@@ -2393,14 +2389,12 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
static int dequeue_from_overflow_chain(struct u132 *u132,
struct u132_endp *endp, struct urb *urb)
{
- struct list_head *scan;
- struct list_head *head = &endp->urb_more;
- list_for_each(scan, head) {
- struct u132_urbq *urbq = list_entry(scan, struct u132_urbq,
- urb_more);
+ struct u132_urbq *urbq;
+
+ list_for_each_entry(urbq, &endp->urb_more, urb_more) {
if (urbq->urb == urb) {
struct usb_hcd *hcd = u132_to_hcd(u132);
- list_del(scan);
+ list_del(&urbq->urb_more);
endp->queue_size -= 1;
urb->error_count = 0;
usb_hcd_giveback_urb(hcd, urb, 0);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index b30b4ce294d3..d61fcc48099e 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -50,14 +50,18 @@ static u8 usb_bos_descriptor [] = {
0x00, /* bU1DevExitLat, set later. */
0x00, 0x00, /* __le16 bU2DevExitLat, set later. */
/* Second device capability, SuperSpeedPlus */
- 0x0c, /* bLength 12, will be adjusted later */
+ 0x1c, /* bLength 28, will be adjusted later */
USB_DT_DEVICE_CAPABILITY, /* Device Capability */
USB_SSP_CAP_TYPE, /* bDevCapabilityType SUPERSPEED_PLUS */
0x00, /* bReserved 0 */
- 0x00, 0x00, 0x00, 0x00, /* bmAttributes, get from xhci psic */
- 0x00, 0x00, /* wFunctionalitySupport */
+ 0x23, 0x00, 0x00, 0x00, /* bmAttributes, SSAC=3 SSIC=1 */
+ 0x01, 0x00, /* wFunctionalitySupport */
0x00, 0x00, /* wReserved 0 */
- /* Sublink Speed Attributes are added in xhci_create_usb3_bos_desc() */
+ /* Default Sublink Speed Attributes, overwrite if custom PSI exists */
+ 0x34, 0x00, 0x05, 0x00, /* 5Gbps, symmetric, rx, ID = 4 */
+ 0xb4, 0x00, 0x05, 0x00, /* 5Gbps, symmetric, tx, ID = 4 */
+ 0x35, 0x40, 0x0a, 0x00, /* 10Gbps, SSP, symmetric, rx, ID = 5 */
+ 0xb5, 0x40, 0x0a, 0x00, /* 10Gbps, SSP, symmetric, tx, ID = 5 */
};
static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
@@ -72,10 +76,14 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
ssp_cap_size = sizeof(usb_bos_descriptor) - desc_size;
/* does xhci support USB 3.1 Enhanced SuperSpeed */
- if (xhci->usb3_rhub.min_rev >= 0x01 && xhci->usb3_rhub.psi_uid_count) {
- /* two SSA entries for each unique PSI ID, one RX and one TX */
- ssa_count = xhci->usb3_rhub.psi_uid_count * 2;
- ssa_size = ssa_count * sizeof(u32);
+ if (xhci->usb3_rhub.min_rev >= 0x01) {
+ /* does xhci provide a PSI table for SSA speed attributes? */
+ if (xhci->usb3_rhub.psi_count) {
+ /* two SSA entries for each unique PSI ID, RX and TX */
+ ssa_count = xhci->usb3_rhub.psi_uid_count * 2;
+ ssa_size = ssa_count * sizeof(u32);
+ ssp_cap_size -= 16; /* skip copying the default SSA */
+ }
desc_size += ssp_cap_size;
usb3_1 = true;
}
@@ -102,7 +110,8 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
}
- if (usb3_1) {
+ /* If PSI table exists, add the custom speed attributes from it */
+ if (usb3_1 && xhci->usb3_rhub.psi_count) {
u32 ssp_cap_base, bm_attrib, psi;
int offset;
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 5cd080e0a685..80c1de239e9a 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1070,7 +1070,7 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
struct usb_device *top_dev;
struct usb_hcd *hcd;
- if (udev->speed == USB_SPEED_SUPER)
+ if (udev->speed >= USB_SPEED_SUPER)
hcd = xhci->shared_hcd;
else
hcd = xhci->main_hcd;
@@ -1105,6 +1105,10 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
/* 3) Only the control endpoint is valid - one endpoint context */
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | udev->route);
switch (udev->speed) {
+ case USB_SPEED_SUPER_PLUS:
+ slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SSP);
+ max_packets = MAX_PACKET(512);
+ break;
case USB_SPEED_SUPER:
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS);
max_packets = MAX_PACKET(512);
@@ -1292,6 +1296,7 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
}
/* Fall through - SS and HS isoc/int have same decoding */
+ case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER:
if (usb_endpoint_xfer_int(&ep->desc) ||
usb_endpoint_xfer_isoc(&ep->desc)) {
@@ -1321,7 +1326,7 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
default:
BUG();
}
- return EP_INTERVAL(interval);
+ return interval;
}
/* The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps.
@@ -1332,39 +1337,42 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
static u32 xhci_get_endpoint_mult(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
- if (udev->speed != USB_SPEED_SUPER ||
+ if (udev->speed < USB_SPEED_SUPER ||
!usb_endpoint_xfer_isoc(&ep->desc))
return 0;
return ep->ss_ep_comp.bmAttributes;
}
+static u32 xhci_get_endpoint_max_burst(struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ /* Super speed and Plus have max burst in ep companion desc */
+ if (udev->speed >= USB_SPEED_SUPER)
+ return ep->ss_ep_comp.bMaxBurst;
+
+ if (udev->speed == USB_SPEED_HIGH &&
+ (usb_endpoint_xfer_isoc(&ep->desc) ||
+ usb_endpoint_xfer_int(&ep->desc)))
+ return (usb_endpoint_maxp(&ep->desc) & 0x1800) >> 11;
+
+ return 0;
+}
+
static u32 xhci_get_endpoint_type(struct usb_host_endpoint *ep)
{
int in;
- u32 type;
in = usb_endpoint_dir_in(&ep->desc);
- if (usb_endpoint_xfer_control(&ep->desc)) {
- type = EP_TYPE(CTRL_EP);
- } else if (usb_endpoint_xfer_bulk(&ep->desc)) {
- if (in)
- type = EP_TYPE(BULK_IN_EP);
- else
- type = EP_TYPE(BULK_OUT_EP);
- } else if (usb_endpoint_xfer_isoc(&ep->desc)) {
- if (in)
- type = EP_TYPE(ISOC_IN_EP);
- else
- type = EP_TYPE(ISOC_OUT_EP);
- } else if (usb_endpoint_xfer_int(&ep->desc)) {
- if (in)
- type = EP_TYPE(INT_IN_EP);
- else
- type = EP_TYPE(INT_OUT_EP);
- } else {
- type = 0;
- }
- return type;
+
+ if (usb_endpoint_xfer_control(&ep->desc))
+ return CTRL_EP;
+ if (usb_endpoint_xfer_bulk(&ep->desc))
+ return in ? BULK_IN_EP : BULK_OUT_EP;
+ if (usb_endpoint_xfer_isoc(&ep->desc))
+ return in ? ISOC_IN_EP : ISOC_OUT_EP;
+ if (usb_endpoint_xfer_int(&ep->desc))
+ return in ? INT_IN_EP : INT_OUT_EP;
+ return 0;
}
/* Return the maximum endpoint service interval time (ESIT) payload.
@@ -1382,7 +1390,12 @@ static u32 xhci_get_max_esit_payload(struct usb_device *udev,
usb_endpoint_xfer_bulk(&ep->desc))
return 0;
- if (udev->speed == USB_SPEED_SUPER)
+ /* SuperSpeedPlus Isoc ep sending over 48k per esit */
+ if ((udev->speed >= USB_SPEED_SUPER_PLUS) &&
+ USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes))
+ return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval);
+ /* SuperSpeed or SuperSpeedPlus Isoc ep with less than 48k per esit */
+ else if (udev->speed >= USB_SPEED_SUPER)
return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
@@ -1404,10 +1417,14 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
struct xhci_ep_ctx *ep_ctx;
struct xhci_ring *ep_ring;
unsigned int max_packet;
- unsigned int max_burst;
- enum xhci_ring_type type;
+ enum xhci_ring_type ring_type;
u32 max_esit_payload;
u32 endpoint_type;
+ unsigned int max_burst;
+ unsigned int interval;
+ unsigned int mult;
+ unsigned int avg_trb_len;
+ unsigned int err_count = 0;
ep_index = xhci_get_endpoint_index(&ep->desc);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
@@ -1415,12 +1432,11 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
endpoint_type = xhci_get_endpoint_type(ep);
if (!endpoint_type)
return -EINVAL;
- ep_ctx->ep_info2 = cpu_to_le32(endpoint_type);
- type = usb_endpoint_type(&ep->desc);
+ ring_type = usb_endpoint_type(&ep->desc);
/* Set up the endpoint ring */
virt_dev->eps[ep_index].new_ring =
- xhci_ring_alloc(xhci, 2, 1, type, mem_flags);
+ xhci_ring_alloc(xhci, 2, 1, ring_type, mem_flags);
if (!virt_dev->eps[ep_index].new_ring) {
/* Attempt to use the ring cache */
if (virt_dev->num_rings_cached == 0)
@@ -1430,80 +1446,52 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
virt_dev->ring_cache[virt_dev->num_rings_cached];
virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
- 1, type);
+ 1, ring_type);
}
virt_dev->eps[ep_index].skip = false;
ep_ring = virt_dev->eps[ep_index].new_ring;
- ep_ctx->deq = cpu_to_le64(ep_ring->first_seg->dma | ep_ring->cycle_state);
- ep_ctx->ep_info = cpu_to_le32(xhci_get_endpoint_interval(udev, ep)
- | EP_MULT(xhci_get_endpoint_mult(udev, ep)));
+ /*
+ * Get values to fill the endpoint context, mostly from ep descriptor.
+ * The average TRB buffer lengt for bulk endpoints is unclear as we
+ * have no clue on scatter gather list entry size. For Isoc and Int,
+ * set it to max available. See xHCI 1.1 spec 4.14.1.1 for details.
+ */
+ max_esit_payload = xhci_get_max_esit_payload(udev, ep);
+ interval = xhci_get_endpoint_interval(udev, ep);
+ mult = xhci_get_endpoint_mult(udev, ep);
+ max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
+ max_burst = xhci_get_endpoint_max_burst(udev, ep);
+ avg_trb_len = max_esit_payload;
/* FIXME dig Mult and streams info out of ep companion desc */
- /* Allow 3 retries for everything but isoc;
- * CErr shall be set to 0 for Isoch endpoints.
- */
+ /* Allow 3 retries for everything but isoc, set CErr = 3 */
if (!usb_endpoint_xfer_isoc(&ep->desc))
- ep_ctx->ep_info2 |= cpu_to_le32(ERROR_COUNT(3));
- else
- ep_ctx->ep_info2 |= cpu_to_le32(ERROR_COUNT(0));
-
- /* Set the max packet size and max burst */
- max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
- max_burst = 0;
- switch (udev->speed) {
- case USB_SPEED_SUPER:
- /* dig out max burst from ep companion desc */
- max_burst = ep->ss_ep_comp.bMaxBurst;
- break;
- case USB_SPEED_HIGH:
- /* Some devices get this wrong */
- if (usb_endpoint_xfer_bulk(&ep->desc))
- max_packet = 512;
- /* bits 11:12 specify the number of additional transaction
- * opportunities per microframe (USB 2.0, section 9.6.6)
- */
- if (usb_endpoint_xfer_isoc(&ep->desc) ||
- usb_endpoint_xfer_int(&ep->desc)) {
- max_burst = (usb_endpoint_maxp(&ep->desc)
- & 0x1800) >> 11;
- }
- break;
- case USB_SPEED_FULL:
- case USB_SPEED_LOW:
- break;
- default:
- BUG();
- }
- ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet) |
- MAX_BURST(max_burst));
- max_esit_payload = xhci_get_max_esit_payload(udev, ep);
- ep_ctx->tx_info = cpu_to_le32(MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload));
-
- /*
- * XXX no idea how to calculate the average TRB buffer length for bulk
- * endpoints, as the driver gives us no clue how big each scatter gather
- * list entry (or buffer) is going to be.
- *
- * For isochronous and interrupt endpoints, we set it to the max
- * available, until we have new API in the USB core to allow drivers to
- * declare how much bandwidth they actually need.
- *
- * Normally, it would be calculated by taking the total of the buffer
- * lengths in the TD and then dividing by the number of TRBs in a TD,
- * including link TRBs, No-op TRBs, and Event data TRBs. Since we don't
- * use Event Data TRBs, and we don't chain in a link TRB on short
- * transfers, we're basically dividing by 1.
- *
- * xHCI 1.0 and 1.1 specification indicates that the Average TRB Length
- * should be set to 8 for control endpoints.
- */
+ err_count = 3;
+ /* Some devices get this wrong */
+ if (usb_endpoint_xfer_bulk(&ep->desc) && udev->speed == USB_SPEED_HIGH)
+ max_packet = 512;
+ /* xHCI 1.0 and 1.1 indicates that ctrl ep avg TRB Length should be 8 */
if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100)
- ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8));
- else
- ep_ctx->tx_info |=
- cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(max_esit_payload));
+ avg_trb_len = 8;
+ /* xhci 1.1 with LEC support doesn't use mult field, use RsvdZ */
+ if ((xhci->hci_version > 0x100) && HCC2_LEC(xhci->hcc_params2))
+ mult = 0;
+
+ /* Fill the endpoint context */
+ ep_ctx->ep_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |
+ EP_INTERVAL(interval) |
+ EP_MULT(mult));
+ ep_ctx->ep_info2 = cpu_to_le32(EP_TYPE(endpoint_type) |
+ MAX_PACKET(max_packet) |
+ MAX_BURST(max_burst) |
+ ERROR_COUNT(err_count));
+ ep_ctx->deq = cpu_to_le64(ep_ring->first_seg->dma |
+ ep_ring->cycle_state);
+
+ ep_ctx->tx_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
+ EP_AVG_TRB_LENGTH(avg_trb_len));
/* FIXME Debug endpoint context */
return 0;
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 9532f5aef71b..79959f17c38c 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -695,7 +695,6 @@ static int xhci_mtk_remove(struct platform_device *dev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
/*
* if ip sleep fails, and all clocks are disabled, access register will hang
* AHB bus, so stop polling roothubs to avoid regs access on bus suspend.
@@ -703,7 +702,7 @@ static int xhci_mtk_remove(struct platform_device *dev)
* to wake up system immediately after system suspend complete if ip sleep
* fails, it is what we wanted.
*/
-static int xhci_mtk_suspend(struct device *dev)
+static int __maybe_unused xhci_mtk_suspend(struct device *dev)
{
struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
struct usb_hcd *hcd = mtk->hcd;
@@ -722,7 +721,7 @@ static int xhci_mtk_suspend(struct device *dev)
return 0;
}
-static int xhci_mtk_resume(struct device *dev)
+static int __maybe_unused xhci_mtk_resume(struct device *dev)
{
struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
struct usb_hcd *hcd = mtk->hcd;
@@ -744,10 +743,7 @@ static int xhci_mtk_resume(struct device *dev)
static const struct dev_pm_ops xhci_mtk_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(xhci_mtk_suspend, xhci_mtk_resume)
};
-#define DEV_PM_OPS (&xhci_mtk_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif /* CONFIG_PM */
+#define DEV_PM_OPS IS_ENABLED(CONFIG_PM) ? &xhci_mtk_pm_ops : NULL
#ifdef CONFIG_OF
static const struct of_device_id mtk_xhci_of_match[] = {
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index d39d6bf1d090..5c15e9bc5f7a 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -110,7 +110,13 @@ static const struct of_device_id usb_xhci_of_match[] = {
.compatible = "renesas,xhci-r8a7795",
.data = &xhci_plat_renesas_rcar_gen3,
}, {
+ .compatible = "renesas,rcar-gen2-xhci",
+ .data = &xhci_plat_renesas_rcar_gen2,
+ }, {
+ .compatible = "renesas,rcar-gen3-xhci",
+ .data = &xhci_plat_renesas_rcar_gen3,
},
+ {},
};
MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
#endif
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 3915657e6078..7cf66212ceae 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3558,12 +3558,11 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
* zero. Only xHCI 1.0 host controllers support this field.
*/
static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
- struct usb_device *udev,
struct urb *urb, unsigned int total_packet_count)
{
unsigned int max_burst;
- if (xhci->hci_version < 0x100 || udev->speed != USB_SPEED_SUPER)
+ if (xhci->hci_version < 0x100 || urb->dev->speed < USB_SPEED_SUPER)
return 0;
max_burst = urb->ep->ss_ep_comp.bMaxBurst;
@@ -3579,7 +3578,6 @@ static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
* contain 1 to (bMaxBurst + 1) packets.
*/
static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
- struct usb_device *udev,
struct urb *urb, unsigned int total_packet_count)
{
unsigned int max_burst;
@@ -3588,8 +3586,7 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
if (xhci->hci_version < 0x100)
return 0;
- switch (udev->speed) {
- case USB_SPEED_SUPER:
+ if (urb->dev->speed >= USB_SPEED_SUPER) {
/* bMaxBurst is zero based: 0 means 1 packet per burst */
max_burst = urb->ep->ss_ep_comp.bMaxBurst;
residue = total_packet_count % (max_burst + 1);
@@ -3599,11 +3596,10 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
if (residue == 0)
return max_burst;
return residue - 1;
- default:
- if (total_packet_count == 0)
- return 0;
- return total_packet_count - 1;
}
+ if (total_packet_count == 0)
+ return 0;
+ return total_packet_count - 1;
}
/*
@@ -3714,6 +3710,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
int i, j;
bool more_trbs_coming;
struct xhci_virt_ep *xep;
+ int frame_id;
xep = &xhci->devs[slot_id]->eps[ep_index];
ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
@@ -3723,33 +3720,31 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
xhci_dbg(xhci, "Isoc URB with zero packets?\n");
return -EINVAL;
}
-
start_addr = (u64) urb->transfer_dma;
start_trb = &ep_ring->enqueue->generic;
start_cycle = ep_ring->cycle_state;
urb_priv = urb->hcpriv;
- /* Queue the first TRB, even if it's zero-length */
+ /* Queue the TRBs for each TD, even if they are zero-length */
for (i = 0; i < num_tds; i++) {
- unsigned int total_packet_count;
- unsigned int burst_count;
- unsigned int residue;
+ unsigned int total_pkt_count, max_pkt;
+ unsigned int burst_count, last_burst_pkt_count;
+ u32 sia_frame_id;
first_trb = true;
running_total = 0;
addr = start_addr + urb->iso_frame_desc[i].offset;
td_len = urb->iso_frame_desc[i].length;
td_remain_len = td_len;
- total_packet_count = DIV_ROUND_UP(td_len,
- GET_MAX_PACKET(
- usb_endpoint_maxp(&urb->ep->desc)));
+ max_pkt = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
+ total_pkt_count = DIV_ROUND_UP(td_len, max_pkt);
+
/* A zero-length transfer still involves at least one packet. */
- if (total_packet_count == 0)
- total_packet_count++;
- burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
- total_packet_count);
- residue = xhci_get_last_burst_packet_count(xhci,
- urb->dev, urb, total_packet_count);
+ if (total_pkt_count == 0)
+ total_pkt_count++;
+ burst_count = xhci_get_burst_count(xhci, urb, total_pkt_count);
+ last_burst_pkt_count = xhci_get_last_burst_packet_count(xhci,
+ urb, total_pkt_count);
trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
@@ -3760,68 +3755,57 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
return ret;
goto cleanup;
}
-
td = urb_priv->td[i];
+
+ /* use SIA as default, if frame id is used overwrite it */
+ sia_frame_id = TRB_SIA;
+ if (!(urb->transfer_flags & URB_ISO_ASAP) &&
+ HCC_CFC(xhci->hcc_params)) {
+ frame_id = xhci_get_isoc_frame_id(xhci, urb, i);
+ if (frame_id >= 0)
+ sia_frame_id = TRB_FRAME_ID(frame_id);
+ }
+ /*
+ * Set isoc specific data for the first TRB in a TD.
+ * Prevent HW from getting the TRBs by keeping the cycle state
+ * inverted in the first TDs isoc TRB.
+ */
+ field = TRB_TYPE(TRB_ISOC) |
+ TRB_TLBPC(last_burst_pkt_count) |
+ sia_frame_id |
+ (i ? ep_ring->cycle_state : !start_cycle);
+
+ /* xhci 1.1 with ETE uses TD_Size field for TBC, old is Rsvdz */
+ if (!xep->use_extended_tbc)
+ field |= TRB_TBC(burst_count);
+
+ /* fill the rest of the TRB fields, and remaining normal TRBs */
for (j = 0; j < trbs_per_td; j++) {
- int frame_id = 0;
u32 remainder = 0;
- field = 0;
-
- if (first_trb) {
- field = TRB_TBC(burst_count) |
- TRB_TLBPC(residue);
- /* Queue the isoc TRB */
- field |= TRB_TYPE(TRB_ISOC);
-
- /* Calculate Frame ID and SIA fields */
- if (!(urb->transfer_flags & URB_ISO_ASAP) &&
- HCC_CFC(xhci->hcc_params)) {
- frame_id = xhci_get_isoc_frame_id(xhci,
- urb,
- i);
- if (frame_id >= 0)
- field |= TRB_FRAME_ID(frame_id);
- else
- field |= TRB_SIA;
- } else
- field |= TRB_SIA;
-
- if (i == 0) {
- if (start_cycle == 0)
- field |= 0x1;
- } else
- field |= ep_ring->cycle_state;
- first_trb = false;
- } else {
- /* Queue other normal TRBs */
- field |= TRB_TYPE(TRB_NORMAL);
- field |= ep_ring->cycle_state;
- }
+
+ /* only first TRB is isoc, overwrite otherwise */
+ if (!first_trb)
+ field = TRB_TYPE(TRB_NORMAL) |
+ ep_ring->cycle_state;
/* Only set interrupt on short packet for IN EPs */
if (usb_urb_dir_in(urb))
field |= TRB_ISP;
- /* Chain all the TRBs together; clear the chain bit in
- * the last TRB to indicate it's the last TRB in the
- * chain.
- */
+ /* Set the chain bit for all except the last TRB */
if (j < trbs_per_td - 1) {
- field |= TRB_CHAIN;
more_trbs_coming = true;
+ field |= TRB_CHAIN;
} else {
+ more_trbs_coming = false;
td->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
- if (xhci->hci_version == 0x100 &&
- !(xhci->quirks &
- XHCI_AVOID_BEI)) {
- /* Set BEI bit except for the last td */
- if (i < num_tds - 1)
- field |= TRB_BEI;
- }
- more_trbs_coming = false;
+ /* set BEI, except for the last TD */
+ if (xhci->hci_version >= 0x100 &&
+ !(xhci->quirks & XHCI_AVOID_BEI) &&
+ i < num_tds - 1)
+ field |= TRB_BEI;
}
-
/* Calculate TRB length */
trb_buff_len = TRB_MAX_BUFF_SIZE -
(addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
@@ -3834,9 +3818,15 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
urb, trbs_per_td - j - 1);
length_field = TRB_LEN(trb_buff_len) |
- TRB_TD_SIZE(remainder) |
TRB_INTR_TARGET(0);
+ /* xhci 1.1 with ETE uses TD Size field for TBC */
+ if (first_trb && xep->use_extended_tbc)
+ length_field |= TRB_TD_SIZE_TBC(burst_count);
+ else
+ length_field |= TRB_TD_SIZE(remainder);
+ first_trb = false;
+
queue_trb(xhci, ep_ring, more_trbs_coming,
lower_32_bits(addr),
upper_32_bits(addr),
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0c8087d3c313..d51ee0c3cf9f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -2086,6 +2086,7 @@ static unsigned int xhci_get_block_size(struct usb_device *udev)
case USB_SPEED_HIGH:
return HS_BLOCK;
case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
return SS_BLOCK;
case USB_SPEED_UNKNOWN:
case USB_SPEED_WIRELESS:
@@ -2211,7 +2212,7 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
unsigned int packets_remaining = 0;
unsigned int i;
- if (virt_dev->udev->speed == USB_SPEED_SUPER)
+ if (virt_dev->udev->speed >= USB_SPEED_SUPER)
return xhci_check_ss_bw(xhci, virt_dev);
if (virt_dev->udev->speed == USB_SPEED_HIGH) {
@@ -2412,7 +2413,7 @@ void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
if (xhci_is_async_ep(ep_bw->type))
return;
- if (udev->speed == USB_SPEED_SUPER) {
+ if (udev->speed >= USB_SPEED_SUPER) {
if (xhci_is_sync_in_ep(ep_bw->type))
xhci->devs[udev->slot_id]->bw_table->ss_bw_in -=
xhci_get_ss_bw_consumed(ep_bw);
@@ -2450,6 +2451,7 @@ void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
interval_bw->overhead[HS_OVERHEAD_TYPE] -= 1;
break;
case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
case USB_SPEED_UNKNOWN:
case USB_SPEED_WIRELESS:
/* Should never happen because only LS/FS/HS endpoints will get
@@ -2509,6 +2511,7 @@ static void xhci_add_ep_to_interval_table(struct xhci_hcd *xhci,
interval_bw->overhead[HS_OVERHEAD_TYPE] += 1;
break;
case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
case USB_SPEED_UNKNOWN:
case USB_SPEED_WIRELESS:
/* Should never happen because only LS/FS/HS endpoints will get
@@ -4897,6 +4900,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (xhci->sbrn == 0x31) {
xhci_info(xhci, "Host supports USB 3.1 Enhanced SuperSpeed\n");
hcd->speed = HCD_USB31;
+ hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
}
/* xHCI private pointer was set in xhci_pci_probe for the second
* registered roothub.
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index cc651383ce5a..e293e0974f48 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -232,7 +232,9 @@ struct xhci_op_regs {
* disabled, or powered-off state.
*/
#define CMD_PM_INDEX (1 << 11)
-/* bits 12:31 are reserved (and should be preserved on writes). */
+/* bit 14 Extended TBC Enable, changes Isoc TRB fields to support larger TBC */
+#define CMD_ETE (1 << 14)
+/* bits 15:31 are reserved (and should be preserved on writes). */
/* IMAN - Interrupt Management Register */
#define IMAN_IE (1 << 1)
@@ -343,6 +345,7 @@ struct xhci_op_regs {
#define SLOT_SPEED_LS (XDEV_LS << 10)
#define SLOT_SPEED_HS (XDEV_HS << 10)
#define SLOT_SPEED_SS (XDEV_SS << 10)
+#define SLOT_SPEED_SSP (XDEV_SSP << 10)
/* Port Indicator Control */
#define PORT_LED_OFF (0 << 14)
#define PORT_LED_AMBER (1 << 14)
@@ -748,8 +751,9 @@ struct xhci_ep_ctx {
#define GET_MAX_PACKET(p) ((p) & 0x7ff)
/* tx_info bitmasks */
-#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff)
-#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16)
+#define EP_AVG_TRB_LENGTH(p) ((p) & 0xffff)
+#define EP_MAX_ESIT_PAYLOAD_LO(p) (((p) & 0xffff) << 16)
+#define EP_MAX_ESIT_PAYLOAD_HI(p) ((((p) >> 16) & 0xff) << 24)
#define CTX_TO_MAX_ESIT_PAYLOAD(p) (((p) >> 16) & 0xffff)
/* deq bitmasks */
@@ -941,6 +945,8 @@ struct xhci_virt_ep {
struct list_head bw_endpoint_list;
/* Isoch Frame ID checking storage */
int next_frame_id;
+ /* Use new Isoch TRB layout needed for extended TBC support */
+ bool use_extended_tbc;
};
enum xhci_overhead_type {
@@ -1182,9 +1188,12 @@ enum xhci_setup_dev {
#define TRB_LEN(p) ((p) & 0x1ffff)
/* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */
#define TRB_TD_SIZE(p) (min((p), (u32)31) << 17)
+/* xhci 1.1 uses the TD_SIZE field for TBC if Extended TBC is enabled (ETE) */
+#define TRB_TD_SIZE_TBC(p) (min((p), (u32)31) << 17)
/* Interrupter Target - which MSI-X vector to target the completion event at */
#define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
#define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)
+/* Total burst count field, Rsvdz on xhci 1.1 with Extended TBC enabled (ETE) */
#define TRB_TBC(p) (((p) & 0x3) << 7)
#define TRB_TLBPC(p) (((p) & 0xf) << 16)
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index 23c794813e6a..76350e4ee807 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -73,6 +73,8 @@ static const struct usb_device_id chaoskey_table[] = {
};
MODULE_DEVICE_TABLE(usb, chaoskey_table);
+static void chaos_read_callback(struct urb *urb);
+
/* Driver-local specific stuff */
struct chaoskey {
struct usb_interface *interface;
@@ -80,7 +82,8 @@ struct chaoskey {
struct mutex lock;
struct mutex rng_lock;
int open; /* open count */
- int present; /* device not disconnected */
+ bool present; /* device not disconnected */
+ bool reading; /* ongoing IO */
int size; /* size of buf */
int valid; /* bytes of buf read */
int used; /* bytes of buf consumed */
@@ -88,15 +91,19 @@ struct chaoskey {
struct hwrng hwrng; /* Embedded struct for hwrng */
int hwrng_registered; /* registered with hwrng API */
wait_queue_head_t wait_q; /* for timeouts */
+ struct urb *urb; /* for performing IO */
char *buf;
};
static void chaoskey_free(struct chaoskey *dev)
{
- usb_dbg(dev->interface, "free");
- kfree(dev->name);
- kfree(dev->buf);
- kfree(dev);
+ if (dev) {
+ usb_dbg(dev->interface, "free");
+ usb_free_urb(dev->urb);
+ kfree(dev->name);
+ kfree(dev->buf);
+ kfree(dev);
+ }
}
static int chaoskey_probe(struct usb_interface *interface,
@@ -107,7 +114,7 @@ static int chaoskey_probe(struct usb_interface *interface,
int i;
int in_ep = -1;
struct chaoskey *dev;
- int result;
+ int result = -ENOMEM;
int size;
usb_dbg(interface, "probe %s-%s", udev->product, udev->serial);
@@ -142,14 +149,25 @@ static int chaoskey_probe(struct usb_interface *interface,
dev = kzalloc(sizeof(struct chaoskey), GFP_KERNEL);
if (dev == NULL)
- return -ENOMEM;
+ goto out;
dev->buf = kmalloc(size, GFP_KERNEL);
- if (dev->buf == NULL) {
- kfree(dev);
- return -ENOMEM;
- }
+ if (dev->buf == NULL)
+ goto out;
+
+ dev->urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ if (!dev->urb)
+ goto out;
+
+ usb_fill_bulk_urb(dev->urb,
+ udev,
+ usb_rcvbulkpipe(udev, in_ep),
+ dev->buf,
+ size,
+ chaos_read_callback,
+ dev);
/* Construct a name using the product and serial values. Each
* device needs a unique name for the hwrng code
@@ -158,11 +176,8 @@ static int chaoskey_probe(struct usb_interface *interface,
if (udev->product && udev->serial) {
dev->name = kmalloc(strlen(udev->product) + 1 +
strlen(udev->serial) + 1, GFP_KERNEL);
- if (dev->name == NULL) {
- kfree(dev->buf);
- kfree(dev);
- return -ENOMEM;
- }
+ if (dev->name == NULL)
+ goto out;
strcpy(dev->name, udev->product);
strcat(dev->name, "-");
@@ -186,9 +201,7 @@ static int chaoskey_probe(struct usb_interface *interface,
result = usb_register_dev(interface, &chaoskey_class);
if (result) {
usb_err(interface, "Unable to allocate minor number.");
- usb_set_intfdata(interface, NULL);
- chaoskey_free(dev);
- return result;
+ goto out;
}
dev->hwrng.name = dev->name ? dev->name : chaoskey_driver.name;
@@ -215,6 +228,11 @@ static int chaoskey_probe(struct usb_interface *interface,
usb_dbg(interface, "chaoskey probe success, size %d", dev->size);
return 0;
+
+out:
+ usb_set_intfdata(interface, NULL);
+ chaoskey_free(dev);
+ return result;
}
static void chaoskey_disconnect(struct usb_interface *interface)
@@ -237,6 +255,7 @@ static void chaoskey_disconnect(struct usb_interface *interface)
mutex_lock(&dev->lock);
dev->present = 0;
+ usb_poison_urb(dev->urb);
if (!dev->open) {
mutex_unlock(&dev->lock);
@@ -311,14 +330,33 @@ static int chaoskey_release(struct inode *inode, struct file *file)
return 0;
}
+static void chaos_read_callback(struct urb *urb)
+{
+ struct chaoskey *dev = urb->context;
+ int status = urb->status;
+
+ usb_dbg(dev->interface, "callback status (%d)", status);
+
+ if (status == 0)
+ dev->valid = urb->actual_length;
+ else
+ dev->valid = 0;
+
+ dev->used = 0;
+
+ /* must be seen first before validity is announced */
+ smp_wmb();
+
+ dev->reading = false;
+ wake_up(&dev->wait_q);
+}
+
/* Fill the buffer. Called with dev->lock held
*/
static int _chaoskey_fill(struct chaoskey *dev)
{
DEFINE_WAIT(wait);
int result;
- int this_read;
- struct usb_device *udev = interface_to_usbdev(dev->interface);
usb_dbg(dev->interface, "fill");
@@ -343,21 +381,31 @@ static int _chaoskey_fill(struct chaoskey *dev)
return result;
}
- result = usb_bulk_msg(udev,
- usb_rcvbulkpipe(udev, dev->in_ep),
- dev->buf, dev->size, &this_read,
- NAK_TIMEOUT);
+ dev->reading = true;
+ result = usb_submit_urb(dev->urb, GFP_KERNEL);
+ if (result < 0) {
+ result = usb_translate_errors(result);
+ dev->reading = false;
+ goto out;
+ }
+
+ result = wait_event_interruptible_timeout(
+ dev->wait_q,
+ !dev->reading,
+ NAK_TIMEOUT);
+
+ if (result < 0)
+ goto out;
+ if (result == 0)
+ result = -ETIMEDOUT;
+ else
+ result = dev->valid;
+out:
/* Let the device go back to sleep eventually */
usb_autopm_put_interface(dev->interface);
- if (result == 0) {
- dev->valid = this_read;
- dev->used = 0;
- }
-
- usb_dbg(dev->interface, "bulk_msg result %d this_read %d",
- result, this_read);
+ usb_dbg(dev->interface, "read %d bytes", dev->valid);
return result;
}
@@ -395,13 +443,7 @@ static ssize_t chaoskey_read(struct file *file,
goto bail;
if (dev->valid == dev->used) {
result = _chaoskey_fill(dev);
- if (result) {
- mutex_unlock(&dev->lock);
- goto bail;
- }
-
- /* Read returned zero bytes */
- if (dev->used == dev->valid) {
+ if (result < 0) {
mutex_unlock(&dev->lock);
goto bail;
}
@@ -435,6 +477,8 @@ bail:
return read_count;
}
usb_dbg(dev->interface, "empty read, result %d", result);
+ if (result == -ETIMEDOUT)
+ result = -EAGAIN;
return result;
}
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 4e38683c653c..5105397e62fc 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -257,9 +257,9 @@ static int idmouse_open(struct inode *inode, struct file *file)
if (result)
goto error;
result = idmouse_create_image (dev);
+ usb_autopm_put_interface(interface);
if (result)
goto error;
- usb_autopm_put_interface(interface);
/* increment our usage count for the driver */
++dev->open;
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 8efbabacc84e..a22de52cb083 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -61,8 +61,8 @@
/* Forward declarations / clean-up routines */
#ifdef INCL_SISUSB_CON
-static int sisusb_first_vc = 0;
-static int sisusb_last_vc = 0;
+static int sisusb_first_vc;
+static int sisusb_last_vc;
module_param_named(first, sisusb_first_vc, int, 0);
module_param_named(last, sisusb_last_vc, int, 0);
MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
@@ -71,25 +71,19 @@ MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES
static struct usb_driver sisusb_driver;
-static void
-sisusb_free_buffers(struct sisusb_usb_data *sisusb)
+static void sisusb_free_buffers(struct sisusb_usb_data *sisusb)
{
int i;
for (i = 0; i < NUMOBUFS; i++) {
- if (sisusb->obuf[i]) {
- kfree(sisusb->obuf[i]);
- sisusb->obuf[i] = NULL;
- }
- }
- if (sisusb->ibuf) {
- kfree(sisusb->ibuf);
- sisusb->ibuf = NULL;
+ kfree(sisusb->obuf[i]);
+ sisusb->obuf[i] = NULL;
}
+ kfree(sisusb->ibuf);
+ sisusb->ibuf = NULL;
}
-static void
-sisusb_free_urbs(struct sisusb_usb_data *sisusb)
+static void sisusb_free_urbs(struct sisusb_usb_data *sisusb)
{
int i;
@@ -108,8 +102,7 @@ sisusb_free_urbs(struct sisusb_usb_data *sisusb)
/* out-urb management */
/* Return 1 if all free, 0 otherwise */
-static int
-sisusb_all_free(struct sisusb_usb_data *sisusb)
+static int sisusb_all_free(struct sisusb_usb_data *sisusb)
{
int i;
@@ -124,8 +117,7 @@ sisusb_all_free(struct sisusb_usb_data *sisusb)
}
/* Kill all busy URBs */
-static void
-sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
+static void sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
{
int i;
@@ -141,20 +133,17 @@ sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
}
/* Return 1 if ok, 0 if error (not all complete within timeout) */
-static int
-sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
+static int sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
{
int timeout = 5 * HZ, i = 1;
- wait_event_timeout(sisusb->wait_q,
- (i = sisusb_all_free(sisusb)),
- timeout);
+ wait_event_timeout(sisusb->wait_q, (i = sisusb_all_free(sisusb)),
+ timeout);
return i;
}
-static int
-sisusb_outurb_available(struct sisusb_usb_data *sisusb)
+static int sisusb_outurb_available(struct sisusb_usb_data *sisusb)
{
int i;
@@ -168,20 +157,17 @@ sisusb_outurb_available(struct sisusb_usb_data *sisusb)
return -1;
}
-static int
-sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
+static int sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
{
int i, timeout = 5 * HZ;
wait_event_timeout(sisusb->wait_q,
- ((i = sisusb_outurb_available(sisusb)) >= 0),
- timeout);
+ ((i = sisusb_outurb_available(sisusb)) >= 0), timeout);
return i;
}
-static int
-sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
+static int sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
{
int i;
@@ -193,8 +179,7 @@ sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
return i;
}
-static void
-sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
+static void sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
{
if ((index >= 0) && (index < sisusb->numobufs))
sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
@@ -202,8 +187,7 @@ sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
/* completion callback */
-static void
-sisusb_bulk_completeout(struct urb *urb)
+static void sisusb_bulk_completeout(struct urb *urb)
{
struct sisusb_urb_context *context = urb->context;
struct sisusb_usb_data *sisusb;
@@ -225,9 +209,9 @@ sisusb_bulk_completeout(struct urb *urb)
wake_up(&sisusb->wait_q);
}
-static int
-sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
- int len, int *actual_length, int timeout, unsigned int tflags)
+static int sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index,
+ unsigned int pipe, void *data, int len, int *actual_length,
+ int timeout, unsigned int tflags)
{
struct urb *urb = sisusb->sisurbout[index];
int retval, byteswritten = 0;
@@ -236,14 +220,15 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe,
urb->transfer_flags = 0;
usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
- sisusb_bulk_completeout, &sisusb->urbout_context[index]);
+ sisusb_bulk_completeout,
+ &sisusb->urbout_context[index]);
urb->transfer_flags |= tflags;
urb->actual_length = 0;
/* Set up context */
sisusb->urbout_context[index].actual_length = (timeout) ?
- NULL : actual_length;
+ NULL : actual_length;
/* Declare this urb/buffer in use */
sisusb->urbstatus[index] |= SU_URB_BUSY;
@@ -254,8 +239,8 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe,
/* If OK, and if timeout > 0, wait for completion */
if ((retval == 0) && timeout) {
wait_event_timeout(sisusb->wait_q,
- (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
- timeout);
+ (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
+ timeout);
if (sisusb->urbstatus[index] & SU_URB_BUSY) {
/* URB timed out... kill it and report error */
usb_kill_urb(urb);
@@ -277,8 +262,7 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe,
/* completion callback */
-static void
-sisusb_bulk_completein(struct urb *urb)
+static void sisusb_bulk_completein(struct urb *urb)
{
struct sisusb_usb_data *sisusb = urb->context;
@@ -289,9 +273,9 @@ sisusb_bulk_completein(struct urb *urb)
wake_up(&sisusb->wait_q);
}
-static int
-sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
- int len, int *actual_length, int timeout, unsigned int tflags)
+static int sisusb_bulkin_msg(struct sisusb_usb_data *sisusb,
+ unsigned int pipe, void *data, int len,
+ int *actual_length, int timeout, unsigned int tflags)
{
struct urb *urb = sisusb->sisurbin;
int retval, readbytes = 0;
@@ -375,7 +359,7 @@ static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
do {
passsize = thispass = (sisusb->obufsize < count) ?
- sisusb->obufsize : count;
+ sisusb->obufsize : count;
if (index < 0)
index = sisusb_get_free_outbuf(sisusb);
@@ -405,14 +389,9 @@ static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
if (!sisusb->sisusb_dev)
return -ENODEV;
- result = sisusb_bulkout_msg(sisusb,
- index,
- pipe,
- buffer,
- thispass,
- &transferred_len,
- async ? 0 : 5 * HZ,
- tflags);
+ result = sisusb_bulkout_msg(sisusb, index, pipe,
+ buffer, thispass, &transferred_len,
+ async ? 0 : 5 * HZ, tflags);
if (result == -ETIMEDOUT) {
@@ -500,13 +479,8 @@ static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
thispass = (bufsize < count) ? bufsize : count;
- result = sisusb_bulkin_msg(sisusb,
- pipe,
- buffer,
- thispass,
- &transferred_len,
- 5 * HZ,
- tflags);
+ result = sisusb_bulkin_msg(sisusb, pipe, buffer, thispass,
+ &transferred_len, 5 * HZ, tflags);
if (transferred_len)
thispass = transferred_len;
@@ -549,7 +523,7 @@ static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
}
static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
- struct sisusb_packet *packet)
+ struct sisusb_packet *packet)
{
int ret;
ssize_t bytes_transferred = 0;
@@ -585,8 +559,7 @@ static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
}
static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
- struct sisusb_packet *packet,
- unsigned int tflags)
+ struct sisusb_packet *packet, unsigned int tflags)
{
int ret;
ssize_t bytes_transferred = 0;
@@ -634,7 +607,7 @@ static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
*/
static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
- u32 addr, u8 data)
+ u32 addr, u8 data)
{
struct sisusb_packet packet;
int ret;
@@ -647,7 +620,7 @@ static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
}
static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
- u32 addr, u16 data)
+ u32 addr, u16 data)
{
struct sisusb_packet packet;
int ret = 0;
@@ -655,36 +628,36 @@ static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
packet.address = addr & ~3;
switch (addr & 3) {
- case 0:
- packet.header = (type << 6) | 0x0003;
- packet.data = (u32)data;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- break;
- case 1:
- packet.header = (type << 6) | 0x0006;
- packet.data = (u32)data << 8;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- break;
- case 2:
- packet.header = (type << 6) | 0x000c;
- packet.data = (u32)data << 16;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- break;
- case 3:
- packet.header = (type << 6) | 0x0008;
- packet.data = (u32)data << 24;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- packet.header = (type << 6) | 0x0001;
- packet.address = (addr & ~3) + 4;
- packet.data = (u32)data >> 8;
- ret |= sisusb_send_packet(sisusb, 10, &packet);
+ case 0:
+ packet.header = (type << 6) | 0x0003;
+ packet.data = (u32)data;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x0006;
+ packet.data = (u32)data << 8;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ packet.data = (u32)data << 16;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ packet.data = (u32)data << 24;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ packet.data = (u32)data >> 8;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
}
return ret;
}
static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
- u32 addr, u32 data)
+ u32 addr, u32 data)
{
struct sisusb_packet packet;
int ret = 0;
@@ -692,40 +665,40 @@ static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
packet.address = addr & ~3;
switch (addr & 3) {
- case 0:
- packet.header = (type << 6) | 0x0007;
- packet.data = data & 0x00ffffff;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- break;
- case 1:
- packet.header = (type << 6) | 0x000e;
- packet.data = data << 8;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- break;
- case 2:
- packet.header = (type << 6) | 0x000c;
- packet.data = data << 16;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- packet.header = (type << 6) | 0x0001;
- packet.address = (addr & ~3) + 4;
- packet.data = (data >> 16) & 0x00ff;
- ret |= sisusb_send_packet(sisusb, 10, &packet);
- break;
- case 3:
- packet.header = (type << 6) | 0x0008;
- packet.data = data << 24;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- packet.header = (type << 6) | 0x0003;
- packet.address = (addr & ~3) + 4;
- packet.data = (data >> 8) & 0xffff;
- ret |= sisusb_send_packet(sisusb, 10, &packet);
+ case 0:
+ packet.header = (type << 6) | 0x0007;
+ packet.data = data & 0x00ffffff;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x000e;
+ packet.data = data << 8;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ packet.data = data << 16;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ packet.data = (data >> 16) & 0x00ff;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ packet.data = data << 24;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0003;
+ packet.address = (addr & ~3) + 4;
+ packet.data = (data >> 8) & 0xffff;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
}
return ret;
}
static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
- u32 addr, u32 data)
+ u32 addr, u32 data)
{
struct sisusb_packet packet;
int ret = 0;
@@ -733,37 +706,37 @@ static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
packet.address = addr & ~3;
switch (addr & 3) {
- case 0:
- packet.header = (type << 6) | 0x000f;
- packet.data = data;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- break;
- case 1:
- packet.header = (type << 6) | 0x000e;
- packet.data = data << 8;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- packet.header = (type << 6) | 0x0001;
- packet.address = (addr & ~3) + 4;
- packet.data = data >> 24;
- ret |= sisusb_send_packet(sisusb, 10, &packet);
- break;
- case 2:
- packet.header = (type << 6) | 0x000c;
- packet.data = data << 16;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- packet.header = (type << 6) | 0x0003;
- packet.address = (addr & ~3) + 4;
- packet.data = data >> 16;
- ret |= sisusb_send_packet(sisusb, 10, &packet);
- break;
- case 3:
- packet.header = (type << 6) | 0x0008;
- packet.data = data << 24;
- ret = sisusb_send_packet(sisusb, 10, &packet);
- packet.header = (type << 6) | 0x0007;
- packet.address = (addr & ~3) + 4;
- packet.data = data >> 8;
- ret |= sisusb_send_packet(sisusb, 10, &packet);
+ case 0:
+ packet.header = (type << 6) | 0x000f;
+ packet.data = data;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x000e;
+ packet.data = data << 8;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ packet.data = data >> 24;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ packet.data = data << 16;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0003;
+ packet.address = (addr & ~3) + 4;
+ packet.data = data >> 16;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ packet.data = data << 24;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0007;
+ packet.address = (addr & ~3) + 4;
+ packet.data = data >> 8;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
}
return ret;
@@ -780,13 +753,12 @@ static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
*/
static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
- char *kernbuffer, int length,
- const char __user *userbuffer, int index,
- ssize_t *bytes_written)
+ char *kernbuffer, int length, const char __user *userbuffer,
+ int index, ssize_t *bytes_written)
{
struct sisusb_packet packet;
int ret = 0;
- static int msgcount = 0;
+ static int msgcount;
u8 swap8, fromkern = kernbuffer ? 1 : 0;
u16 swap16;
u32 swap32, flag = (length >> 28) & 1;
@@ -803,9 +775,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
length &= 0x00ffffff;
while (length) {
-
- switch (length) {
-
+ switch (length) {
case 1:
if (userbuffer) {
if (get_user(swap8, (u8 __user *)userbuffer))
@@ -813,9 +783,8 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
} else
swap8 = kernbuffer[0];
- ret = sisusb_write_memio_byte(sisusb,
- SISUSB_TYPE_MEM,
- addr, swap8);
+ ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM,
+ addr, swap8);
if (!ret)
(*bytes_written)++;
@@ -829,10 +798,8 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
} else
swap16 = *((u16 *)kernbuffer);
- ret = sisusb_write_memio_word(sisusb,
- SISUSB_TYPE_MEM,
- addr,
- swap16);
+ ret = sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+ addr, swap16);
if (!ret)
(*bytes_written) += 2;
@@ -863,10 +830,8 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
kernbuffer[0];
#endif
- ret = sisusb_write_memio_24bit(sisusb,
- SISUSB_TYPE_MEM,
- addr,
- swap32);
+ ret = sisusb_write_memio_24bit(sisusb, SISUSB_TYPE_MEM,
+ addr, swap32);
if (!ret)
(*bytes_written) += 3;
@@ -880,10 +845,8 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
} else
swap32 = *((u32 *)kernbuffer);
- ret = sisusb_write_memio_long(sisusb,
- SISUSB_TYPE_MEM,
- addr,
- swap32);
+ ret = sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM,
+ addr, swap32);
if (!ret)
(*bytes_written) += 4;
@@ -892,103 +855,106 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
default:
if ((length & ~3) > 0x10000) {
- packet.header = 0x001f;
- packet.address = 0x000001d4;
- packet.data = addr;
- ret = sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001d0;
- packet.data = (length & ~3);
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001c0;
- packet.data = flag | 0x16;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- if (userbuffer) {
- ret |= sisusb_send_bulk_msg(sisusb,
+ packet.header = 0x001f;
+ packet.address = 0x000001d4;
+ packet.data = addr;
+ ret = sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ packet.header = 0x001f;
+ packet.address = 0x000001d0;
+ packet.data = (length & ~3);
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ packet.header = 0x001f;
+ packet.address = 0x000001c0;
+ packet.data = flag | 0x16;
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ if (userbuffer) {
+ ret |= sisusb_send_bulk_msg(sisusb,
SISUSB_EP_GFX_LBULK_OUT,
(length & ~3),
NULL, userbuffer, 0,
bytes_written, 0, 1);
- userbuffer += (*bytes_written);
- } else if (fromkern) {
- ret |= sisusb_send_bulk_msg(sisusb,
+ userbuffer += (*bytes_written);
+ } else if (fromkern) {
+ ret |= sisusb_send_bulk_msg(sisusb,
SISUSB_EP_GFX_LBULK_OUT,
(length & ~3),
kernbuffer, NULL, 0,
bytes_written, 0, 1);
- kernbuffer += (*bytes_written);
- } else {
- ret |= sisusb_send_bulk_msg(sisusb,
+ kernbuffer += (*bytes_written);
+ } else {
+ ret |= sisusb_send_bulk_msg(sisusb,
SISUSB_EP_GFX_LBULK_OUT,
(length & ~3),
NULL, NULL, index,
bytes_written, 0, 1);
- kernbuffer += ((*bytes_written) &
- (sisusb->obufsize-1));
- }
+ kernbuffer += ((*bytes_written) &
+ (sisusb->obufsize-1));
+ }
} else {
- packet.header = 0x001f;
- packet.address = 0x00000194;
- packet.data = addr;
- ret = sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x00000190;
- packet.data = (length & ~3);
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- if (sisusb->flagb0 != 0x16) {
packet.header = 0x001f;
- packet.address = 0x00000180;
- packet.data = flag | 0x16;
+ packet.address = 0x00000194;
+ packet.data = addr;
+ ret = sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ packet.header = 0x001f;
+ packet.address = 0x00000190;
+ packet.data = (length & ~3);
ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- sisusb->flagb0 = 0x16;
- }
- if (userbuffer) {
- ret |= sisusb_send_bulk_msg(sisusb,
+ &packet, 0);
+ if (sisusb->flagb0 != 0x16) {
+ packet.header = 0x001f;
+ packet.address = 0x00000180;
+ packet.data = flag | 0x16;
+ ret |= sisusb_send_bridge_packet(sisusb,
+ 10, &packet, 0);
+ sisusb->flagb0 = 0x16;
+ }
+ if (userbuffer) {
+ ret |= sisusb_send_bulk_msg(sisusb,
SISUSB_EP_GFX_BULK_OUT,
(length & ~3),
NULL, userbuffer, 0,
bytes_written, 0, 1);
- userbuffer += (*bytes_written);
- } else if (fromkern) {
- ret |= sisusb_send_bulk_msg(sisusb,
+ userbuffer += (*bytes_written);
+ } else if (fromkern) {
+ ret |= sisusb_send_bulk_msg(sisusb,
SISUSB_EP_GFX_BULK_OUT,
(length & ~3),
kernbuffer, NULL, 0,
bytes_written, 0, 1);
- kernbuffer += (*bytes_written);
- } else {
- ret |= sisusb_send_bulk_msg(sisusb,
+ kernbuffer += (*bytes_written);
+ } else {
+ ret |= sisusb_send_bulk_msg(sisusb,
SISUSB_EP_GFX_BULK_OUT,
(length & ~3),
NULL, NULL, index,
bytes_written, 0, 1);
- kernbuffer += ((*bytes_written) &
- (sisusb->obufsize-1));
- }
+ kernbuffer += ((*bytes_written) &
+ (sisusb->obufsize-1));
+ }
}
if (ret) {
msgcount++;
if (msgcount < 500)
- dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
- *bytes_written, length, ret);
+ dev_err(&sisusb->sisusb_dev->dev,
+ "Wrote %zd of %d bytes, error %d\n",
+ *bytes_written, length,
+ ret);
else if (msgcount == 500)
- dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
+ dev_err(&sisusb->sisusb_dev->dev,
+ "Too many errors, logging stopped\n");
}
addr += (*bytes_written);
length -= (*bytes_written);
- }
+ }
- if (ret)
- break;
+ if (ret)
+ break;
}
@@ -1000,7 +966,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
*/
static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
- u32 addr, u8 *data)
+ u32 addr, u8 *data)
{
struct sisusb_packet packet;
int ret;
@@ -1014,7 +980,7 @@ static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
}
static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
- u32 addr, u16 *data)
+ u32 addr, u16 *data)
{
struct sisusb_packet packet;
int ret = 0;
@@ -1024,36 +990,36 @@ static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
packet.address = addr & ~3;
switch (addr & 3) {
- case 0:
- packet.header = (type << 6) | 0x0003;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = (u16)(packet.data);
- break;
- case 1:
- packet.header = (type << 6) | 0x0006;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = (u16)(packet.data >> 8);
- break;
- case 2:
- packet.header = (type << 6) | 0x000c;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = (u16)(packet.data >> 16);
- break;
- case 3:
- packet.header = (type << 6) | 0x0008;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = (u16)(packet.data >> 24);
- packet.header = (type << 6) | 0x0001;
- packet.address = (addr & ~3) + 4;
- ret |= sisusb_send_packet(sisusb, 6, &packet);
- *data |= (u16)(packet.data << 8);
+ case 0:
+ packet.header = (type << 6) | 0x0003;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = (u16)(packet.data);
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x0006;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = (u16)(packet.data >> 8);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = (u16)(packet.data >> 16);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = (u16)(packet.data >> 24);
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= (u16)(packet.data << 8);
}
return ret;
}
static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
- u32 addr, u32 *data)
+ u32 addr, u32 *data)
{
struct sisusb_packet packet;
int ret = 0;
@@ -1061,40 +1027,40 @@ static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
packet.address = addr & ~3;
switch (addr & 3) {
- case 0:
- packet.header = (type << 6) | 0x0007;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = packet.data & 0x00ffffff;
- break;
- case 1:
- packet.header = (type << 6) | 0x000e;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = packet.data >> 8;
- break;
- case 2:
- packet.header = (type << 6) | 0x000c;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = packet.data >> 16;
- packet.header = (type << 6) | 0x0001;
- packet.address = (addr & ~3) + 4;
- ret |= sisusb_send_packet(sisusb, 6, &packet);
- *data |= ((packet.data & 0xff) << 16);
- break;
- case 3:
- packet.header = (type << 6) | 0x0008;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = packet.data >> 24;
- packet.header = (type << 6) | 0x0003;
- packet.address = (addr & ~3) + 4;
- ret |= sisusb_send_packet(sisusb, 6, &packet);
- *data |= ((packet.data & 0xffff) << 8);
+ case 0:
+ packet.header = (type << 6) | 0x0007;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data & 0x00ffffff;
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x000e;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 8;
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 16;
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= ((packet.data & 0xff) << 16);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 24;
+ packet.header = (type << 6) | 0x0003;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= ((packet.data & 0xffff) << 8);
}
return ret;
}
static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
- u32 addr, u32 *data)
+ u32 addr, u32 *data)
{
struct sisusb_packet packet;
int ret = 0;
@@ -1102,45 +1068,45 @@ static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
packet.address = addr & ~3;
switch (addr & 3) {
- case 0:
- packet.header = (type << 6) | 0x000f;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = packet.data;
- break;
- case 1:
- packet.header = (type << 6) | 0x000e;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = packet.data >> 8;
- packet.header = (type << 6) | 0x0001;
- packet.address = (addr & ~3) + 4;
- ret |= sisusb_send_packet(sisusb, 6, &packet);
- *data |= (packet.data << 24);
- break;
- case 2:
- packet.header = (type << 6) | 0x000c;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = packet.data >> 16;
- packet.header = (type << 6) | 0x0003;
- packet.address = (addr & ~3) + 4;
- ret |= sisusb_send_packet(sisusb, 6, &packet);
- *data |= (packet.data << 16);
- break;
- case 3:
- packet.header = (type << 6) | 0x0008;
- ret = sisusb_send_packet(sisusb, 6, &packet);
- *data = packet.data >> 24;
- packet.header = (type << 6) | 0x0007;
- packet.address = (addr & ~3) + 4;
- ret |= sisusb_send_packet(sisusb, 6, &packet);
- *data |= (packet.data << 8);
+ case 0:
+ packet.header = (type << 6) | 0x000f;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data;
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x000e;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 8;
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= (packet.data << 24);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 16;
+ packet.header = (type << 6) | 0x0003;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= (packet.data << 16);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 24;
+ packet.header = (type << 6) | 0x0007;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= (packet.data << 8);
}
return ret;
}
static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
- char *kernbuffer, int length,
- char __user *userbuffer, ssize_t *bytes_read)
+ char *kernbuffer, int length, char __user *userbuffer,
+ ssize_t *bytes_read)
{
int ret = 0;
char buf[4];
@@ -1152,34 +1118,27 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
length &= 0x00ffffff;
while (length) {
-
- switch (length) {
-
+ switch (length) {
case 1:
-
ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
- addr, &buf[0]);
+ addr, &buf[0]);
if (!ret) {
(*bytes_read)++;
if (userbuffer) {
- if (put_user(buf[0],
- (u8 __user *)userbuffer)) {
+ if (put_user(buf[0], (u8 __user *)userbuffer))
return -EFAULT;
- }
- } else {
+ } else
kernbuffer[0] = buf[0];
- }
}
return ret;
case 2:
ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
- addr, &swap16);
+ addr, &swap16);
if (!ret) {
(*bytes_read) += 2;
if (userbuffer) {
- if (put_user(swap16,
- (u16 __user *)userbuffer))
+ if (put_user(swap16, (u16 __user *)userbuffer))
return -EFAULT;
} else {
*((u16 *)kernbuffer) = swap16;
@@ -1189,7 +1148,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
case 3:
ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
- addr, &swap32);
+ addr, &swap32);
if (!ret) {
(*bytes_read) += 3;
#ifdef __BIG_ENDIAN
@@ -1202,7 +1161,8 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
buf[0] = swap32 & 0xff;
#endif
if (userbuffer) {
- if (copy_to_user(userbuffer, &buf[0], 3))
+ if (copy_to_user(userbuffer,
+ &buf[0], 3))
return -EFAULT;
} else {
kernbuffer[0] = buf[0];
@@ -1214,12 +1174,11 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
default:
ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
- addr, &swap32);
+ addr, &swap32);
if (!ret) {
(*bytes_read) += 4;
if (userbuffer) {
- if (put_user(swap32,
- (u32 __user *)userbuffer))
+ if (put_user(swap32, (u32 __user *)userbuffer))
return -EFAULT;
userbuffer += 4;
@@ -1230,10 +1189,9 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
addr += 4;
length -= 4;
}
- }
-
- if (ret)
- break;
+ }
+ if (ret)
+ break;
}
return ret;
@@ -1242,40 +1200,39 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
/* High level: Gfx (indexed) register access */
#ifdef INCL_SISUSB_CON
-int
-sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
+int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
{
return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
}
-int
-sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
+int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
{
return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
}
#endif
-int
-sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
+int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 data)
{
int ret;
+
ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
return ret;
}
-int
-sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
+int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 *data)
{
int ret;
+
ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
return ret;
}
-int
-sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
- u8 myand, u8 myor)
+int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
+ u8 myand, u8 myor)
{
int ret;
u8 tmp;
@@ -1288,12 +1245,12 @@ sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
return ret;
}
-static int
-sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
- u8 data, u8 mask)
+static int sisusb_setidxregmask(struct sisusb_usb_data *sisusb,
+ int port, u8 idx, u8 data, u8 mask)
{
int ret;
u8 tmp;
+
ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
tmp &= ~(mask);
@@ -1302,75 +1259,76 @@ sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
return ret;
}
-int
-sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
+int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 myor)
{
- return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
+ return sisusb_setidxregandor(sisusb, port, index, 0xff, myor);
}
-int
-sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
+int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+ u8 idx, u8 myand)
{
- return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
+ return sisusb_setidxregandor(sisusb, port, idx, myand, 0x00);
}
/* Write/read video ram */
#ifdef INCL_SISUSB_CON
-int
-sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
+int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
{
- return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
+ return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data);
}
-int
-sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
{
- return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
+ return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data);
}
-int
-sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
- u32 dest, int length, size_t *bytes_written)
+int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
+ u32 dest, int length, size_t *bytes_written)
{
- return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
+ return sisusb_write_mem_bulk(sisusb, dest, src, length,
+ NULL, 0, bytes_written);
}
#ifdef SISUSBENDIANTEST
-int
-sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
- u32 src, int length, size_t *bytes_written)
+int sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
+ u32 src, int length, size_t *bytes_written)
{
- return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
+ return sisusb_read_mem_bulk(sisusb, src, dest, length,
+ NULL, bytes_written);
}
#endif
#endif
#ifdef SISUSBENDIANTEST
-static void
-sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
-{
- static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
- char destbuffer[10];
- size_t dummy;
- int i,j;
-
- sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
-
- for(i = 1; i <= 7; i++) {
- dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
- sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
- for(j = 0; j < i; j++) {
- dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
+static void sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
+{
+ static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
+ char destbuffer[10];
+ size_t dummy;
+ int i, j;
+
+ sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
+
+ for (i = 1; i <= 7; i++) {
+ dev_dbg(&sisusb->sisusb_dev->dev,
+ "sisusb: rwtest %d bytes\n", i);
+ sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase,
+ i, &dummy);
+ for (j = 0; j < i; j++) {
+ dev_dbg(&sisusb->sisusb_dev->dev,
+ "rwtest read[%d] = %x\n",
+ j, destbuffer[j]);
+ }
}
- }
}
#endif
/* access pci config registers (reg numbers 0, 4, 8, etc) */
-static int
-sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
+static int sisusb_write_pci_config(struct sisusb_usb_data *sisusb,
+ int regnum, u32 data)
{
struct sisusb_packet packet;
int ret;
@@ -1382,8 +1340,8 @@ sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
return ret;
}
-static int
-sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
+static int sisusb_read_pci_config(struct sisusb_usb_data *sisusb,
+ int regnum, u32 *data)
{
struct sisusb_packet packet;
int ret;
@@ -1397,8 +1355,8 @@ sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
/* Clear video RAM */
-static int
-sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
+static int sisusb_clear_vram(struct sisusb_usb_data *sisusb,
+ u32 address, int length)
{
int ret, i;
ssize_t j;
@@ -1416,7 +1374,8 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
return 0;
/* allocate free buffer/urb and clear the buffer */
- if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
+ i = sisusb_alloc_outbuf(sisusb);
+ if (i < 0)
return -EBUSY;
memset(sisusb->obuf[i], 0, sisusb->obufsize);
@@ -1437,20 +1396,19 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
* a defined mode (640x480@60Hz)
*/
-#define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
-#define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
-#define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
-#define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
-#define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
-#define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
-#define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
-#define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
-#define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
-
-static int
-sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
+#define GETREG(r, d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
+#define SETREG(r, d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
+#define SETIREG(r, i, d) sisusb_setidxreg(sisusb, r, i, d)
+#define GETIREG(r, i, d) sisusb_getidxreg(sisusb, r, i, d)
+#define SETIREGOR(r, i, o) sisusb_setidxregor(sisusb, r, i, o)
+#define SETIREGAND(r, i, a) sisusb_setidxregand(sisusb, r, i, a)
+#define SETIREGANDOR(r, i, a, o) sisusb_setidxregandor(sisusb, r, i, a, o)
+#define READL(a, d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a, d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define READB(a, d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a, d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+
+static int sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
{
int ret;
u8 tmp8;
@@ -1480,8 +1438,8 @@ sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
return ret;
}
-static int
-sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
+static int sisusb_getbuswidth(struct sisusb_usb_data *sisusb,
+ int *bw, int *chab)
{
int ret;
u8 ramtype, done = 0;
@@ -1526,7 +1484,7 @@ sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
}
if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
*chab = 1; *bw = 64;
- ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
+ ret |= SETIREGANDOR(SISSR, 0x14, 0xfc, 0x01);
ret |= sisusb_triggersr16(sisusb, ramtype);
ret |= WRITEL(ramptr + 0, 0x89abcdef);
@@ -1593,8 +1551,7 @@ sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
return ret;
}
-static int
-sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
+static int sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
{
int ret = 0;
u32 ramptr = SISUSB_PCI_MEMBASE;
@@ -1622,10 +1579,8 @@ sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
return ret;
}
-static int
-sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
- u8 rankno, u8 chab, const u8 dramtype[][5],
- int bw)
+static int sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret,
+ int index, u8 rankno, u8 chab, const u8 dramtype[][5], int bw)
{
int ret = 0, ranksize;
u8 tmp;
@@ -1641,7 +1596,9 @@ sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
return ret;
tmp = 0;
- while ((ranksize >>= 1) > 0) tmp += 0x10;
+ while ((ranksize >>= 1) > 0)
+ tmp += 0x10;
+
tmp |= ((rankno - 1) << 2);
tmp |= ((bw / 64) & 0x02);
tmp |= (chab & 0x01);
@@ -1654,8 +1611,8 @@ sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
return ret;
}
-static int
-sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
+static int sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret,
+ u32 inc, int testn)
{
int ret = 0, i;
u32 j, tmp;
@@ -1669,7 +1626,9 @@ sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
for (i = 0, j = 0; i < testn; i++) {
ret |= READL(sisusb->vrambase + j, &tmp);
- if (tmp != j) return ret;
+ if (tmp != j)
+ return ret;
+
j += inc;
}
@@ -1677,9 +1636,8 @@ sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
return ret;
}
-static int
-sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
- int idx, int bw, const u8 rtype[][5])
+static int sisusb_check_ranks(struct sisusb_usb_data *sisusb,
+ int *iret, int rankno, int idx, int bw, const u8 rtype[][5])
{
int ret = 0, i, i2ret;
u32 inc;
@@ -1687,10 +1645,8 @@ sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
*iret = 0;
for (i = rankno; i >= 1; i--) {
- inc = 1 << (rtype[idx][2] +
- rtype[idx][1] +
- rtype[idx][0] +
- bw / 64 + i);
+ inc = 1 << (rtype[idx][2] + rtype[idx][1] + rtype[idx][0] +
+ bw / 64 + i);
ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
if (!i2ret)
return ret;
@@ -1710,9 +1666,8 @@ sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
return ret;
}
-static int
-sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
- int chab)
+static int sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret,
+ int bw, int chab)
{
int ret = 0, i2ret = 0, i, j;
static const u8 sdramtype[13][5] = {
@@ -1736,13 +1691,13 @@ sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
for (i = 0; i < 13; i++) {
ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
for (j = 2; j > 0; j--) {
- ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
- chab, sdramtype, bw);
+ ret |= sisusb_set_rank(sisusb, &i2ret, i, j, chab,
+ sdramtype, bw);
if (!i2ret)
continue;
- ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
- bw, sdramtype);
+ ret |= sisusb_check_ranks(sisusb, &i2ret, j, i, bw,
+ sdramtype);
if (i2ret) {
*iret = 0; /* ram size found */
return ret;
@@ -1753,8 +1708,8 @@ sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
return ret;
}
-static int
-sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
+static int sisusb_setup_screen(struct sisusb_usb_data *sisusb,
+ int clrall, int drwfr)
{
int ret = 0;
u32 address;
@@ -1775,47 +1730,47 @@ sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
for (i = 0; i < modex; i++) {
address = sisusb->vrambase + (i * bpp);
ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
- address, 0xf100);
+ address, 0xf100);
address += (modex * (modey-1) * bpp);
ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
- address, 0xf100);
+ address, 0xf100);
}
for (i = 0; i < modey; i++) {
address = sisusb->vrambase + ((i * modex) * bpp);
ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
- address, 0xf100);
+ address, 0xf100);
address += ((modex - 1) * bpp);
ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
- address, 0xf100);
+ address, 0xf100);
}
}
return ret;
}
-static int
-sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
+static int sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
+ int touchengines)
{
int ret = 0, i, j, modex, modey, bpp, du;
u8 sr31, cr63, tmp8;
static const char attrdata[] = {
- 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
- 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
- 0x01,0x00,0x00,0x00
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x01, 0x00, 0x00, 0x00
};
static const char crtcrdata[] = {
- 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
- 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
- 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
0xff
};
static const char grcdata[] = {
- 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
0xff
};
static const char crtcdata[] = {
- 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
+ 0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
0x00
};
@@ -1858,28 +1813,32 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
SETIREGAND(SISSR, 0x37, 0xfe);
SETREG(SISMISCW, 0xef); /* sync */
SETIREG(SISCR, 0x11, 0x00); /* crtc */
- for (j = 0x00, i = 0; i <= 7; i++, j++) {
+ for (j = 0x00, i = 0; i <= 7; i++, j++)
SETIREG(SISCR, j, crtcdata[i]);
- }
- for (j = 0x10; i <= 10; i++, j++) {
+
+ for (j = 0x10; i <= 10; i++, j++)
SETIREG(SISCR, j, crtcdata[i]);
- }
- for (j = 0x15; i <= 12; i++, j++) {
+
+ for (j = 0x15; i <= 12; i++, j++)
SETIREG(SISCR, j, crtcdata[i]);
- }
- for (j = 0x0A; i <= 15; i++, j++) {
+
+ for (j = 0x0A; i <= 15; i++, j++)
SETIREG(SISSR, j, crtcdata[i]);
- }
+
SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
SETIREG(SISCR, 0x14, 0x4f);
du = (modex / 16) * (bpp * 2); /* offset/pitch */
- if (modex % 16) du += bpp;
+ if (modex % 16)
+ du += bpp;
+
SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
SETIREG(SISCR, 0x13, (du & 0xff));
du <<= 5;
tmp8 = du >> 8;
- if (du & 0xff) tmp8++;
+ if (du & 0xff)
+ tmp8++;
+
SETIREG(SISSR, 0x10, tmp8);
SETIREG(SISSR, 0x31, 0x00); /* VCLK */
SETIREG(SISSR, 0x2b, 0x1b);
@@ -1925,8 +1884,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
return ret;
}
-static int
-sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
+static int sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
{
int ret = 0, i, j, bw, chab, iret, retry = 3;
u8 tmp8, ramtype;
@@ -1970,7 +1928,8 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
ret |= GETREG(SISMISCR, &tmp8);
ret |= SETREG(SISMISCW, (tmp8 | 0x01));
- if (ret) continue;
+ if (ret)
+ continue;
/* Reset registers */
ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
@@ -1979,23 +1938,23 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
ret |= SETREG(SISMISCW, 0x67);
- for (i = 0x06; i <= 0x1f; i++) {
+ for (i = 0x06; i <= 0x1f; i++)
ret |= SETIREG(SISSR, i, 0x00);
- }
- for (i = 0x21; i <= 0x27; i++) {
+
+ for (i = 0x21; i <= 0x27; i++)
ret |= SETIREG(SISSR, i, 0x00);
- }
- for (i = 0x31; i <= 0x3d; i++) {
+
+ for (i = 0x31; i <= 0x3d; i++)
ret |= SETIREG(SISSR, i, 0x00);
- }
- for (i = 0x12; i <= 0x1b; i++) {
+
+ for (i = 0x12; i <= 0x1b; i++)
ret |= SETIREG(SISSR, i, 0x00);
- }
- for (i = 0x79; i <= 0x7c; i++) {
+
+ for (i = 0x79; i <= 0x7c; i++)
ret |= SETIREG(SISCR, i, 0x00);
- }
- if (ret) continue;
+ if (ret)
+ continue;
ret |= SETIREG(SISCR, 0x63, 0x80);
@@ -2013,13 +1972,16 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
ret |= SETIREG(SISSR, 0x07, 0x18);
ret |= SETIREG(SISSR, 0x11, 0x0f);
- if (ret) continue;
+ if (ret)
+ continue;
for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
- ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
+ ret |= SETIREG(SISSR, i,
+ ramtypetable1[(j*4) + ramtype]);
}
for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
- ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
+ ret |= SETIREG(SISCR, i,
+ ramtypetable2[(j*4) + ramtype]);
}
ret |= SETIREG(SISCR, 0x49, 0xaa);
@@ -2036,7 +1998,8 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
- if (ret) continue;
+ if (ret)
+ continue;
ret |= SETIREG(SISPART1, 0x00, 0x00);
@@ -2058,7 +2021,8 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
ret |= SETIREG(SISSR, 0x32, 0x11);
ret |= SETIREG(SISSR, 0x33, 0x00);
- if (ret) continue;
+ if (ret)
+ continue;
ret |= SETIREG(SISCR, 0x83, 0x00);
@@ -2080,13 +2044,15 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
if (ramtype <= 1) {
ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
if (iret) {
- dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
- ret |= SETIREG(SISSR,0x14,0x31);
+ dev_err(&sisusb->sisusb_dev->dev,
+ "RAM size detection failed, assuming 8MB video RAM\n");
+ ret |= SETIREG(SISSR, 0x14, 0x31);
/* TODO */
}
} else {
- dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
- ret |= SETIREG(SISSR,0x14,0x31);
+ dev_err(&sisusb->sisusb_dev->dev,
+ "DDR RAM device found, assuming 8MB video RAM\n");
+ ret |= SETIREG(SISSR, 0x14, 0x31);
/* *** TODO *** */
}
@@ -2117,8 +2083,7 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
#undef READL
#undef WRITEL
-static void
-sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
+static void sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
{
u8 tmp8, tmp82, ramtype;
int bw = 0;
@@ -2127,7 +2092,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
static const char ram_dynamictype[4] = {'D', 'G', 'D', 'G'};
static const int busSDR[4] = {64, 64, 128, 128};
static const int busDDR[4] = {32, 32, 64, 64};
- static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
+ static const int busDDRA[4] = {64+32, 64+32, (64+32)*2, (64+32)*2};
sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
@@ -2135,35 +2100,38 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
ramtype &= 0x03;
switch ((tmp8 >> 2) & 0x03) {
- case 0: ramtypetext1 = "1 ch/1 r";
- if (tmp82 & 0x10) {
+ case 0:
+ ramtypetext1 = "1 ch/1 r";
+ if (tmp82 & 0x10)
bw = 32;
- } else {
+ else
bw = busSDR[(tmp8 & 0x03)];
- }
+
break;
- case 1: ramtypetext1 = "1 ch/2 r";
+ case 1:
+ ramtypetext1 = "1 ch/2 r";
sisusb->vramsize <<= 1;
bw = busSDR[(tmp8 & 0x03)];
break;
- case 2: ramtypetext1 = "asymmeric";
+ case 2:
+ ramtypetext1 = "asymmeric";
sisusb->vramsize += sisusb->vramsize/2;
bw = busDDRA[(tmp8 & 0x03)];
break;
- case 3: ramtypetext1 = "2 channel";
+ case 3:
+ ramtypetext1 = "2 channel";
sisusb->vramsize <<= 1;
bw = busDDR[(tmp8 & 0x03)];
break;
}
-
- dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %cDR S%cRAM, bus width %d\n",
- sisusb->vramsize >> 20, ramtypetext1,
- ram_datarate[ramtype], ram_dynamictype[ramtype], bw);
+ dev_info(&sisusb->sisusb_dev->dev,
+ "%dMB %s %cDR S%cRAM, bus width %d\n",
+ sisusb->vramsize >> 20, ramtypetext1,
+ ram_datarate[ramtype], ram_dynamictype[ramtype], bw);
}
-static int
-sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
+static int sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
{
struct sisusb_packet packet;
int ret;
@@ -2241,8 +2209,7 @@ sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
* of the graphics board.
*/
-static int
-sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
+static int sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
{
int ret = 0, test = 0;
u32 tmp32;
@@ -2250,16 +2217,25 @@ sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
if (sisusb->devinit == 1) {
/* Read PCI BARs and see if they have been set up */
ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
- if (ret) return ret;
- if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
+ if (ret)
+ return ret;
+
+ if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE)
+ test++;
ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
- if (ret) return ret;
- if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
+ if (ret)
+ return ret;
+
+ if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE)
+ test++;
ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
- if (ret) return ret;
- if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
+ if (ret)
+ return ret;
+
+ if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE)
+ test++;
}
/* No? So reset the device */
@@ -2289,20 +2265,20 @@ sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
#ifdef INCL_SISUSB_CON
/* Set up default text mode:
- - Set text mode (0x03)
- - Upload default font
- - Upload user font (if available)
-*/
+ * - Set text mode (0x03)
+ * - Upload default font
+ * - Upload user font (if available)
+ */
-int
-sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
+int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
{
int ret = 0, slot = sisusb->font_slot, i;
const struct font_desc *myfont;
u8 *tempbuf;
u16 *tempbufb;
size_t written;
- static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
+ static const char bootstring[] =
+ "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
static const char bootlogo[] = "(o_ //\\ V_/_";
/* sisusb->lock is down */
@@ -2328,7 +2304,8 @@ sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
/* Upload default font */
- ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
+ ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192,
+ 0, 1, NULL, 16, 0);
vfree(tempbuf);
@@ -2366,7 +2343,7 @@ sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
*(tempbufb++) = 0x0700 | bootstring[i++];
ret |= sisusb_copy_memory(sisusb, tempbuf,
- sisusb->vrambase, 8192, &written);
+ sisusb->vrambase, 8192, &written);
vfree(tempbuf);
@@ -2375,12 +2352,13 @@ sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
} else if (sisusb->scrbuf) {
ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
- sisusb->vrambase, sisusb->scrbuf_size, &written);
+ sisusb->vrambase, sisusb->scrbuf_size,
+ &written);
}
if (sisusb->sisusb_cursor_size_from >= 0 &&
- sisusb->sisusb_cursor_size_to >= 0) {
+ sisusb->sisusb_cursor_size_to >= 0) {
sisusb_setidxreg(sisusb, SISCR, 0x0a,
sisusb->sisusb_cursor_size_from);
sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
@@ -2392,7 +2370,8 @@ sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
}
slot = sisusb->sisusb_cursor_loc;
- if(slot < 0) slot = 0;
+ if (slot < 0)
+ slot = 0;
sisusb->sisusb_cursor_loc = -1;
sisusb->bad_cursor_pos = 1;
@@ -2413,22 +2392,19 @@ sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
/* fops */
-static int
-sisusb_open(struct inode *inode, struct file *file)
+static int sisusb_open(struct inode *inode, struct file *file)
{
struct sisusb_usb_data *sisusb;
struct usb_interface *interface;
int subminor = iminor(inode);
interface = usb_find_interface(&sisusb_driver, subminor);
- if (!interface) {
+ if (!interface)
return -ENODEV;
- }
sisusb = usb_get_intfdata(interface);
- if (!sisusb) {
+ if (!sisusb)
return -ENODEV;
- }
mutex_lock(&sisusb->lock);
@@ -2444,15 +2420,17 @@ sisusb_open(struct inode *inode, struct file *file)
if (!sisusb->devinit) {
if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH ||
- sisusb->sisusb_dev->speed == USB_SPEED_SUPER) {
+ sisusb->sisusb_dev->speed == USB_SPEED_SUPER) {
if (sisusb_init_gfxdevice(sisusb, 0)) {
mutex_unlock(&sisusb->lock);
- dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
+ dev_err(&sisusb->sisusb_dev->dev,
+ "Failed to initialize device\n");
return -EIO;
}
} else {
mutex_unlock(&sisusb->lock);
- dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
+ dev_err(&sisusb->sisusb_dev->dev,
+ "Device not attached to USB 2.0 hub\n");
return -EIO;
}
}
@@ -2469,8 +2447,7 @@ sisusb_open(struct inode *inode, struct file *file)
return 0;
}
-void
-sisusb_delete(struct kref *kref)
+void sisusb_delete(struct kref *kref)
{
struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
@@ -2488,8 +2465,7 @@ sisusb_delete(struct kref *kref)
kfree(sisusb);
}
-static int
-sisusb_release(struct inode *inode, struct file *file)
+static int sisusb_release(struct inode *inode, struct file *file)
{
struct sisusb_usb_data *sisusb;
@@ -2516,8 +2492,8 @@ sisusb_release(struct inode *inode, struct file *file)
return 0;
}
-static ssize_t
-sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+static ssize_t sisusb_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct sisusb_usb_data *sisusb;
ssize_t bytes_read = 0;
@@ -2539,11 +2515,10 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
}
if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
- (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
+ (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
- address = (*ppos) -
- SISUSB_PCI_PSEUDO_IOPORTBASE +
- SISUSB_PCI_IOPORTBASE;
+ address = (*ppos) - SISUSB_PCI_PSEUDO_IOPORTBASE +
+ SISUSB_PCI_IOPORTBASE;
/* Read i/o ports
* Byte, word and long(32) can be read. As this
@@ -2551,82 +2526,77 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
* in machine-endianness.
*/
switch (count) {
+ case 1:
+ if (sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO,
+ address, &buf8))
+ errno = -EIO;
+ else if (put_user(buf8, (u8 __user *)buffer))
+ errno = -EFAULT;
+ else
+ bytes_read = 1;
- case 1:
- if (sisusb_read_memio_byte(sisusb,
- SISUSB_TYPE_IO,
- address, &buf8))
- errno = -EIO;
- else if (put_user(buf8, (u8 __user *)buffer))
- errno = -EFAULT;
- else
- bytes_read = 1;
-
- break;
+ break;
- case 2:
- if (sisusb_read_memio_word(sisusb,
- SISUSB_TYPE_IO,
- address, &buf16))
- errno = -EIO;
- else if (put_user(buf16, (u16 __user *)buffer))
- errno = -EFAULT;
- else
- bytes_read = 2;
+ case 2:
+ if (sisusb_read_memio_word(sisusb, SISUSB_TYPE_IO,
+ address, &buf16))
+ errno = -EIO;
+ else if (put_user(buf16, (u16 __user *)buffer))
+ errno = -EFAULT;
+ else
+ bytes_read = 2;
- break;
+ break;
- case 4:
- if (sisusb_read_memio_long(sisusb,
- SISUSB_TYPE_IO,
- address, &buf32))
- errno = -EIO;
- else if (put_user(buf32, (u32 __user *)buffer))
- errno = -EFAULT;
- else
- bytes_read = 4;
+ case 4:
+ if (sisusb_read_memio_long(sisusb, SISUSB_TYPE_IO,
+ address, &buf32))
+ errno = -EIO;
+ else if (put_user(buf32, (u32 __user *)buffer))
+ errno = -EFAULT;
+ else
+ bytes_read = 4;
- break;
+ break;
- default:
- errno = -EIO;
+ default:
+ errno = -EIO;
}
- } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
- (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
+ } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE && (*ppos) <
+ SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
- address = (*ppos) -
- SISUSB_PCI_PSEUDO_MEMBASE +
- SISUSB_PCI_MEMBASE;
+ address = (*ppos) - SISUSB_PCI_PSEUDO_MEMBASE +
+ SISUSB_PCI_MEMBASE;
/* Read video ram
* Remember: Data delivered is never endian-corrected
*/
errno = sisusb_read_mem_bulk(sisusb, address,
- NULL, count, buffer, &bytes_read);
+ NULL, count, buffer, &bytes_read);
if (bytes_read)
errno = bytes_read;
} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
- (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
+ (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE +
+ SISUSB_PCI_MMIOSIZE) {
- address = (*ppos) -
- SISUSB_PCI_PSEUDO_MMIOBASE +
- SISUSB_PCI_MMIOBASE;
+ address = (*ppos) - SISUSB_PCI_PSEUDO_MMIOBASE +
+ SISUSB_PCI_MMIOBASE;
/* Read MMIO
* Remember: Data delivered is never endian-corrected
*/
errno = sisusb_read_mem_bulk(sisusb, address,
- NULL, count, buffer, &bytes_read);
+ NULL, count, buffer, &bytes_read);
if (bytes_read)
errno = bytes_read;
} else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
- (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
+ (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
if (count != 4) {
mutex_unlock(&sisusb->lock);
@@ -2658,9 +2628,8 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
return errno ? errno : bytes_read;
}
-static ssize_t
-sisusb_write(struct file *file, const char __user *buffer, size_t count,
- loff_t *ppos)
+static ssize_t sisusb_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct sisusb_usb_data *sisusb;
int errno = 0;
@@ -2682,11 +2651,10 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count,
}
if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
- (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
+ (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
- address = (*ppos) -
- SISUSB_PCI_PSEUDO_IOPORTBASE +
- SISUSB_PCI_IOPORTBASE;
+ address = (*ppos) - SISUSB_PCI_PSEUDO_IOPORTBASE +
+ SISUSB_PCI_IOPORTBASE;
/* Write i/o ports
* Byte, word and long(32) can be written. As this
@@ -2694,53 +2662,49 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count,
* in machine-endianness.
*/
switch (count) {
+ case 1:
+ if (get_user(buf8, (u8 __user *)buffer))
+ errno = -EFAULT;
+ else if (sisusb_write_memio_byte(sisusb,
+ SISUSB_TYPE_IO, address, buf8))
+ errno = -EIO;
+ else
+ bytes_written = 1;
- case 1:
- if (get_user(buf8, (u8 __user *)buffer))
- errno = -EFAULT;
- else if (sisusb_write_memio_byte(sisusb,
- SISUSB_TYPE_IO,
- address, buf8))
- errno = -EIO;
- else
- bytes_written = 1;
-
- break;
+ break;
- case 2:
- if (get_user(buf16, (u16 __user *)buffer))
- errno = -EFAULT;
- else if (sisusb_write_memio_word(sisusb,
- SISUSB_TYPE_IO,
- address, buf16))
- errno = -EIO;
- else
- bytes_written = 2;
+ case 2:
+ if (get_user(buf16, (u16 __user *)buffer))
+ errno = -EFAULT;
+ else if (sisusb_write_memio_word(sisusb,
+ SISUSB_TYPE_IO, address, buf16))
+ errno = -EIO;
+ else
+ bytes_written = 2;
- break;
+ break;
- case 4:
- if (get_user(buf32, (u32 __user *)buffer))
- errno = -EFAULT;
- else if (sisusb_write_memio_long(sisusb,
- SISUSB_TYPE_IO,
- address, buf32))
- errno = -EIO;
- else
- bytes_written = 4;
+ case 4:
+ if (get_user(buf32, (u32 __user *)buffer))
+ errno = -EFAULT;
+ else if (sisusb_write_memio_long(sisusb,
+ SISUSB_TYPE_IO, address, buf32))
+ errno = -EIO;
+ else
+ bytes_written = 4;
- break;
+ break;
- default:
- errno = -EIO;
+ default:
+ errno = -EIO;
}
} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
- (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
+ (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE +
+ sisusb->vramsize) {
- address = (*ppos) -
- SISUSB_PCI_PSEUDO_MEMBASE +
- SISUSB_PCI_MEMBASE;
+ address = (*ppos) - SISUSB_PCI_PSEUDO_MEMBASE +
+ SISUSB_PCI_MEMBASE;
/* Write video ram.
* Buffer is copied 1:1, therefore, on big-endian
@@ -2749,17 +2713,17 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count,
* mode or if YUV data is being transferred).
*/
errno = sisusb_write_mem_bulk(sisusb, address, NULL,
- count, buffer, 0, &bytes_written);
+ count, buffer, 0, &bytes_written);
if (bytes_written)
errno = bytes_written;
} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
- (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
+ (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE +
+ SISUSB_PCI_MMIOSIZE) {
- address = (*ppos) -
- SISUSB_PCI_PSEUDO_MMIOBASE +
- SISUSB_PCI_MMIOBASE;
+ address = (*ppos) - SISUSB_PCI_PSEUDO_MMIOBASE +
+ SISUSB_PCI_MMIOBASE;
/* Write MMIO.
* Buffer is copied 1:1, therefore, on big-endian
@@ -2767,13 +2731,14 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count,
* in advance.
*/
errno = sisusb_write_mem_bulk(sisusb, address, NULL,
- count, buffer, 0, &bytes_written);
+ count, buffer, 0, &bytes_written);
if (bytes_written)
errno = bytes_written;
} else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
- (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
+ (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE +
+ SISUSB_PCI_PCONFSIZE) {
if (count != 4) {
mutex_unlock(&sisusb->lock);
@@ -2807,8 +2772,7 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count,
return errno ? errno : bytes_written;
}
-static loff_t
-sisusb_lseek(struct file *file, loff_t offset, int orig)
+static loff_t sisusb_lseek(struct file *file, loff_t offset, int orig)
{
struct sisusb_usb_data *sisusb;
loff_t ret;
@@ -2831,9 +2795,8 @@ sisusb_lseek(struct file *file, loff_t offset, int orig)
return ret;
}
-static int
-sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
- unsigned long arg)
+static int sisusb_handle_command(struct sisusb_usb_data *sisusb,
+ struct sisusb_command *y, unsigned long arg)
{
int retval, port, length;
u32 address;
@@ -2849,105 +2812,99 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
SISUSB_PCI_IOPORTBASE;
switch (y->operation) {
- case SUCMD_GET:
- retval = sisusb_getidxreg(sisusb, port,
- y->data0, &y->data1);
- if (!retval) {
- if (copy_to_user((void __user *)arg, y,
- sizeof(*y)))
- retval = -EFAULT;
- }
- break;
+ case SUCMD_GET:
+ retval = sisusb_getidxreg(sisusb, port, y->data0, &y->data1);
+ if (!retval) {
+ if (copy_to_user((void __user *)arg, y, sizeof(*y)))
+ retval = -EFAULT;
+ }
+ break;
- case SUCMD_SET:
- retval = sisusb_setidxreg(sisusb, port,
- y->data0, y->data1);
- break;
+ case SUCMD_SET:
+ retval = sisusb_setidxreg(sisusb, port, y->data0, y->data1);
+ break;
- case SUCMD_SETOR:
- retval = sisusb_setidxregor(sisusb, port,
- y->data0, y->data1);
- break;
+ case SUCMD_SETOR:
+ retval = sisusb_setidxregor(sisusb, port, y->data0, y->data1);
+ break;
- case SUCMD_SETAND:
- retval = sisusb_setidxregand(sisusb, port,
- y->data0, y->data1);
- break;
+ case SUCMD_SETAND:
+ retval = sisusb_setidxregand(sisusb, port, y->data0, y->data1);
+ break;
- case SUCMD_SETANDOR:
- retval = sisusb_setidxregandor(sisusb, port,
- y->data0, y->data1, y->data2);
- break;
+ case SUCMD_SETANDOR:
+ retval = sisusb_setidxregandor(sisusb, port, y->data0,
+ y->data1, y->data2);
+ break;
- case SUCMD_SETMASK:
- retval = sisusb_setidxregmask(sisusb, port,
- y->data0, y->data1, y->data2);
- break;
+ case SUCMD_SETMASK:
+ retval = sisusb_setidxregmask(sisusb, port, y->data0,
+ y->data1, y->data2);
+ break;
- case SUCMD_CLRSCR:
- /* Gfx core must be initialized */
- if (!sisusb->gfxinit)
- return -ENODEV;
+ case SUCMD_CLRSCR:
+ /* Gfx core must be initialized */
+ if (!sisusb->gfxinit)
+ return -ENODEV;
- length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
- address = y->data3 -
- SISUSB_PCI_PSEUDO_MEMBASE +
+ length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
+ address = y->data3 - SISUSB_PCI_PSEUDO_MEMBASE +
SISUSB_PCI_MEMBASE;
- retval = sisusb_clear_vram(sisusb, address, length);
- break;
+ retval = sisusb_clear_vram(sisusb, address, length);
+ break;
- case SUCMD_HANDLETEXTMODE:
- retval = 0;
+ case SUCMD_HANDLETEXTMODE:
+ retval = 0;
#ifdef INCL_SISUSB_CON
- /* Gfx core must be initialized, SiS_Pr must exist */
- if (!sisusb->gfxinit || !sisusb->SiS_Pr)
- return -ENODEV;
+ /* Gfx core must be initialized, SiS_Pr must exist */
+ if (!sisusb->gfxinit || !sisusb->SiS_Pr)
+ return -ENODEV;
- switch (y->data0) {
- case 0:
- retval = sisusb_reset_text_mode(sisusb, 0);
- break;
- case 1:
- sisusb->textmodedestroyed = 1;
- break;
- }
-#endif
+ switch (y->data0) {
+ case 0:
+ retval = sisusb_reset_text_mode(sisusb, 0);
+ break;
+ case 1:
+ sisusb->textmodedestroyed = 1;
break;
+ }
+#endif
+ break;
#ifdef INCL_SISUSB_CON
- case SUCMD_SETMODE:
- /* Gfx core must be initialized, SiS_Pr must exist */
- if (!sisusb->gfxinit || !sisusb->SiS_Pr)
- return -ENODEV;
+ case SUCMD_SETMODE:
+ /* Gfx core must be initialized, SiS_Pr must exist */
+ if (!sisusb->gfxinit || !sisusb->SiS_Pr)
+ return -ENODEV;
- retval = 0;
+ retval = 0;
- sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
- sisusb->SiS_Pr->sisusb = (void *)sisusb;
+ sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
+ sisusb->SiS_Pr->sisusb = (void *)sisusb;
- if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
- retval = -EINVAL;
+ if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
+ retval = -EINVAL;
- break;
+ break;
- case SUCMD_SETVESAMODE:
- /* Gfx core must be initialized, SiS_Pr must exist */
- if (!sisusb->gfxinit || !sisusb->SiS_Pr)
- return -ENODEV;
+ case SUCMD_SETVESAMODE:
+ /* Gfx core must be initialized, SiS_Pr must exist */
+ if (!sisusb->gfxinit || !sisusb->SiS_Pr)
+ return -ENODEV;
- retval = 0;
+ retval = 0;
- sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
- sisusb->SiS_Pr->sisusb = (void *)sisusb;
+ sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
+ sisusb->SiS_Pr->sisusb = (void *)sisusb;
- if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
- retval = -EINVAL;
+ if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
+ retval = -EINVAL;
- break;
+ break;
#endif
- default:
- retval = -EINVAL;
+ default:
+ retval = -EINVAL;
}
if (retval > 0)
@@ -2956,8 +2913,7 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
return retval;
}
-static long
-sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct sisusb_usb_data *sisusb;
struct sisusb_info x;
@@ -2978,52 +2934,51 @@ sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
switch (cmd) {
+ case SISUSB_GET_CONFIG_SIZE:
- case SISUSB_GET_CONFIG_SIZE:
-
- if (put_user(sizeof(x), argp))
- retval = -EFAULT;
+ if (put_user(sizeof(x), argp))
+ retval = -EFAULT;
- break;
+ break;
- case SISUSB_GET_CONFIG:
-
- x.sisusb_id = SISUSB_ID;
- x.sisusb_version = SISUSB_VERSION;
- x.sisusb_revision = SISUSB_REVISION;
- x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
- x.sisusb_gfxinit = sisusb->gfxinit;
- x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
- x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
- x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
- x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
- x.sisusb_vramsize = sisusb->vramsize;
- x.sisusb_minor = sisusb->minor;
- x.sisusb_fbdevactive= 0;
+ case SISUSB_GET_CONFIG:
+
+ x.sisusb_id = SISUSB_ID;
+ x.sisusb_version = SISUSB_VERSION;
+ x.sisusb_revision = SISUSB_REVISION;
+ x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
+ x.sisusb_gfxinit = sisusb->gfxinit;
+ x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
+ x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
+ x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
+ x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
+ x.sisusb_vramsize = sisusb->vramsize;
+ x.sisusb_minor = sisusb->minor;
+ x.sisusb_fbdevactive = 0;
#ifdef INCL_SISUSB_CON
- x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
+ x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
#else
- x.sisusb_conactive = 0;
+ x.sisusb_conactive = 0;
#endif
- memset(x.sisusb_reserved, 0, sizeof(x.sisusb_reserved));
+ memset(x.sisusb_reserved, 0, sizeof(x.sisusb_reserved));
- if (copy_to_user((void __user *)arg, &x, sizeof(x)))
- retval = -EFAULT;
+ if (copy_to_user((void __user *)arg, &x, sizeof(x)))
+ retval = -EFAULT;
- break;
+ break;
- case SISUSB_COMMAND:
+ case SISUSB_COMMAND:
- if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
- retval = -EFAULT;
- else
- retval = sisusb_handle_command(sisusb, &y, arg);
+ if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
+ retval = -EFAULT;
+ else
+ retval = sisusb_handle_command(sisusb, &y, arg);
- break;
+ break;
- default:
- retval = -ENOTTY;
- break;
+ default:
+ retval = -ENOTTY;
+ break;
}
err_out:
@@ -3032,20 +2987,20 @@ err_out:
}
#ifdef SISUSB_NEW_CONFIG_COMPAT
-static long
-sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+static long sisusb_compat_ioctl(struct file *f, unsigned int cmd,
+ unsigned long arg)
{
long retval;
switch (cmd) {
- case SISUSB_GET_CONFIG_SIZE:
- case SISUSB_GET_CONFIG:
- case SISUSB_COMMAND:
- retval = sisusb_ioctl(f, cmd, arg);
- return retval;
+ case SISUSB_GET_CONFIG_SIZE:
+ case SISUSB_GET_CONFIG:
+ case SISUSB_COMMAND:
+ retval = sisusb_ioctl(f, cmd, arg);
+ return retval;
- default:
- return -ENOIOCTLCMD;
+ default:
+ return -ENOIOCTLCMD;
}
}
#endif
@@ -3070,21 +3025,20 @@ static struct usb_class_driver usb_sisusb_class = {
};
static int sisusb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+ const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct sisusb_usb_data *sisusb;
int retval = 0, i;
dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
- dev->devnum);
+ dev->devnum);
/* Allocate memory for our private */
sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL);
- if (!sisusb) {
- dev_err(&dev->dev, "Failed to allocate memory for private data\n");
+ if (!sisusb)
return -ENOMEM;
- }
+
kref_init(&sisusb->kref);
mutex_init(&(sisusb->lock));
@@ -3092,8 +3046,9 @@ static int sisusb_probe(struct usb_interface *intf,
/* Register device */
retval = usb_register_dev(intf, &usb_sisusb_class);
if (retval) {
- dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
- dev->devnum);
+ dev_err(&sisusb->sisusb_dev->dev,
+ "Failed to get a minor for device %d\n",
+ dev->devnum);
retval = -ENODEV;
goto error_1;
}
@@ -3108,8 +3063,8 @@ static int sisusb_probe(struct usb_interface *intf,
/* Allocate buffers */
sisusb->ibufsize = SISUSB_IBUF_SIZE;
- if (!(sisusb->ibuf = kmalloc(SISUSB_IBUF_SIZE, GFP_KERNEL))) {
- dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
+ sisusb->ibuf = kmalloc(SISUSB_IBUF_SIZE, GFP_KERNEL);
+ if (!sisusb->ibuf) {
retval = -ENOMEM;
goto error_2;
}
@@ -3117,20 +3072,20 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->numobufs = 0;
sisusb->obufsize = SISUSB_OBUF_SIZE;
for (i = 0; i < NUMOBUFS; i++) {
- if (!(sisusb->obuf[i] = kmalloc(SISUSB_OBUF_SIZE, GFP_KERNEL))) {
+ sisusb->obuf[i] = kmalloc(SISUSB_OBUF_SIZE, GFP_KERNEL);
+ if (!sisusb->obuf[i]) {
if (i == 0) {
- dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
retval = -ENOMEM;
goto error_3;
}
break;
- } else
- sisusb->numobufs++;
-
+ }
+ sisusb->numobufs++;
}
/* Allocate URBs */
- if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
+ sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL);
+ if (!sisusb->sisurbin) {
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_3;
@@ -3138,8 +3093,10 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->completein = 1;
for (i = 0; i < sisusb->numobufs; i++) {
- if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
- dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
+ sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!sisusb->sisurbout[i]) {
+ dev_err(&sisusb->sisusb_dev->dev,
+ "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_4;
}
@@ -3148,12 +3105,15 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->urbstatus[i] = 0;
}
- dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
+ dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n",
+ sisusb->numobufs);
#ifdef INCL_SISUSB_CON
/* Allocate our SiS_Pr */
- if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
- dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
+ sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL);
+ if (!sisusb->SiS_Pr) {
+ retval = -ENOMEM;
+ goto error_4;
}
#endif
@@ -3170,17 +3130,18 @@ static int sisusb_probe(struct usb_interface *intf,
if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) {
int initscreen = 1;
#ifdef INCL_SISUSB_CON
- if (sisusb_first_vc > 0 &&
- sisusb_last_vc > 0 &&
- sisusb_first_vc <= sisusb_last_vc &&
- sisusb_last_vc <= MAX_NR_CONSOLES)
+ if (sisusb_first_vc > 0 && sisusb_last_vc > 0 &&
+ sisusb_first_vc <= sisusb_last_vc &&
+ sisusb_last_vc <= MAX_NR_CONSOLES)
initscreen = 0;
#endif
if (sisusb_init_gfxdevice(sisusb, initscreen))
- dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
+ dev_err(&sisusb->sisusb_dev->dev,
+ "Failed to early initialize device\n");
} else
- dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
+ dev_info(&sisusb->sisusb_dev->dev,
+ "Not attached to USB 2.0 hub, deferring init\n");
sisusb->ready = 1;
@@ -3254,7 +3215,7 @@ static const struct usb_device_id sisusb_table[] = {
{ }
};
-MODULE_DEVICE_TABLE (usb, sisusb_table);
+MODULE_DEVICE_TABLE(usb, sisusb_table);
static struct usb_driver sisusb_driver = {
.name = "sisusb",
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index fec3f1128fdc..33ff49c4cea4 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -349,7 +349,7 @@ struct mon_bus *mon_bus_lookup(unsigned int num)
static int __init mon_init(void)
{
struct usb_bus *ubus;
- int rc;
+ int rc, id;
if ((rc = mon_text_init()) != 0)
goto err_text;
@@ -365,12 +365,11 @@ static int __init mon_init(void)
}
// MOD_INC_USE_COUNT(which_module?);
- mutex_lock(&usb_bus_list_lock);
- list_for_each_entry (ubus, &usb_bus_list, bus_list) {
+ mutex_lock(&usb_bus_idr_lock);
+ idr_for_each_entry(&usb_bus_idr, ubus, id)
mon_bus_init(ubus);
- }
usb_register_notify(&mon_nb);
- mutex_unlock(&usb_bus_list_lock);
+ mutex_unlock(&usb_bus_idr_lock);
return 0;
err_reg:
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 45c83baf675d..886526b5fcdd 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -7,6 +7,7 @@
config USB_MUSB_HDRC
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)'
depends on (USB || USB_GADGET)
+ depends on HAS_IOMEM
help
Say Y here if your system has a dual role high speed USB
controller based on the Mentor Graphics silicon IP. Then
@@ -85,6 +86,7 @@ config USB_MUSB_DA8XX
config USB_MUSB_TUSB6010
tristate "TUSB6010"
+ depends on HAS_IOMEM
depends on ARCH_OMAP2PLUS || COMPILE_TEST
depends on NOP_USB_XCEIV = USB_MUSB_HDRC # both built-in or both modules
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index c3791a01ab31..39fd95833eb8 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1901,7 +1901,7 @@ static void musb_recover_from_babble(struct musb *musb)
*/
static struct musb *allocate_instance(struct device *dev,
- struct musb_hdrc_config *config, void __iomem *mbase)
+ const struct musb_hdrc_config *config, void __iomem *mbase)
{
struct musb *musb;
struct musb_hw_ep *ep;
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index fd215fb45fd4..b6afe9e43305 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -438,7 +438,7 @@ struct musb {
*/
unsigned double_buffer_not_ok:1;
- struct musb_hdrc_config *config;
+ const struct musb_hdrc_config *config;
int xceiv_old_state;
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 795a45b1b25b..58487a473521 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -662,7 +662,7 @@ static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */
}
- channel->desired_mode = mode;
+ channel->desired_mode = *mode;
musb_writew(epio, MUSB_TXCSR, csr);
return 0;
@@ -2003,10 +2003,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
qh->offset,
urb->transfer_buffer_length);
- done = musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh,
- urb, xfer_len,
- iso_err);
- if (done)
+ if (musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh, urb,
+ xfer_len, iso_err))
goto finish;
else
dev_err(musb->controller, "error: rx_dma failed\n");
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 7539c3188ffc..8abfe4ec62fb 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -117,8 +117,8 @@ static void configure_channel(struct dma_channel *channel,
u8 bchannel = musb_channel->idx;
u16 csr = 0;
- dev_dbg(musb->controller, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
- channel, packet_sz, dma_addr, len, mode);
+ dev_dbg(musb->controller, "%p, pkt_sz %d, addr %pad, len %d, mode %d\n",
+ channel, packet_sz, &dma_addr, len, mode);
if (mode) {
csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
@@ -152,10 +152,10 @@ static int dma_channel_program(struct dma_channel *channel,
struct musb_dma_controller *controller = musb_channel->controller;
struct musb *musb = controller->private_data;
- dev_dbg(musb->controller, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
+ dev_dbg(musb->controller, "ep%d-%s pkt_sz %d, dma_addr %pad length %d, mode %d\n",
musb_channel->epnum,
musb_channel->transmit ? "Tx" : "Rx",
- packet_sz, dma_addr, len, mode);
+ packet_sz, &dma_addr, len, mode);
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c
index d9b0dc461439..fdab4232cfbf 100644
--- a/drivers/usb/musb/sunxi.c
+++ b/drivers/usb/musb/sunxi.c
@@ -752,6 +752,7 @@ static const struct of_device_id sunxi_musb_match[] = {
{ .compatible = "allwinner,sun8i-a33-musb", },
{}
};
+MODULE_DEVICE_TABLE(of, sunxi_musb_match);
static struct platform_driver sunxi_musb_driver = {
.probe = sunxi_musb_probe,
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index 4c82077da475..e6959ccb4453 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -310,9 +310,9 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
dma_params.frame_count = chdat->transfer_len / 32; /* Burst sz frame */
- dev_dbg(musb->controller, "ep%i %s dma ch%i dma: %08x len: %u(%u) packet_sz: %i(%i)\n",
+ dev_dbg(musb->controller, "ep%i %s dma ch%i dma: %pad len: %u(%u) packet_sz: %i(%i)\n",
chdat->epnum, chdat->tx ? "tx" : "rx",
- ch, dma_addr, chdat->transfer_len, len,
+ ch, &dma_addr, chdat->transfer_len, len,
chdat->transfer_packet_sz, packet_sz);
/*
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index d0b6a1cd7f62..c92a295049ad 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -207,9 +207,6 @@ static int ux500_dma_channel_program(struct dma_channel *channel,
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
- if (!ux500_dma_is_compatible(channel, packet_sz, (void *)dma_addr, len))
- return false;
-
channel->status = MUSB_DMA_STATUS_BUSY;
channel->actual_len = 0;
ret = ux500_configure_channel(channel, packet_sz, mode, dma_addr, len);
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
index 39b424f7f629..a262a4343f29 100644
--- a/drivers/usb/phy/phy-am335x.c
+++ b/drivers/usb/phy/phy-am335x.c
@@ -5,7 +5,6 @@
#include <linux/usb/usb_phy_generic.h>
#include <linux/slab.h>
#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/usb/of.h>
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 5320cb8642cb..980c9dee09eb 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -118,7 +118,8 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
status = USB_EVENT_VBUS;
otg->state = OTG_STATE_B_PERIPHERAL;
nop->phy.last_event = status;
- usb_gadget_vbus_connect(otg->gadget);
+ if (otg->gadget)
+ usb_gadget_vbus_connect(otg->gadget);
/* drawing a "unit load" is *always* OK, except for OTG */
nop_set_vbus_draw(nop, 100);
@@ -128,7 +129,8 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
} else {
nop_set_vbus_draw(nop, 0);
- usb_gadget_vbus_disconnect(otg->gadget);
+ if (otg->gadget)
+ usb_gadget_vbus_disconnect(otg->gadget);
status = USB_EVENT_NONE;
otg->state = OTG_STATE_B_IDLE;
nop->phy.last_event = status;
@@ -184,7 +186,10 @@ static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
}
otg->gadget = gadget;
- otg->state = OTG_STATE_B_IDLE;
+ if (otg->state == OTG_STATE_B_PERIPHERAL)
+ usb_gadget_vbus_connect(gadget);
+ else
+ otg->state = OTG_STATE_B_IDLE;
return 0;
}
diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c
index 3af263cc0caa..8d111ec653e4 100644
--- a/drivers/usb/phy/phy-isp1301-omap.c
+++ b/drivers/usb/phy/phy-isp1301-omap.c
@@ -258,7 +258,7 @@ static void power_down(struct isp1301 *isp)
isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
}
-static void power_up(struct isp1301 *isp)
+static void __maybe_unused power_up(struct isp1301 *isp)
{
// isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index 970a30e155cb..72b387d592c2 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -757,14 +757,8 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
otg->host = host;
dev_dbg(otg->usb_phy->dev, "host driver registered w/ tranceiver\n");
- /*
- * Kick the state machine work, if peripheral is not supported
- * or peripheral is already registered with us.
- */
- if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) {
- pm_runtime_get_sync(otg->usb_phy->dev);
- schedule_work(&motg->sm_work);
- }
+ pm_runtime_get_sync(otg->usb_phy->dev);
+ schedule_work(&motg->sm_work);
return 0;
}
@@ -827,14 +821,8 @@ static int msm_otg_set_peripheral(struct usb_otg *otg,
dev_dbg(otg->usb_phy->dev,
"peripheral driver registered w/ tranceiver\n");
- /*
- * Kick the state machine work, if host is not supported
- * or host is already registered with us.
- */
- if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) {
- pm_runtime_get_sync(otg->usb_phy->dev);
- schedule_work(&motg->sm_work);
- }
+ pm_runtime_get_sync(otg->usb_phy->dev);
+ schedule_work(&motg->sm_work);
return 0;
}
diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig
index ebc99ee076ce..b26d7c339c05 100644
--- a/drivers/usb/renesas_usbhs/Kconfig
+++ b/drivers/usb/renesas_usbhs/Kconfig
@@ -5,7 +5,7 @@
config USB_RENESAS_USBHS
tristate 'Renesas USBHS controller'
depends on USB_GADGET
- depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
+ depends on ARCH_RENESAS || SUPERH || COMPILE_TEST
depends on EXTCON || !EXTCON # if EXTCON=m, USBHS cannot be built-in
default n
help
diff --git a/drivers/usb/renesas_usbhs/Makefile b/drivers/usb/renesas_usbhs/Makefile
index 9e47f477b6d2..d787d05f6546 100644
--- a/drivers/usb/renesas_usbhs/Makefile
+++ b/drivers/usb/renesas_usbhs/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o
-renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o
+renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o
ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
renesas_usbhs-y += mod_host.o
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 5af9ca5d54ab..baeb7d23bf24 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -25,6 +25,7 @@
#include <linux/sysfs.h>
#include "common.h"
#include "rcar2.h"
+#include "rcar3.h"
/*
* image of renesas_usbhs
@@ -477,18 +478,16 @@ static const struct of_device_id usbhs_of_match[] = {
.data = (void *)USBHS_TYPE_RCAR_GEN2,
},
{
- /* Gen3 is compatible with Gen2 */
.compatible = "renesas,usbhs-r8a7795",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = (void *)USBHS_TYPE_RCAR_GEN3,
},
{
.compatible = "renesas,rcar-gen2-usbhs",
.data = (void *)USBHS_TYPE_RCAR_GEN2,
},
{
- /* Gen3 is compatible with Gen2 */
.compatible = "renesas,rcar-gen3-usbhs",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = (void *)USBHS_TYPE_RCAR_GEN3,
},
{ },
};
@@ -578,6 +577,13 @@ static int usbhs_probe(struct platform_device *pdev)
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
}
break;
+ case USBHS_TYPE_RCAR_GEN3:
+ priv->pfunc = usbhs_rcar3_ops;
+ if (!priv->dparam.pipe_configs) {
+ priv->dparam.pipe_configs = usbhsc_new_pipe;
+ priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
+ }
+ break;
default:
if (!info->platform_callback.get_id) {
dev_err(&pdev->dev, "no platform callbacks");
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index c0f5c652d272..b4de70ee16d3 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -46,7 +46,7 @@ static int usbhsf_null_handle(struct usbhs_pkt *pkt, int *is_done)
return -EINVAL;
}
-static struct usbhs_pkt_handle usbhsf_null_handler = {
+static const struct usbhs_pkt_handle usbhsf_null_handler = {
.prepare = usbhsf_null_handle,
.try_run = usbhsf_null_handle,
};
@@ -422,12 +422,12 @@ static int usbhs_dcp_dir_switch_done(struct usbhs_pkt *pkt, int *is_done)
return 0;
}
-struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler = {
+const struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler = {
.prepare = usbhs_dcp_dir_switch_to_write,
.try_run = usbhs_dcp_dir_switch_done,
};
-struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler = {
+const struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler = {
.prepare = usbhs_dcp_dir_switch_to_read,
.try_run = usbhs_dcp_dir_switch_done,
};
@@ -449,7 +449,7 @@ static int usbhsf_dcp_data_stage_try_push(struct usbhs_pkt *pkt, int *is_done)
return pkt->handler->prepare(pkt, is_done);
}
-struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler = {
+const struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler = {
.prepare = usbhsf_dcp_data_stage_try_push,
};
@@ -488,7 +488,7 @@ static int usbhsf_dcp_data_stage_prepare_pop(struct usbhs_pkt *pkt,
return pkt->handler->prepare(pkt, is_done);
}
-struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler = {
+const struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler = {
.prepare = usbhsf_dcp_data_stage_prepare_pop,
};
@@ -600,7 +600,7 @@ static int usbhsf_pio_prepare_push(struct usbhs_pkt *pkt, int *is_done)
return usbhsf_pio_try_push(pkt, is_done);
}
-struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = {
+const struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = {
.prepare = usbhsf_pio_prepare_push,
.try_run = usbhsf_pio_try_push,
};
@@ -730,7 +730,7 @@ usbhs_fifo_read_busy:
return ret;
}
-struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler = {
+const struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler = {
.prepare = usbhsf_prepare_pop,
.try_run = usbhsf_pio_try_pop,
};
@@ -747,7 +747,7 @@ static int usbhsf_ctrl_stage_end(struct usbhs_pkt *pkt, int *is_done)
return 0;
}
-struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler = {
+const struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler = {
.prepare = usbhsf_ctrl_stage_end,
.try_run = usbhsf_ctrl_stage_end,
};
@@ -934,7 +934,7 @@ static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done)
return 0;
}
-struct usbhs_pkt_handle usbhs_fifo_dma_push_handler = {
+const struct usbhs_pkt_handle usbhs_fifo_dma_push_handler = {
.prepare = usbhsf_dma_prepare_push,
.dma_done = usbhsf_dma_push_done,
};
@@ -1182,7 +1182,7 @@ static int usbhsf_dma_pop_done(struct usbhs_pkt *pkt, int *is_done)
return usbhsf_dma_pop_done_with_rx_irq(pkt, is_done);
}
-struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler = {
+const struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler = {
.prepare = usbhsf_dma_prepare_pop,
.try_run = usbhsf_dma_try_pop,
.dma_done = usbhsf_dma_pop_done
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index c7d9b86d51bf..8b98507d7abc 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -54,7 +54,7 @@ struct usbhs_pkt_handle;
struct usbhs_pkt {
struct list_head node;
struct usbhs_pipe *pipe;
- struct usbhs_pkt_handle *handler;
+ const struct usbhs_pkt_handle *handler;
void (*done)(struct usbhs_priv *priv,
struct usbhs_pkt *pkt);
struct work_struct work;
@@ -86,18 +86,18 @@ void usbhs_fifo_clear_dcp(struct usbhs_pipe *pipe);
/*
* packet info
*/
-extern struct usbhs_pkt_handle usbhs_fifo_pio_push_handler;
-extern struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler;
-extern struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler;
+extern const struct usbhs_pkt_handle usbhs_fifo_pio_push_handler;
+extern const struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler;
+extern const struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler;
-extern struct usbhs_pkt_handle usbhs_fifo_dma_push_handler;
-extern struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler;
+extern const struct usbhs_pkt_handle usbhs_fifo_dma_push_handler;
+extern const struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler;
-extern struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler;
-extern struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler;
+extern const struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler;
+extern const struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler;
-extern struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler;
-extern struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler;
+extern const struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler;
+extern const struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler;
void usbhs_pkt_init(struct usbhs_pkt *pkt);
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 657f9672ceba..664b263e4b20 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -561,7 +561,7 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep)
if (!pkt)
break;
- usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ECONNRESET);
+ usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ESHUTDOWN);
}
usbhs_pipe_disable(pipe);
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index 0e95d2925dc5..78e9dba701c4 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -241,7 +241,7 @@ static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
int timeout = 1024;
- u16 val;
+ u16 mask = usbhs_mod_is_host(priv) ? (CSSTS | PID_MASK) : PID_MASK;
/*
* make sure....
@@ -265,9 +265,7 @@ static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe)
usbhs_pipe_disable(pipe);
do {
- val = usbhsp_pipectrl_get(pipe);
- val &= CSSTS | PID_MASK;
- if (!val)
+ if (!(usbhsp_pipectrl_get(pipe) & mask))
return 0;
udelay(10);
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index 3212ab51e844..7835747f9803 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -38,7 +38,7 @@ struct usbhs_pipe {
#define USBHS_PIPE_FLAGS_IS_DIR_HOST (1 << 2)
#define USBHS_PIPE_FLAGS_IS_RUNNING (1 << 3)
- struct usbhs_pkt_handle *handler;
+ const struct usbhs_pkt_handle *handler;
void *mod_private;
};
diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c
new file mode 100644
index 000000000000..38b01f2aeeb0
--- /dev/null
+++ b/drivers/usb/renesas_usbhs/rcar3.c
@@ -0,0 +1,54 @@
+/*
+ * Renesas USB driver R-Car Gen. 3 initialization and power control
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/io.h>
+#include "common.h"
+#include "rcar3.h"
+
+#define LPSTS 0x102
+#define UGCTRL2 0x184 /* 32-bit register */
+
+/* Low Power Status register (LPSTS) */
+#define LPSTS_SUSPM 0x4000
+
+/* USB General control register 2 (UGCTRL2), bit[31:6] should be 0 */
+#define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */
+#define UGCTRL2_USB0SEL_OTG 0x00000030
+
+void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
+{
+ iowrite32(data, priv->base + reg);
+}
+
+static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
+ void __iomem *base, int enable)
+{
+ struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+
+ usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG);
+
+ if (enable)
+ usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
+ else
+ usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0);
+
+ return 0;
+}
+
+static int usbhs_rcar3_get_id(struct platform_device *pdev)
+{
+ return USBHS_GADGET;
+}
+
+const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
+ .power_ctrl = usbhs_rcar3_power_ctrl,
+ .get_id = usbhs_rcar3_get_id,
+};
diff --git a/drivers/usb/renesas_usbhs/rcar3.h b/drivers/usb/renesas_usbhs/rcar3.h
new file mode 100644
index 000000000000..5f850b23ff18
--- /dev/null
+++ b/drivers/usb/renesas_usbhs/rcar3.h
@@ -0,0 +1,3 @@
+#include "common.h"
+
+extern const struct renesas_usbhs_platform_callback usbhs_rcar3_ops;
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index f612dda9c977..56ecb8b5115d 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -475,22 +475,6 @@ config USB_SERIAL_MOS7840
To compile this driver as a module, choose M here: the
module will be called mos7840. If unsure, choose N.
-config USB_SERIAL_MXUPORT11
- tristate "USB Moxa UPORT 11x0 Serial Driver"
- ---help---
- Say Y here if you want to use a MOXA UPort 11x0 Serial hub.
-
- This driver supports:
-
- - UPort 1110 : 1 port RS-232 USB to Serial Hub.
- - UPort 1130 : 1 port RS-422/485 USB to Serial Hub.
- - UPort 1130I : 1 port RS-422/485 USB to Serial Hub with Isolation.
- - UPort 1150 : 1 port RS-232/422/485 USB to Serial Hub.
- - UPort 1150I : 1 port RS-232/422/485 USB to Serial Hub with Isolation.
-
- To compile this driver as a module, choose M here: the
- module will be called mxu11x0.
-
config USB_SERIAL_MXUPORT
tristate "USB Moxa UPORT Serial Driver"
---help---
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index f3fa5e53702d..349d9df0895f 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -38,7 +38,6 @@ obj-$(CONFIG_USB_SERIAL_METRO) += metro-usb.o
obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_MXUPORT) += mxuport.o
-obj-$(CONFIG_USB_SERIAL_MXUPORT11) += mxu11x0.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index c73808f095bb..f139488d0816 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -370,7 +370,7 @@ static void ch341_set_termios(struct tty_struct *tty,
static void ch341_break_ctl(struct tty_struct *tty, int break_state)
{
const uint16_t ch341_break_reg =
- CH341_REG_BREAK1 | ((uint16_t) CH341_REG_BREAK2 << 8);
+ ((uint16_t) CH341_REG_BREAK2 << 8) | CH341_REG_BREAK1;
struct usb_serial_port *port = tty->driver_data;
int r;
uint16_t reg_contents;
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 3806e7014199..a66b01bb1fa1 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -147,10 +147,7 @@ static int usb_console_setup(struct console *co, char *options)
kref_get(&tty->driver->kref);
__module_get(tty->driver->owner);
tty->ops = &usb_console_fake_tty_ops;
- if (tty_init_termios(tty)) {
- retval = -ENOMEM;
- goto put_tty;
- }
+ tty_init_termios(tty);
tty_port_tty_set(&port->port, tty);
}
@@ -185,7 +182,6 @@ static int usb_console_setup(struct console *co, char *options)
fail:
tty_port_tty_set(&port->port, NULL);
- put_tty:
tty_kref_put(tty);
reset_open_count:
port->port.count = 0;
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 987813b8a7f9..fbfe761c7fba 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -163,6 +163,9 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
{ USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */
+ { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */
+ { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC 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 */
{ USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */
@@ -324,113 +327,169 @@ struct cp210x_comm_status {
#define PURGE_ALL 0x000f
/*
- * cp210x_get_config
- * Reads from the CP210x configuration registers
- * 'size' is specified in bytes.
- * 'data' is a pointer to a pre-allocated array of integers large
- * enough to hold 'size' bytes (with 4 bytes to each integer)
+ * Reads a variable-sized block of CP210X_ registers, identified by req.
+ * Returns data into buf in native USB byte order.
*/
-static int cp210x_get_config(struct usb_serial_port *port, u8 request,
- unsigned int *data, int size)
+static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
+ void *buf, int bufsize)
{
struct usb_serial *serial = port->serial;
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
- __le32 *buf;
- int result, i, length;
-
- /* Number of integers required to contain the array */
- length = (((size - 1) | 3) + 1) / 4;
+ void *dmabuf;
+ int result;
- buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
- if (!buf)
+ dmabuf = kmalloc(bufsize, GFP_KERNEL);
+ if (!dmabuf) {
+ /*
+ * FIXME Some callers don't bother to check for error,
+ * at least give them consistent junk until they are fixed
+ */
+ memset(buf, 0, bufsize);
return -ENOMEM;
+ }
- /* Issue the request, attempting to read 'size' bytes */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- request, REQTYPE_INTERFACE_TO_HOST, 0x0000,
- port_priv->bInterfaceNumber, buf, size,
- USB_CTRL_GET_TIMEOUT);
+ req, REQTYPE_INTERFACE_TO_HOST, 0,
+ port_priv->bInterfaceNumber, dmabuf, bufsize,
+ USB_CTRL_SET_TIMEOUT);
+ if (result == bufsize) {
+ memcpy(buf, dmabuf, bufsize);
+ result = 0;
+ } else {
+ dev_err(&port->dev, "failed get req 0x%x size %d status: %d\n",
+ req, bufsize, result);
+ if (result >= 0)
+ result = -EPROTO;
- /* Convert data into an array of integers */
- for (i = 0; i < length; i++)
- data[i] = le32_to_cpu(buf[i]);
+ /*
+ * FIXME Some callers don't bother to check for error,
+ * at least give them consistent junk until they are fixed
+ */
+ memset(buf, 0, bufsize);
+ }
- kfree(buf);
+ kfree(dmabuf);
- if (result != size) {
- dev_dbg(&port->dev, "%s - Unable to send config request, request=0x%x size=%d result=%d\n",
- __func__, request, size, result);
- if (result > 0)
- result = -EPROTO;
+ return result;
+}
- return result;
+/*
+ * Reads any 32-bit CP210X_ register identified by req.
+ */
+static int cp210x_read_u32_reg(struct usb_serial_port *port, u8 req, u32 *val)
+{
+ __le32 le32_val;
+ int err;
+
+ err = cp210x_read_reg_block(port, req, &le32_val, sizeof(le32_val));
+ if (err) {
+ /*
+ * FIXME Some callers don't bother to check for error,
+ * at least give them consistent junk until they are fixed
+ */
+ *val = 0;
+ return err;
}
+ *val = le32_to_cpu(le32_val);
+
+ return 0;
+}
+
+/*
+ * Reads any 16-bit CP210X_ register identified by req.
+ */
+static int cp210x_read_u16_reg(struct usb_serial_port *port, u8 req, u16 *val)
+{
+ __le16 le16_val;
+ int err;
+
+ err = cp210x_read_reg_block(port, req, &le16_val, sizeof(le16_val));
+ if (err)
+ return err;
+
+ *val = le16_to_cpu(le16_val);
+
return 0;
}
/*
- * cp210x_set_config
- * Writes to the CP210x configuration registers
- * Values less than 16 bits wide are sent directly
- * 'size' is specified in bytes.
+ * Reads any 8-bit CP210X_ register identified by req.
+ */
+static int cp210x_read_u8_reg(struct usb_serial_port *port, u8 req, u8 *val)
+{
+ return cp210x_read_reg_block(port, req, val, sizeof(*val));
+}
+
+/*
+ * Writes any 16-bit CP210X_ register (req) whose value is passed
+ * entirely in the wValue field of the USB request.
*/
-static int cp210x_set_config(struct usb_serial_port *port, u8 request,
- unsigned int *data, int size)
+static int cp210x_write_u16_reg(struct usb_serial_port *port, u8 req, u16 val)
{
struct usb_serial *serial = port->serial;
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
- __le32 *buf;
- int result, i, length;
+ int result;
+
+ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ req, REQTYPE_HOST_TO_INTERFACE, val,
+ port_priv->bInterfaceNumber, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ if (result < 0) {
+ dev_err(&port->dev, "failed set request 0x%x status: %d\n",
+ req, result);
+ }
+
+ return result;
+}
- /* Number of integers required to contain the array */
- length = (((size - 1) | 3) + 1) / 4;
+/*
+ * Writes a variable-sized block of CP210X_ registers, identified by req.
+ * Data in buf must be in native USB byte order.
+ */
+static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req,
+ void *buf, int bufsize)
+{
+ struct usb_serial *serial = port->serial;
+ struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
+ void *dmabuf;
+ int result;
- buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
- if (!buf)
+ dmabuf = kmalloc(bufsize, GFP_KERNEL);
+ if (!dmabuf)
return -ENOMEM;
- /* Array of integers into bytes */
- for (i = 0; i < length; i++)
- buf[i] = cpu_to_le32(data[i]);
+ memcpy(dmabuf, buf, bufsize);
- if (size > 2) {
- result = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- request, REQTYPE_HOST_TO_INTERFACE, 0x0000,
- port_priv->bInterfaceNumber, buf, size,
- USB_CTRL_SET_TIMEOUT);
- } else {
- result = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- request, REQTYPE_HOST_TO_INTERFACE, data[0],
- port_priv->bInterfaceNumber, NULL, 0,
- USB_CTRL_SET_TIMEOUT);
- }
+ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ req, REQTYPE_HOST_TO_INTERFACE, 0,
+ port_priv->bInterfaceNumber, dmabuf, bufsize,
+ USB_CTRL_SET_TIMEOUT);
- kfree(buf);
+ kfree(dmabuf);
- if ((size > 2 && result != size) || result < 0) {
- dev_dbg(&port->dev, "%s - Unable to send request, request=0x%x size=%d result=%d\n",
- __func__, request, size, result);
- if (result > 0)
+ if (result == bufsize) {
+ result = 0;
+ } else {
+ dev_err(&port->dev, "failed set req 0x%x size %d status: %d\n",
+ req, bufsize, result);
+ if (result >= 0)
result = -EPROTO;
-
- return result;
}
- return 0;
+ return result;
}
/*
- * cp210x_set_config_single
- * Convenience function for calling cp210x_set_config on single data values
- * without requiring an integer pointer
+ * Writes any 32-bit CP210X_ register identified by req.
*/
-static inline int cp210x_set_config_single(struct usb_serial_port *port,
- u8 request, unsigned int data)
+static int cp210x_write_u32_reg(struct usb_serial_port *port, u8 req, u32 val)
{
- return cp210x_set_config(port, request, &data, 2);
+ __le32 le32_val;
+
+ le32_val = cpu_to_le32(val);
+
+ return cp210x_write_reg_block(port, req, &le32_val, sizeof(le32_val));
}
/*
@@ -442,47 +501,46 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port,
static int cp210x_detect_swapped_line_ctl(struct usb_serial_port *port)
{
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
- unsigned int line_ctl_save;
- unsigned int line_ctl_test;
+ u16 line_ctl_save;
+ u16 line_ctl_test;
int err;
- err = cp210x_get_config(port, CP210X_GET_LINE_CTL, &line_ctl_save, 2);
+ err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_save);
if (err)
return err;
- line_ctl_test = 0x800;
- err = cp210x_set_config(port, CP210X_SET_LINE_CTL, &line_ctl_test, 2);
+ err = cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, 0x800);
if (err)
return err;
- err = cp210x_get_config(port, CP210X_GET_LINE_CTL, &line_ctl_test, 2);
+ err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_test);
if (err)
return err;
if (line_ctl_test == 8) {
port_priv->has_swapped_line_ctl = true;
- line_ctl_save = swab16((u16)line_ctl_save);
+ line_ctl_save = swab16(line_ctl_save);
}
- return cp210x_set_config(port, CP210X_SET_LINE_CTL, &line_ctl_save, 2);
+ return cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, line_ctl_save);
}
/*
- * Must always be called instead of cp210x_get_config(CP210X_GET_LINE_CTL)
+ * Must always be called instead of cp210x_read_u16_reg(CP210X_GET_LINE_CTL)
* to workaround cp2108 bug and get correct value.
*/
-static int cp210x_get_line_ctl(struct usb_serial_port *port, unsigned int *ctl)
+static int cp210x_get_line_ctl(struct usb_serial_port *port, u16 *ctl)
{
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
int err;
- err = cp210x_get_config(port, CP210X_GET_LINE_CTL, ctl, 2);
+ err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, ctl);
if (err)
return err;
/* Workaround swapped bytes in 16-bit value from CP210X_GET_LINE_CTL */
if (port_priv->has_swapped_line_ctl)
- *ctl = swab16((u16)(*ctl));
+ *ctl = swab16(*ctl);
return 0;
}
@@ -533,8 +591,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result;
- result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
- UART_ENABLE);
+ result = cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_ENABLE);
if (result) {
dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);
return result;
@@ -552,15 +609,12 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
static void cp210x_close(struct usb_serial_port *port)
{
- unsigned int purge_ctl;
-
usb_serial_generic_close(port);
/* Clear both queues; cp2108 needs this to avoid an occasional hang */
- purge_ctl = PURGE_ALL;
- cp210x_set_config(port, CP210X_PURGE, &purge_ctl, 2);
+ cp210x_write_u16_reg(port, CP210X_PURGE, PURGE_ALL);
- cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
+ cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_DISABLE);
}
/*
@@ -638,11 +692,12 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
unsigned int *cflagp, unsigned int *baudp)
{
struct device *dev = &port->dev;
- unsigned int cflag, modem_ctl[4];
- unsigned int baud;
- unsigned int bits;
+ unsigned int cflag;
+ u8 modem_ctl[16];
+ u32 baud;
+ u16 bits;
- cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
+ cp210x_read_u32_reg(port, CP210X_GET_BAUDRATE, &baud);
dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud);
*baudp = baud;
@@ -673,14 +728,14 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
cflag |= CS8;
bits &= ~BITS_DATA_MASK;
bits |= BITS_DATA_8;
- cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
+ cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
break;
default:
dev_dbg(dev, "%s - Unknown number of data bits, using 8\n", __func__);
cflag |= CS8;
bits &= ~BITS_DATA_MASK;
bits |= BITS_DATA_8;
- cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
+ cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
break;
}
@@ -711,7 +766,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
dev_dbg(dev, "%s - Unknown parity mode, disabling parity\n", __func__);
cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK;
- cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
+ cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
break;
}
@@ -723,7 +778,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
case BITS_STOP_1_5:
dev_dbg(dev, "%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__);
bits &= ~BITS_STOP_MASK;
- cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
+ cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
break;
case BITS_STOP_2:
dev_dbg(dev, "%s - stop bits = 2\n", __func__);
@@ -732,12 +787,13 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
default:
dev_dbg(dev, "%s - Unknown number of stop bits, using 1 stop bit\n", __func__);
bits &= ~BITS_STOP_MASK;
- cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
+ cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
break;
}
- cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
- if (modem_ctl[0] & 0x0008) {
+ cp210x_read_reg_block(port, CP210X_GET_FLOW, modem_ctl,
+ sizeof(modem_ctl));
+ if (modem_ctl[0] & 0x08) {
dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
cflag |= CRTSCTS;
} else {
@@ -789,8 +845,7 @@ static void cp210x_change_speed(struct tty_struct *tty,
baud = cp210x_quantise_baudrate(baud);
dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud);
- if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud,
- sizeof(baud))) {
+ if (cp210x_write_u32_reg(port, CP210X_SET_BAUDRATE, baud)) {
dev_warn(&port->dev, "failed to set baud rate to %u\n", baud);
if (old_termios)
baud = old_termios->c_ospeed;
@@ -806,8 +861,8 @@ static void cp210x_set_termios(struct tty_struct *tty,
{
struct device *dev = &port->dev;
unsigned int cflag, old_cflag;
- unsigned int bits;
- unsigned int modem_ctl[4];
+ u16 bits;
+ u8 modem_ctl[16];
cflag = tty->termios.c_cflag;
old_cflag = old_termios->c_cflag;
@@ -845,7 +900,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
bits |= BITS_DATA_8;
break;
}
- if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
+ if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
dev_dbg(dev, "Number of data bits requested not supported by device\n");
}
@@ -872,7 +927,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
}
}
}
- if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
+ if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
dev_dbg(dev, "Parity mode not supported by device\n");
}
@@ -886,32 +941,40 @@ static void cp210x_set_termios(struct tty_struct *tty,
bits |= BITS_STOP_1;
dev_dbg(dev, "%s - stop bits = 1\n", __func__);
}
- if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
+ if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
dev_dbg(dev, "Number of stop bits requested not supported by device\n");
}
if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
- cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
- dev_dbg(dev, "%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n",
- __func__, modem_ctl[0], modem_ctl[1],
- modem_ctl[2], modem_ctl[3]);
+
+ /* Only bytes 0, 4 and 7 out of first 8 have functional bits */
+
+ cp210x_read_reg_block(port, CP210X_GET_FLOW, modem_ctl,
+ sizeof(modem_ctl));
+ dev_dbg(dev, "%s - read modem controls = %02x .. .. .. %02x .. .. %02x\n",
+ __func__, modem_ctl[0], modem_ctl[4], modem_ctl[7]);
if (cflag & CRTSCTS) {
modem_ctl[0] &= ~0x7B;
modem_ctl[0] |= 0x09;
- modem_ctl[1] = 0x80;
+ modem_ctl[4] = 0x80;
+ /* FIXME - why clear reserved bits just read? */
+ modem_ctl[5] = 0;
+ modem_ctl[6] = 0;
+ modem_ctl[7] = 0;
dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
} else {
modem_ctl[0] &= ~0x7B;
modem_ctl[0] |= 0x01;
- modem_ctl[1] |= 0x40;
+ /* FIXME - OR here instead of assignment looks wrong */
+ modem_ctl[4] |= 0x40;
dev_dbg(dev, "%s - flow control = NONE\n", __func__);
}
- dev_dbg(dev, "%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n",
- __func__, modem_ctl[0], modem_ctl[1],
- modem_ctl[2], modem_ctl[3]);
- cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16);
+ dev_dbg(dev, "%s - write modem controls = %02x .. .. .. %02x .. .. %02x\n",
+ __func__, modem_ctl[0], modem_ctl[4], modem_ctl[7]);
+ cp210x_write_reg_block(port, CP210X_SET_FLOW, modem_ctl,
+ sizeof(modem_ctl));
}
}
@@ -926,7 +989,7 @@ static int cp210x_tiocmset(struct tty_struct *tty,
static int cp210x_tiocmset_port(struct usb_serial_port *port,
unsigned int set, unsigned int clear)
{
- unsigned int control = 0;
+ u16 control = 0;
if (set & TIOCM_RTS) {
control |= CONTROL_RTS;
@@ -947,7 +1010,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control);
- return cp210x_set_config(port, CP210X_SET_MHS, &control, 2);
+ return cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
}
static void cp210x_dtr_rts(struct usb_serial_port *p, int on)
@@ -961,10 +1024,10 @@ static void cp210x_dtr_rts(struct usb_serial_port *p, int on)
static int cp210x_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- unsigned int control;
+ u8 control;
int result;
- cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);
+ cp210x_read_u8_reg(port, CP210X_GET_MDMSTS, &control);
result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
|((control & CONTROL_RTS) ? TIOCM_RTS : 0)
@@ -981,7 +1044,7 @@ static int cp210x_tiocmget(struct tty_struct *tty)
static void cp210x_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- unsigned int state;
+ u16 state;
if (break_state == 0)
state = BREAK_OFF;
@@ -989,7 +1052,7 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state)
state = BREAK_ON;
dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
state == BREAK_OFF ? "off" : "on");
- cp210x_set_config(port, CP210X_SET_BREAK, &state, 2);
+ cp210x_write_u16_reg(port, CP210X_SET_BREAK, state);
}
static int cp210x_port_probe(struct usb_serial_port *port)
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 2916dea3ede8..5f17a3b9916d 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -140,7 +140,6 @@ static int cyberjack_open(struct tty_struct *tty,
{
struct cyberjack_private *priv;
unsigned long flags;
- int result = 0;
dev_dbg(&port->dev, "%s - usb_clear_halt\n", __func__);
usb_clear_halt(port->serial->dev, port->write_urb->pipe);
@@ -152,7 +151,7 @@ static int cyberjack_open(struct tty_struct *tty,
priv->wrsent = 0;
spin_unlock_irqrestore(&priv->lock, flags);
- return result;
+ return 0;
}
static void cyberjack_close(struct usb_serial_port *port)
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 01bf53392819..b283eb8b86d6 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -1165,8 +1165,7 @@ static void cypress_read_int_callback(struct urb *urb)
/* hangup, as defined in acm.c... this might be a bad place for it
* though */
- if (tty && !(tty->termios.c_cflag & CLOCAL) &&
- !(priv->current_status & UART_CD)) {
+ if (tty && !C_CLOCAL(tty) && !(priv->current_status & UART_CD)) {
dev_dbg(dev, "%s - calling hangup\n", __func__);
tty_hangup(tty);
goto continue_read;
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 12b0e67473ba..010a42a92688 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -695,11 +695,11 @@ static void digi_set_termios(struct tty_struct *tty,
arg = -1;
/* reassert DTR and (maybe) RTS on transition from B0 */
- if ((old_cflag&CBAUD) == B0) {
+ if ((old_cflag & CBAUD) == B0) {
/* don't set RTS if using hardware flow control */
/* and throttling input */
modem_signals = TIOCM_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
+ if (!C_CRTSCTS(tty) ||
!test_bit(TTY_THROTTLED, &tty->flags))
modem_signals |= TIOCM_RTS;
digi_set_modem_signals(port, modem_signals, 1);
@@ -1491,8 +1491,8 @@ static int digi_read_oob_callback(struct urb *urb)
rts = 0;
if (tty)
- rts = tty->termios.c_cflag & CRTSCTS;
-
+ rts = C_CRTSCTS(tty);
+
if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
spin_lock(&priv->dp_port_lock);
/* convert from digi flags to termiox flags */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 8c660ae401d8..427ae43ee898 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1320,11 +1320,11 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
if (baud <= 3000000) {
__u16 product_id = le16_to_cpu(
port->serial->dev->descriptor.idProduct);
- if (((FTDI_NDI_HUC_PID == product_id) ||
- (FTDI_NDI_SPECTRA_SCU_PID == product_id) ||
- (FTDI_NDI_FUTURE_2_PID == product_id) ||
- (FTDI_NDI_FUTURE_3_PID == product_id) ||
- (FTDI_NDI_AURORA_SCU_PID == product_id)) &&
+ if (((product_id == FTDI_NDI_HUC_PID) ||
+ (product_id == FTDI_NDI_SPECTRA_SCU_PID) ||
+ (product_id == FTDI_NDI_FUTURE_2_PID) ||
+ (product_id == FTDI_NDI_FUTURE_3_PID) ||
+ (product_id == FTDI_NDI_AURORA_SCU_PID)) &&
(baud == 19200)) {
baud = 1200000;
}
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index ed58c6fa8dbe..bbcc13df11ac 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -239,11 +239,11 @@ enum ftdi_sio_baudrate {
*/
#define FTDI_SIO_SET_DTR_MASK 0x1
-#define FTDI_SIO_SET_DTR_HIGH (1 | (FTDI_SIO_SET_DTR_MASK << 8))
-#define FTDI_SIO_SET_DTR_LOW (0 | (FTDI_SIO_SET_DTR_MASK << 8))
+#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1)
+#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0)
#define FTDI_SIO_SET_RTS_MASK 0x2
-#define FTDI_SIO_SET_RTS_HIGH (2 | (FTDI_SIO_SET_RTS_MASK << 8))
-#define FTDI_SIO_SET_RTS_LOW (0 | (FTDI_SIO_SET_RTS_MASK << 8))
+#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2)
+#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0)
/*
* ControlValue
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index db591d19d416..97cabf803c2f 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -237,10 +237,10 @@ static inline int getDataLength(const __u8 *usbPacket)
*/
static inline int isAbortTrfCmnd(const unsigned char *buf)
{
- if (0 == memcmp(buf, GARMIN_STOP_TRANSFER_REQ,
- sizeof(GARMIN_STOP_TRANSFER_REQ)) ||
- 0 == memcmp(buf, GARMIN_STOP_TRANSFER_REQ_V2,
- sizeof(GARMIN_STOP_TRANSFER_REQ_V2)))
+ if (memcmp(buf, GARMIN_STOP_TRANSFER_REQ,
+ sizeof(GARMIN_STOP_TRANSFER_REQ)) == 0 ||
+ memcmp(buf, GARMIN_STOP_TRANSFER_REQ_V2,
+ sizeof(GARMIN_STOP_TRANSFER_REQ_V2)) == 0)
return 1;
else
return 0;
@@ -350,7 +350,7 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id)
unsigned l = 0;
dev_dbg(&garmin_data_p->port->dev, "%s - pkt-id: 0x%X.\n", __func__,
- 0xFF & pkt_id);
+ pkt_id);
*ptr++ = DLE;
*ptr++ = ACK;
@@ -366,7 +366,7 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id)
*ptr++ = DLE;
*ptr++ = 0;
- *ptr++ = 0xFF & (-cksum);
+ *ptr++ = (-cksum) & 0xFF;
*ptr++ = DLE;
*ptr++ = ETX;
@@ -423,9 +423,9 @@ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count)
n++;
}
- if ((0xff & (cksum + *recpkt)) != 0) {
+ if (((cksum + *recpkt) & 0xff) != 0) {
dev_dbg(dev, "%s - invalid checksum, expected %02x, got %02x\n",
- __func__, 0xff & -cksum, 0xff & *recpkt);
+ __func__, -cksum & 0xff, *recpkt);
return -EINVPKT;
}
@@ -528,7 +528,7 @@ static int gsp_receive(struct garmin_data *garmin_data_p,
dev_dbg(dev, "NAK packet complete.\n");
} else {
dev_dbg(dev, "packet complete - id=0x%X.\n",
- 0xFF & data);
+ data);
gsp_rec_packet(garmin_data_p, size);
}
@@ -636,7 +636,7 @@ static int gsp_send(struct garmin_data *garmin_data_p,
garmin_data_p->outsize = 0;
- if (GARMIN_LAYERID_APPL != getLayerId(garmin_data_p->outbuffer)) {
+ if (getLayerId(garmin_data_p->outbuffer) != GARMIN_LAYERID_APPL) {
dev_dbg(dev, "not an application packet (%d)\n",
getLayerId(garmin_data_p->outbuffer));
return -1;
@@ -688,7 +688,7 @@ static int gsp_send(struct garmin_data *garmin_data_p,
*dst++ = DLE;
}
- cksum = 0xFF & -cksum;
+ cksum = -cksum & 0xFF;
*dst++ = cksum;
if (cksum == DLE)
*dst++ = DLE;
@@ -860,7 +860,6 @@ static int process_resetdev_request(struct usb_serial_port *port)
static int garmin_clear(struct garmin_data *garmin_data_p)
{
unsigned long flags;
- int status = 0;
/* flush all queued data */
pkt_clear(garmin_data_p);
@@ -870,7 +869,7 @@ static int garmin_clear(struct garmin_data *garmin_data_p)
garmin_data_p->outsize = 0;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
- return status;
+ return 0;
}
@@ -970,7 +969,7 @@ static void garmin_write_bulk_callback(struct urb *urb)
struct garmin_data *garmin_data_p =
usb_get_serial_port_data(port);
- if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) {
+ if (getLayerId(urb->transfer_buffer) == GARMIN_LAYERID_APPL) {
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
gsp_send_ack(garmin_data_p,
@@ -1025,7 +1024,7 @@ static int garmin_write_bulk(struct usb_serial_port *port,
dismiss_ack ? NULL : port);
urb->transfer_flags |= URB_ZERO_PACKET;
- if (GARMIN_LAYERID_APPL == getLayerId(buffer)) {
+ if (getLayerId(buffer) == GARMIN_LAYERID_APPL) {
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= APP_REQ_SEEN;
@@ -1077,9 +1076,9 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
pktsiz = getDataLength(garmin_data_p->privpkt);
pktid = getPacketId(garmin_data_p->privpkt);
- if (count == (GARMIN_PKTHDR_LENGTH+pktsiz)
- && GARMIN_LAYERID_PRIVATE ==
- getLayerId(garmin_data_p->privpkt)) {
+ if (count == (GARMIN_PKTHDR_LENGTH + pktsiz) &&
+ getLayerId(garmin_data_p->privpkt) ==
+ GARMIN_LAYERID_PRIVATE) {
dev_dbg(dev, "%s - processing private request %d\n",
__func__, pktid);
@@ -1192,7 +1191,7 @@ static void garmin_read_bulk_callback(struct urb *urb)
garmin_read_process(garmin_data_p, data, urb->actual_length, 1);
if (urb->actual_length == 0 &&
- 0 != (garmin_data_p->flags & FLAGS_BULK_IN_RESTART)) {
+ (garmin_data_p->flags & FLAGS_BULK_IN_RESTART) != 0) {
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_BULK_IN_RESTART;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1203,7 +1202,7 @@ static void garmin_read_bulk_callback(struct urb *urb)
__func__, retval);
} else if (urb->actual_length > 0) {
/* Continue trying to read until nothing more is received */
- if (0 == (garmin_data_p->flags & FLAGS_THROTTLED)) {
+ if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) {
retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (retval)
dev_err(&port->dev,
@@ -1249,12 +1248,12 @@ static void garmin_read_int_callback(struct urb *urb)
urb->transfer_buffer);
if (urb->actual_length == sizeof(GARMIN_BULK_IN_AVAIL_REPLY) &&
- 0 == memcmp(data, GARMIN_BULK_IN_AVAIL_REPLY,
- sizeof(GARMIN_BULK_IN_AVAIL_REPLY))) {
+ memcmp(data, GARMIN_BULK_IN_AVAIL_REPLY,
+ sizeof(GARMIN_BULK_IN_AVAIL_REPLY)) == 0) {
dev_dbg(&port->dev, "%s - bulk data available.\n", __func__);
- if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
+ if ((garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE) == 0) {
/* bulk data available */
retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
@@ -1276,8 +1275,8 @@ static void garmin_read_int_callback(struct urb *urb)
}
} else if (urb->actual_length == (4+sizeof(GARMIN_START_SESSION_REPLY))
- && 0 == memcmp(data, GARMIN_START_SESSION_REPLY,
- sizeof(GARMIN_START_SESSION_REPLY))) {
+ && memcmp(data, GARMIN_START_SESSION_REPLY,
+ sizeof(GARMIN_START_SESSION_REPLY)) == 0) {
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_SESSION_REPLY1_SEEN;
@@ -1356,7 +1355,7 @@ static void garmin_unthrottle(struct tty_struct *tty)
if (garmin_data_p->mode == MODE_NATIVE)
garmin_flush_queue(garmin_data_p);
- if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
+ if ((garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE) != 0) {
status = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (status)
dev_err(&port->dev,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index f49327d20ee8..f3007ecdd1b4 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1398,7 +1398,7 @@ static void edge_throttle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
edge_port->shadowMCR &= ~MCR_RTS;
status = send_cmd_write_uart_register(edge_port, MCR,
edge_port->shadowMCR);
@@ -1435,7 +1435,7 @@ static void edge_unthrottle(struct tty_struct *tty)
return;
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
edge_port->shadowMCR |= MCR_RTS;
send_cmd_write_uart_register(edge_port, MCR,
edge_port->shadowMCR);
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 5ad4a0fb4b26..344b4eea4bd5 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -360,7 +360,7 @@ static void iuu_led_activity_on(struct urb *urb)
int result;
char *buf_ptr = port->write_urb->transfer_buffer;
*buf_ptr++ = IUU_SET_LED;
- if (xmas == 1) {
+ if (xmas) {
get_random_bytes(buf_ptr, 6);
*(buf_ptr+7) = 1;
} else {
@@ -380,7 +380,7 @@ static void iuu_led_activity_off(struct urb *urb)
struct usb_serial_port *port = urb->context;
int result;
char *buf_ptr = port->write_urb->transfer_buffer;
- if (xmas == 1) {
+ if (xmas) {
iuu_rxcmd(urb);
return;
} else {
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index e07b15ed5814..b6bd8e4a6486 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1963,7 +1963,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
if (d_details->product_id == keyspan_usa49wg_product_id) {
dr = (void *)(s_priv->ctrl_buf);
dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
- dr->bRequest = 0xB0; /* 49wg control message */;
+ dr->bRequest = 0xB0; /* 49wg control message */
dr->wValue = 0;
dr->wIndex = 0;
dr->wLength = cpu_to_le16(sizeof(msg));
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index e020ad28a00c..fc5d3a791e08 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -472,7 +472,6 @@ static void klsi_105_set_termios(struct tty_struct *tty,
/* maybe this should be simulated by sending read
* disable and read enable messages?
*/
- ;
#if 0
priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
mct_u232_set_modem_ctrl(serial, priv->control_state);
@@ -527,7 +526,6 @@ static void klsi_105_set_termios(struct tty_struct *tty,
mct_u232_set_line_ctrl(serial, priv->last_lcr);
#endif
- ;
}
/*
* Set flow control: well, I do not really now how to handle DTR/RTS.
@@ -546,7 +544,6 @@ static void klsi_105_set_termios(struct tty_struct *tty,
priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
- ;
}
memcpy(cfg, &priv->cfg, sizeof(*cfg));
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index fd707d6a10e2..4446b8d70ac2 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -428,7 +428,7 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
* either.
*/
spin_lock_irqsave(&priv->lock, flags);
- if (tty && (tty->termios.c_cflag & CBAUD))
+ if (tty && C_BAUD(tty))
priv->control_state = TIOCM_DTR | TIOCM_RTS;
else
priv->control_state = 0;
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 78b4f64c6b00..2eddbe538cda 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1308,7 +1308,7 @@ static void mos7720_throttle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
mos7720_port->shadowMCR &= ~UART_MCR_RTS;
write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
mos7720_port->shadowMCR);
@@ -1338,7 +1338,7 @@ static void mos7720_unthrottle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
mos7720_port->shadowMCR |= UART_MCR_RTS;
write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
mos7720_port->shadowMCR);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 2c69bfcdacc6..ed378fb232e7 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1425,7 +1425,7 @@ static void mos7840_throttle(struct tty_struct *tty)
return;
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
mos7840_port->shadowMCR &= ~MCR_RTS;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
mos7840_port->shadowMCR);
@@ -1466,7 +1466,7 @@ static void mos7840_unthrottle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
mos7840_port->shadowMCR |= MCR_RTS;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
mos7840_port->shadowMCR);
@@ -1842,7 +1842,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
Data = 0x0c;
mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
- if (mos7840_port->read_urb_busy == false) {
+ if (!mos7840_port->read_urb_busy) {
mos7840_port->read_urb_busy = true;
status = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
if (status) {
@@ -1906,7 +1906,7 @@ static void mos7840_set_termios(struct tty_struct *tty,
return;
}
- if (mos7840_port->read_urb_busy == false) {
+ if (!mos7840_port->read_urb_busy) {
mos7840_port->read_urb_busy = true;
status = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
if (status) {
diff --git a/drivers/usb/serial/mxu11x0.c b/drivers/usb/serial/mxu11x0.c
deleted file mode 100644
index 619607323bfd..000000000000
--- a/drivers/usb/serial/mxu11x0.c
+++ /dev/null
@@ -1,1006 +0,0 @@
-/*
- * USB Moxa UPORT 11x0 Serial Driver
- *
- * Copyright (C) 2007 MOXA Technologies Co., Ltd.
- * Copyright (C) 2015 Mathieu Othacehe <m.othacehe@gmail.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.
- *
- *
- * Supports the following Moxa USB to serial converters:
- * UPort 1110, 1 port RS-232 USB to Serial Hub.
- * UPort 1130, 1 port RS-422/485 USB to Serial Hub.
- * UPort 1130I, 1 port RS-422/485 USB to Serial Hub with isolation
- * protection.
- * UPort 1150, 1 port RS-232/422/485 USB to Serial Hub.
- * UPort 1150I, 1 port RS-232/422/485 USB to Serial Hub with isolation
- * protection.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/firmware.h>
-#include <linux/jiffies.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-/* Vendor and product ids */
-#define MXU1_VENDOR_ID 0x110a
-#define MXU1_1110_PRODUCT_ID 0x1110
-#define MXU1_1130_PRODUCT_ID 0x1130
-#define MXU1_1150_PRODUCT_ID 0x1150
-#define MXU1_1151_PRODUCT_ID 0x1151
-#define MXU1_1131_PRODUCT_ID 0x1131
-
-/* Commands */
-#define MXU1_GET_VERSION 0x01
-#define MXU1_GET_PORT_STATUS 0x02
-#define MXU1_GET_PORT_DEV_INFO 0x03
-#define MXU1_GET_CONFIG 0x04
-#define MXU1_SET_CONFIG 0x05
-#define MXU1_OPEN_PORT 0x06
-#define MXU1_CLOSE_PORT 0x07
-#define MXU1_START_PORT 0x08
-#define MXU1_STOP_PORT 0x09
-#define MXU1_TEST_PORT 0x0A
-#define MXU1_PURGE_PORT 0x0B
-#define MXU1_RESET_EXT_DEVICE 0x0C
-#define MXU1_GET_OUTQUEUE 0x0D
-#define MXU1_WRITE_DATA 0x80
-#define MXU1_READ_DATA 0x81
-#define MXU1_REQ_TYPE_CLASS 0x82
-
-/* Module identifiers */
-#define MXU1_I2C_PORT 0x01
-#define MXU1_IEEE1284_PORT 0x02
-#define MXU1_UART1_PORT 0x03
-#define MXU1_UART2_PORT 0x04
-#define MXU1_RAM_PORT 0x05
-
-/* Modem status */
-#define MXU1_MSR_DELTA_CTS 0x01
-#define MXU1_MSR_DELTA_DSR 0x02
-#define MXU1_MSR_DELTA_RI 0x04
-#define MXU1_MSR_DELTA_CD 0x08
-#define MXU1_MSR_CTS 0x10
-#define MXU1_MSR_DSR 0x20
-#define MXU1_MSR_RI 0x40
-#define MXU1_MSR_CD 0x80
-#define MXU1_MSR_DELTA_MASK 0x0F
-#define MXU1_MSR_MASK 0xF0
-
-/* Line status */
-#define MXU1_LSR_OVERRUN_ERROR 0x01
-#define MXU1_LSR_PARITY_ERROR 0x02
-#define MXU1_LSR_FRAMING_ERROR 0x04
-#define MXU1_LSR_BREAK 0x08
-#define MXU1_LSR_ERROR 0x0F
-#define MXU1_LSR_RX_FULL 0x10
-#define MXU1_LSR_TX_EMPTY 0x20
-
-/* Modem control */
-#define MXU1_MCR_LOOP 0x04
-#define MXU1_MCR_DTR 0x10
-#define MXU1_MCR_RTS 0x20
-
-/* Mask settings */
-#define MXU1_UART_ENABLE_RTS_IN 0x0001
-#define MXU1_UART_DISABLE_RTS 0x0002
-#define MXU1_UART_ENABLE_PARITY_CHECKING 0x0008
-#define MXU1_UART_ENABLE_DSR_OUT 0x0010
-#define MXU1_UART_ENABLE_CTS_OUT 0x0020
-#define MXU1_UART_ENABLE_X_OUT 0x0040
-#define MXU1_UART_ENABLE_XA_OUT 0x0080
-#define MXU1_UART_ENABLE_X_IN 0x0100
-#define MXU1_UART_ENABLE_DTR_IN 0x0800
-#define MXU1_UART_DISABLE_DTR 0x1000
-#define MXU1_UART_ENABLE_MS_INTS 0x2000
-#define MXU1_UART_ENABLE_AUTO_START_DMA 0x4000
-#define MXU1_UART_SEND_BREAK_SIGNAL 0x8000
-
-/* Parity */
-#define MXU1_UART_NO_PARITY 0x00
-#define MXU1_UART_ODD_PARITY 0x01
-#define MXU1_UART_EVEN_PARITY 0x02
-#define MXU1_UART_MARK_PARITY 0x03
-#define MXU1_UART_SPACE_PARITY 0x04
-
-/* Stop bits */
-#define MXU1_UART_1_STOP_BITS 0x00
-#define MXU1_UART_1_5_STOP_BITS 0x01
-#define MXU1_UART_2_STOP_BITS 0x02
-
-/* Bits per character */
-#define MXU1_UART_5_DATA_BITS 0x00
-#define MXU1_UART_6_DATA_BITS 0x01
-#define MXU1_UART_7_DATA_BITS 0x02
-#define MXU1_UART_8_DATA_BITS 0x03
-
-/* Operation modes */
-#define MXU1_UART_232 0x00
-#define MXU1_UART_485_RECEIVER_DISABLED 0x01
-#define MXU1_UART_485_RECEIVER_ENABLED 0x02
-
-/* Pipe transfer mode and timeout */
-#define MXU1_PIPE_MODE_CONTINUOUS 0x01
-#define MXU1_PIPE_MODE_MASK 0x03
-#define MXU1_PIPE_TIMEOUT_MASK 0x7C
-#define MXU1_PIPE_TIMEOUT_ENABLE 0x80
-
-/* Config struct */
-struct mxu1_uart_config {
- __be16 wBaudRate;
- __be16 wFlags;
- u8 bDataBits;
- u8 bParity;
- u8 bStopBits;
- char cXon;
- char cXoff;
- u8 bUartMode;
-} __packed;
-
-/* Purge modes */
-#define MXU1_PURGE_OUTPUT 0x00
-#define MXU1_PURGE_INPUT 0x80
-
-/* Read/Write data */
-#define MXU1_RW_DATA_ADDR_SFR 0x10
-#define MXU1_RW_DATA_ADDR_IDATA 0x20
-#define MXU1_RW_DATA_ADDR_XDATA 0x30
-#define MXU1_RW_DATA_ADDR_CODE 0x40
-#define MXU1_RW_DATA_ADDR_GPIO 0x50
-#define MXU1_RW_DATA_ADDR_I2C 0x60
-#define MXU1_RW_DATA_ADDR_FLASH 0x70
-#define MXU1_RW_DATA_ADDR_DSP 0x80
-
-#define MXU1_RW_DATA_UNSPECIFIED 0x00
-#define MXU1_RW_DATA_BYTE 0x01
-#define MXU1_RW_DATA_WORD 0x02
-#define MXU1_RW_DATA_DOUBLE_WORD 0x04
-
-struct mxu1_write_data_bytes {
- u8 bAddrType;
- u8 bDataType;
- u8 bDataCounter;
- __be16 wBaseAddrHi;
- __be16 wBaseAddrLo;
- u8 bData[0];
-} __packed;
-
-/* Interrupt codes */
-#define MXU1_CODE_HARDWARE_ERROR 0xFF
-#define MXU1_CODE_DATA_ERROR 0x03
-#define MXU1_CODE_MODEM_STATUS 0x04
-
-static inline int mxu1_get_func_from_code(unsigned char code)
-{
- return code & 0x0f;
-}
-
-/* Download firmware max packet size */
-#define MXU1_DOWNLOAD_MAX_PACKET_SIZE 64
-
-/* Firmware image header */
-struct mxu1_firmware_header {
- __le16 wLength;
- u8 bCheckSum;
-} __packed;
-
-#define MXU1_UART_BASE_ADDR 0xFFA0
-#define MXU1_UART_OFFSET_MCR 0x0004
-
-#define MXU1_BAUD_BASE 923077
-
-#define MXU1_TRANSFER_TIMEOUT 2
-#define MXU1_DOWNLOAD_TIMEOUT 1000
-#define MXU1_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */
-
-struct mxu1_port {
- u8 msr;
- u8 mcr;
- u8 uart_mode;
- spinlock_t spinlock; /* Protects msr */
- struct mutex mutex; /* Protects mcr */
- bool send_break;
-};
-
-struct mxu1_device {
- u16 mxd_model;
-};
-
-static const struct usb_device_id mxu1_idtable[] = {
- { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
- { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
- { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
- { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
- { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, mxu1_idtable);
-
-/* Write the given buffer out to the control pipe. */
-static int mxu1_send_ctrl_data_urb(struct usb_serial *serial,
- u8 request,
- u16 value, u16 index,
- void *data, size_t size)
-{
- int status;
-
- status = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- request,
- (USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE), value, index,
- data, size,
- USB_CTRL_SET_TIMEOUT);
- if (status < 0) {
- dev_err(&serial->interface->dev,
- "%s - usb_control_msg failed: %d\n",
- __func__, status);
- return status;
- }
-
- if (status != size) {
- dev_err(&serial->interface->dev,
- "%s - short write (%d / %zd)\n",
- __func__, status, size);
- return -EIO;
- }
-
- return 0;
-}
-
-/* Send a vendor request without any data */
-static int mxu1_send_ctrl_urb(struct usb_serial *serial,
- u8 request, u16 value, u16 index)
-{
- return mxu1_send_ctrl_data_urb(serial, request, value, index,
- NULL, 0);
-}
-
-static int mxu1_download_firmware(struct usb_serial *serial,
- const struct firmware *fw_p)
-{
- int status = 0;
- int buffer_size;
- int pos;
- int len;
- int done;
- u8 cs = 0;
- u8 *buffer;
- struct usb_device *dev = serial->dev;
- struct mxu1_firmware_header *header;
- unsigned int pipe;
-
- pipe = usb_sndbulkpipe(dev, serial->port[0]->bulk_out_endpointAddress);
-
- buffer_size = fw_p->size + sizeof(*header);
- buffer = kmalloc(buffer_size, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- memcpy(buffer, fw_p->data, fw_p->size);
- memset(buffer + fw_p->size, 0xff, buffer_size - fw_p->size);
-
- for (pos = sizeof(*header); pos < buffer_size; pos++)
- cs = (u8)(cs + buffer[pos]);
-
- header = (struct mxu1_firmware_header *)buffer;
- header->wLength = cpu_to_le16(buffer_size - sizeof(*header));
- header->bCheckSum = cs;
-
- dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__);
-
- for (pos = 0; pos < buffer_size; pos += done) {
- len = min(buffer_size - pos, MXU1_DOWNLOAD_MAX_PACKET_SIZE);
-
- status = usb_bulk_msg(dev, pipe, buffer + pos, len, &done,
- MXU1_DOWNLOAD_TIMEOUT);
- if (status)
- break;
- }
-
- kfree(buffer);
-
- if (status) {
- dev_err(&dev->dev, "failed to download firmware: %d\n", status);
- return status;
- }
-
- msleep_interruptible(100);
- usb_reset_device(dev);
-
- dev_dbg(&dev->dev, "%s - download successful\n", __func__);
-
- return 0;
-}
-
-static int mxu1_port_probe(struct usb_serial_port *port)
-{
- struct mxu1_port *mxport;
- struct mxu1_device *mxdev;
-
- if (!port->interrupt_in_urb) {
- dev_err(&port->dev, "no interrupt urb\n");
- return -ENODEV;
- }
-
- mxport = kzalloc(sizeof(struct mxu1_port), GFP_KERNEL);
- if (!mxport)
- return -ENOMEM;
-
- spin_lock_init(&mxport->spinlock);
- mutex_init(&mxport->mutex);
-
- mxdev = usb_get_serial_data(port->serial);
-
- switch (mxdev->mxd_model) {
- case MXU1_1110_PRODUCT_ID:
- case MXU1_1150_PRODUCT_ID:
- case MXU1_1151_PRODUCT_ID:
- mxport->uart_mode = MXU1_UART_232;
- break;
- case MXU1_1130_PRODUCT_ID:
- case MXU1_1131_PRODUCT_ID:
- mxport->uart_mode = MXU1_UART_485_RECEIVER_DISABLED;
- break;
- }
-
- usb_set_serial_port_data(port, mxport);
-
- port->port.closing_wait =
- msecs_to_jiffies(MXU1_DEFAULT_CLOSING_WAIT * 10);
- port->port.drain_delay = 1;
-
- return 0;
-}
-
-static int mxu1_port_remove(struct usb_serial_port *port)
-{
- struct mxu1_port *mxport;
-
- mxport = usb_get_serial_port_data(port);
- kfree(mxport);
-
- return 0;
-}
-
-static int mxu1_startup(struct usb_serial *serial)
-{
- struct mxu1_device *mxdev;
- struct usb_device *dev = serial->dev;
- struct usb_host_interface *cur_altsetting;
- char fw_name[32];
- const struct firmware *fw_p = NULL;
- int err;
-
- dev_dbg(&serial->interface->dev, "%s - product 0x%04X, num configurations %d, configuration value %d\n",
- __func__, le16_to_cpu(dev->descriptor.idProduct),
- dev->descriptor.bNumConfigurations,
- dev->actconfig->desc.bConfigurationValue);
-
- /* create device structure */
- mxdev = kzalloc(sizeof(struct mxu1_device), GFP_KERNEL);
- if (!mxdev)
- return -ENOMEM;
-
- usb_set_serial_data(serial, mxdev);
-
- mxdev->mxd_model = le16_to_cpu(dev->descriptor.idProduct);
-
- cur_altsetting = serial->interface->cur_altsetting;
-
- /* if we have only 1 configuration, download firmware */
- if (cur_altsetting->desc.bNumEndpoints == 1) {
-
- snprintf(fw_name,
- sizeof(fw_name),
- "moxa/moxa-%04x.fw",
- mxdev->mxd_model);
-
- err = request_firmware(&fw_p, fw_name, &serial->interface->dev);
- if (err) {
- dev_err(&serial->interface->dev, "failed to request firmware: %d\n",
- err);
- goto err_free_mxdev;
- }
-
- err = mxu1_download_firmware(serial, fw_p);
- if (err)
- goto err_release_firmware;
-
- /* device is being reset */
- err = -ENODEV;
- goto err_release_firmware;
- }
-
- return 0;
-
-err_release_firmware:
- release_firmware(fw_p);
-err_free_mxdev:
- kfree(mxdev);
-
- return err;
-}
-
-static void mxu1_release(struct usb_serial *serial)
-{
- struct mxu1_device *mxdev;
-
- mxdev = usb_get_serial_data(serial);
- kfree(mxdev);
-}
-
-static int mxu1_write_byte(struct usb_serial_port *port, u32 addr,
- u8 mask, u8 byte)
-{
- int status;
- size_t size;
- struct mxu1_write_data_bytes *data;
-
- dev_dbg(&port->dev, "%s - addr 0x%08X, mask 0x%02X, byte 0x%02X\n",
- __func__, addr, mask, byte);
-
- size = sizeof(struct mxu1_write_data_bytes) + 2;
- data = kzalloc(size, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->bAddrType = MXU1_RW_DATA_ADDR_XDATA;
- data->bDataType = MXU1_RW_DATA_BYTE;
- data->bDataCounter = 1;
- data->wBaseAddrHi = cpu_to_be16(addr >> 16);
- data->wBaseAddrLo = cpu_to_be16(addr);
- data->bData[0] = mask;
- data->bData[1] = byte;
-
- status = mxu1_send_ctrl_data_urb(port->serial, MXU1_WRITE_DATA, 0,
- MXU1_RAM_PORT, data, size);
- if (status < 0)
- dev_err(&port->dev, "%s - failed: %d\n", __func__, status);
-
- kfree(data);
-
- return status;
-}
-
-static int mxu1_set_mcr(struct usb_serial_port *port, unsigned int mcr)
-{
- int status;
-
- status = mxu1_write_byte(port,
- MXU1_UART_BASE_ADDR + MXU1_UART_OFFSET_MCR,
- MXU1_MCR_RTS | MXU1_MCR_DTR | MXU1_MCR_LOOP,
- mcr);
- return status;
-}
-
-static void mxu1_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ktermios *old_termios)
-{
- struct mxu1_port *mxport = usb_get_serial_port_data(port);
- struct mxu1_uart_config *config;
- tcflag_t cflag, iflag;
- speed_t baud;
- int status;
- unsigned int mcr;
-
- cflag = tty->termios.c_cflag;
- iflag = tty->termios.c_iflag;
-
- if (old_termios &&
- !tty_termios_hw_change(&tty->termios, old_termios) &&
- tty->termios.c_iflag == old_termios->c_iflag) {
- dev_dbg(&port->dev, "%s - nothing to change\n", __func__);
- return;
- }
-
- dev_dbg(&port->dev,
- "%s - cflag 0x%08x, iflag 0x%08x\n", __func__, cflag, iflag);
-
- if (old_termios) {
- dev_dbg(&port->dev, "%s - old cflag 0x%08x, old iflag 0x%08x\n",
- __func__,
- old_termios->c_cflag,
- old_termios->c_iflag);
- }
-
- config = kzalloc(sizeof(*config), GFP_KERNEL);
- if (!config)
- return;
-
- /* these flags must be set */
- config->wFlags |= MXU1_UART_ENABLE_MS_INTS;
- config->wFlags |= MXU1_UART_ENABLE_AUTO_START_DMA;
- if (mxport->send_break)
- config->wFlags |= MXU1_UART_SEND_BREAK_SIGNAL;
- config->bUartMode = mxport->uart_mode;
-
- switch (C_CSIZE(tty)) {
- case CS5:
- config->bDataBits = MXU1_UART_5_DATA_BITS;
- break;
- case CS6:
- config->bDataBits = MXU1_UART_6_DATA_BITS;
- break;
- case CS7:
- config->bDataBits = MXU1_UART_7_DATA_BITS;
- break;
- default:
- case CS8:
- config->bDataBits = MXU1_UART_8_DATA_BITS;
- break;
- }
-
- if (C_PARENB(tty)) {
- config->wFlags |= MXU1_UART_ENABLE_PARITY_CHECKING;
- if (C_CMSPAR(tty)) {
- if (C_PARODD(tty))
- config->bParity = MXU1_UART_MARK_PARITY;
- else
- config->bParity = MXU1_UART_SPACE_PARITY;
- } else {
- if (C_PARODD(tty))
- config->bParity = MXU1_UART_ODD_PARITY;
- else
- config->bParity = MXU1_UART_EVEN_PARITY;
- }
- } else {
- config->bParity = MXU1_UART_NO_PARITY;
- }
-
- if (C_CSTOPB(tty))
- config->bStopBits = MXU1_UART_2_STOP_BITS;
- else
- config->bStopBits = MXU1_UART_1_STOP_BITS;
-
- if (C_CRTSCTS(tty)) {
- /* RTS flow control must be off to drop RTS for baud rate B0 */
- if (C_BAUD(tty) != B0)
- config->wFlags |= MXU1_UART_ENABLE_RTS_IN;
- config->wFlags |= MXU1_UART_ENABLE_CTS_OUT;
- }
-
- if (I_IXOFF(tty) || I_IXON(tty)) {
- config->cXon = START_CHAR(tty);
- config->cXoff = STOP_CHAR(tty);
-
- if (I_IXOFF(tty))
- config->wFlags |= MXU1_UART_ENABLE_X_IN;
-
- if (I_IXON(tty))
- config->wFlags |= MXU1_UART_ENABLE_X_OUT;
- }
-
- baud = tty_get_baud_rate(tty);
- if (!baud)
- baud = 9600;
- config->wBaudRate = MXU1_BAUD_BASE / baud;
-
- dev_dbg(&port->dev, "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n",
- __func__, baud, config->wBaudRate, config->wFlags,
- config->bDataBits, config->bParity, config->bStopBits,
- config->cXon, config->cXoff, config->bUartMode);
-
- cpu_to_be16s(&config->wBaudRate);
- cpu_to_be16s(&config->wFlags);
-
- status = mxu1_send_ctrl_data_urb(port->serial, MXU1_SET_CONFIG, 0,
- MXU1_UART1_PORT, config,
- sizeof(*config));
- if (status)
- dev_err(&port->dev, "cannot set config: %d\n", status);
-
- mutex_lock(&mxport->mutex);
- mcr = mxport->mcr;
-
- if (C_BAUD(tty) == B0)
- mcr &= ~(MXU1_MCR_DTR | MXU1_MCR_RTS);
- else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
- mcr |= MXU1_MCR_DTR | MXU1_MCR_RTS;
-
- status = mxu1_set_mcr(port, mcr);
- if (status)
- dev_err(&port->dev, "cannot set modem control: %d\n", status);
- else
- mxport->mcr = mcr;
-
- mutex_unlock(&mxport->mutex);
-
- kfree(config);
-}
-
-static int mxu1_get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *ret_arg)
-{
- struct serial_struct ret_serial;
- unsigned cwait;
-
- if (!ret_arg)
- return -EFAULT;
-
- cwait = port->port.closing_wait;
- if (cwait != ASYNC_CLOSING_WAIT_NONE)
- cwait = jiffies_to_msecs(cwait) / 10;
-
- memset(&ret_serial, 0, sizeof(ret_serial));
-
- ret_serial.type = PORT_16550A;
- ret_serial.line = port->minor;
- ret_serial.port = 0;
- ret_serial.xmit_fifo_size = port->bulk_out_size;
- ret_serial.baud_base = MXU1_BAUD_BASE;
- ret_serial.close_delay = 5*HZ;
- ret_serial.closing_wait = cwait;
-
- if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int mxu1_set_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *new_arg)
-{
- struct serial_struct new_serial;
- unsigned cwait;
-
- if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
- return -EFAULT;
-
- cwait = new_serial.closing_wait;
- if (cwait != ASYNC_CLOSING_WAIT_NONE)
- cwait = msecs_to_jiffies(10 * new_serial.closing_wait);
-
- port->port.closing_wait = cwait;
-
- return 0;
-}
-
-static int mxu1_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- switch (cmd) {
- case TIOCGSERIAL:
- return mxu1_get_serial_info(port,
- (struct serial_struct __user *)arg);
- case TIOCSSERIAL:
- return mxu1_set_serial_info(port,
- (struct serial_struct __user *)arg);
- }
-
- return -ENOIOCTLCMD;
-}
-
-static int mxu1_tiocmget(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct mxu1_port *mxport = usb_get_serial_port_data(port);
- unsigned int result;
- unsigned int msr;
- unsigned int mcr;
- unsigned long flags;
-
- mutex_lock(&mxport->mutex);
- spin_lock_irqsave(&mxport->spinlock, flags);
-
- msr = mxport->msr;
- mcr = mxport->mcr;
-
- spin_unlock_irqrestore(&mxport->spinlock, flags);
- mutex_unlock(&mxport->mutex);
-
- result = ((mcr & MXU1_MCR_DTR) ? TIOCM_DTR : 0) |
- ((mcr & MXU1_MCR_RTS) ? TIOCM_RTS : 0) |
- ((mcr & MXU1_MCR_LOOP) ? TIOCM_LOOP : 0) |
- ((msr & MXU1_MSR_CTS) ? TIOCM_CTS : 0) |
- ((msr & MXU1_MSR_CD) ? TIOCM_CAR : 0) |
- ((msr & MXU1_MSR_RI) ? TIOCM_RI : 0) |
- ((msr & MXU1_MSR_DSR) ? TIOCM_DSR : 0);
-
- dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result);
-
- return result;
-}
-
-static int mxu1_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct mxu1_port *mxport = usb_get_serial_port_data(port);
- int err;
- unsigned int mcr;
-
- mutex_lock(&mxport->mutex);
- mcr = mxport->mcr;
-
- if (set & TIOCM_RTS)
- mcr |= MXU1_MCR_RTS;
- if (set & TIOCM_DTR)
- mcr |= MXU1_MCR_DTR;
- if (set & TIOCM_LOOP)
- mcr |= MXU1_MCR_LOOP;
-
- if (clear & TIOCM_RTS)
- mcr &= ~MXU1_MCR_RTS;
- if (clear & TIOCM_DTR)
- mcr &= ~MXU1_MCR_DTR;
- if (clear & TIOCM_LOOP)
- mcr &= ~MXU1_MCR_LOOP;
-
- err = mxu1_set_mcr(port, mcr);
- if (!err)
- mxport->mcr = mcr;
-
- mutex_unlock(&mxport->mutex);
-
- return err;
-}
-
-static void mxu1_break(struct tty_struct *tty, int break_state)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct mxu1_port *mxport = usb_get_serial_port_data(port);
-
- if (break_state == -1)
- mxport->send_break = true;
- else
- mxport->send_break = false;
-
- mxu1_set_termios(tty, port, NULL);
-}
-
-static int mxu1_open(struct tty_struct *tty, struct usb_serial_port *port)
-{
- struct mxu1_port *mxport = usb_get_serial_port_data(port);
- struct usb_serial *serial = port->serial;
- int status;
- u16 open_settings;
-
- open_settings = (MXU1_PIPE_MODE_CONTINUOUS |
- MXU1_PIPE_TIMEOUT_ENABLE |
- (MXU1_TRANSFER_TIMEOUT << 2));
-
- mxport->msr = 0;
-
- status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
- if (status) {
- dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
- status);
- return status;
- }
-
- if (tty)
- mxu1_set_termios(tty, port, NULL);
-
- status = mxu1_send_ctrl_urb(serial, MXU1_OPEN_PORT,
- open_settings, MXU1_UART1_PORT);
- if (status) {
- dev_err(&port->dev, "cannot send open command: %d\n", status);
- goto unlink_int_urb;
- }
-
- status = mxu1_send_ctrl_urb(serial, MXU1_START_PORT,
- 0, MXU1_UART1_PORT);
- if (status) {
- dev_err(&port->dev, "cannot send start command: %d\n", status);
- goto unlink_int_urb;
- }
-
- status = mxu1_send_ctrl_urb(serial, MXU1_PURGE_PORT,
- MXU1_PURGE_INPUT, MXU1_UART1_PORT);
- if (status) {
- dev_err(&port->dev, "cannot clear input buffers: %d\n",
- status);
-
- goto unlink_int_urb;
- }
-
- status = mxu1_send_ctrl_urb(serial, MXU1_PURGE_PORT,
- MXU1_PURGE_OUTPUT, MXU1_UART1_PORT);
- if (status) {
- dev_err(&port->dev, "cannot clear output buffers: %d\n",
- status);
-
- goto unlink_int_urb;
- }
-
- /*
- * reset the data toggle on the bulk endpoints to work around bug in
- * host controllers where things get out of sync some times
- */
- usb_clear_halt(serial->dev, port->write_urb->pipe);
- usb_clear_halt(serial->dev, port->read_urb->pipe);
-
- if (tty)
- mxu1_set_termios(tty, port, NULL);
-
- status = mxu1_send_ctrl_urb(serial, MXU1_OPEN_PORT,
- open_settings, MXU1_UART1_PORT);
- if (status) {
- dev_err(&port->dev, "cannot send open command: %d\n", status);
- goto unlink_int_urb;
- }
-
- status = mxu1_send_ctrl_urb(serial, MXU1_START_PORT,
- 0, MXU1_UART1_PORT);
- if (status) {
- dev_err(&port->dev, "cannot send start command: %d\n", status);
- goto unlink_int_urb;
- }
-
- status = usb_serial_generic_open(tty, port);
- if (status)
- goto unlink_int_urb;
-
- return 0;
-
-unlink_int_urb:
- usb_kill_urb(port->interrupt_in_urb);
-
- return status;
-}
-
-static void mxu1_close(struct usb_serial_port *port)
-{
- int status;
-
- usb_serial_generic_close(port);
- usb_kill_urb(port->interrupt_in_urb);
-
- status = mxu1_send_ctrl_urb(port->serial, MXU1_CLOSE_PORT,
- 0, MXU1_UART1_PORT);
- if (status) {
- dev_err(&port->dev, "failed to send close port command: %d\n",
- status);
- }
-}
-
-static void mxu1_handle_new_msr(struct usb_serial_port *port, u8 msr)
-{
- struct mxu1_port *mxport = usb_get_serial_port_data(port);
- struct async_icount *icount;
- unsigned long flags;
-
- dev_dbg(&port->dev, "%s - msr 0x%02X\n", __func__, msr);
-
- spin_lock_irqsave(&mxport->spinlock, flags);
- mxport->msr = msr & MXU1_MSR_MASK;
- spin_unlock_irqrestore(&mxport->spinlock, flags);
-
- if (msr & MXU1_MSR_DELTA_MASK) {
- icount = &port->icount;
- if (msr & MXU1_MSR_DELTA_CTS)
- icount->cts++;
- if (msr & MXU1_MSR_DELTA_DSR)
- icount->dsr++;
- if (msr & MXU1_MSR_DELTA_CD)
- icount->dcd++;
- if (msr & MXU1_MSR_DELTA_RI)
- icount->rng++;
-
- wake_up_interruptible(&port->port.delta_msr_wait);
- }
-}
-
-static void mxu1_interrupt_callback(struct urb *urb)
-{
- struct usb_serial_port *port = urb->context;
- unsigned char *data = urb->transfer_buffer;
- int length = urb->actual_length;
- int function;
- int status;
- u8 msr;
-
- switch (urb->status) {
- case 0:
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- dev_dbg(&port->dev, "%s - urb shutting down: %d\n",
- __func__, urb->status);
- return;
- default:
- dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
- __func__, urb->status);
- goto exit;
- }
-
- if (length != 2) {
- dev_dbg(&port->dev, "%s - bad packet size: %d\n",
- __func__, length);
- goto exit;
- }
-
- if (data[0] == MXU1_CODE_HARDWARE_ERROR) {
- dev_err(&port->dev, "hardware error: %d\n", data[1]);
- goto exit;
- }
-
- function = mxu1_get_func_from_code(data[0]);
-
- dev_dbg(&port->dev, "%s - function %d, data 0x%02X\n",
- __func__, function, data[1]);
-
- switch (function) {
- case MXU1_CODE_DATA_ERROR:
- dev_dbg(&port->dev, "%s - DATA ERROR, data 0x%02X\n",
- __func__, data[1]);
- break;
-
- case MXU1_CODE_MODEM_STATUS:
- msr = data[1];
- mxu1_handle_new_msr(port, msr);
- break;
-
- default:
- dev_err(&port->dev, "unknown interrupt code: 0x%02X\n",
- data[1]);
- break;
- }
-
-exit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status) {
- dev_err(&port->dev, "resubmit interrupt urb failed: %d\n",
- status);
- }
-}
-
-static struct usb_serial_driver mxu11x0_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "mxu11x0",
- },
- .description = "MOXA UPort 11x0",
- .id_table = mxu1_idtable,
- .num_ports = 1,
- .port_probe = mxu1_port_probe,
- .port_remove = mxu1_port_remove,
- .attach = mxu1_startup,
- .release = mxu1_release,
- .open = mxu1_open,
- .close = mxu1_close,
- .ioctl = mxu1_ioctl,
- .set_termios = mxu1_set_termios,
- .tiocmget = mxu1_tiocmget,
- .tiocmset = mxu1_tiocmset,
- .tiocmiwait = usb_serial_generic_tiocmiwait,
- .get_icount = usb_serial_generic_get_icount,
- .break_ctl = mxu1_break,
- .read_int_callback = mxu1_interrupt_callback,
-};
-
-static struct usb_serial_driver *const serial_drivers[] = {
- &mxu11x0_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, mxu1_idtable);
-
-MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
-MODULE_DESCRIPTION("MOXA UPort 11x0 USB to Serial Hub Driver");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("moxa/moxa-1110.fw");
-MODULE_FIRMWARE("moxa/moxa-1130.fw");
-MODULE_FIRMWARE("moxa/moxa-1131.fw");
-MODULE_FIRMWARE("moxa/moxa-1150.fw");
-MODULE_FIRMWARE("moxa/moxa-1151.fw");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index db86e512e0fc..348e19834b83 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -270,6 +270,7 @@ static void option_instat_callback(struct urb *urb);
#define TELIT_PRODUCT_UE910_V2 0x1012
#define TELIT_PRODUCT_LE922_USBCFG0 0x1042
#define TELIT_PRODUCT_LE922_USBCFG3 0x1043
+#define TELIT_PRODUCT_LE922_USBCFG5 0x1045
#define TELIT_PRODUCT_LE920 0x1200
#define TELIT_PRODUCT_LE910 0x1201
@@ -315,6 +316,7 @@ static void option_instat_callback(struct urb *urb);
#define TOSHIBA_PRODUCT_G450 0x0d45
#define ALINK_VENDOR_ID 0x1e0e
+#define SIMCOM_PRODUCT_SIM7100E 0x9001 /* Yes, ALINK_VENDOR_ID */
#define ALINK_PRODUCT_PH300 0x9100
#define ALINK_PRODUCT_3GU 0x9200
@@ -607,6 +609,10 @@ static const struct option_blacklist_info zte_1255_blacklist = {
.reserved = BIT(3) | BIT(4),
};
+static const struct option_blacklist_info simcom_sim7100e_blacklist = {
+ .reserved = BIT(5) | BIT(6),
+};
+
static const struct option_blacklist_info telit_le910_blacklist = {
.sendsetup = BIT(0),
.reserved = BIT(1) | BIT(2),
@@ -1122,9 +1128,13 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
+ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, 0x6001, 0xff, 0xff, 0xff), /* 4G LTE usb-modem U901 */
+ .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9003), /* Quectel UC20 */
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
@@ -1176,6 +1186,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3),
.driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff),
+ .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
.driver_info = (kernel_ulong_t)&telit_le910_blacklist },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
@@ -1645,6 +1657,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
{ USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) },
{ USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
+ { USB_DEVICE(ALINK_VENDOR_ID, SIMCOM_PRODUCT_SIM7100E),
+ .driver_info = (kernel_ulong_t)&simcom_sim7100e_blacklist },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
.driver_info = (kernel_ulong_t)&alcatel_x200_blacklist
},
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 9919d2a9faf2..1bc6089b9008 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -157,14 +157,17 @@ static const struct usb_device_id id_table[] = {
{DEVICE_SWI(0x1199, 0x9056)}, /* Sierra Wireless Modem */
{DEVICE_SWI(0x1199, 0x9060)}, /* Sierra Wireless Modem */
{DEVICE_SWI(0x1199, 0x9061)}, /* Sierra Wireless Modem */
- {DEVICE_SWI(0x1199, 0x9070)}, /* Sierra Wireless MC74xx/EM74xx */
- {DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx/EM74xx */
+ {DEVICE_SWI(0x1199, 0x9070)}, /* Sierra Wireless MC74xx */
+ {DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx */
+ {DEVICE_SWI(0x1199, 0x9078)}, /* Sierra Wireless EM74xx */
+ {DEVICE_SWI(0x1199, 0x9079)}, /* Sierra Wireless EM74xx */
{DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81b1)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
+ {DEVICE_SWI(0x413c, 0x81b3)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
/* Huawei devices */
{DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 504f5bff79c0..2df8ad5ede89 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -973,7 +973,7 @@ static int qt2_write(struct tty_struct *tty,
data = write_urb->transfer_buffer;
spin_lock_irqsave(&port_priv->urb_lock, flags);
- if (port_priv->urb_in_use == true) {
+ if (port_priv->urb_in_use) {
dev_err(&port->dev, "qt2_write - urb is in use\n");
goto write_out;
}
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index b2dff0f14743..93c6c9b08daa 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -76,13 +76,8 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
-
-#ifndef CONFIG_USB_SERIAL_SAFE_PADDED
-#define CONFIG_USB_SERIAL_SAFE_PADDED 0
-#endif
-
-static bool safe = 1;
-static bool padded = CONFIG_USB_SERIAL_SAFE_PADDED;
+static bool safe = true;
+static bool padded = IS_ENABLED(CONFIG_USB_SERIAL_SAFE_PADDED);
#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>"
#define DRIVER_DESC "USB Safe Encapsulated Serial"
@@ -278,7 +273,7 @@ static int safe_startup(struct usb_serial *serial)
case LINEO_SAFESERIAL_CRC:
break;
case LINEO_SAFESERIAL_CRC_PADDED:
- padded = 1;
+ padded = true;
break;
default:
return -EINVAL;
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
index 57bf3ad41fb6..5a12c03138f8 100644
--- a/drivers/usb/storage/debug.c
+++ b/drivers/usb/storage/debug.c
@@ -57,7 +57,6 @@
void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb)
{
char *what = NULL;
- int i;
switch (srb->cmnd[0]) {
case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
@@ -153,10 +152,8 @@ void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb)
default: what = "(unknown command)"; break;
}
usb_stor_dbg(us, "Command %s (%d bytes)\n", what, srb->cmd_len);
- usb_stor_dbg(us, "bytes: ");
- for (i = 0; i < srb->cmd_len && i < 16; i++)
- US_DEBUGPX(" %02x", srb->cmnd[i]);
- US_DEBUGPX("\n");
+ usb_stor_dbg(us, "bytes: %*ph\n", min_t(int, srb->cmd_len, 16),
+ (const unsigned char *)srb->cmnd);
}
void usb_stor_show_sense(const struct us_data *us,
@@ -174,11 +171,10 @@ void usb_stor_show_sense(const struct us_data *us,
if (what == NULL)
what = "(unknown ASC/ASCQ)";
- usb_stor_dbg(us, "%s: ", keystr);
if (fmt)
- US_DEBUGPX("%s (%s%x)\n", what, fmt, ascq);
+ usb_stor_dbg(us, "%s: %s (%s%x)\n", keystr, what, fmt, ascq);
else
- US_DEBUGPX("%s\n", what);
+ usb_stor_dbg(us, "%s: %s\n", keystr, what);
}
void usb_stor_dbg(const struct us_data *us, const char *fmt, ...)
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
index f52520306e1a..6b365ce4e610 100644
--- a/drivers/usb/storage/debug.h
+++ b/drivers/usb/storage/debug.h
@@ -53,7 +53,6 @@ void usb_stor_show_sense(const struct us_data *us, unsigned char key,
__printf(2, 3) void usb_stor_dbg(const struct us_data *us,
const char *fmt, ...);
-#define US_DEBUGPX(fmt, ...) printk(fmt, ##__VA_ARGS__)
#define US_DEBUG(x) x
#else
__printf(2, 3)
@@ -63,8 +62,6 @@ static inline void _usb_stor_dbg(const struct us_data *us,
}
#define usb_stor_dbg(us, fmt, ...) \
do { if (0) _usb_stor_dbg(us, fmt, ##__VA_ARGS__); } while (0)
-#define US_DEBUGPX(fmt, ...) \
- do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)
#define US_DEBUG(x)
#endif
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index f3cf4cecd2b7..d3a17c65a702 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -1067,12 +1067,12 @@ static void ms_lib_free_writebuf(struct us_data *us)
ms_lib_clear_pagemap(info); /* (pdx)->MS_Lib.pagemap memset 0 in ms.h */
if (info->MS_Lib.blkpag) {
- kfree((u8 *)(info->MS_Lib.blkpag)); /* Arnold test ... */
+ kfree(info->MS_Lib.blkpag); /* Arnold test ... */
info->MS_Lib.blkpag = NULL;
}
if (info->MS_Lib.blkext) {
- kfree((u8 *)(info->MS_Lib.blkext)); /* Arnold test ... */
+ kfree(info->MS_Lib.blkext); /* Arnold test ... */
info->MS_Lib.blkext = NULL;
}
}
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index b74603689b9e..79224fcf9b59 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -1102,24 +1102,24 @@ static int
sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) {
int result;
unsigned char status;
+ const char *wp_fmt;
result = sddr09_read_status(us, &status);
if (result) {
usb_stor_dbg(us, "read_status fails\n");
return result;
}
- usb_stor_dbg(us, "status 0x%02X", status);
if ((status & 0x80) == 0) {
info->flags |= SDDR09_WP; /* write protected */
- US_DEBUGPX(" WP");
+ wp_fmt = " WP";
+ } else {
+ wp_fmt = "";
}
- if (status & 0x40)
- US_DEBUGPX(" Ready");
- if (status & LUNBITS)
- US_DEBUGPX(" Suspended");
- if (status & 0x1)
- US_DEBUGPX(" Error");
- US_DEBUGPX("\n");
+ usb_stor_dbg(us, "status 0x%02X%s%s%s%s\n", status, wp_fmt,
+ status & 0x40 ? " Ready" : "",
+ status & LUNBITS ? " Suspended" : "",
+ status & 0x01 ? " Error" : "");
+
return 0;
}
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 9ff9404f99d7..44b096c1737b 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -246,6 +246,29 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
}
}
+static bool uas_evaluate_response_iu(struct response_iu *riu, struct scsi_cmnd *cmnd)
+{
+ u8 response_code = riu->response_code;
+
+ switch (response_code) {
+ case RC_INCORRECT_LUN:
+ cmnd->result = DID_BAD_TARGET << 16;
+ break;
+ case RC_TMF_SUCCEEDED:
+ cmnd->result = DID_OK << 16;
+ break;
+ case RC_TMF_NOT_SUPPORTED:
+ cmnd->result = DID_TARGET_FAILURE << 16;
+ break;
+ default:
+ uas_log_cmd_state(cmnd, "response iu", response_code);
+ cmnd->result = DID_ERROR << 16;
+ break;
+ }
+
+ return response_code == RC_TMF_SUCCEEDED;
+}
+
static void uas_stat_cmplt(struct urb *urb)
{
struct iu *iu = urb->transfer_buffer;
@@ -258,6 +281,7 @@ static void uas_stat_cmplt(struct urb *urb)
unsigned long flags;
unsigned int idx;
int status = urb->status;
+ bool success;
spin_lock_irqsave(&devinfo->lock, flags);
@@ -313,13 +337,13 @@ static void uas_stat_cmplt(struct urb *urb)
uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
break;
case IU_ID_RESPONSE:
- uas_log_cmd_state(cmnd, "unexpected response iu",
- ((struct response_iu *)iu)->response_code);
- /* Error, cancel data transfers */
- data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
- data_out_urb = usb_get_urb(cmdinfo->data_out_urb);
cmdinfo->state &= ~COMMAND_INFLIGHT;
- cmnd->result = DID_ERROR << 16;
+ success = uas_evaluate_response_iu((struct response_iu *)iu, cmnd);
+ if (!success) {
+ /* Error, cancel data transfers */
+ data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
+ data_out_urb = usb_get_urb(cmdinfo->data_out_urb);
+ }
uas_try_complete(cmnd, __func__);
break;
default:
diff --git a/drivers/usb/usbip/usbip_event.c b/drivers/usb/usbip/usbip_event.c
index 64933b993d7a..2580a32bcdff 100644
--- a/drivers/usb/usbip/usbip_event.c
+++ b/drivers/usb/usbip/usbip_event.c
@@ -117,11 +117,12 @@ EXPORT_SYMBOL_GPL(usbip_event_add);
int usbip_event_happened(struct usbip_device *ud)
{
int happened = 0;
+ unsigned long flags;
- spin_lock(&ud->lock);
+ spin_lock_irqsave(&ud->lock, flags);
if (ud->event != 0)
happened = 1;
- spin_unlock(&ud->lock);
+ spin_unlock_irqrestore(&ud->lock, flags);
return happened;
}
diff --git a/drivers/usb/usbip/usbip_protocol.txt b/drivers/usb/usbip/usbip_protocol.txt
deleted file mode 100644
index 16b6fe27284c..000000000000
--- a/drivers/usb/usbip/usbip_protocol.txt
+++ /dev/null
@@ -1,358 +0,0 @@
-PRELIMINARY DRAFT, MAY CONTAIN MISTAKES!
-28 Jun 2011
-
-The USB/IP protocol follows a server/client architecture. The server exports the
-USB devices and the clients imports them. The device driver for the exported
-USB device runs on the client machine.
-
-The client may ask for the list of the exported USB devices. To get the list the
-client opens a TCP/IP connection towards the server, and sends an OP_REQ_DEVLIST
-packet on top of the TCP/IP connection (so the actual OP_REQ_DEVLIST may be sent
-in one or more pieces at the low level transport layer). The server sends back
-the OP_REP_DEVLIST packet which lists the exported USB devices. Finally the
-TCP/IP connection is closed.
-
- virtual host controller usb host
- "client" "server"
- (imports USB devices) (exports USB devices)
- | |
- | OP_REQ_DEVLIST |
- | ----------------------------------------------> |
- | |
- | OP_REP_DEVLIST |
- | <---------------------------------------------- |
- | |
-
-Once the client knows the list of exported USB devices it may decide to use one
-of them. First the client opens a TCP/IP connection towards the server and
-sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the
-import was successful the TCP/IP connection remains open and will be used
-to transfer the URB traffic between the client and the server. The client may
-send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and
-USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the
-server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively.
-
- virtual host controller usb host
- "client" "server"
- (imports USB devices) (exports USB devices)
- | |
- | OP_REQ_IMPORT |
- | ----------------------------------------------> |
- | |
- | OP_REP_IMPORT |
- | <---------------------------------------------- |
- | |
- | |
- | USBIP_CMD_SUBMIT(seqnum = n) |
- | ----------------------------------------------> |
- | |
- | USBIP_RET_SUBMIT(seqnum = n) |
- | <---------------------------------------------- |
- | . |
- | : |
- | |
- | USBIP_CMD_SUBMIT(seqnum = m) |
- | ----------------------------------------------> |
- | |
- | USBIP_CMD_SUBMIT(seqnum = m+1) |
- | ----------------------------------------------> |
- | |
- | USBIP_CMD_SUBMIT(seqnum = m+2) |
- | ----------------------------------------------> |
- | |
- | USBIP_RET_SUBMIT(seqnum = m) |
- | <---------------------------------------------- |
- | |
- | USBIP_CMD_SUBMIT(seqnum = m+3) |
- | ----------------------------------------------> |
- | |
- | USBIP_RET_SUBMIT(seqnum = m+1) |
- | <---------------------------------------------- |
- | |
- | USBIP_CMD_SUBMIT(seqnum = m+4) |
- | ----------------------------------------------> |
- | |
- | USBIP_RET_SUBMIT(seqnum = m+2) |
- | <---------------------------------------------- |
- | . |
- | : |
- | |
- | USBIP_CMD_UNLINK |
- | ----------------------------------------------> |
- | |
- | USBIP_RET_UNLINK |
- | <---------------------------------------------- |
- | |
-
-The fields are in network (big endian) byte order meaning that the most significant
-byte (MSB) is stored at the lowest address.
-
-
-OP_REQ_DEVLIST: Retrieve the list of exported USB devices.
-
- Offset | Length | Value | Description
------------+--------+------------+---------------------------------------------------
- 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0
------------+--------+------------+---------------------------------------------------
- 2 | 2 | 0x8005 | Command code: Retrieve the list of exported USB
- | | | devices.
------------+--------+------------+---------------------------------------------------
- 4 | 4 | 0x00000000 | Status: unused, shall be set to 0
-
-OP_REP_DEVLIST: Reply with the list of exported USB devices.
-
- Offset | Length | Value | Description
------------+--------+------------+---------------------------------------------------
- 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0.
------------+--------+------------+---------------------------------------------------
- 2 | 2 | 0x0005 | Reply code: The list of exported USB devices.
------------+--------+------------+---------------------------------------------------
- 4 | 4 | 0x00000000 | Status: 0 for OK
------------+--------+------------+---------------------------------------------------
- 8 | 4 | n | Number of exported devices: 0 means no exported
- | | | devices.
------------+--------+------------+---------------------------------------------------
- 0x0C | | | From now on the exported n devices are described,
- | | | if any. If no devices are exported the message
- | | | ends with the previous "number of exported
- | | | devices" field.
------------+--------+------------+---------------------------------------------------
- | 256 | | path: Path of the device on the host exporting the
- | | | USB device, string closed with zero byte, e.g.
- | | | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"
- | | | The unused bytes shall be filled with zero
- | | | bytes.
------------+--------+------------+---------------------------------------------------
- 0x10C | 32 | | busid: Bus ID of the exported device, string
- | | | closed with zero byte, e.g. "3-2". The unused
- | | | bytes shall be filled with zero bytes.
------------+--------+------------+---------------------------------------------------
- 0x12C | 4 | | busnum
------------+--------+------------+---------------------------------------------------
- 0x130 | 4 | | devnum
------------+--------+------------+---------------------------------------------------
- 0x134 | 4 | | speed
------------+--------+------------+---------------------------------------------------
- 0x138 | 2 | | idVendor
------------+--------+------------+---------------------------------------------------
- 0x13A | 2 | | idProduct
------------+--------+------------+---------------------------------------------------
- 0x13C | 2 | | bcdDevice
------------+--------+------------+---------------------------------------------------
- 0x13E | 1 | | bDeviceClass
------------+--------+------------+---------------------------------------------------
- 0x13F | 1 | | bDeviceSubClass
------------+--------+------------+---------------------------------------------------
- 0x140 | 1 | | bDeviceProtocol
------------+--------+------------+---------------------------------------------------
- 0x141 | 1 | | bConfigurationValue
------------+--------+------------+---------------------------------------------------
- 0x142 | 1 | | bNumConfigurations
------------+--------+------------+---------------------------------------------------
- 0x143 | 1 | | bNumInterfaces
------------+--------+------------+---------------------------------------------------
- 0x144 | | m_0 | From now on each interface is described, all
- | | | together bNumInterfaces times, with the
- | | | the following 4 fields:
------------+--------+------------+---------------------------------------------------
- | 1 | | bInterfaceClass
------------+--------+------------+---------------------------------------------------
- 0x145 | 1 | | bInterfaceSubClass
------------+--------+------------+---------------------------------------------------
- 0x146 | 1 | | bInterfaceProtocol
------------+--------+------------+---------------------------------------------------
- 0x147 | 1 | | padding byte for alignment, shall be set to zero
------------+--------+------------+---------------------------------------------------
- 0xC + | | | The second exported USB device starts at i=1
- i*0x138 + | | | with the busid field.
- m_(i-1)*4 | | |
-
-OP_REQ_IMPORT: Request to import (attach) a remote USB device.
-
- Offset | Length | Value | Description
------------+--------+------------+---------------------------------------------------
- 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0
------------+--------+------------+---------------------------------------------------
- 2 | 2 | 0x8003 | Command code: import a remote USB device.
------------+--------+------------+---------------------------------------------------
- 4 | 4 | 0x00000000 | Status: unused, shall be set to 0
------------+--------+------------+---------------------------------------------------
- 8 | 32 | | busid: the busid of the exported device on the
- | | | remote host. The possible values are taken
- | | | from the message field OP_REP_DEVLIST.busid.
- | | | A string closed with zero, the unused bytes
- | | | shall be filled with zeros.
------------+--------+------------+---------------------------------------------------
-
-OP_REP_IMPORT: Reply to import (attach) a remote USB device.
-
- Offset | Length | Value | Description
------------+--------+------------+---------------------------------------------------
- 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0
------------+--------+------------+---------------------------------------------------
- 2 | 2 | 0x0003 | Reply code: Reply to import.
------------+--------+------------+---------------------------------------------------
- 4 | 4 | 0x00000000 | Status: 0 for OK
- | | | 1 for error
------------+--------+------------+---------------------------------------------------
- 8 | | | From now on comes the details of the imported
- | | | device, if the previous status field was OK (0),
- | | | otherwise the reply ends with the status field.
------------+--------+------------+---------------------------------------------------
- | 256 | | path: Path of the device on the host exporting the
- | | | USB device, string closed with zero byte, e.g.
- | | | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"
- | | | The unused bytes shall be filled with zero
- | | | bytes.
------------+--------+------------+---------------------------------------------------
- 0x108 | 32 | | busid: Bus ID of the exported device, string
- | | | closed with zero byte, e.g. "3-2". The unused
- | | | bytes shall be filled with zero bytes.
------------+--------+------------+---------------------------------------------------
- 0x128 | 4 | | busnum
------------+--------+------------+---------------------------------------------------
- 0x12C | 4 | | devnum
------------+--------+------------+---------------------------------------------------
- 0x130 | 4 | | speed
------------+--------+------------+---------------------------------------------------
- 0x134 | 2 | | idVendor
------------+--------+------------+---------------------------------------------------
- 0x136 | 2 | | idProduct
------------+--------+------------+---------------------------------------------------
- 0x138 | 2 | | bcdDevice
------------+--------+------------+---------------------------------------------------
- 0x139 | 1 | | bDeviceClass
------------+--------+------------+---------------------------------------------------
- 0x13A | 1 | | bDeviceSubClass
------------+--------+------------+---------------------------------------------------
- 0x13B | 1 | | bDeviceProtocol
------------+--------+------------+---------------------------------------------------
- 0x13C | 1 | | bConfigurationValue
------------+--------+------------+---------------------------------------------------
- 0x13D | 1 | | bNumConfigurations
------------+--------+------------+---------------------------------------------------
- 0x13E | 1 | | bNumInterfaces
-
-USBIP_CMD_SUBMIT: Submit an URB
-
- Offset | Length | Value | Description
------------+--------+------------+---------------------------------------------------
- 0 | 4 | 0x00000001 | command: Submit an URB
------------+--------+------------+---------------------------------------------------
- 4 | 4 | | seqnum: the sequence number of the URB to submit
------------+--------+------------+---------------------------------------------------
- 8 | 4 | | devid
------------+--------+------------+---------------------------------------------------
- 0xC | 4 | | direction: 0: USBIP_DIR_OUT
- | | | 1: USBIP_DIR_IN
------------+--------+------------+---------------------------------------------------
- 0x10 | 4 | | ep: endpoint number, possible values are: 0...15
------------+--------+------------+---------------------------------------------------
- 0x14 | 4 | | transfer_flags: possible values depend on the
- | | | URB transfer type, see below
------------+--------+------------+---------------------------------------------------
- 0x18 | 4 | | transfer_buffer_length
------------+--------+------------+---------------------------------------------------
- 0x1C | 4 | | start_frame: specify the selected frame to
- | | | transmit an ISO frame, ignored if URB_ISO_ASAP
- | | | is specified at transfer_flags
------------+--------+------------+---------------------------------------------------
- 0x20 | 4 | | number_of_packets: number of ISO packets
------------+--------+------------+---------------------------------------------------
- 0x24 | 4 | | interval: maximum time for the request on the
- | | | server-side host controller
------------+--------+------------+---------------------------------------------------
- 0x28 | 8 | | setup: data bytes for USB setup, filled with
- | | | zeros if not used
------------+--------+------------+---------------------------------------------------
- 0x30 | | | URB data. For ISO transfers the padding between
- | | | each ISO packets is not transmitted.
-
-
- Allowed transfer_flags | value | control | interrupt | bulk | isochronous
- -------------------------+------------+---------+-----------+----------+-------------
- URB_SHORT_NOT_OK | 0x00000001 | only in | only in | only in | no
- URB_ISO_ASAP | 0x00000002 | no | no | no | yes
- URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes | yes | yes | yes
- URB_NO_FSBR | 0x00000020 | yes | no | no | no
- URB_ZERO_PACKET | 0x00000040 | no | no | only out | no
- URB_NO_INTERRUPT | 0x00000080 | yes | yes | yes | yes
- URB_FREE_BUFFER | 0x00000100 | yes | yes | yes | yes
- URB_DIR_MASK | 0x00000200 | yes | yes | yes | yes
-
-
-USBIP_RET_SUBMIT: Reply for submitting an URB
-
- Offset | Length | Value | Description
------------+--------+------------+---------------------------------------------------
- 0 | 4 | 0x00000003 | command
------------+--------+------------+---------------------------------------------------
- 4 | 4 | | seqnum: URB sequence number
------------+--------+------------+---------------------------------------------------
- 8 | 4 | | devid
------------+--------+------------+---------------------------------------------------
- 0xC | 4 | | direction: 0: USBIP_DIR_OUT
- | | | 1: USBIP_DIR_IN
------------+--------+------------+---------------------------------------------------
- 0x10 | 4 | | ep: endpoint number
------------+--------+------------+---------------------------------------------------
- 0x14 | 4 | | status: zero for successful URB transaction,
- | | | otherwise some kind of error happened.
------------+--------+------------+---------------------------------------------------
- 0x18 | 4 | n | actual_length: number of URB data bytes
------------+--------+------------+---------------------------------------------------
- 0x1C | 4 | | start_frame: for an ISO frame the actually
- | | | selected frame for transmit.
------------+--------+------------+---------------------------------------------------
- 0x20 | 4 | | number_of_packets
------------+--------+------------+---------------------------------------------------
- 0x24 | 4 | | error_count
------------+--------+------------+---------------------------------------------------
- 0x28 | 8 | | setup: data bytes for USB setup, filled with
- | | | zeros if not used
------------+--------+------------+---------------------------------------------------
- 0x30 | n | | URB data bytes. For ISO transfers the padding
- | | | between each ISO packets is not transmitted.
-
-USBIP_CMD_UNLINK: Unlink an URB
-
- Offset | Length | Value | Description
------------+--------+------------+---------------------------------------------------
- 0 | 4 | 0x00000002 | command: URB unlink command
------------+--------+------------+---------------------------------------------------
- 4 | 4 | | seqnum: URB sequence number to unlink: FIXME: is this so?
------------+--------+------------+---------------------------------------------------
- 8 | 4 | | devid
------------+--------+------------+---------------------------------------------------
- 0xC | 4 | | direction: 0: USBIP_DIR_OUT
- | | | 1: USBIP_DIR_IN
------------+--------+------------+---------------------------------------------------
- 0x10 | 4 | | ep: endpoint number: zero
------------+--------+------------+---------------------------------------------------
- 0x14 | 4 | | seqnum: the URB sequence number given previously
- | | | at USBIP_CMD_SUBMIT.seqnum field
------------+--------+------------+---------------------------------------------------
- 0x30 | n | | URB data bytes. For ISO transfers the padding
- | | | between each ISO packets is not transmitted.
-
-USBIP_RET_UNLINK: Reply for URB unlink
-
- Offset | Length | Value | Description
------------+--------+------------+---------------------------------------------------
- 0 | 4 | 0x00000004 | command: reply for the URB unlink command
------------+--------+------------+---------------------------------------------------
- 4 | 4 | | seqnum: the unlinked URB sequence number
------------+--------+------------+---------------------------------------------------
- 8 | 4 | | devid
------------+--------+------------+---------------------------------------------------
- 0xC | 4 | | direction: 0: USBIP_DIR_OUT
- | | | 1: USBIP_DIR_IN
------------+--------+------------+---------------------------------------------------
- 0x10 | 4 | | ep: endpoint number
------------+--------+------------+---------------------------------------------------
- 0x14 | 4 | | status: This is the value contained in the
- | | | urb->status in the URB completition handler.
- | | | FIXME: a better explanation needed.
------------+--------+------------+---------------------------------------------------
- 0x30 | n | | URB data bytes. For ISO transfers the padding
- | | | between each ISO packets is not transmitted.
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 7fbe19d5279e..fca51105974e 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -121,9 +121,11 @@ static void dump_port_status_diff(u32 prev_status, u32 new_status)
void rh_port_connect(int rhport, enum usb_device_speed speed)
{
+ unsigned long flags;
+
usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
| (1 << USB_PORT_FEAT_C_CONNECTION);
@@ -139,22 +141,24 @@ void rh_port_connect(int rhport, enum usb_device_speed speed)
break;
}
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
}
static void rh_port_disconnect(int rhport)
{
+ unsigned long flags;
+
usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
the_controller->port_status[rhport] |=
(1 << USB_PORT_FEAT_C_CONNECTION);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
}
@@ -182,13 +186,14 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
int retval;
int rhport;
int changed = 0;
+ unsigned long flags;
retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8);
memset(buf, 0, retval);
vhci = hcd_to_vhci(hcd);
- spin_lock(&vhci->lock);
+ spin_lock_irqsave(&vhci->lock, flags);
if (!HCD_HW_ACCESSIBLE(hcd)) {
usbip_dbg_vhci_rh("hw accessible flag not on?\n");
goto done;
@@ -209,7 +214,7 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
usb_hcd_resume_root_hub(hcd);
done:
- spin_unlock(&vhci->lock);
+ spin_unlock_irqrestore(&vhci->lock, flags);
return changed ? retval : 0;
}
@@ -231,6 +236,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
struct vhci_hcd *dum;
int retval = 0;
int rhport;
+ unsigned long flags;
u32 prev_port_status[VHCI_NPORTS];
@@ -249,7 +255,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dum = hcd_to_vhci(hcd);
- spin_lock(&dum->lock);
+ spin_lock_irqsave(&dum->lock, flags);
/* store old status and compare now and old later */
if (usbip_dbg_flag_vhci_rh) {
@@ -403,7 +409,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
usbip_dbg_vhci_rh(" bye\n");
- spin_unlock(&dum->lock);
+ spin_unlock_irqrestore(&dum->lock, flags);
return retval;
}
@@ -426,6 +432,7 @@ static void vhci_tx_urb(struct urb *urb)
{
struct vhci_device *vdev = get_vdev(urb->dev);
struct vhci_priv *priv;
+ unsigned long flags;
if (!vdev) {
pr_err("could not get virtual device");
@@ -438,7 +445,7 @@ static void vhci_tx_urb(struct urb *urb)
return;
}
- spin_lock(&vdev->priv_lock);
+ spin_lock_irqsave(&vdev->priv_lock, flags);
priv->seqnum = atomic_inc_return(&the_controller->seqnum);
if (priv->seqnum == 0xffff)
@@ -452,7 +459,7 @@ static void vhci_tx_urb(struct urb *urb)
list_add_tail(&priv->list, &vdev->priv_tx);
wake_up(&vdev->waitq_tx);
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
}
static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
@@ -461,6 +468,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
struct device *dev = &urb->dev->dev;
int ret = 0;
struct vhci_device *vdev;
+ unsigned long flags;
usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
hcd, urb, mem_flags);
@@ -468,11 +476,11 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
/* patch to usb_sg_init() is in 2.5.60 */
BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
if (urb->status != -EINPROGRESS) {
dev_err(dev, "URB already unlinked!, status %d\n", urb->status);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
return urb->status;
}
@@ -484,7 +492,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
vdev->ud.status == VDEV_ST_ERROR) {
dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport);
spin_unlock(&vdev->ud.lock);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
return -ENODEV;
}
spin_unlock(&vdev->ud.lock);
@@ -557,14 +565,14 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
out:
vhci_tx_urb(urb);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
return 0;
no_need_xmit:
usb_hcd_unlink_urb_from_ep(hcd, urb);
no_need_unlink:
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
if (!ret)
usb_hcd_giveback_urb(vhci_to_hcd(the_controller),
urb, urb->status);
@@ -621,16 +629,17 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct vhci_priv *priv;
struct vhci_device *vdev;
+ unsigned long flags;
pr_info("dequeue a urb %p\n", urb);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
priv = urb->hcpriv;
if (!priv) {
/* URB was never linked! or will be soon given back by
* vhci_rx. */
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
return -EIDRM;
}
@@ -639,7 +648,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
if (ret) {
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
return ret;
}
}
@@ -667,10 +676,10 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
urb->status);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
} else {
/* tcp connection is alive */
@@ -682,7 +691,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC);
if (!unlink) {
spin_unlock(&vdev->priv_lock);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
return -ENOMEM;
}
@@ -703,7 +712,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
spin_unlock(&vdev->priv_lock);
}
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
usbip_dbg_vhci_hc("leave\n");
return 0;
@@ -712,8 +721,9 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
{
struct vhci_unlink *unlink, *tmp;
+ unsigned long flags;
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
spin_lock(&vdev->priv_lock);
list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
@@ -747,19 +757,19 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
list_del(&unlink->list);
spin_unlock(&vdev->priv_lock);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
urb->status);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
spin_lock(&vdev->priv_lock);
kfree(unlink);
}
spin_unlock(&vdev->priv_lock);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
}
/*
@@ -826,8 +836,9 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
static void vhci_device_reset(struct usbip_device *ud)
{
struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+ unsigned long flags;
- spin_lock(&ud->lock);
+ spin_lock_irqsave(&ud->lock, flags);
vdev->speed = 0;
vdev->devid = 0;
@@ -841,14 +852,16 @@ static void vhci_device_reset(struct usbip_device *ud)
}
ud->status = VDEV_ST_NULL;
- spin_unlock(&ud->lock);
+ spin_unlock_irqrestore(&ud->lock, flags);
}
static void vhci_device_unusable(struct usbip_device *ud)
{
- spin_lock(&ud->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ud->lock, flags);
ud->status = VDEV_ST_ERROR;
- spin_unlock(&ud->lock);
+ spin_unlock_irqrestore(&ud->lock, flags);
}
static void vhci_device_init(struct vhci_device *vdev)
@@ -938,12 +951,13 @@ static int vhci_get_frame_number(struct usb_hcd *hcd)
static int vhci_bus_suspend(struct usb_hcd *hcd)
{
struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ unsigned long flags;
dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
- spin_lock(&vhci->lock);
+ spin_lock_irqsave(&vhci->lock, flags);
hcd->state = HC_STATE_SUSPENDED;
- spin_unlock(&vhci->lock);
+ spin_unlock_irqrestore(&vhci->lock, flags);
return 0;
}
@@ -952,15 +966,16 @@ static int vhci_bus_resume(struct usb_hcd *hcd)
{
struct vhci_hcd *vhci = hcd_to_vhci(hcd);
int rc = 0;
+ unsigned long flags;
dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
- spin_lock(&vhci->lock);
+ spin_lock_irqsave(&vhci->lock, flags);
if (!HCD_HW_ACCESSIBLE(hcd))
rc = -ESHUTDOWN;
else
hcd->state = HC_STATE_RUNNING;
- spin_unlock(&vhci->lock);
+ spin_unlock_irqrestore(&vhci->lock, flags);
return rc;
}
@@ -1058,17 +1073,18 @@ static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
int rhport = 0;
int connected = 0;
int ret = 0;
+ unsigned long flags;
hcd = platform_get_drvdata(pdev);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
for (rhport = 0; rhport < VHCI_NPORTS; rhport++)
if (the_controller->port_status[rhport] &
USB_PORT_STAT_CONNECTION)
connected += 1;
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
if (connected > 0) {
dev_info(&pdev->dev,
diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c
index 00e4a54308e4..d656e0edc3d5 100644
--- a/drivers/usb/usbip/vhci_rx.c
+++ b/drivers/usb/usbip/vhci_rx.c
@@ -72,10 +72,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
{
struct usbip_device *ud = &vdev->ud;
struct urb *urb;
+ unsigned long flags;
- spin_lock(&vdev->priv_lock);
+ spin_lock_irqsave(&vdev->priv_lock, flags);
urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
if (!urb) {
pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
@@ -104,9 +105,9 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
@@ -117,8 +118,9 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
struct usbip_header *pdu)
{
struct vhci_unlink *unlink, *tmp;
+ unsigned long flags;
- spin_lock(&vdev->priv_lock);
+ spin_lock_irqsave(&vdev->priv_lock, flags);
list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
pr_info("unlink->seqnum %lu\n", unlink->seqnum);
@@ -127,12 +129,12 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
unlink->seqnum);
list_del(&unlink->list);
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
return unlink;
}
}
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
return NULL;
}
@@ -142,6 +144,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
{
struct vhci_unlink *unlink;
struct urb *urb;
+ unsigned long flags;
usbip_dump_header(pdu);
@@ -152,9 +155,9 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
return;
}
- spin_lock(&vdev->priv_lock);
+ spin_lock_irqsave(&vdev->priv_lock, flags);
urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
if (!urb) {
/*
@@ -171,9 +174,9 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
urb->status = pdu->u.ret_unlink.status;
pr_info("urb->status %d\n", urb->status);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
urb->status);
@@ -185,10 +188,11 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
static int vhci_priv_tx_empty(struct vhci_device *vdev)
{
int empty = 0;
+ unsigned long flags;
- spin_lock(&vdev->priv_lock);
+ spin_lock_irqsave(&vdev->priv_lock, flags);
empty = list_empty(&vdev->priv_rx);
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
return empty;
}
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
index 211f43f67ea2..5b5462eb1665 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -32,10 +32,11 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
{
char *s = out;
int i = 0;
+ unsigned long flags;
BUG_ON(!the_controller || !out);
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
/*
* output example:
@@ -70,7 +71,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
spin_unlock(&vdev->ud.lock);
}
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
return out - s;
}
@@ -80,11 +81,12 @@ static DEVICE_ATTR_RO(status);
static int vhci_port_disconnect(__u32 rhport)
{
struct vhci_device *vdev;
+ unsigned long flags;
usbip_dbg_vhci_sysfs("enter\n");
/* lock */
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
vdev = port_to_vdev(rhport);
@@ -94,14 +96,14 @@ static int vhci_port_disconnect(__u32 rhport)
/* unlock */
spin_unlock(&vdev->ud.lock);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
return -EINVAL;
}
/* unlock */
spin_unlock(&vdev->ud.lock);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
@@ -177,6 +179,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
int sockfd = 0;
__u32 rhport = 0, devid = 0, speed = 0;
int err;
+ unsigned long flags;
/*
* @rhport: port number of vhci_hcd
@@ -202,14 +205,14 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
/* now need lock until setting vdev status as used */
/* begin a lock */
- spin_lock(&the_controller->lock);
+ spin_lock_irqsave(&the_controller->lock, flags);
vdev = port_to_vdev(rhport);
spin_lock(&vdev->ud.lock);
if (vdev->ud.status != VDEV_ST_NULL) {
/* end of the lock */
spin_unlock(&vdev->ud.lock);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
sockfd_put(socket);
@@ -227,7 +230,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
vdev->ud.status = VDEV_ST_NOTASSIGNED;
spin_unlock(&vdev->ud.lock);
- spin_unlock(&the_controller->lock);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
/* end the lock */
vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
diff --git a/drivers/usb/usbip/vhci_tx.c b/drivers/usb/usbip/vhci_tx.c
index 409fd99f3257..3e7878fe2fd4 100644
--- a/drivers/usb/usbip/vhci_tx.c
+++ b/drivers/usb/usbip/vhci_tx.c
@@ -47,16 +47,17 @@ static void setup_cmd_submit_pdu(struct usbip_header *pdup, struct urb *urb)
static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev)
{
struct vhci_priv *priv, *tmp;
+ unsigned long flags;
- spin_lock(&vdev->priv_lock);
+ spin_lock_irqsave(&vdev->priv_lock, flags);
list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
list_move_tail(&priv->list, &vdev->priv_rx);
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
return priv;
}
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
return NULL;
}
@@ -136,16 +137,17 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev)
static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
{
struct vhci_unlink *unlink, *tmp;
+ unsigned long flags;
- spin_lock(&vdev->priv_lock);
+ spin_lock_irqsave(&vdev->priv_lock, flags);
list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
list_move_tail(&unlink->list, &vdev->unlink_rx);
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
return unlink;
}
- spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
return NULL;
}
diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c
index 50ce80d604f3..8ed8e34c3492 100644
--- a/drivers/usb/wusbcore/crypto.c
+++ b/drivers/usb/wusbcore/crypto.c
@@ -45,6 +45,7 @@
* funneled through AES are...16 bytes in size!
*/
+#include <crypto/skcipher.h>
#include <linux/crypto.h>
#include <linux/module.h>
#include <linux/err.h>
@@ -195,21 +196,22 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
* NOTE: blen is not aligned to a block size, we'll pad zeros, that's
* what sg[4] is for. Maybe there is a smarter way to do this.
*/
-static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc,
+static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
struct crypto_cipher *tfm_aes, void *mic,
const struct aes_ccm_nonce *n,
const struct aes_ccm_label *a, const void *b,
size_t blen)
{
int result = 0;
- struct blkcipher_desc desc;
+ SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc);
struct aes_ccm_b0 b0;
struct aes_ccm_b1 b1;
struct aes_ccm_a ax;
struct scatterlist sg[4], sg_dst;
- void *iv, *dst_buf;
- size_t ivsize, dst_size;
+ void *dst_buf;
+ size_t dst_size;
const u8 bzero[16] = { 0 };
+ u8 iv[crypto_skcipher_ivsize(tfm_cbc)];
size_t zero_padding;
/*
@@ -232,9 +234,7 @@ static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc,
goto error_dst_buf;
}
- iv = crypto_blkcipher_crt(tfm_cbc)->iv;
- ivsize = crypto_blkcipher_ivsize(tfm_cbc);
- memset(iv, 0, ivsize);
+ memset(iv, 0, sizeof(iv));
/* Setup B0 */
b0.flags = 0x59; /* Format B0 */
@@ -259,9 +259,11 @@ static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc,
sg_set_buf(&sg[3], bzero, zero_padding);
sg_init_one(&sg_dst, dst_buf, dst_size);
- desc.tfm = tfm_cbc;
- desc.flags = 0;
- result = crypto_blkcipher_encrypt(&desc, &sg_dst, sg, dst_size);
+ skcipher_request_set_tfm(req, tfm_cbc);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, sg, &sg_dst, dst_size, iv);
+ result = crypto_skcipher_encrypt(req);
+ skcipher_request_zero(req);
if (result < 0) {
printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n",
result);
@@ -301,18 +303,18 @@ ssize_t wusb_prf(void *out, size_t out_size,
{
ssize_t result, bytes = 0, bitr;
struct aes_ccm_nonce n = *_n;
- struct crypto_blkcipher *tfm_cbc;
+ struct crypto_skcipher *tfm_cbc;
struct crypto_cipher *tfm_aes;
u64 sfn = 0;
__le64 sfn_le;
- tfm_cbc = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+ tfm_cbc = crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm_cbc)) {
result = PTR_ERR(tfm_cbc);
printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result);
goto error_alloc_cbc;
}
- result = crypto_blkcipher_setkey(tfm_cbc, key, 16);
+ result = crypto_skcipher_setkey(tfm_cbc, key, 16);
if (result < 0) {
printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result);
goto error_setkey_cbc;
@@ -345,7 +347,7 @@ error_setkey_aes:
crypto_free_cipher(tfm_aes);
error_alloc_aes:
error_setkey_cbc:
- crypto_free_blkcipher(tfm_cbc);
+ crypto_free_skcipher(tfm_cbc);
error_alloc_cbc:
return result;
}
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h
index 41838db7f85c..8c5bd000739b 100644
--- a/drivers/usb/wusbcore/wusbhc.h
+++ b/drivers/usb/wusbcore/wusbhc.h
@@ -336,7 +336,7 @@ static inline
struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev)
{
struct usb_hcd *usb_hcd;
- usb_hcd = container_of(usb_dev->bus, struct usb_hcd, self);
+ usb_hcd = bus_to_hcd(usb_dev->bus);
return usb_get_hcd(usb_hcd);
}
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
index 02912f180c6d..24ee2605b9f0 100644
--- a/drivers/vfio/pci/Kconfig
+++ b/drivers/vfio/pci/Kconfig
@@ -26,3 +26,7 @@ config VFIO_PCI_MMAP
config VFIO_PCI_INTX
depends on VFIO_PCI
def_bool y if !S390
+
+config VFIO_PCI_IGD
+ depends on VFIO_PCI
+ def_bool y if X86
diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
index 131079255fd9..76d8ec058edd 100644
--- a/drivers/vfio/pci/Makefile
+++ b/drivers/vfio/pci/Makefile
@@ -1,4 +1,5 @@
vfio-pci-y := vfio_pci.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o
+vfio-pci-$(CONFIG_VFIO_PCI_IGD) += vfio_pci_igd.o
obj-$(CONFIG_VFIO_PCI) += vfio-pci.o
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 2760a7ba3f30..712a84978e97 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -111,6 +111,7 @@ static inline bool vfio_pci_is_vga(struct pci_dev *pdev)
}
static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev);
+static void vfio_pci_disable(struct vfio_pci_device *vdev);
static int vfio_pci_enable(struct vfio_pci_device *vdev)
{
@@ -169,13 +170,26 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
if (!vfio_vga_disabled() && vfio_pci_is_vga(pdev))
vdev->has_vga = true;
+
+ if (vfio_pci_is_vga(pdev) &&
+ pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ IS_ENABLED(CONFIG_VFIO_PCI_IGD)) {
+ ret = vfio_pci_igd_init(vdev);
+ if (ret) {
+ dev_warn(&vdev->pdev->dev,
+ "Failed to setup Intel IGD regions\n");
+ vfio_pci_disable(vdev);
+ return ret;
+ }
+ }
+
return 0;
}
static void vfio_pci_disable(struct vfio_pci_device *vdev)
{
struct pci_dev *pdev = vdev->pdev;
- int bar;
+ int i, bar;
/* Stop the device from further DMA */
pci_clear_master(pdev);
@@ -186,6 +200,13 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
vdev->virq_disabled = false;
+ for (i = 0; i < vdev->num_regions; i++)
+ vdev->region[i].ops->release(vdev, &vdev->region[i]);
+
+ vdev->num_regions = 0;
+ kfree(vdev->region);
+ vdev->region = NULL; /* don't krealloc a freed pointer */
+
vfio_config_free(vdev);
for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) {
@@ -421,6 +442,93 @@ static int vfio_pci_for_each_slot_or_bus(struct pci_dev *pdev,
return walk.ret;
}
+static int msix_sparse_mmap_cap(struct vfio_pci_device *vdev,
+ struct vfio_info_cap *caps)
+{
+ struct vfio_info_cap_header *header;
+ struct vfio_region_info_cap_sparse_mmap *sparse;
+ size_t end, size;
+ int nr_areas = 2, i = 0;
+
+ end = pci_resource_len(vdev->pdev, vdev->msix_bar);
+
+ /* If MSI-X table is aligned to the start or end, only one area */
+ if (((vdev->msix_offset & PAGE_MASK) == 0) ||
+ (PAGE_ALIGN(vdev->msix_offset + vdev->msix_size) >= end))
+ nr_areas = 1;
+
+ size = sizeof(*sparse) + (nr_areas * sizeof(*sparse->areas));
+
+ header = vfio_info_cap_add(caps, size,
+ VFIO_REGION_INFO_CAP_SPARSE_MMAP, 1);
+ if (IS_ERR(header))
+ return PTR_ERR(header);
+
+ sparse = container_of(header,
+ struct vfio_region_info_cap_sparse_mmap, header);
+ sparse->nr_areas = nr_areas;
+
+ if (vdev->msix_offset & PAGE_MASK) {
+ sparse->areas[i].offset = 0;
+ sparse->areas[i].size = vdev->msix_offset & PAGE_MASK;
+ i++;
+ }
+
+ if (PAGE_ALIGN(vdev->msix_offset + vdev->msix_size) < end) {
+ sparse->areas[i].offset = PAGE_ALIGN(vdev->msix_offset +
+ vdev->msix_size);
+ sparse->areas[i].size = end - sparse->areas[i].offset;
+ i++;
+ }
+
+ return 0;
+}
+
+static int region_type_cap(struct vfio_pci_device *vdev,
+ struct vfio_info_cap *caps,
+ unsigned int type, unsigned int subtype)
+{
+ struct vfio_info_cap_header *header;
+ struct vfio_region_info_cap_type *cap;
+
+ header = vfio_info_cap_add(caps, sizeof(*cap),
+ VFIO_REGION_INFO_CAP_TYPE, 1);
+ if (IS_ERR(header))
+ return PTR_ERR(header);
+
+ cap = container_of(header, struct vfio_region_info_cap_type, header);
+ cap->type = type;
+ cap->subtype = subtype;
+
+ return 0;
+}
+
+int vfio_pci_register_dev_region(struct vfio_pci_device *vdev,
+ unsigned int type, unsigned int subtype,
+ const struct vfio_pci_regops *ops,
+ size_t size, u32 flags, void *data)
+{
+ struct vfio_pci_region *region;
+
+ region = krealloc(vdev->region,
+ (vdev->num_regions + 1) * sizeof(*region),
+ GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+
+ vdev->region = region;
+ vdev->region[vdev->num_regions].type = type;
+ vdev->region[vdev->num_regions].subtype = subtype;
+ vdev->region[vdev->num_regions].ops = ops;
+ vdev->region[vdev->num_regions].size = size;
+ vdev->region[vdev->num_regions].flags = flags;
+ vdev->region[vdev->num_regions].data = data;
+
+ vdev->num_regions++;
+
+ return 0;
+}
+
static long vfio_pci_ioctl(void *device_data,
unsigned int cmd, unsigned long arg)
{
@@ -443,14 +551,17 @@ static long vfio_pci_ioctl(void *device_data,
if (vdev->reset_works)
info.flags |= VFIO_DEVICE_FLAGS_RESET;
- info.num_regions = VFIO_PCI_NUM_REGIONS;
+ info.num_regions = VFIO_PCI_NUM_REGIONS + vdev->num_regions;
info.num_irqs = VFIO_PCI_NUM_IRQS;
- return copy_to_user((void __user *)arg, &info, minsz);
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
} else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
struct pci_dev *pdev = vdev->pdev;
struct vfio_region_info info;
+ struct vfio_info_cap caps = { .buf = NULL, .size = 0 };
+ int i, ret;
minsz = offsetofend(struct vfio_region_info, offset);
@@ -479,8 +590,15 @@ static long vfio_pci_ioctl(void *device_data,
VFIO_REGION_INFO_FLAG_WRITE;
if (IS_ENABLED(CONFIG_VFIO_PCI_MMAP) &&
pci_resource_flags(pdev, info.index) &
- IORESOURCE_MEM && info.size >= PAGE_SIZE)
+ IORESOURCE_MEM && info.size >= PAGE_SIZE) {
info.flags |= VFIO_REGION_INFO_FLAG_MMAP;
+ if (info.index == vdev->msix_bar) {
+ ret = msix_sparse_mmap_cap(vdev, &caps);
+ if (ret)
+ return ret;
+ }
+ }
+
break;
case VFIO_PCI_ROM_REGION_INDEX:
{
@@ -492,8 +610,14 @@ static long vfio_pci_ioctl(void *device_data,
/* Report the BAR size, not the ROM size */
info.size = pci_resource_len(pdev, info.index);
- if (!info.size)
- break;
+ if (!info.size) {
+ /* Shadow ROMs appear as PCI option ROMs */
+ if (pdev->resource[PCI_ROM_RESOURCE].flags &
+ IORESOURCE_ROM_SHADOW)
+ info.size = 0x20000;
+ else
+ break;
+ }
/* Is it really there? */
io = pci_map_rom(pdev, &size);
@@ -517,10 +641,44 @@ static long vfio_pci_ioctl(void *device_data,
break;
default:
- return -EINVAL;
+ if (info.index >=
+ VFIO_PCI_NUM_REGIONS + vdev->num_regions)
+ return -EINVAL;
+
+ i = info.index - VFIO_PCI_NUM_REGIONS;
+
+ info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+ info.size = vdev->region[i].size;
+ info.flags = vdev->region[i].flags;
+
+ ret = region_type_cap(vdev, &caps,
+ vdev->region[i].type,
+ vdev->region[i].subtype);
+ if (ret)
+ return ret;
+ }
+
+ if (caps.size) {
+ info.flags |= VFIO_REGION_INFO_FLAG_CAPS;
+ if (info.argsz < sizeof(info) + caps.size) {
+ info.argsz = sizeof(info) + caps.size;
+ info.cap_offset = 0;
+ } else {
+ vfio_info_cap_shift(&caps, sizeof(info));
+ if (copy_to_user((void __user *)arg +
+ sizeof(info), caps.buf,
+ caps.size)) {
+ kfree(caps.buf);
+ return -EFAULT;
+ }
+ info.cap_offset = sizeof(info);
+ }
+
+ kfree(caps.buf);
}
- return copy_to_user((void __user *)arg, &info, minsz);
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
} else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
struct vfio_irq_info info;
@@ -555,7 +713,8 @@ static long vfio_pci_ioctl(void *device_data,
else
info.flags |= VFIO_IRQ_INFO_NORESIZE;
- return copy_to_user((void __user *)arg, &info, minsz);
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
} else if (cmd == VFIO_DEVICE_SET_IRQS) {
struct vfio_irq_set hdr;
@@ -795,7 +954,7 @@ static ssize_t vfio_pci_rw(void *device_data, char __user *buf,
unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
struct vfio_pci_device *vdev = device_data;
- if (index >= VFIO_PCI_NUM_REGIONS)
+ if (index >= VFIO_PCI_NUM_REGIONS + vdev->num_regions)
return -EINVAL;
switch (index) {
@@ -812,6 +971,10 @@ static ssize_t vfio_pci_rw(void *device_data, char __user *buf,
case VFIO_PCI_VGA_REGION_INDEX:
return vfio_pci_vga_rw(vdev, buf, count, ppos, iswrite);
+ default:
+ index -= VFIO_PCI_NUM_REGIONS;
+ return vdev->region[index].ops->rw(vdev, buf,
+ count, ppos, iswrite);
}
return -EINVAL;
@@ -994,6 +1157,7 @@ static void vfio_pci_remove(struct pci_dev *pdev)
return;
vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev);
+ kfree(vdev->region);
kfree(vdev);
if (vfio_pci_is_vga(pdev)) {
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index fe2b470d7ec6..142c533efec7 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -33,9 +33,8 @@
#define PCI_CFG_SPACE_SIZE 256
-/* Useful "pseudo" capabilities */
+/* Fake capability ID for standard config space */
#define PCI_CAP_ID_BASIC 0
-#define PCI_CAP_ID_INVALID 0xFF
#define is_bar(offset) \
((offset >= PCI_BASE_ADDRESS_0 && offset < PCI_BASE_ADDRESS_5 + 4) || \
@@ -301,6 +300,23 @@ static int vfio_raw_config_read(struct vfio_pci_device *vdev, int pos,
return count;
}
+/* Virt access uses only virtualization */
+static int vfio_virt_config_write(struct vfio_pci_device *vdev, int pos,
+ int count, struct perm_bits *perm,
+ int offset, __le32 val)
+{
+ memcpy(vdev->vconfig + pos, &val, count);
+ return count;
+}
+
+static int vfio_virt_config_read(struct vfio_pci_device *vdev, int pos,
+ int count, struct perm_bits *perm,
+ int offset, __le32 *val)
+{
+ memcpy(val, vdev->vconfig + pos, count);
+ return count;
+}
+
/* Default capability regions to read-only, no-virtualization */
static struct perm_bits cap_perms[PCI_CAP_ID_MAX + 1] = {
[0 ... PCI_CAP_ID_MAX] = { .readfn = vfio_direct_config_read }
@@ -319,6 +335,11 @@ static struct perm_bits unassigned_perms = {
.writefn = vfio_raw_config_write
};
+static struct perm_bits virt_perms = {
+ .readfn = vfio_virt_config_read,
+ .writefn = vfio_virt_config_write
+};
+
static void free_perm_bits(struct perm_bits *perm)
{
kfree(perm->virt);
@@ -454,14 +475,19 @@ static void vfio_bar_fixup(struct vfio_pci_device *vdev)
bar = (__le32 *)&vdev->vconfig[PCI_ROM_ADDRESS];
/*
- * NB. we expose the actual BAR size here, regardless of whether
- * we can read it. When we report the REGION_INFO for the ROM
- * we report what PCI tells us is the actual ROM size.
+ * NB. REGION_INFO will have reported zero size if we weren't able
+ * to read the ROM, but we still return the actual BAR size here if
+ * it exists (or the shadow ROM space).
*/
if (pci_resource_start(pdev, PCI_ROM_RESOURCE)) {
mask = ~(pci_resource_len(pdev, PCI_ROM_RESOURCE) - 1);
mask |= PCI_ROM_ADDRESS_ENABLE;
*bar &= cpu_to_le32((u32)mask);
+ } else if (pdev->resource[PCI_ROM_RESOURCE].flags &
+ IORESOURCE_ROM_SHADOW) {
+ mask = ~(0x20000 - 1);
+ mask |= PCI_ROM_ADDRESS_ENABLE;
+ *bar &= cpu_to_le32((u32)mask);
} else
*bar = 0;
@@ -1332,6 +1358,8 @@ static int vfio_cap_init(struct vfio_pci_device *vdev)
pos + i, map[pos + i], cap);
}
+ BUILD_BUG_ON(PCI_CAP_ID_MAX >= PCI_CAP_ID_INVALID_VIRT);
+
memset(map + pos, cap, len);
ret = vfio_fill_vconfig_bytes(vdev, pos, len);
if (ret)
@@ -1419,9 +1447,9 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
/*
* Even though ecap is 2 bytes, we're currently a long way
* from exceeding 1 byte capabilities. If we ever make it
- * up to 0xFF we'll need to up this to a two-byte, byte map.
+ * up to 0xFE we'll need to up this to a two-byte, byte map.
*/
- BUILD_BUG_ON(PCI_EXT_CAP_ID_MAX >= PCI_CAP_ID_INVALID);
+ BUILD_BUG_ON(PCI_EXT_CAP_ID_MAX >= PCI_CAP_ID_INVALID_VIRT);
memset(map + epos, ecap, len);
ret = vfio_fill_vconfig_bytes(vdev, epos, len);
@@ -1597,6 +1625,9 @@ static ssize_t vfio_config_do_rw(struct vfio_pci_device *vdev, char __user *buf,
if (cap_id == PCI_CAP_ID_INVALID) {
perm = &unassigned_perms;
cap_start = *ppos;
+ } else if (cap_id == PCI_CAP_ID_INVALID_VIRT) {
+ perm = &virt_perms;
+ cap_start = *ppos;
} else {
if (*ppos >= PCI_CFG_SPACE_SIZE) {
WARN_ON(cap_id > PCI_EXT_CAP_ID_MAX);
diff --git a/drivers/vfio/pci/vfio_pci_igd.c b/drivers/vfio/pci/vfio_pci_igd.c
new file mode 100644
index 000000000000..6394b168ef29
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_igd.c
@@ -0,0 +1,280 @@
+/*
+ * VFIO PCI Intel Graphics support
+ *
+ * Copyright (C) 2016 Red Hat, Inc. All rights reserved.
+ * Author: Alex Williamson <alex.williamson@redhat.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * Register a device specific region through which to provide read-only
+ * access to the Intel IGD opregion. The register defining the opregion
+ * address is also virtualized to prevent user modification.
+ */
+
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+#include <linux/vfio.h>
+
+#include "vfio_pci_private.h"
+
+#define OPREGION_SIGNATURE "IntelGraphicsMem"
+#define OPREGION_SIZE (8 * 1024)
+#define OPREGION_PCI_ADDR 0xfc
+
+static size_t vfio_pci_igd_rw(struct vfio_pci_device *vdev, char __user *buf,
+ size_t count, loff_t *ppos, bool iswrite)
+{
+ unsigned int i = VFIO_PCI_OFFSET_TO_INDEX(*ppos) - VFIO_PCI_NUM_REGIONS;
+ void *base = vdev->region[i].data;
+ loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+
+ if (pos >= vdev->region[i].size || iswrite)
+ return -EINVAL;
+
+ count = min(count, (size_t)(vdev->region[i].size - pos));
+
+ if (copy_to_user(buf, base + pos, count))
+ return -EFAULT;
+
+ *ppos += count;
+
+ return count;
+}
+
+static void vfio_pci_igd_release(struct vfio_pci_device *vdev,
+ struct vfio_pci_region *region)
+{
+ memunmap(region->data);
+}
+
+static const struct vfio_pci_regops vfio_pci_igd_regops = {
+ .rw = vfio_pci_igd_rw,
+ .release = vfio_pci_igd_release,
+};
+
+static int vfio_pci_igd_opregion_init(struct vfio_pci_device *vdev)
+{
+ __le32 *dwordp = (__le32 *)(vdev->vconfig + OPREGION_PCI_ADDR);
+ u32 addr, size;
+ void *base;
+ int ret;
+
+ ret = pci_read_config_dword(vdev->pdev, OPREGION_PCI_ADDR, &addr);
+ if (ret)
+ return ret;
+
+ if (!addr || !(~addr))
+ return -ENODEV;
+
+ base = memremap(addr, OPREGION_SIZE, MEMREMAP_WB);
+ if (!base)
+ return -ENOMEM;
+
+ if (memcmp(base, OPREGION_SIGNATURE, 16)) {
+ memunmap(base);
+ return -EINVAL;
+ }
+
+ size = le32_to_cpu(*(__le32 *)(base + 16));
+ if (!size) {
+ memunmap(base);
+ return -EINVAL;
+ }
+
+ size *= 1024; /* In KB */
+
+ if (size != OPREGION_SIZE) {
+ memunmap(base);
+ base = memremap(addr, size, MEMREMAP_WB);
+ if (!base)
+ return -ENOMEM;
+ }
+
+ ret = vfio_pci_register_dev_region(vdev,
+ PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE,
+ VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION,
+ &vfio_pci_igd_regops, size, VFIO_REGION_INFO_FLAG_READ, base);
+ if (ret) {
+ memunmap(base);
+ return ret;
+ }
+
+ /* Fill vconfig with the hw value and virtualize register */
+ *dwordp = cpu_to_le32(addr);
+ memset(vdev->pci_config_map + OPREGION_PCI_ADDR,
+ PCI_CAP_ID_INVALID_VIRT, 4);
+
+ return ret;
+}
+
+static size_t vfio_pci_igd_cfg_rw(struct vfio_pci_device *vdev,
+ char __user *buf, size_t count, loff_t *ppos,
+ bool iswrite)
+{
+ unsigned int i = VFIO_PCI_OFFSET_TO_INDEX(*ppos) - VFIO_PCI_NUM_REGIONS;
+ struct pci_dev *pdev = vdev->region[i].data;
+ loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+ size_t size;
+ int ret;
+
+ if (pos >= vdev->region[i].size || iswrite)
+ return -EINVAL;
+
+ size = count = min(count, (size_t)(vdev->region[i].size - pos));
+
+ if ((pos & 1) && size) {
+ u8 val;
+
+ ret = pci_user_read_config_byte(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ if (copy_to_user(buf + count - size, &val, 1))
+ return -EFAULT;
+
+ pos++;
+ size--;
+ }
+
+ if ((pos & 3) && size > 2) {
+ u16 val;
+
+ ret = pci_user_read_config_word(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ val = cpu_to_le16(val);
+ if (copy_to_user(buf + count - size, &val, 2))
+ return -EFAULT;
+
+ pos += 2;
+ size -= 2;
+ }
+
+ while (size > 3) {
+ u32 val;
+
+ ret = pci_user_read_config_dword(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ val = cpu_to_le32(val);
+ if (copy_to_user(buf + count - size, &val, 4))
+ return -EFAULT;
+
+ pos += 4;
+ size -= 4;
+ }
+
+ while (size >= 2) {
+ u16 val;
+
+ ret = pci_user_read_config_word(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ val = cpu_to_le16(val);
+ if (copy_to_user(buf + count - size, &val, 2))
+ return -EFAULT;
+
+ pos += 2;
+ size -= 2;
+ }
+
+ while (size) {
+ u8 val;
+
+ ret = pci_user_read_config_byte(pdev, pos, &val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ if (copy_to_user(buf + count - size, &val, 1))
+ return -EFAULT;
+
+ pos++;
+ size--;
+ }
+
+ *ppos += count;
+
+ return count;
+}
+
+static void vfio_pci_igd_cfg_release(struct vfio_pci_device *vdev,
+ struct vfio_pci_region *region)
+{
+ struct pci_dev *pdev = region->data;
+
+ pci_dev_put(pdev);
+}
+
+static const struct vfio_pci_regops vfio_pci_igd_cfg_regops = {
+ .rw = vfio_pci_igd_cfg_rw,
+ .release = vfio_pci_igd_cfg_release,
+};
+
+static int vfio_pci_igd_cfg_init(struct vfio_pci_device *vdev)
+{
+ struct pci_dev *host_bridge, *lpc_bridge;
+ int ret;
+
+ host_bridge = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
+ if (!host_bridge)
+ return -ENODEV;
+
+ if (host_bridge->vendor != PCI_VENDOR_ID_INTEL ||
+ host_bridge->class != (PCI_CLASS_BRIDGE_HOST << 8)) {
+ pci_dev_put(host_bridge);
+ return -EINVAL;
+ }
+
+ ret = vfio_pci_register_dev_region(vdev,
+ PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE,
+ VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG,
+ &vfio_pci_igd_cfg_regops, host_bridge->cfg_size,
+ VFIO_REGION_INFO_FLAG_READ, host_bridge);
+ if (ret) {
+ pci_dev_put(host_bridge);
+ return ret;
+ }
+
+ lpc_bridge = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x1f, 0));
+ if (!lpc_bridge)
+ return -ENODEV;
+
+ if (lpc_bridge->vendor != PCI_VENDOR_ID_INTEL ||
+ lpc_bridge->class != (PCI_CLASS_BRIDGE_ISA << 8)) {
+ pci_dev_put(lpc_bridge);
+ return -EINVAL;
+ }
+
+ ret = vfio_pci_register_dev_region(vdev,
+ PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE,
+ VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG,
+ &vfio_pci_igd_cfg_regops, lpc_bridge->cfg_size,
+ VFIO_REGION_INFO_FLAG_READ, lpc_bridge);
+ if (ret) {
+ pci_dev_put(lpc_bridge);
+ return ret;
+ }
+
+ return 0;
+}
+
+int vfio_pci_igd_init(struct vfio_pci_device *vdev)
+{
+ int ret;
+
+ ret = vfio_pci_igd_opregion_init(vdev);
+ if (ret)
+ return ret;
+
+ ret = vfio_pci_igd_cfg_init(vdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 3b3ba15558b7..e9ea3fef144a 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -309,14 +309,14 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_device *vdev,
int vector, int fd, bool msix)
{
struct pci_dev *pdev = vdev->pdev;
- int irq = msix ? vdev->msix[vector].vector : pdev->irq + vector;
- char *name = msix ? "vfio-msix" : "vfio-msi";
struct eventfd_ctx *trigger;
- int ret;
+ int irq, ret;
- if (vector >= vdev->num_ctx)
+ if (vector < 0 || vector >= vdev->num_ctx)
return -EINVAL;
+ irq = msix ? vdev->msix[vector].vector : pdev->irq + vector;
+
if (vdev->ctx[vector].trigger) {
free_irq(irq, vdev->ctx[vector].trigger);
irq_bypass_unregister_producer(&vdev->ctx[vector].producer);
@@ -328,8 +328,9 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_device *vdev,
if (fd < 0)
return 0;
- vdev->ctx[vector].name = kasprintf(GFP_KERNEL, "%s[%d](%s)",
- name, vector, pci_name(pdev));
+ vdev->ctx[vector].name = kasprintf(GFP_KERNEL, "vfio-msi%s[%d](%s)",
+ msix ? "x" : "", vector,
+ pci_name(pdev));
if (!vdev->ctx[vector].name)
return -ENOMEM;
@@ -379,7 +380,7 @@ static int vfio_msi_set_block(struct vfio_pci_device *vdev, unsigned start,
{
int i, j, ret = 0;
- if (start + count > vdev->num_ctx)
+ if (start >= vdev->num_ctx || start + count > vdev->num_ctx)
return -EINVAL;
for (i = 0, j = start; i < count && !ret; i++, j++) {
@@ -388,7 +389,7 @@ static int vfio_msi_set_block(struct vfio_pci_device *vdev, unsigned start,
}
if (ret) {
- for (--j; j >= start; j--)
+ for (--j; j >= (int)start; j--)
vfio_msi_set_vector_signal(vdev, j, -1, msix);
}
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
index 0e7394f8f69b..8a7d546d18a0 100644
--- a/drivers/vfio/pci/vfio_pci_private.h
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -14,6 +14,7 @@
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/irqbypass.h>
+#include <linux/types.h>
#ifndef VFIO_PCI_PRIVATE_H
#define VFIO_PCI_PRIVATE_H
@@ -24,6 +25,10 @@
#define VFIO_PCI_INDEX_TO_OFFSET(index) ((u64)(index) << VFIO_PCI_OFFSET_SHIFT)
#define VFIO_PCI_OFFSET_MASK (((u64)(1) << VFIO_PCI_OFFSET_SHIFT) - 1)
+/* Special capability IDs predefined access */
+#define PCI_CAP_ID_INVALID 0xFF /* default raw access */
+#define PCI_CAP_ID_INVALID_VIRT 0xFE /* default virt access */
+
struct vfio_pci_irq_ctx {
struct eventfd_ctx *trigger;
struct virqfd *unmask;
@@ -33,6 +38,25 @@ struct vfio_pci_irq_ctx {
struct irq_bypass_producer producer;
};
+struct vfio_pci_device;
+struct vfio_pci_region;
+
+struct vfio_pci_regops {
+ size_t (*rw)(struct vfio_pci_device *vdev, char __user *buf,
+ size_t count, loff_t *ppos, bool iswrite);
+ void (*release)(struct vfio_pci_device *vdev,
+ struct vfio_pci_region *region);
+};
+
+struct vfio_pci_region {
+ u32 type;
+ u32 subtype;
+ const struct vfio_pci_regops *ops;
+ void *data;
+ size_t size;
+ u32 flags;
+};
+
struct vfio_pci_device {
struct pci_dev *pdev;
void __iomem *barmap[PCI_STD_RESOURCE_END + 1];
@@ -45,6 +69,8 @@ struct vfio_pci_device {
struct vfio_pci_irq_ctx *ctx;
int num_ctx;
int irq_type;
+ int num_regions;
+ struct vfio_pci_region *region;
u8 msi_qmax;
u8 msix_bar;
u16 msix_size;
@@ -91,4 +117,17 @@ extern void vfio_pci_uninit_perm_bits(void);
extern int vfio_config_init(struct vfio_pci_device *vdev);
extern void vfio_config_free(struct vfio_pci_device *vdev);
+
+extern int vfio_pci_register_dev_region(struct vfio_pci_device *vdev,
+ unsigned int type, unsigned int subtype,
+ const struct vfio_pci_regops *ops,
+ size_t size, u32 flags, void *data);
+#ifdef CONFIG_VFIO_PCI_IGD
+extern int vfio_pci_igd_init(struct vfio_pci_device *vdev);
+#else
+static inline int vfio_pci_igd_init(struct vfio_pci_device *vdev)
+{
+ return -ENODEV;
+}
+#endif
#endif /* VFIO_PCI_PRIVATE_H */
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
index 210db24d2204..5ffd1d9ad4bd 100644
--- a/drivers/vfio/pci/vfio_pci_rdwr.c
+++ b/drivers/vfio/pci/vfio_pci_rdwr.c
@@ -124,11 +124,14 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_device *vdev, char __user *buf,
void __iomem *io;
ssize_t done;
- if (!pci_resource_start(pdev, bar))
+ if (pci_resource_start(pdev, bar))
+ end = pci_resource_len(pdev, bar);
+ else if (bar == PCI_ROM_RESOURCE &&
+ pdev->resource[bar].flags & IORESOURCE_ROM_SHADOW)
+ end = 0x20000;
+ else
return -EINVAL;
- end = pci_resource_len(pdev, bar);
-
if (pos >= end)
return -EINVAL;
diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c
index 418cdd9ba3f4..e65b142d3422 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -219,7 +219,8 @@ static long vfio_platform_ioctl(void *device_data,
info.num_regions = vdev->num_regions;
info.num_irqs = vdev->num_irqs;
- return copy_to_user((void __user *)arg, &info, minsz);
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
} else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
struct vfio_region_info info;
@@ -240,7 +241,8 @@ static long vfio_platform_ioctl(void *device_data,
info.size = vdev->regions[info.index].size;
info.flags = vdev->regions[info.index].flags;
- return copy_to_user((void __user *)arg, &info, minsz);
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
} else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
struct vfio_irq_info info;
@@ -259,7 +261,8 @@ static long vfio_platform_ioctl(void *device_data,
info.flags = vdev->irqs[info.index].flags;
info.count = vdev->irqs[info.index].count;
- return copy_to_user((void __user *)arg, &info, minsz);
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
} else if (cmd == VFIO_DEVICE_SET_IRQS) {
struct vfio_irq_set hdr;
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index ecca316386f5..6fd6fa5469de 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -1080,30 +1080,26 @@ static long vfio_ioctl_set_iommu(struct vfio_container *container,
continue;
}
- /* module reference holds the driver we're working on */
- mutex_unlock(&vfio.iommu_drivers_lock);
-
data = driver->ops->open(arg);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
module_put(driver->ops->owner);
- goto skip_drivers_unlock;
+ continue;
}
ret = __vfio_container_attach_groups(container, driver, data);
- if (!ret) {
- container->iommu_driver = driver;
- container->iommu_data = data;
- } else {
+ if (ret) {
driver->ops->release(data);
module_put(driver->ops->owner);
+ continue;
}
- goto skip_drivers_unlock;
+ container->iommu_driver = driver;
+ container->iommu_data = data;
+ break;
}
mutex_unlock(&vfio.iommu_drivers_lock);
-skip_drivers_unlock:
up_write(&container->group_lock);
return ret;
@@ -1733,6 +1729,60 @@ long vfio_external_check_extension(struct vfio_group *group, unsigned long arg)
EXPORT_SYMBOL_GPL(vfio_external_check_extension);
/**
+ * Sub-module support
+ */
+/*
+ * Helper for managing a buffer of info chain capabilities, allocate or
+ * reallocate a buffer with additional @size, filling in @id and @version
+ * of the capability. A pointer to the new capability is returned.
+ *
+ * NB. The chain is based at the head of the buffer, so new entries are
+ * added to the tail, vfio_info_cap_shift() should be called to fixup the
+ * next offsets prior to copying to the user buffer.
+ */
+struct vfio_info_cap_header *vfio_info_cap_add(struct vfio_info_cap *caps,
+ size_t size, u16 id, u16 version)
+{
+ void *buf;
+ struct vfio_info_cap_header *header, *tmp;
+
+ buf = krealloc(caps->buf, caps->size + size, GFP_KERNEL);
+ if (!buf) {
+ kfree(caps->buf);
+ caps->size = 0;
+ return ERR_PTR(-ENOMEM);
+ }
+
+ caps->buf = buf;
+ header = buf + caps->size;
+
+ /* Eventually copied to user buffer, zero */
+ memset(header, 0, size);
+
+ header->id = id;
+ header->version = version;
+
+ /* Add to the end of the capability chain */
+ for (tmp = caps->buf; tmp->next; tmp = (void *)tmp + tmp->next)
+ ; /* nothing */
+
+ tmp->next = caps->size;
+ caps->size += size;
+
+ return header;
+}
+EXPORT_SYMBOL_GPL(vfio_info_cap_add);
+
+void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset)
+{
+ struct vfio_info_cap_header *tmp;
+
+ for (tmp = caps->buf; tmp->next; tmp = (void *)tmp + tmp->next - offset)
+ tmp->next += offset;
+}
+EXPORT_SYMBOL_GPL(vfio_info_cap_shift);
+
+/**
* Module/class support
*/
static char *vfio_devnode(struct device *dev, umode_t *mode)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 6f1ea3dddbad..75b24e93cedb 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -999,7 +999,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
info.iova_pgsizes = vfio_pgsize_bitmap(iommu);
- return copy_to_user((void __user *)arg, &info, minsz);
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
} else if (cmd == VFIO_IOMMU_MAP_DMA) {
struct vfio_iommu_type1_dma_map map;
@@ -1032,7 +1033,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
if (ret)
return ret;
- return copy_to_user((void __user *)arg, &unmap, minsz);
+ return copy_to_user((void __user *)arg, &unmap, minsz) ?
+ -EFAULT : 0;
}
return -ENOTTY;
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index ad2146a9ab2d..236553e81027 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1156,6 +1156,8 @@ int vhost_init_used(struct vhost_virtqueue *vq)
{
__virtio16 last_used_idx;
int r;
+ bool is_le = vq->is_le;
+
if (!vq->private_data) {
vq->is_le = virtio_legacy_is_little_endian();
return 0;
@@ -1165,15 +1167,20 @@ int vhost_init_used(struct vhost_virtqueue *vq)
r = vhost_update_used_flags(vq);
if (r)
- return r;
+ goto err;
vq->signalled_used_valid = false;
- if (!access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx))
- return -EFAULT;
+ if (!access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx)) {
+ r = -EFAULT;
+ goto err;
+ }
r = __get_user(last_used_idx, &vq->used->idx);
if (r)
- return r;
+ goto err;
vq->last_used_idx = vhost16_to_cpu(vq, last_used_idx);
return 0;
+err:
+ vq->is_le = is_le;
+ return r;
}
EXPORT_SYMBOL_GPL(vhost_init_used);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 92f394927f24..6e92917ba77a 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -709,6 +709,7 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
}
if (!err) {
+ ops->cur_blink_jiffies = HZ / 5;
info->fbcon_par = ops;
if (vc)
@@ -956,6 +957,7 @@ static const char *fbcon_startup(void)
ops->currcon = -1;
ops->graphics = 1;
ops->cur_rotate = -1;
+ ops->cur_blink_jiffies = HZ / 5;
info->fbcon_par = ops;
p->con_rotate = initial_rotation;
set_blitting_type(vc, info);
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 8ea45a5cd806..983280e8d93f 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1808,8 +1808,8 @@ config FB_HIT
frame buffer card.
config FB_PMAG_AA
- bool "PMAG-AA TURBOchannel framebuffer support"
- depends on (FB = y) && TC
+ tristate "PMAG-AA TURBOchannel framebuffer support"
+ depends on FB && TC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1985,7 +1985,7 @@ config FB_W100
config FB_SH_MOBILE_LCDC
tristate "SuperH Mobile LCDC framebuffer support"
- depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
+ depends on FB && (SUPERH || ARCH_RENESAS) && HAVE_CLK
depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
@@ -2246,7 +2246,6 @@ config XEN_FBDEV_FRONTEND
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
select FB_DEFERRED_IO
- select INPUT_XEN_KBDDEV_FRONTEND if INPUT_MISC
select XEN_XENBUS_FRONTEND
default y
help
diff --git a/drivers/video/fbdev/acornfb.c b/drivers/video/fbdev/acornfb.c
index a305caea58ee..fb75b7e5a19a 100644
--- a/drivers/video/fbdev/acornfb.c
+++ b/drivers/video/fbdev/acornfb.c
@@ -1040,8 +1040,8 @@ static int acornfb_probe(struct platform_device *dev)
* for the framebuffer if we are not using
* VRAM.
*/
- base = dma_alloc_writecombine(current_par.dev, size, &handle,
- GFP_KERNEL);
+ base = dma_alloc_wc(current_par.dev, size, &handle,
+ GFP_KERNEL);
if (base == NULL) {
printk(KERN_ERR "acornfb: unable to allocate screen "
"memory\n");
diff --git a/drivers/video/fbdev/amba-clcd-versatile.c b/drivers/video/fbdev/amba-clcd-versatile.c
index 7a8afcd4573e..a8a22daa3f9d 100644
--- a/drivers/video/fbdev/amba-clcd-versatile.c
+++ b/drivers/video/fbdev/amba-clcd-versatile.c
@@ -154,8 +154,8 @@ int versatile_clcd_setup_dma(struct clcd_fb *fb, unsigned long framesize)
{
dma_addr_t dma;
- fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
- &dma, GFP_KERNEL);
+ fb->fb.screen_base = dma_alloc_wc(&fb->dev->dev, framesize, &dma,
+ GFP_KERNEL);
if (!fb->fb.screen_base) {
pr_err("CLCD: unable to map framebuffer\n");
return -ENOMEM;
@@ -169,14 +169,12 @@ int versatile_clcd_setup_dma(struct clcd_fb *fb, unsigned long framesize)
int versatile_clcd_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
{
- return dma_mmap_writecombine(&fb->dev->dev, vma,
- fb->fb.screen_base,
- fb->fb.fix.smem_start,
- fb->fb.fix.smem_len);
+ return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
+ fb->fb.fix.smem_start, fb->fb.fix.smem_len);
}
void versatile_clcd_remove_dma(struct clcd_fb *fb)
{
- dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
- fb->fb.screen_base, fb->fb.fix.smem_start);
+ dma_free_wc(&fb->dev->dev, fb->fb.fix.smem_len, fb->fb.screen_base,
+ fb->fb.fix.smem_start);
}
diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c
index 9362424c2340..fe274b5851c7 100644
--- a/drivers/video/fbdev/amba-clcd.c
+++ b/drivers/video/fbdev/amba-clcd.c
@@ -774,8 +774,8 @@ static int clcdfb_of_dma_setup(struct clcd_fb *fb)
static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
{
- return dma_mmap_writecombine(&fb->dev->dev, vma, fb->fb.screen_base,
- fb->fb.fix.smem_start, fb->fb.fix.smem_len);
+ return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
+ fb->fb.fix.smem_start, fb->fb.fix.smem_len);
}
static void clcdfb_of_dma_remove(struct clcd_fb *fb)
diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c
index d6ce613e12ad..fcd2dd670a65 100644
--- a/drivers/video/fbdev/atafb.c
+++ b/drivers/video/fbdev/atafb.c
@@ -313,9 +313,6 @@ extern unsigned char fontdata_8x16[];
* * Draws cursor *
* int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
*
- * * Rotates the display *
- * void (*fb_rotate)(struct fb_info *info, int angle);
- *
* * wait for blit idle, optional *
* int (*fb_sync)(struct fb_info *info);
*
diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c
index 19eb42b57d87..56c60e67316a 100644
--- a/drivers/video/fbdev/atmel_lcdfb.c
+++ b/drivers/video/fbdev/atmel_lcdfb.c
@@ -414,8 +414,8 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
{
struct fb_info *info = sinfo->info;
- dma_free_writecombine(info->device, info->fix.smem_len,
- info->screen_base, info->fix.smem_start);
+ dma_free_wc(info->device, info->fix.smem_len, info->screen_base,
+ info->fix.smem_start);
}
/**
@@ -435,8 +435,9 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
* ((var->bits_per_pixel + 7) / 8));
info->fix.smem_len = max(smem_len, sinfo->smem_len);
- info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
- (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+ info->screen_base = dma_alloc_wc(info->device, info->fix.smem_len,
+ (dma_addr_t *)&info->fix.smem_start,
+ GFP_KERNEL);
if (!info->screen_base) {
return -ENOMEM;
diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c
index c42ce2fdfd44..0a4626886b00 100644
--- a/drivers/video/fbdev/aty/aty128fb.c
+++ b/drivers/video/fbdev/aty/aty128fb.c
@@ -68,7 +68,6 @@
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/prom.h>
-#include <asm/pci-bridge.h>
#include "../macmodes.h"
#endif
diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c
index ce0b1d05a388..218339a4edaa 100644
--- a/drivers/video/fbdev/aty/radeon_base.c
+++ b/drivers/video/fbdev/aty/radeon_base.c
@@ -76,7 +76,6 @@
#ifdef CONFIG_PPC
-#include <asm/pci-bridge.h>
#include "../macmodes.h"
#ifdef CONFIG_BOOTX_TEXT
diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c
index 59560189b24a..35df2c1a8a63 100644
--- a/drivers/video/fbdev/au1100fb.c
+++ b/drivers/video/fbdev/au1100fb.c
@@ -334,27 +334,6 @@ int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
return 0;
}
-/* fb_rotate
- * Rotate the display of this angle. This doesn't seems to be used by the core,
- * but as our hardware supports it, so why not implementing it...
- */
-void au1100fb_fb_rotate(struct fb_info *fbi, int angle)
-{
- struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
-
- print_dbg("fb_rotate %p %d", fbi, angle);
-
- if (fbdev && (angle > 0) && !(angle % 90)) {
-
- fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
-
- fbdev->regs->lcd_control &= ~(LCD_CONTROL_SM_MASK);
- fbdev->regs->lcd_control |= ((angle/90) << LCD_CONTROL_SM_BIT);
-
- fbdev->regs->lcd_control |= LCD_CONTROL_GO;
- }
-}
-
/* fb_mmap
* Map video memory in user space. We don't use the generic fb_mmap method mainly
* to allow the use of the TLB streaming flag (CCA=6)
@@ -380,7 +359,6 @@ static struct fb_ops au1100fb_ops =
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
- .fb_rotate = au1100fb_fb_rotate,
.fb_mmap = au1100fb_fb_mmap,
};
diff --git a/drivers/video/fbdev/bf537-lq035.c b/drivers/video/fbdev/bf537-lq035.c
index 7db3052b471d..ef29fb425122 100644
--- a/drivers/video/fbdev/bf537-lq035.c
+++ b/drivers/video/fbdev/bf537-lq035.c
@@ -554,28 +554,6 @@ static int bfin_lq035_fb_check_var(struct fb_var_screeninfo *var,
return 0;
}
-/* fb_rotate
- * Rotate the display of this angle. This doesn't seems to be used by the core,
- * but as our hardware supports it, so why not implementing it...
- */
-static void bfin_lq035_fb_rotate(struct fb_info *fbi, int angle)
-{
- pr_debug("%s: %p %d", __func__, fbi, angle);
-#if (defined(UD) && defined(LBR))
- switch (angle) {
-
- case 180:
- gpio_set_value(LBR, 0);
- gpio_set_value(UD, 1);
- break;
- default:
- gpio_set_value(LBR, 1);
- gpio_set_value(UD, 0);
- break;
- }
-#endif
-}
-
static int bfin_lq035_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
if (nocursor)
@@ -623,7 +601,6 @@ static struct fb_ops bfin_lq035_fb_ops = {
.fb_open = bfin_lq035_fb_open,
.fb_release = bfin_lq035_fb_release,
.fb_check_var = bfin_lq035_fb_check_var,
- .fb_rotate = bfin_lq035_fb_rotate,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
diff --git a/drivers/video/fbdev/bt431.h b/drivers/video/fbdev/bt431.h
index 04e0cfbba538..3929602f5867 100644
--- a/drivers/video/fbdev/bt431.h
+++ b/drivers/video/fbdev/bt431.h
@@ -2,6 +2,7 @@
* linux/drivers/video/bt431.h
*
* Copyright 2003 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
+ * Copyright 2016 Maciej W. Rozycki <macro@linux-mips.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -9,6 +10,8 @@
*/
#include <linux/types.h>
+#define BT431_CURSOR_SIZE 64
+
/*
* Bt431 cursor generator registers, 32-bit aligned.
* Two twin Bt431 are used on the DECstation's PMAG-AA.
@@ -60,7 +63,7 @@ static inline u8 bt431_get_value(u16 val)
#define BT431_CMD_CURS_ENABLE 0x40
#define BT431_CMD_XHAIR_ENABLE 0x20
#define BT431_CMD_OR_CURSORS 0x10
-#define BT431_CMD_AND_CURSORS 0x00
+#define BT431_CMD_XOR_CURSORS 0x00
#define BT431_CMD_1_1_MUX 0x00
#define BT431_CMD_4_1_MUX 0x04
#define BT431_CMD_5_1_MUX 0x08
@@ -196,28 +199,30 @@ static inline void bt431_position_cursor(struct bt431_regs *regs, u16 x, u16 y)
bt431_write_reg_inc(regs, (y >> 8) & 0x0f); /* BT431_REG_CYHI */
}
-static inline void bt431_set_font(struct bt431_regs *regs, u8 fgc,
- u16 width, u16 height)
+static inline void bt431_set_cursor(struct bt431_regs *regs,
+ const char *data, const char *mask,
+ u16 rop, u16 width, u16 height)
{
+ u16 x, y;
int i;
- u16 fgp = fgc ? 0xffff : 0x0000;
- u16 bgp = fgc ? 0x0000 : 0xffff;
+ i = 0;
+ width = DIV_ROUND_UP(width, 8);
bt431_select_reg(regs, BT431_REG_CRAM_BASE);
- for (i = BT431_REG_CRAM_BASE; i <= BT431_REG_CRAM_END; i++) {
- u16 value;
-
- if (height << 6 <= i << 3)
- value = bgp;
- else if (width <= i % 8 << 3)
- value = bgp;
- else if (((width >> 3) & 0xffff) > i % 8)
- value = fgp;
- else
- value = fgp & ~(bgp << (width % 8 << 1));
-
- bt431_write_cmap_inc(regs, value);
- }
+ for (y = 0; y < BT431_CURSOR_SIZE; y++)
+ for (x = 0; x < BT431_CURSOR_SIZE / 8; x++) {
+ u16 val = 0;
+
+ if (y < height && x < width) {
+ val = mask[i];
+ if (rop == ROP_XOR)
+ val = (val << 8) | (val ^ data[i]);
+ else
+ val = (val << 8) | (val & data[i]);
+ i++;
+ }
+ bt431_write_cmap_inc(regs, val);
+ }
}
static inline void bt431_init_cursor(struct bt431_regs *regs)
diff --git a/drivers/video/fbdev/bt455.h b/drivers/video/fbdev/bt455.h
index 80f61b03e9ae..dd1404b40611 100644
--- a/drivers/video/fbdev/bt455.h
+++ b/drivers/video/fbdev/bt455.h
@@ -2,6 +2,7 @@
* linux/drivers/video/bt455.h
*
* Copyright 2003 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
+ * Copyright 2016 Maciej W. Rozycki <macro@linux-mips.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -29,66 +30,61 @@ static inline void bt455_select_reg(struct bt455_regs *regs, int ir)
regs->addr_cmap = ir & 0x0f;
}
+static inline void bt455_reset_reg(struct bt455_regs *regs)
+{
+ mb();
+ regs->addr_clr = 0;
+}
+
/*
* Read/write to a Bt455 color map register.
*/
-static inline void bt455_read_cmap_entry(struct bt455_regs *regs, int cr,
- u8* red, u8* green, u8* blue)
+static inline void bt455_read_cmap_next(struct bt455_regs *regs, u8 *grey)
{
- bt455_select_reg(regs, cr);
mb();
- *red = regs->addr_cmap_data & 0x0f;
+ regs->addr_cmap_data;
rmb();
- *green = regs->addr_cmap_data & 0x0f;
+ *grey = regs->addr_cmap_data & 0xf;
rmb();
- *blue = regs->addr_cmap_data & 0x0f;
+ regs->addr_cmap_data;
}
-static inline void bt455_write_cmap_entry(struct bt455_regs *regs, int cr,
- u8 red, u8 green, u8 blue)
+static inline void bt455_write_cmap_next(struct bt455_regs *regs, u8 grey)
{
- bt455_select_reg(regs, cr);
wmb();
- regs->addr_cmap_data = red & 0x0f;
+ regs->addr_cmap_data = 0x0;
wmb();
- regs->addr_cmap_data = green & 0x0f;
+ regs->addr_cmap_data = grey & 0xf;
wmb();
- regs->addr_cmap_data = blue & 0x0f;
+ regs->addr_cmap_data = 0x0;
}
-static inline void bt455_write_ovly_entry(struct bt455_regs *regs, int cr,
- u8 red, u8 green, u8 blue)
+static inline void bt455_write_ovly_next(struct bt455_regs *regs, u8 grey)
{
- bt455_select_reg(regs, cr);
wmb();
- regs->addr_ovly = red & 0x0f;
+ regs->addr_ovly = 0x0;
wmb();
- regs->addr_ovly = green & 0x0f;
+ regs->addr_ovly = grey & 0xf;
wmb();
- regs->addr_ovly = blue & 0x0f;
+ regs->addr_ovly = 0x0;
}
-static inline void bt455_set_cursor(struct bt455_regs *regs)
+static inline void bt455_read_cmap_entry(struct bt455_regs *regs,
+ int cr, u8 *grey)
{
- mb();
- regs->addr_ovly = 0x0f;
- wmb();
- regs->addr_ovly = 0x0f;
- wmb();
- regs->addr_ovly = 0x0f;
+ bt455_select_reg(regs, cr);
+ bt455_read_cmap_next(regs, grey);
}
-static inline void bt455_erase_cursor(struct bt455_regs *regs)
+static inline void bt455_write_cmap_entry(struct bt455_regs *regs,
+ int cr, u8 grey)
{
- /* bt455_write_cmap_entry(regs, 8, 0x00, 0x00, 0x00); */
- /* bt455_write_cmap_entry(regs, 9, 0x00, 0x00, 0x00); */
- bt455_write_ovly_entry(regs, 8, 0x03, 0x03, 0x03);
- bt455_write_ovly_entry(regs, 9, 0x07, 0x07, 0x07);
+ bt455_select_reg(regs, cr);
+ bt455_write_cmap_next(regs, grey);
+}
- wmb();
- regs->addr_ovly = 0x09;
- wmb();
- regs->addr_ovly = 0x09;
- wmb();
- regs->addr_ovly = 0x09;
+static inline void bt455_write_ovly_entry(struct bt455_regs *regs, u8 grey)
+{
+ bt455_reset_reg(regs);
+ bt455_write_ovly_next(regs, grey);
}
diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c
index 6b2a06d09f2b..d8d583d32a37 100644
--- a/drivers/video/fbdev/da8xx-fb.c
+++ b/drivers/video/fbdev/da8xx-fb.c
@@ -209,8 +209,7 @@ static struct fb_videomode known_lcd_panels[] = {
.lower_margin = 2,
.hsync_len = 0,
.vsync_len = 0,
- .sync = FB_SYNC_CLK_INVERT |
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = FB_SYNC_CLK_INVERT,
},
/* Sharp LK043T1DG01 */
[1] = {
@@ -224,7 +223,7 @@ static struct fb_videomode known_lcd_panels[] = {
.lower_margin = 2,
.hsync_len = 41,
.vsync_len = 10,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = 0,
.flag = 0,
},
[2] = {
@@ -239,7 +238,7 @@ static struct fb_videomode known_lcd_panels[] = {
.lower_margin = 10,
.hsync_len = 10,
.vsync_len = 10,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = 0,
.flag = 0,
},
[3] = {
diff --git a/drivers/video/fbdev/ep93xx-fb.c b/drivers/video/fbdev/ep93xx-fb.c
index 5b1081030cbb..75f0db25d19f 100644
--- a/drivers/video/fbdev/ep93xx-fb.c
+++ b/drivers/video/fbdev/ep93xx-fb.c
@@ -316,9 +316,8 @@ static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
unsigned int offset = vma->vm_pgoff << PAGE_SHIFT;
if (offset < info->fix.smem_len) {
- return dma_mmap_writecombine(info->dev, vma, info->screen_base,
- info->fix.smem_start,
- info->fix.smem_len);
+ return dma_mmap_wc(info->dev, vma, info->screen_base,
+ info->fix.smem_start, info->fix.smem_len);
}
return -EINVAL;
@@ -428,8 +427,7 @@ static int ep93xxfb_alloc_videomem(struct fb_info *info)
/* Maximum 16bpp -> used memory is maximum x*y*2 bytes */
fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES * 2;
- virt_addr = dma_alloc_writecombine(info->dev, fb_size,
- &phys_addr, GFP_KERNEL);
+ virt_addr = dma_alloc_wc(info->dev, fb_size, &phys_addr, GFP_KERNEL);
if (!virt_addr)
return -ENOMEM;
diff --git a/drivers/video/fbdev/exynos/Kconfig b/drivers/video/fbdev/exynos/Kconfig
index 1f16b4678c71..d916bef94f25 100644
--- a/drivers/video/fbdev/exynos/Kconfig
+++ b/drivers/video/fbdev/exynos/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig EXYNOS_VIDEO
- bool "Exynos Video driver support"
+ tristate "Exynos Video driver support"
depends on ARCH_S5PV210 || ARCH_EXYNOS
help
This enables support for EXYNOS Video device.
@@ -15,13 +15,13 @@ if EXYNOS_VIDEO
#
config EXYNOS_MIPI_DSI
- bool "EXYNOS MIPI DSI driver support."
+ tristate "EXYNOS MIPI DSI driver support."
select GENERIC_PHY
help
This enables support for MIPI-DSI device.
config EXYNOS_LCD_S6E8AX0
- bool "S6E8AX0 MIPI AMOLED LCD Driver"
+ tristate "S6E8AX0 MIPI AMOLED LCD Driver"
depends on EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE
depends on (LCD_CLASS_DEVICE = y)
default n
diff --git a/drivers/video/fbdev/exynos/Makefile b/drivers/video/fbdev/exynos/Makefile
index b5b1bd228abb..02d8dc522fea 100644
--- a/drivers/video/fbdev/exynos/Makefile
+++ b/drivers/video/fbdev/exynos/Makefile
@@ -2,6 +2,8 @@
# Makefile for the exynos video drivers.
#
-obj-$(CONFIG_EXYNOS_MIPI_DSI) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
- exynos_mipi_dsi_lowlevel.o
+obj-$(CONFIG_EXYNOS_MIPI_DSI) += exynos-mipi-dsi-mod.o
+
+exynos-mipi-dsi-mod-objs += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
+ exynos_mipi_dsi_lowlevel.o
obj-$(CONFIG_EXYNOS_LCD_S6E8AX0) += s6e8ax0.o
diff --git a/drivers/video/fbdev/exynos/exynos_mipi_dsi.c b/drivers/video/fbdev/exynos/exynos_mipi_dsi.c
index b527fe464628..92e4af3caaf8 100644
--- a/drivers/video/fbdev/exynos/exynos_mipi_dsi.c
+++ b/drivers/video/fbdev/exynos/exynos_mipi_dsi.c
@@ -263,6 +263,7 @@ int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
return 0;
}
+EXPORT_SYMBOL_GPL(exynos_mipi_dsi_register_lcd_driver);
static struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(
struct mipi_dsim_device *dsim,
@@ -402,12 +403,12 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
goto error;
}
- dsim->irq = platform_get_irq(pdev, 0);
- if (IS_ERR_VALUE(dsim->irq)) {
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
dev_err(&pdev->dev, "failed to request dsim irq resource\n");
- ret = -EINVAL;
goto error;
}
+ dsim->irq = ret;
init_completion(&dsim_wr_comp);
init_completion(&dsim_rd_comp);
diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c
index b63d55f481fa..1a242b1338e9 100644
--- a/drivers/video/fbdev/gbefb.c
+++ b/drivers/video/fbdev/gbefb.c
@@ -1185,8 +1185,8 @@ static int gbefb_probe(struct platform_device *p_dev)
} else {
/* try to allocate memory with the classical allocator
* this has high chance to fail on low memory machines */
- gbe_mem = dma_alloc_writecombine(NULL, gbe_mem_size,
- &gbe_dma_addr, GFP_KERNEL);
+ gbe_mem = dma_alloc_wc(NULL, gbe_mem_size, &gbe_dma_addr,
+ GFP_KERNEL);
if (!gbe_mem) {
printk(KERN_ERR "gbefb: couldn't allocate framebuffer memory\n");
ret = -ENOMEM;
@@ -1238,7 +1238,7 @@ static int gbefb_probe(struct platform_device *p_dev)
out_gbe_unmap:
arch_phys_wc_del(par->wc_cookie);
if (gbe_dma_addr)
- dma_free_writecombine(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
+ dma_free_wc(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
out_tiles_free:
dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
(void *)gbe_tiles.cpu, gbe_tiles.dma);
@@ -1259,7 +1259,7 @@ static int gbefb_remove(struct platform_device* p_dev)
gbe_turn_off();
arch_phys_wc_del(par->wc_cookie);
if (gbe_dma_addr)
- dma_free_writecombine(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
+ dma_free_wc(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
(void *)gbe_tiles.cpu, gbe_tiles.dma);
release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c
index 9b167f7ef6c6..4363c64d74e8 100644
--- a/drivers/video/fbdev/imsttfb.c
+++ b/drivers/video/fbdev/imsttfb.c
@@ -33,7 +33,6 @@
#if defined(CONFIG_PPC)
#include <linux/nvram.h>
#include <asm/prom.h>
-#include <asm/pci-bridge.h>
#include "macmodes.h"
#endif
diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c
index bb2f1e866020..76b6a7784b06 100644
--- a/drivers/video/fbdev/imxfb.c
+++ b/drivers/video/fbdev/imxfb.c
@@ -937,8 +937,8 @@ static int imxfb_probe(struct platform_device *pdev)
}
fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
- info->screen_base = dma_alloc_writecombine(&pdev->dev, fbi->map_size,
- &fbi->map_dma, GFP_KERNEL);
+ info->screen_base = dma_alloc_wc(&pdev->dev, fbi->map_size,
+ &fbi->map_dma, GFP_KERNEL);
if (!info->screen_base) {
dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
@@ -1005,8 +1005,8 @@ failed_cmap:
if (pdata && pdata->exit)
pdata->exit(fbi->pdev);
failed_platform_init:
- dma_free_writecombine(&pdev->dev, fbi->map_size, info->screen_base,
- fbi->map_dma);
+ dma_free_wc(&pdev->dev, fbi->map_size, info->screen_base,
+ fbi->map_dma);
failed_map:
iounmap(fbi->regs);
failed_ioremap:
@@ -1041,8 +1041,8 @@ static int imxfb_remove(struct platform_device *pdev)
kfree(info->pseudo_palette);
framebuffer_release(info);
- dma_free_writecombine(&pdev->dev, fbi->map_size, info->screen_base,
- fbi->map_dma);
+ dma_free_wc(&pdev->dev, fbi->map_size, info->screen_base,
+ fbi->map_dma);
iounmap(fbi->regs);
release_mem_region(res->start, resource_size(res));
diff --git a/drivers/video/fbdev/intelfb/intelfbdrv.c b/drivers/video/fbdev/intelfb/intelfbdrv.c
index bbec737eef30..bf207444ba0c 100644
--- a/drivers/video/fbdev/intelfb/intelfbdrv.c
+++ b/drivers/video/fbdev/intelfb/intelfbdrv.c
@@ -302,7 +302,7 @@ static __inline__ int get_opt_int(const char *this_opt, const char *name,
}
static __inline__ int get_opt_bool(const char *this_opt, const char *name,
- int *ret)
+ bool *ret)
{
if (!ret)
return 0;
diff --git a/drivers/video/fbdev/matrox/matroxfb_base.h b/drivers/video/fbdev/matrox/matroxfb_base.h
index 09b02cd1eb0e..7a90ea2c4613 100644
--- a/drivers/video/fbdev/matrox/matroxfb_base.h
+++ b/drivers/video/fbdev/matrox/matroxfb_base.h
@@ -47,7 +47,6 @@
#if defined(CONFIG_PPC_PMAC)
#include <asm/prom.h>
-#include <asm/pci-bridge.h>
#include "../macmodes.h"
#endif
diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c
index ad04a01e2761..abb6bbf226d5 100644
--- a/drivers/video/fbdev/metronomefb.c
+++ b/drivers/video/fbdev/metronomefb.c
@@ -354,7 +354,8 @@ static int metronome_powerup_cmd(struct metronomefb_par *par)
}
/* the rest are 0 */
- memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
+ memset(&par->metromem_cmd->args[i], 0,
+ (ARRAY_SIZE(par->metromem_cmd->args) - i) * 2);
par->metromem_cmd->csum = cs;
@@ -376,7 +377,8 @@ static int metronome_config_cmd(struct metronomefb_par *par)
memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config,
sizeof(epd_frame_table[par->dt].config));
/* the rest are 0 */
- memset((u8 *) (par->metromem_cmd->args + 4), 0, (32-4)*2);
+ memset(&par->metromem_cmd->args[4], 0,
+ (ARRAY_SIZE(par->metromem_cmd->args) - 4) * 2);
par->metromem_cmd->csum = 0xCC10;
par->metromem_cmd->csum += calc_img_cksum(par->metromem_cmd->args, 4);
diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c
index 7947634ee6b0..f91b1db262b0 100644
--- a/drivers/video/fbdev/mx3fb.c
+++ b/drivers/video/fbdev/mx3fb.c
@@ -1336,9 +1336,8 @@ static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len,
int retval = 0;
dma_addr_t addr;
- fbi->screen_base = dma_alloc_writecombine(fbi->device,
- mem_len,
- &addr, GFP_DMA | GFP_KERNEL);
+ fbi->screen_base = dma_alloc_wc(fbi->device, mem_len, &addr,
+ GFP_DMA | GFP_KERNEL);
if (!fbi->screen_base) {
dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n",
@@ -1378,8 +1377,8 @@ err0:
*/
static int mx3fb_unmap_video_memory(struct fb_info *fbi)
{
- dma_free_writecombine(fbi->device, fbi->fix.smem_len,
- fbi->screen_base, fbi->fix.smem_start);
+ dma_free_wc(fbi->device, fbi->fix.smem_len, fbi->screen_base,
+ fbi->fix.smem_start);
fbi->screen_base = NULL;
mutex_lock(&fbi->mm_lock);
diff --git a/drivers/video/fbdev/n411.c b/drivers/video/fbdev/n411.c
index 935830fea7b6..053deacad7cc 100644
--- a/drivers/video/fbdev/n411.c
+++ b/drivers/video/fbdev/n411.c
@@ -165,16 +165,22 @@ static int __init n411_init(void)
if (!n411_device)
return -ENOMEM;
- platform_device_add_data(n411_device, &n411_board, sizeof(n411_board));
+ ret = platform_device_add_data(n411_device, &n411_board,
+ sizeof(n411_board));
+ if (ret)
+ goto put_plat_device;
/* this _add binds hecubafb to n411. hecubafb refcounts n411 */
ret = platform_device_add(n411_device);
if (ret)
- platform_device_put(n411_device);
+ goto put_plat_device;
- return ret;
+ return 0;
+put_plat_device:
+ platform_device_put(n411_device);
+ return ret;
}
static void __exit n411_exit(void)
diff --git a/drivers/video/fbdev/nuc900fb.c b/drivers/video/fbdev/nuc900fb.c
index 389fa2cbb713..6680edae4696 100644
--- a/drivers/video/fbdev/nuc900fb.c
+++ b/drivers/video/fbdev/nuc900fb.c
@@ -396,8 +396,8 @@ static int nuc900fb_map_video_memory(struct fb_info *info)
dev_dbg(fbi->dev, "nuc900fb_map_video_memory(fbi=%p) map_size %lu\n",
fbi, map_size);
- info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
- &map_dma, GFP_KERNEL);
+ info->screen_base = dma_alloc_wc(fbi->dev, map_size, &map_dma,
+ GFP_KERNEL);
if (!info->screen_base)
return -ENOMEM;
@@ -411,8 +411,8 @@ static int nuc900fb_map_video_memory(struct fb_info *info)
static inline void nuc900fb_unmap_video_memory(struct fb_info *info)
{
struct nuc900fb_info *fbi = info->par;
- dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
- info->screen_base, info->fix.smem_start);
+ dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
+ info->screen_base, info->fix.smem_start);
}
static irqreturn_t nuc900fb_irqhandler(int irq, void *dev_id)
diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c
index 43a0a52fc527..fb60a8f0cc94 100644
--- a/drivers/video/fbdev/offb.c
+++ b/drivers/video/fbdev/offb.c
@@ -28,10 +28,6 @@
#include <linux/pci.h>
#include <asm/io.h>
-#ifdef CONFIG_PPC64
-#include <asm/pci-bridge.h>
-#endif
-
#ifdef CONFIG_PPC32
#include <asm/bootx.h>
#endif
diff --git a/drivers/video/fbdev/omap/lcdc.c b/drivers/video/fbdev/omap/lcdc.c
index 6efa2591eaa8..e3d9b9ea5498 100644
--- a/drivers/video/fbdev/omap/lcdc.c
+++ b/drivers/video/fbdev/omap/lcdc.c
@@ -612,8 +612,8 @@ static void lcdc_dma_handler(u16 status, void *data)
static int alloc_palette_ram(void)
{
- lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev,
- MAX_PALETTE_SIZE, &lcdc.palette_phys, GFP_KERNEL);
+ lcdc.palette_virt = dma_alloc_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE,
+ &lcdc.palette_phys, GFP_KERNEL);
if (lcdc.palette_virt == NULL) {
dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n");
return -ENOMEM;
@@ -625,8 +625,8 @@ static int alloc_palette_ram(void)
static void free_palette_ram(void)
{
- dma_free_writecombine(lcdc.fbdev->dev, MAX_PALETTE_SIZE,
- lcdc.palette_virt, lcdc.palette_phys);
+ dma_free_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE, lcdc.palette_virt,
+ lcdc.palette_phys);
}
static int alloc_fbmem(struct omapfb_mem_region *region)
@@ -642,8 +642,8 @@ static int alloc_fbmem(struct omapfb_mem_region *region)
if (region->size > frame_size)
frame_size = region->size;
lcdc.vram_size = frame_size;
- lcdc.vram_virt = dma_alloc_writecombine(lcdc.fbdev->dev,
- lcdc.vram_size, &lcdc.vram_phys, GFP_KERNEL);
+ lcdc.vram_virt = dma_alloc_wc(lcdc.fbdev->dev, lcdc.vram_size,
+ &lcdc.vram_phys, GFP_KERNEL);
if (lcdc.vram_virt == NULL) {
dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n");
return -ENOMEM;
@@ -660,8 +660,8 @@ static int alloc_fbmem(struct omapfb_mem_region *region)
static void free_fbmem(void)
{
- dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size,
- lcdc.vram_virt, lcdc.vram_phys);
+ dma_free_wc(lcdc.fbdev->dev, lcdc.vram_size, lcdc.vram_virt,
+ lcdc.vram_phys);
}
static int setup_fbmem(struct omapfb_mem_desc *req_md)
diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c
index 393ae1bc07e8..6429f33167f5 100644
--- a/drivers/video/fbdev/omap/omapfb_main.c
+++ b/drivers/video/fbdev/omap/omapfb_main.c
@@ -594,27 +594,6 @@ static int set_fb_var(struct fb_info *fbi,
}
-/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
-static void omapfb_rotate(struct fb_info *fbi, int rotate)
-{
- struct omapfb_plane_struct *plane = fbi->par;
- struct omapfb_device *fbdev = plane->fbdev;
-
- omapfb_rqueue_lock(fbdev);
- if (rotate != fbi->var.rotate) {
- struct fb_var_screeninfo *new_var = &fbdev->new_var;
-
- memcpy(new_var, &fbi->var, sizeof(*new_var));
- new_var->rotate = rotate;
- if (set_fb_var(fbi, new_var) == 0 &&
- memcmp(new_var, &fbi->var, sizeof(*new_var))) {
- memcpy(&fbi->var, new_var, sizeof(*new_var));
- ctrl_change_mode(fbi);
- }
- }
- omapfb_rqueue_unlock(fbdev);
-}
-
/*
* Set new x,y offsets in the virtual display for the visible area and switch
* to the new mode.
@@ -1256,7 +1235,6 @@ static struct fb_ops omapfb_ops = {
.fb_ioctl = omapfb_ioctl,
.fb_check_var = omapfb_check_var,
.fb_set_par = omapfb_set_par,
- .fb_rotate = omapfb_rotate,
.fb_pan_display = omapfb_pan_display,
};
diff --git a/drivers/video/fbdev/pmag-aa-fb.c b/drivers/video/fbdev/pmag-aa-fb.c
index 838424817de2..ffe2dd482f84 100644
--- a/drivers/video/fbdev/pmag-aa-fb.c
+++ b/drivers/video/fbdev/pmag-aa-fb.c
@@ -8,6 +8,7 @@
* and Harald Koerfgen <hkoerfg@web.de>, which itself is derived from
* "HP300 Topcat framebuffer support (derived from macfb of all things)
* Phil Blundell <philb@gnu.org> 1998"
+ * Copyright (c) 2016 Maciej W. Rozycki
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -21,37 +22,29 @@
*
* 2003-09-21 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
* Hardware cursor support.
+ *
+ * 2016-02-21 Maciej W. Rozycki <macro@linux-mips.org>
+ * Version 0.03: Rewritten for the new FB and TC APIs.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
+
+#include <linux/compiler.h>
#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/fb.h>
-#include <linux/console.h>
-
-#include <asm/bootinfo.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/tc.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tc.h>
+#include <linux/timer.h>
#include "bt455.h"
#include "bt431.h"
/* Version information */
-#define DRIVER_VERSION "0.02"
+#define DRIVER_VERSION "0.03"
#define DRIVER_AUTHOR "Karsten Merker <merker@linuxtag.org>"
#define DRIVER_DESCRIPTION "PMAG-AA Framebuffer Driver"
-/* Prototypes */
-static int aafb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-
/*
* Bt455 RAM DAC register base offset (rel. to TC slot base address).
*/
@@ -68,443 +61,246 @@ static int aafb_set_var(struct fb_var_screeninfo *var, int con,
*/
#define PMAG_AA_ONBOARD_FBMEM_OFFSET 0x200000
-struct aafb_cursor {
- struct timer_list timer;
- int enable;
- int on;
- int vbl_cnt;
- int blink_rate;
- u16 x, y, width, height;
+struct aafb_par {
+ void __iomem *mmio;
+ struct bt455_regs __iomem *bt455;
+ struct bt431_regs __iomem *bt431;
};
-#define CURSOR_TIMER_FREQ (HZ / 50)
-#define CURSOR_BLINK_RATE (20)
-#define CURSOR_DRAW_DELAY (2)
-
-struct aafb_info {
- struct fb_info info;
- struct display disp;
- struct aafb_cursor cursor;
- struct bt455_regs *bt455;
- struct bt431_regs *bt431;
- unsigned long fb_start;
- unsigned long fb_size;
- unsigned long fb_line_length;
+static struct fb_var_screeninfo aafb_defined = {
+ .xres = 1280,
+ .yres = 1024,
+ .xres_virtual = 2048,
+ .yres_virtual = 1024,
+ .bits_per_pixel = 8,
+ .grayscale = 1,
+ .red.length = 0,
+ .green.length = 1,
+ .blue.length = 0,
+ .activate = FB_ACTIVATE_NOW,
+ .accel_flags = FB_ACCEL_NONE,
+ .pixclock = 7645,
+ .left_margin = 224,
+ .right_margin = 32,
+ .upper_margin = 33,
+ .lower_margin = 3,
+ .hsync_len = 160,
+ .vsync_len = 3,
+ .sync = FB_SYNC_ON_GREEN,
+ .vmode = FB_VMODE_NONINTERLACED,
};
-/*
- * Max 3 TURBOchannel slots -> max 3 PMAG-AA.
- */
-static struct aafb_info my_fb_info[3];
-
-static struct aafb_par {
-} current_par;
-
-static int currcon = -1;
-
-static void aafb_set_cursor(struct aafb_info *info, int on)
-{
- struct aafb_cursor *c = &info->cursor;
-
- if (on) {
- bt431_position_cursor(info->bt431, c->x, c->y);
- bt431_enable_cursor(info->bt431);
- } else
- bt431_erase_cursor(info->bt431);
-}
-
-static void aafbcon_cursor(struct display *disp, int mode, int x, int y)
-{
- struct aafb_info *info = (struct aafb_info *)disp->fb_info;
- struct aafb_cursor *c = &info->cursor;
-
- x *= fontwidth(disp);
- y *= fontheight(disp);
-
- if (c->x == x && c->y == y && (mode == CM_ERASE) == !c->enable)
- return;
-
- c->enable = 0;
- if (c->on)
- aafb_set_cursor(info, 0);
- c->x = x - disp->var.xoffset;
- c->y = y - disp->var.yoffset;
-
- switch (mode) {
- case CM_ERASE:
- c->on = 0;
- break;
- case CM_DRAW:
- case CM_MOVE:
- if (c->on)
- aafb_set_cursor(info, c->on);
- else
- c->vbl_cnt = CURSOR_DRAW_DELAY;
- c->enable = 1;
- break;
- }
-}
+static struct fb_fix_screeninfo aafb_fix = {
+ .id = "PMAG-AA",
+ .smem_len = (2048 * 1024),
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_MONO10,
+ .ypanstep = 1,
+ .ywrapstep = 1,
+ .line_length = 2048,
+ .mmio_len = PMAG_AA_ONBOARD_FBMEM_OFFSET - PMAG_AA_BT455_OFFSET,
+};
-static int aafbcon_set_font(struct display *disp, int width, int height)
+static int aafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
- struct aafb_info *info = (struct aafb_info *)disp->fb_info;
- struct aafb_cursor *c = &info->cursor;
- u8 fgc = ~attr_bgcol_ec(disp, disp->conp, &info->info);
+ struct aafb_par *par = info->par;
- if (width > 64 || height > 64 || width < 0 || height < 0)
+ if (cursor->image.height > BT431_CURSOR_SIZE ||
+ cursor->image.width > BT431_CURSOR_SIZE) {
+ bt431_erase_cursor(par->bt431);
return -EINVAL;
-
- c->height = height;
- c->width = width;
-
- bt431_set_font(info->bt431, fgc, width, height);
-
- return 1;
-}
-
-static void aafb_cursor_timer_handler(unsigned long data)
-{
- struct aafb_info *info = (struct aafb_info *)data;
- struct aafb_cursor *c = &info->cursor;
-
- if (!c->enable)
- goto out;
-
- if (c->vbl_cnt && --c->vbl_cnt == 0) {
- c->on ^= 1;
- aafb_set_cursor(info, c->on);
- c->vbl_cnt = c->blink_rate;
}
-out:
- c->timer.expires = jiffies + CURSOR_TIMER_FREQ;
- add_timer(&c->timer);
-}
-
-static void __init aafb_cursor_init(struct aafb_info *info)
-{
- struct aafb_cursor *c = &info->cursor;
-
- c->enable = 1;
- c->on = 1;
- c->x = c->y = 0;
- c->width = c->height = 0;
- c->vbl_cnt = CURSOR_DRAW_DELAY;
- c->blink_rate = CURSOR_BLINK_RATE;
-
- init_timer(&c->timer);
- c->timer.data = (unsigned long)info;
- c->timer.function = aafb_cursor_timer_handler;
- mod_timer(&c->timer, jiffies + CURSOR_TIMER_FREQ);
-}
-
-static void __exit aafb_cursor_exit(struct aafb_info *info)
-{
- struct aafb_cursor *c = &info->cursor;
-
- del_timer_sync(&c->timer);
-}
-
-static struct display_switch aafb_switch8 = {
- .setup = fbcon_cfb8_setup,
- .bmove = fbcon_cfb8_bmove,
- .clear = fbcon_cfb8_clear,
- .putc = fbcon_cfb8_putc,
- .putcs = fbcon_cfb8_putcs,
- .revc = fbcon_cfb8_revc,
- .cursor = aafbcon_cursor,
- .set_font = aafbcon_set_font,
- .clear_margins = fbcon_cfb8_clear_margins,
- .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-
-static void aafb_get_par(struct aafb_par *par)
-{
- *par = current_par;
-}
-
-static int aafb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- struct aafb_info *ip = (struct aafb_info *)info;
-
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, "PMAG-AA");
- fix->smem_start = ip->fb_start;
- fix->smem_len = ip->fb_size;
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->ypanstep = 1;
- fix->ywrapstep = 1;
- fix->visual = FB_VISUAL_MONO10;
- fix->line_length = 1280;
- fix->accel = FB_ACCEL_NONE;
+ if (!cursor->enable)
+ bt431_erase_cursor(par->bt431);
- return 0;
-}
+ if (cursor->set & FB_CUR_SETPOS)
+ bt431_position_cursor(par->bt431,
+ cursor->image.dx, cursor->image.dy);
+ if (cursor->set & FB_CUR_SETCMAP) {
+ u8 fg = cursor->image.fg_color ? 0xf : 0x0;
+ u8 bg = cursor->image.bg_color ? 0xf : 0x0;
-static void aafb_set_disp(struct display *disp, int con,
- struct aafb_info *info)
-{
- struct fb_fix_screeninfo fix;
-
- disp->fb_info = &info->info;
- aafb_set_var(&disp->var, con, &info->info);
- if (disp->conp && disp->conp->vc_sw && disp->conp->vc_sw->con_cursor)
- disp->conp->vc_sw->con_cursor(disp->conp, CM_ERASE);
- disp->dispsw = &aafb_switch8;
- disp->dispsw_data = 0;
-
- aafb_get_fix(&fix, con, &info->info);
- disp->screen_base = (u8 *) fix.smem_start;
- disp->visual = fix.visual;
- disp->type = fix.type;
- disp->type_aux = fix.type_aux;
- disp->ypanstep = fix.ypanstep;
- disp->ywrapstep = fix.ywrapstep;
- disp->line_length = fix.line_length;
- disp->next_line = 2048;
- disp->can_soft_blank = 1;
- disp->inverse = 0;
- disp->scrollmode = SCROLL_YREDRAW;
-
- aafbcon_set_font(disp, fontwidth(disp), fontheight(disp));
-}
+ bt455_write_cmap_entry(par->bt455, 8, bg);
+ bt455_write_cmap_next(par->bt455, bg);
+ bt455_write_ovly_next(par->bt455, fg);
+ }
+ if (cursor->set & (FB_CUR_SETSIZE | FB_CUR_SETSHAPE | FB_CUR_SETIMAGE))
+ bt431_set_cursor(par->bt431,
+ cursor->image.data, cursor->mask, cursor->rop,
+ cursor->image.width, cursor->image.height);
-static int aafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- static u16 color[2] = {0x0000, 0x000f};
- static struct fb_cmap aafb_cmap = {0, 2, color, color, color, NULL};
+ if (cursor->enable)
+ bt431_enable_cursor(par->bt431);
- fb_copy_cmap(&aafb_cmap, cmap, kspc ? 0 : 2);
return 0;
}
-static int aafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- u16 color[2] = {0x0000, 0x000f};
-
- if (cmap->start == 0
- && cmap->len == 2
- && memcmp(cmap->red, color, sizeof(color)) == 0
- && memcmp(cmap->green, color, sizeof(color)) == 0
- && memcmp(cmap->blue, color, sizeof(color)) == 0
- && cmap->transp == NULL)
- return 0;
- else
- return -EINVAL;
-}
-
-static int aafb_ioctl(struct fb_info *info, u32 cmd, unsigned long arg)
-{
- /* TODO: Not yet implemented */
- return -ENOIOCTLCMD;
-}
+/* 0 unblanks, any other blanks. */
-static int aafb_switch(int con, struct fb_info *info)
+static int aafb_blank(int blank, struct fb_info *info)
{
- struct aafb_info *ip = (struct aafb_info *)info;
- struct display *old = (currcon < 0) ? &ip->disp : (fb_display + currcon);
- struct display *new = (con < 0) ? &ip->disp : (fb_display + con);
-
- if (old->conp && old->conp->vc_sw && old->conp->vc_sw->con_cursor)
- old->conp->vc_sw->con_cursor(old->conp, CM_ERASE);
-
- /* Set the current console. */
- currcon = con;
- aafb_set_disp(new, con, ip);
+ struct aafb_par *par = info->par;
+ u8 val = blank ? 0x00 : 0x0f;
+ bt455_write_cmap_entry(par->bt455, 1, val);
return 0;
}
-static void aafb_encode_var(struct fb_var_screeninfo *var,
- struct aafb_par *par)
-{
- var->xres = 1280;
- var->yres = 1024;
- var->xres_virtual = 2048;
- var->yres_virtual = 1024;
- var->xoffset = 0;
- var->yoffset = 0;
- var->bits_per_pixel = 8;
- var->grayscale = 1;
- var->red.offset = 0;
- var->red.length = 0;
- var->red.msb_right = 0;
- var->green.offset = 0;
- var->green.length = 1;
- var->green.msb_right = 0;
- var->blue.offset = 0;
- var->blue.length = 0;
- var->blue.msb_right = 0;
- var->transp.offset = 0;
- var->transp.length = 0;
- var->transp.msb_right = 0;
- var->nonstd = 0;
- var->activate &= ~FB_ACTIVATE_MASK & FB_ACTIVATE_NOW;
- var->accel_flags = 0;
- var->sync = FB_SYNC_ON_GREEN;
- var->vmode &= ~FB_VMODE_MASK & FB_VMODE_NONINTERLACED;
-}
+static struct fb_ops aafb_ops = {
+ .owner = THIS_MODULE,
+ .fb_blank = aafb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_cursor = aafb_cursor,
+};
-static int aafb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+static int pmagaafb_probe(struct device *dev)
{
- if (con < 0) {
- struct aafb_par par;
-
- memset(var, 0, sizeof(struct fb_var_screeninfo));
- aafb_get_par(&par);
- aafb_encode_var(var, &par);
- } else
- *var = info->var;
+ struct tc_dev *tdev = to_tc_dev(dev);
+ resource_size_t start, len;
+ struct fb_info *info;
+ struct aafb_par *par;
+ int err;
+
+ info = framebuffer_alloc(sizeof(struct aafb_par), dev);
+ if (!info) {
+ printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev));
+ return -ENOMEM;
+ }
- return 0;
-}
+ par = info->par;
+ dev_set_drvdata(dev, info);
+
+ info->fbops = &aafb_ops;
+ info->fix = aafb_fix;
+ info->var = aafb_defined;
+ info->flags = FBINFO_DEFAULT;
+
+ /* Request the I/O MEM resource. */
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ if (!request_mem_region(start, len, dev_name(dev))) {
+ printk(KERN_ERR "%s: Cannot reserve FB region\n",
+ dev_name(dev));
+ err = -EBUSY;
+ goto err_alloc;
+ }
-static int aafb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- struct aafb_par par;
+ /* MMIO mapping setup. */
+ info->fix.mmio_start = start + PMAG_AA_BT455_OFFSET;
+ par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
+ if (!par->mmio) {
+ printk(KERN_ERR "%s: Cannot map MMIO\n", dev_name(dev));
+ err = -ENOMEM;
+ goto err_resource;
+ }
+ par->bt455 = par->mmio - PMAG_AA_BT455_OFFSET + PMAG_AA_BT455_OFFSET;
+ par->bt431 = par->mmio - PMAG_AA_BT455_OFFSET + PMAG_AA_BT431_OFFSET;
+
+ /* Frame buffer mapping setup. */
+ info->fix.smem_start = start + PMAG_AA_ONBOARD_FBMEM_OFFSET;
+ info->screen_base = ioremap_nocache(info->fix.smem_start,
+ info->fix.smem_len);
+ if (!info->screen_base) {
+ printk(KERN_ERR "%s: Cannot map FB\n", dev_name(dev));
+ err = -ENOMEM;
+ goto err_mmio_map;
+ }
+ info->screen_size = info->fix.smem_len;
- aafb_get_par(&par);
- aafb_encode_var(var, &par);
- info->var = *var;
+ /* Init colormap. */
+ bt455_write_cmap_entry(par->bt455, 0, 0x0);
+ bt455_write_cmap_next(par->bt455, 0xf);
- return 0;
-}
+ /* Init hardware cursor. */
+ bt431_erase_cursor(par->bt431);
+ bt431_init_cursor(par->bt431);
+
+ err = register_framebuffer(info);
+ if (err < 0) {
+ printk(KERN_ERR "%s: Cannot register framebuffer\n",
+ dev_name(dev));
+ goto err_smem_map;
+ }
-static int aafb_update_var(int con, struct fb_info *info)
-{
- struct aafb_info *ip = (struct aafb_info *)info;
- struct display *disp = (con < 0) ? &ip->disp : (fb_display + con);
+ get_device(dev);
- if (con == currcon)
- aafbcon_cursor(disp, CM_ERASE, ip->cursor.x, ip->cursor.y);
+ pr_info("fb%d: %s frame buffer device at %s\n",
+ info->node, info->fix.id, dev_name(dev));
return 0;
-}
-/* 0 unblanks, any other blanks. */
-static void aafb_blank(int blank, struct fb_info *info)
-{
- struct aafb_info *ip = (struct aafb_info *)info;
- u8 val = blank ? 0x00 : 0x0f;
+err_smem_map:
+ iounmap(info->screen_base);
- bt455_write_cmap_entry(ip->bt455, 1, val, val, val);
- aafbcon_cursor(&ip->disp, CM_ERASE, ip->cursor.x, ip->cursor.y);
-}
+err_mmio_map:
+ iounmap(par->mmio);
-static struct fb_ops aafb_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = aafb_get_fix,
- .fb_get_var = aafb_get_var,
- .fb_set_var = aafb_set_var,
- .fb_get_cmap = aafb_get_cmap,
- .fb_set_cmap = aafb_set_cmap,
- .fb_ioctl = aafb_ioctl
-};
+err_resource:
+ release_mem_region(start, len);
-static int __init init_one(int slot)
-{
- unsigned long base_addr = CKSEG1ADDR(get_tc_base_addr(slot));
- struct aafb_info *ip = &my_fb_info[slot];
-
- memset(ip, 0, sizeof(struct aafb_info));
-
- /*
- * Framebuffer display memory base address and friends.
- */
- ip->bt455 = (struct bt455_regs *) (base_addr + PMAG_AA_BT455_OFFSET);
- ip->bt431 = (struct bt431_regs *) (base_addr + PMAG_AA_BT431_OFFSET);
- ip->fb_start = base_addr + PMAG_AA_ONBOARD_FBMEM_OFFSET;
- ip->fb_size = 2048 * 1024; /* fb_fix_screeninfo.smem_length
- seems to be physical */
- ip->fb_line_length = 2048;
-
- /*
- * Let there be consoles..
- */
- strcpy(ip->info.modename, "PMAG-AA");
- ip->info.node = -1;
- ip->info.flags = FBINFO_FLAG_DEFAULT;
- ip->info.fbops = &aafb_ops;
- ip->info.disp = &ip->disp;
- ip->info.changevar = NULL;
- ip->info.switch_con = &aafb_switch;
- ip->info.updatevar = &aafb_update_var;
- ip->info.blank = &aafb_blank;
-
- aafb_set_disp(&ip->disp, currcon, ip);
-
- /*
- * Configure the RAM DACs.
- */
- bt455_erase_cursor(ip->bt455);
-
- /* Init colormap. */
- bt455_write_cmap_entry(ip->bt455, 0, 0x00, 0x00, 0x00);
- bt455_write_cmap_entry(ip->bt455, 1, 0x0f, 0x0f, 0x0f);
-
- /* Init hardware cursor. */
- bt431_init_cursor(ip->bt431);
- aafb_cursor_init(ip);
-
- /* Clear the screen. */
- memset ((void *)ip->fb_start, 0, ip->fb_size);
-
- if (register_framebuffer(&ip->info) < 0)
- return -EINVAL;
-
- printk(KERN_INFO "fb%d: %s frame buffer in TC slot %d\n",
- GET_FB_IDX(ip->info.node), ip->info.modename, slot);
-
- return 0;
+err_alloc:
+ framebuffer_release(info);
+ return err;
}
-static int __exit exit_one(int slot)
+static int __exit pmagaafb_remove(struct device *dev)
{
- struct aafb_info *ip = &my_fb_info[slot];
-
- if (unregister_framebuffer(&ip->info) < 0)
- return -EINVAL;
-
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct aafb_par *par = info->par;
+ resource_size_t start, len;
+
+ put_device(dev);
+ unregister_framebuffer(info);
+ iounmap(info->screen_base);
+ iounmap(par->mmio);
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ release_mem_region(start, len);
+ framebuffer_release(info);
return 0;
}
/*
* Initialise the framebuffer.
*/
-int __init pmagaafb_init(void)
-{
- int sid;
- int found = 0;
-
- while ((sid = search_tc_card("PMAG-AA")) >= 0) {
- found = 1;
- claim_tc_card(sid);
- init_one(sid);
- }
+static const struct tc_device_id pmagaafb_tc_table[] = {
+ { "DEC ", "PMAG-AA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, pmagaafb_tc_table);
+
+static struct tc_driver pmagaafb_driver = {
+ .id_table = pmagaafb_tc_table,
+ .driver = {
+ .name = "pmagaafb",
+ .bus = &tc_bus_type,
+ .probe = pmagaafb_probe,
+ .remove = __exit_p(pmagaafb_remove),
+ },
+};
- return found ? 0 : -ENXIO;
+static int __init pmagaafb_init(void)
+{
+#ifndef MODULE
+ if (fb_get_options("pmagaafb", NULL))
+ return -ENXIO;
+#endif
+ return tc_register_driver(&pmagaafb_driver);
}
static void __exit pmagaafb_exit(void)
{
- int sid;
-
- while ((sid = search_tc_card("PMAG-AA")) >= 0) {
- exit_one(sid);
- release_tc_card(sid);
- }
+ tc_unregister_driver(&pmagaafb_driver);
}
+module_init(pmagaafb_init);
+module_exit(pmagaafb_exit);
+
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
MODULE_LICENSE("GPL");
-#ifdef MODULE
-module_init(pmagaafb_init);
-module_exit(pmagaafb_exit);
-#endif
diff --git a/drivers/video/fbdev/pmag-ba-fb.c b/drivers/video/fbdev/pmag-ba-fb.c
index 914a52ba8477..5872bc4af3ce 100644
--- a/drivers/video/fbdev/pmag-ba-fb.c
+++ b/drivers/video/fbdev/pmag-ba-fb.c
@@ -60,7 +60,7 @@ static struct fb_var_screeninfo pmagbafb_defined = {
.left_margin = 116,
.right_margin = 12,
.upper_margin = 34,
- .lower_margin = 12,
+ .lower_margin = 0,
.hsync_len = 128,
.vsync_len = 3,
.sync = FB_SYNC_ON_GREEN,
diff --git a/drivers/video/fbdev/pxa168fb.c b/drivers/video/fbdev/pxa168fb.c
index efb57c059997..def3a501acd6 100644
--- a/drivers/video/fbdev/pxa168fb.c
+++ b/drivers/video/fbdev/pxa168fb.c
@@ -680,8 +680,8 @@ static int pxa168fb_probe(struct platform_device *pdev)
*/
info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE);
- info->screen_base = dma_alloc_writecombine(fbi->dev, info->fix.smem_len,
- &fbi->fb_start_dma, GFP_KERNEL);
+ info->screen_base = dma_alloc_wc(fbi->dev, info->fix.smem_len,
+ &fbi->fb_start_dma, GFP_KERNEL);
if (info->screen_base == NULL) {
ret = -ENOMEM;
goto failed_free_info;
@@ -804,8 +804,8 @@ static int pxa168fb_remove(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
- dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
- info->screen_base, info->fix.smem_start);
+ dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
+ info->screen_base, info->fix.smem_start);
clk_disable(fbi->clk);
diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c
index 33b2bb315a2a..2c0487f4f805 100644
--- a/drivers/video/fbdev/pxafb.c
+++ b/drivers/video/fbdev/pxafb.c
@@ -2446,8 +2446,8 @@ static int pxafb_remove(struct platform_device *dev)
free_pages_exact(fbi->video_mem, fbi->video_mem_size);
- dma_free_writecombine(&dev->dev, fbi->dma_buff_size,
- fbi->dma_buff, fbi->dma_buff_phys);
+ dma_free_wc(&dev->dev, fbi->dma_buff_size, fbi->dma_buff,
+ fbi->dma_buff_phys);
iounmap(fbi->mmio_base);
diff --git a/drivers/video/fbdev/s3c-fb.c b/drivers/video/fbdev/s3c-fb.c
index f72dd12456f9..5f4f696c2ecf 100644
--- a/drivers/video/fbdev/s3c-fb.c
+++ b/drivers/video/fbdev/s3c-fb.c
@@ -1105,8 +1105,7 @@ static int s3c_fb_alloc_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
dev_dbg(sfb->dev, "want %u bytes for window\n", size);
- fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
- &map_dma, GFP_KERNEL);
+ fbi->screen_base = dma_alloc_wc(sfb->dev, size, &map_dma, GFP_KERNEL);
if (!fbi->screen_base)
return -ENOMEM;
@@ -1131,8 +1130,8 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
struct fb_info *fbi = win->fbinfo;
if (fbi->screen_base)
- dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
- fbi->screen_base, fbi->fix.smem_start);
+ dma_free_wc(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
+ fbi->screen_base, fbi->fix.smem_start);
}
/**
diff --git a/drivers/video/fbdev/s3c2410fb.c b/drivers/video/fbdev/s3c2410fb.c
index d6704add1601..0dd86be36afb 100644
--- a/drivers/video/fbdev/s3c2410fb.c
+++ b/drivers/video/fbdev/s3c2410fb.c
@@ -645,8 +645,8 @@ static int s3c2410fb_map_video_memory(struct fb_info *info)
dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
- info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
- &map_dma, GFP_KERNEL);
+ info->screen_base = dma_alloc_wc(fbi->dev, map_size, &map_dma,
+ GFP_KERNEL);
if (info->screen_base) {
/* prevent initial garbage on screen */
@@ -667,8 +667,8 @@ static inline void s3c2410fb_unmap_video_memory(struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
- dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
- info->screen_base, info->fix.smem_start);
+ dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
+ info->screen_base, info->fix.smem_start);
}
static inline void modify_gpio(void __iomem *reg,
diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c
index dcf774c15889..fc2aaa5aca23 100644
--- a/drivers/video/fbdev/sa1100fb.c
+++ b/drivers/video/fbdev/sa1100fb.c
@@ -567,8 +567,8 @@ static int sa1100fb_mmap(struct fb_info *info,
if (off < info->fix.smem_len) {
vma->vm_pgoff += 1; /* skip over the palette */
- return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
- fbi->map_dma, fbi->map_size);
+ return dma_mmap_wc(fbi->dev, vma, fbi->map_cpu, fbi->map_dma,
+ fbi->map_size);
}
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
@@ -1099,8 +1099,8 @@ static int sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
* of the framebuffer.
*/
fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
- fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
- &fbi->map_dma, GFP_KERNEL);
+ fbi->map_cpu = dma_alloc_wc(fbi->dev, fbi->map_size, &fbi->map_dma,
+ GFP_KERNEL);
if (fbi->map_cpu) {
fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
diff --git a/drivers/video/fbdev/sis/init301.c b/drivers/video/fbdev/sis/init301.c
index 295e0dedaf1f..20f7234e809e 100644
--- a/drivers/video/fbdev/sis/init301.c
+++ b/drivers/video/fbdev/sis/init301.c
@@ -2151,17 +2151,15 @@ SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor
unsigned short RefreshRateTableIndex)
{
unsigned short CRT2Index, VCLKIndex = 0, VCLKIndexGEN = 0, VCLKIndexGENCRT = 0;
- unsigned short modeflag, resinfo, tempbx;
+ unsigned short resinfo, tempbx;
const unsigned char *CHTVVCLKPtr = NULL;
if(ModeNo <= 0x13) {
- modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
VCLKIndexGEN = (SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)) >> 2) & 0x03;
VCLKIndexGENCRT = VCLKIndexGEN;
} else {
- modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
VCLKIndexGEN = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
@@ -7270,7 +7268,7 @@ SiS_ShiftXPos(struct SiS_Private *SiS_Pr, int shift)
static void
SiS_SetGroup4_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
{
- unsigned short temp, temp1, resinfo = 0;
+ unsigned short temp, temp1;
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
if(!(SiS_Pr->SiS_VBType & VB_SIS30xCLV)) return;
@@ -7282,10 +7280,6 @@ SiS_SetGroup4_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
if(!(ROMAddr[0x61] & 0x04)) return;
}
- if(ModeNo > 0x13) {
- resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
- }
-
SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3a,0x08);
temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x3a);
if(!(temp & 0x01)) {
diff --git a/drivers/video/fbdev/skeletonfb.c b/drivers/video/fbdev/skeletonfb.c
index fefde7c6add7..f948baa16d82 100644
--- a/drivers/video/fbdev/skeletonfb.c
+++ b/drivers/video/fbdev/skeletonfb.c
@@ -614,22 +614,6 @@ int xxxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
}
/**
- * xxxfb_rotate - NOT a required function. If your hardware
- * supports rotation the whole screen then
- * you would provide a hook for this.
- *
- * @info: frame buffer structure that represents a single frame buffer
- * @angle: The angle we rotate the screen.
- *
- * This operation is used to set or alter the properities of the
- * cursor.
- */
-void xxxfb_rotate(struct fb_info *info, int angle)
-{
-/* Will be deprecated */
-}
-
-/**
* xxxfb_sync - NOT a required function. Normally the accel engine
* for a graphics card take a specific amount of time.
* Often we have to wait for the accelerator to finish
@@ -665,7 +649,6 @@ static struct fb_ops xxxfb_ops = {
.fb_copyarea = xxxfb_copyarea, /* Needed !!! */
.fb_imageblit = xxxfb_imageblit, /* Needed !!! */
.fb_cursor = xxxfb_cursor, /* Optional !!! */
- .fb_rotate = xxxfb_rotate,
.fb_sync = xxxfb_sync,
.fb_ioctl = xxxfb_ioctl,
.fb_mmap = xxxfb_mmap,
diff --git a/drivers/video/fbdev/sunxvr1000.c b/drivers/video/fbdev/sunxvr1000.c
index 08879bdfad35..fb37f6e05391 100644
--- a/drivers/video/fbdev/sunxvr1000.c
+++ b/drivers/video/fbdev/sunxvr1000.c
@@ -1,9 +1,10 @@
-/* sunxvr1000.c: Sun XVR-1000 driver for sparc64 systems
+/* sunxvr1000.c: Sun XVR-1000 fb driver for sparc64 systems
+ *
+ * License: GPL
*
* Copyright (C) 2010 David S. Miller (davem@davemloft.net)
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/init.h>
@@ -173,36 +174,19 @@ err_out:
return err;
}
-static int gfb_remove(struct platform_device *op)
-{
- struct fb_info *info = dev_get_drvdata(&op->dev);
- struct gfb_info *gp = info->par;
-
- unregister_framebuffer(info);
-
- iounmap(gp->fb_base);
-
- of_iounmap(&op->resource[6], gp->fb_base, gp->fb_size);
-
- framebuffer_release(info);
-
- return 0;
-}
-
static const struct of_device_id gfb_match[] = {
{
.name = "SUNW,gfb",
},
{},
};
-MODULE_DEVICE_TABLE(of, ffb_match);
static struct platform_driver gfb_driver = {
.probe = gfb_probe,
- .remove = gfb_remove,
.driver = {
- .name = "gfb",
- .of_match_table = gfb_match,
+ .name = "gfb",
+ .of_match_table = gfb_match,
+ .suppress_bind_attrs = true,
},
};
@@ -213,16 +197,4 @@ static int __init gfb_init(void)
return platform_driver_register(&gfb_driver);
}
-
-static void __exit gfb_exit(void)
-{
- platform_driver_unregister(&gfb_driver);
-}
-
-module_init(gfb_init);
-module_exit(gfb_exit);
-
-MODULE_DESCRIPTION("framebuffer driver for Sun XVR-1000 graphics");
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
+device_initcall(gfb_init);
diff --git a/drivers/video/fbdev/sunxvr2500.c b/drivers/video/fbdev/sunxvr2500.c
index 843b6bab0483..1a053292f2eb 100644
--- a/drivers/video/fbdev/sunxvr2500.c
+++ b/drivers/video/fbdev/sunxvr2500.c
@@ -1,9 +1,10 @@
-/* s3d.c: Sun 3DLABS XVR-2500 et al. driver for sparc64 systems
+/* sunxvr2500.c: Sun 3DLABS XVR-2500 et al. fb driver for sparc64 systems
+ *
+ * License: GPL
*
* Copyright (C) 2007 David S. Miller (davem@davemloft.net)
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/pci.h>
@@ -219,22 +220,6 @@ err_out:
return err;
}
-static void s3d_pci_unregister(struct pci_dev *pdev)
-{
- struct fb_info *info = pci_get_drvdata(pdev);
- struct s3d_info *sp = info->par;
-
- unregister_framebuffer(info);
-
- iounmap(sp->fb_base);
-
- pci_release_region(pdev, 1);
-
- framebuffer_release(info);
-
- pci_disable_device(pdev);
-}
-
static struct pci_device_id s3d_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002c), },
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002d), },
@@ -248,10 +233,12 @@ static struct pci_device_id s3d_pci_table[] = {
};
static struct pci_driver s3d_driver = {
+ .driver = {
+ .suppress_bind_attrs = true,
+ },
.name = "s3d",
.id_table = s3d_pci_table,
.probe = s3d_pci_register,
- .remove = s3d_pci_unregister,
};
static int __init s3d_init(void)
@@ -261,16 +248,4 @@ static int __init s3d_init(void)
return pci_register_driver(&s3d_driver);
}
-
-static void __exit s3d_exit(void)
-{
- pci_unregister_driver(&s3d_driver);
-}
-
-module_init(s3d_init);
-module_exit(s3d_exit);
-
-MODULE_DESCRIPTION("framebuffer driver for Sun XVR-2500 graphics");
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
+device_initcall(s3d_init);
diff --git a/drivers/video/fbdev/sunxvr500.c b/drivers/video/fbdev/sunxvr500.c
index 387350d004df..dc0d886e4e7e 100644
--- a/drivers/video/fbdev/sunxvr500.c
+++ b/drivers/video/fbdev/sunxvr500.c
@@ -1,9 +1,10 @@
-/* sunxvr500.c: Sun 3DLABS XVR-500 Expert3D driver for sparc64 systems
+/* sunxvr500.c: Sun 3DLABS XVR-500 Expert3D fb driver for sparc64 systems
+ *
+ * License: GPL
*
* Copyright (C) 2007 David S. Miller (davem@davemloft.net)
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/pci.h>
@@ -392,25 +393,6 @@ err_out:
return err;
}
-static void e3d_pci_unregister(struct pci_dev *pdev)
-{
- struct fb_info *info = pci_get_drvdata(pdev);
- struct e3d_info *ep = info->par;
-
- unregister_framebuffer(info);
-
- iounmap(ep->ramdac);
- iounmap(ep->fb_base);
-
- pci_release_region(pdev, 0);
- pci_release_region(pdev, 1);
-
- fb_dealloc_cmap(&info->cmap);
- framebuffer_release(info);
-
- pci_disable_device(pdev);
-}
-
static struct pci_device_id e3d_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a0), },
{ PCI_DEVICE(0x1091, 0x7a0), },
@@ -434,10 +416,12 @@ static struct pci_device_id e3d_pci_table[] = {
};
static struct pci_driver e3d_driver = {
+ .driver = {
+ .suppress_bind_attrs = true,
+ },
.name = "e3d",
.id_table = e3d_pci_table,
.probe = e3d_pci_register,
- .remove = e3d_pci_unregister,
};
static int __init e3d_init(void)
@@ -447,16 +431,4 @@ static int __init e3d_init(void)
return pci_register_driver(&e3d_driver);
}
-
-static void __exit e3d_exit(void)
-{
- pci_unregister_driver(&e3d_driver);
-}
-
-module_init(e3d_init);
-module_exit(e3d_exit);
-
-MODULE_DESCRIPTION("framebuffer driver for Sun XVR-500 graphics");
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
+device_initcall(e3d_init);
diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c
index f6bed86c17f9..d9a905827967 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -467,7 +467,7 @@ static const struct dev_pm_ops virtio_pci_pm_ops = {
/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
static const struct pci_device_id virtio_pci_id_table[] = {
- { PCI_DEVICE(0x1af4, PCI_ANY_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_ANY_ID) },
{ 0 }
};
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
index c0c11fad4611..7760fc1a2218 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -679,7 +679,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
pci_read_config_dword(pci_dev,
notify + offsetof(struct virtio_pci_notify_cap,
- cap.length),
+ cap.offset),
&notify_offset);
/* We don't know how many VQs we'll map, ahead of the time.
diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c
index b79a74a98a23..5fbeab38889e 100644
--- a/drivers/vme/bridges/vme_ca91cx42.c
+++ b/drivers/vme/bridges/vme_ca91cx42.c
@@ -202,7 +202,7 @@ static int ca91cx42_irq_init(struct vme_bridge *ca91cx42_bridge)
bridge = ca91cx42_bridge->driver_priv;
/* Need pdev */
- pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
+ pdev = to_pci_dev(ca91cx42_bridge->parent);
INIT_LIST_HEAD(&ca91cx42_bridge->vme_error_handlers);
@@ -293,8 +293,7 @@ static void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level,
iowrite32(tmp, bridge->base + LINT_EN);
if ((state == 0) && (sync != 0)) {
- pdev = container_of(ca91cx42_bridge->parent, struct pci_dev,
- dev);
+ pdev = to_pci_dev(ca91cx42_bridge->parent);
synchronize_irq(pdev->irq);
}
@@ -518,7 +517,7 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
dev_err(ca91cx42_bridge->parent, "Dev entry NULL\n");
return -EINVAL;
}
- pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
+ pdev = to_pci_dev(ca91cx42_bridge->parent);
existing_size = (unsigned long long)(image->bus_resource.end -
image->bus_resource.start);
@@ -1519,7 +1518,7 @@ static void *ca91cx42_alloc_consistent(struct device *parent, size_t size,
struct pci_dev *pdev;
/* Find pci_dev container of dev */
- pdev = container_of(parent, struct pci_dev, dev);
+ pdev = to_pci_dev(parent);
return pci_alloc_consistent(pdev, size, dma);
}
@@ -1530,7 +1529,7 @@ static void ca91cx42_free_consistent(struct device *parent, size_t size,
struct pci_dev *pdev;
/* Find pci_dev container of dev */
- pdev = container_of(parent, struct pci_dev, dev);
+ pdev = to_pci_dev(parent);
pci_free_consistent(pdev, size, vaddr, dma);
}
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 0e2f43bccf1f..a2eec97d5064 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -618,7 +618,6 @@ static u8 omap_w1_read_byte(void *_hdq)
hdq_disable_interrupt(hdq_data, OMAP_HDQ_CTRL_STATUS,
~OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
- hdq_data->hdq_usecount = 0;
/* Write followed by a read, release the module */
if (hdq_data->init_trans) {
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index c9a7ff67d395..89a784751738 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -1147,7 +1147,6 @@ int w1_process(void *data)
jremain = 1;
}
- try_to_freeze();
__set_current_state(TASK_INTERRUPTIBLE);
/* hold list_mutex until after interruptible to prevent loosing
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 0f6d8515ba4f..9289da313d98 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1214,6 +1214,21 @@ config SBC_EPX_C3_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called sbc_epx_c3.
+config INTEL_MEI_WDT
+ tristate "Intel MEI iAMT Watchdog"
+ depends on INTEL_MEI && X86
+ select WATCHDOG_CORE
+ ---help---
+ A device driver for the Intel MEI iAMT watchdog.
+
+ The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog.
+ Whenever the OS hangs or crashes, iAMT will send an event
+ to any subscriber to this event. The watchdog doesn't reset the
+ the platform.
+
+ To compile this driver as a module, choose M here:
+ the module will be called mei_wdt.
+
# M32R Architecture
# M68K Architecture
@@ -1569,6 +1584,17 @@ config WATCHDOG_RIO
machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter.
+config WATCHDOG_SUN4V
+ tristate "Sun4v Watchdog support"
+ select WATCHDOG_CORE
+ depends on SPARC64
+ help
+ Say Y here to support the hypervisor watchdog capability embedded
+ in the SPARC sun4v architecture.
+
+ To compile this driver as a module, choose M here. The module will
+ be called sun4v_wdt.
+
# XTENSA Architecture
# Xen Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index f566753256ab..14bd772d3e66 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -126,6 +126,7 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o
+obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o
# M32R Architecture
@@ -179,6 +180,7 @@ obj-$(CONFIG_SH_WDT) += shwdt.o
obj-$(CONFIG_WATCHDOG_RIO) += riowd.o
obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o
+obj-$(CONFIG_WATCHDOG_SUN4V) += sun4v_wdt.o
# XTENSA Architecture
diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c
new file mode 100644
index 000000000000..630bd189f167
--- /dev/null
+++ b/drivers/watchdog/mei_wdt.c
@@ -0,0 +1,724 @@
+/*
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/slab.h>
+#include <linux/interrupt.h>
+#include <linux/debugfs.h>
+#include <linux/completion.h>
+#include <linux/watchdog.h>
+
+#include <linux/uuid.h>
+#include <linux/mei_cl_bus.h>
+
+/*
+ * iAMT Watchdog Device
+ */
+#define INTEL_AMT_WATCHDOG_ID "iamt_wdt"
+
+#define MEI_WDT_DEFAULT_TIMEOUT 120 /* seconds */
+#define MEI_WDT_MIN_TIMEOUT 120 /* seconds */
+#define MEI_WDT_MAX_TIMEOUT 65535 /* seconds */
+
+/* Commands */
+#define MEI_MANAGEMENT_CONTROL 0x02
+
+/* MEI Management Control version number */
+#define MEI_MC_VERSION_NUMBER 0x10
+
+/* Sub Commands */
+#define MEI_MC_START_WD_TIMER_REQ 0x13
+#define MEI_MC_START_WD_TIMER_RES 0x83
+#define MEI_WDT_STATUS_SUCCESS 0
+#define MEI_WDT_WDSTATE_NOT_REQUIRED 0x1
+#define MEI_MC_STOP_WD_TIMER_REQ 0x14
+
+/**
+ * enum mei_wdt_state - internal watchdog state
+ *
+ * @MEI_WDT_PROBE: wd in probing stage
+ * @MEI_WDT_IDLE: wd is idle and not opened
+ * @MEI_WDT_START: wd was opened, start was called
+ * @MEI_WDT_RUNNING: wd is expecting keep alive pings
+ * @MEI_WDT_STOPPING: wd is stopping and will move to IDLE
+ * @MEI_WDT_NOT_REQUIRED: wd device is not required
+ */
+enum mei_wdt_state {
+ MEI_WDT_PROBE,
+ MEI_WDT_IDLE,
+ MEI_WDT_START,
+ MEI_WDT_RUNNING,
+ MEI_WDT_STOPPING,
+ MEI_WDT_NOT_REQUIRED,
+};
+
+static const char *mei_wdt_state_str(enum mei_wdt_state state)
+{
+ switch (state) {
+ case MEI_WDT_PROBE:
+ return "PROBE";
+ case MEI_WDT_IDLE:
+ return "IDLE";
+ case MEI_WDT_START:
+ return "START";
+ case MEI_WDT_RUNNING:
+ return "RUNNING";
+ case MEI_WDT_STOPPING:
+ return "STOPPING";
+ case MEI_WDT_NOT_REQUIRED:
+ return "NOT_REQUIRED";
+ default:
+ return "unknown";
+ }
+}
+
+/**
+ * struct mei_wdt - mei watchdog driver
+ * @wdd: watchdog device
+ *
+ * @cldev: mei watchdog client device
+ * @state: watchdog internal state
+ * @resp_required: ping required response
+ * @response: ping response completion
+ * @unregister: unregister worker
+ * @reg_lock: watchdog device registration lock
+ * @timeout: watchdog current timeout
+ *
+ * @dbgfs_dir: debugfs dir entry
+ */
+struct mei_wdt {
+ struct watchdog_device wdd;
+
+ struct mei_cl_device *cldev;
+ enum mei_wdt_state state;
+ bool resp_required;
+ struct completion response;
+ struct work_struct unregister;
+ struct mutex reg_lock;
+ u16 timeout;
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+ struct dentry *dbgfs_dir;
+#endif /* CONFIG_DEBUG_FS */
+};
+
+/*
+ * struct mei_mc_hdr - Management Control Command Header
+ *
+ * @command: Management Control (0x2)
+ * @bytecount: Number of bytes in the message beyond this byte
+ * @subcommand: Management Control Subcommand
+ * @versionnumber: Management Control Version (0x10)
+ */
+struct mei_mc_hdr {
+ u8 command;
+ u8 bytecount;
+ u8 subcommand;
+ u8 versionnumber;
+};
+
+/**
+ * struct mei_wdt_start_request watchdog start/ping
+ *
+ * @hdr: Management Control Command Header
+ * @timeout: timeout value
+ * @reserved: reserved (legacy)
+ */
+struct mei_wdt_start_request {
+ struct mei_mc_hdr hdr;
+ u16 timeout;
+ u8 reserved[17];
+} __packed;
+
+/**
+ * struct mei_wdt_start_response watchdog start/ping response
+ *
+ * @hdr: Management Control Command Header
+ * @status: operation status
+ * @wdstate: watchdog status bit mask
+ */
+struct mei_wdt_start_response {
+ struct mei_mc_hdr hdr;
+ u8 status;
+ u8 wdstate;
+} __packed;
+
+/**
+ * struct mei_wdt_stop_request - watchdog stop
+ *
+ * @hdr: Management Control Command Header
+ */
+struct mei_wdt_stop_request {
+ struct mei_mc_hdr hdr;
+} __packed;
+
+/**
+ * mei_wdt_ping - send wd start/ping command
+ *
+ * @wdt: mei watchdog device
+ *
+ * Return: 0 on success,
+ * negative errno code on failure
+ */
+static int mei_wdt_ping(struct mei_wdt *wdt)
+{
+ struct mei_wdt_start_request req;
+ const size_t req_len = sizeof(req);
+ int ret;
+
+ memset(&req, 0, req_len);
+ req.hdr.command = MEI_MANAGEMENT_CONTROL;
+ req.hdr.bytecount = req_len - offsetof(struct mei_mc_hdr, subcommand);
+ req.hdr.subcommand = MEI_MC_START_WD_TIMER_REQ;
+ req.hdr.versionnumber = MEI_MC_VERSION_NUMBER;
+ req.timeout = wdt->timeout;
+
+ ret = mei_cldev_send(wdt->cldev, (u8 *)&req, req_len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * mei_wdt_stop - send wd stop command
+ *
+ * @wdt: mei watchdog device
+ *
+ * Return: 0 on success,
+ * negative errno code on failure
+ */
+static int mei_wdt_stop(struct mei_wdt *wdt)
+{
+ struct mei_wdt_stop_request req;
+ const size_t req_len = sizeof(req);
+ int ret;
+
+ memset(&req, 0, req_len);
+ req.hdr.command = MEI_MANAGEMENT_CONTROL;
+ req.hdr.bytecount = req_len - offsetof(struct mei_mc_hdr, subcommand);
+ req.hdr.subcommand = MEI_MC_STOP_WD_TIMER_REQ;
+ req.hdr.versionnumber = MEI_MC_VERSION_NUMBER;
+
+ ret = mei_cldev_send(wdt->cldev, (u8 *)&req, req_len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * mei_wdt_ops_start - wd start command from the watchdog core.
+ *
+ * @wdd: watchdog device
+ *
+ * Return: 0 on success or -ENODEV;
+ */
+static int mei_wdt_ops_start(struct watchdog_device *wdd)
+{
+ struct mei_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ wdt->state = MEI_WDT_START;
+ wdd->timeout = wdt->timeout;
+ return 0;
+}
+
+/**
+ * mei_wdt_ops_stop - wd stop command from the watchdog core.
+ *
+ * @wdd: watchdog device
+ *
+ * Return: 0 if success, negative errno code for failure
+ */
+static int mei_wdt_ops_stop(struct watchdog_device *wdd)
+{
+ struct mei_wdt *wdt = watchdog_get_drvdata(wdd);
+ int ret;
+
+ if (wdt->state != MEI_WDT_RUNNING)
+ return 0;
+
+ wdt->state = MEI_WDT_STOPPING;
+
+ ret = mei_wdt_stop(wdt);
+ if (ret)
+ return ret;
+
+ wdt->state = MEI_WDT_IDLE;
+
+ return 0;
+}
+
+/**
+ * mei_wdt_ops_ping - wd ping command from the watchdog core.
+ *
+ * @wdd: watchdog device
+ *
+ * Return: 0 if success, negative errno code on failure
+ */
+static int mei_wdt_ops_ping(struct watchdog_device *wdd)
+{
+ struct mei_wdt *wdt = watchdog_get_drvdata(wdd);
+ int ret;
+
+ if (wdt->state != MEI_WDT_START && wdt->state != MEI_WDT_RUNNING)
+ return 0;
+
+ if (wdt->resp_required)
+ init_completion(&wdt->response);
+
+ wdt->state = MEI_WDT_RUNNING;
+ ret = mei_wdt_ping(wdt);
+ if (ret)
+ return ret;
+
+ if (wdt->resp_required)
+ ret = wait_for_completion_killable(&wdt->response);
+
+ return ret;
+}
+
+/**
+ * mei_wdt_ops_set_timeout - wd set timeout command from the watchdog core.
+ *
+ * @wdd: watchdog device
+ * @timeout: timeout value to set
+ *
+ * Return: 0 if success, negative errno code for failure
+ */
+static int mei_wdt_ops_set_timeout(struct watchdog_device *wdd,
+ unsigned int timeout)
+{
+
+ struct mei_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ /* valid value is already checked by the caller */
+ wdt->timeout = timeout;
+ wdd->timeout = timeout;
+
+ return 0;
+}
+
+static const struct watchdog_ops wd_ops = {
+ .owner = THIS_MODULE,
+ .start = mei_wdt_ops_start,
+ .stop = mei_wdt_ops_stop,
+ .ping = mei_wdt_ops_ping,
+ .set_timeout = mei_wdt_ops_set_timeout,
+};
+
+/* not const as the firmware_version field need to be retrieved */
+static struct watchdog_info wd_info = {
+ .identity = INTEL_AMT_WATCHDOG_ID,
+ .options = WDIOF_KEEPALIVEPING |
+ WDIOF_SETTIMEOUT |
+ WDIOF_ALARMONLY,
+};
+
+/**
+ * __mei_wdt_is_registered - check if wdt is registered
+ *
+ * @wdt: mei watchdog device
+ *
+ * Return: true if the wdt is registered with the watchdog subsystem
+ * Locking: should be called under wdt->reg_lock
+ */
+static inline bool __mei_wdt_is_registered(struct mei_wdt *wdt)
+{
+ return !!watchdog_get_drvdata(&wdt->wdd);
+}
+
+/**
+ * mei_wdt_unregister - unregister from the watchdog subsystem
+ *
+ * @wdt: mei watchdog device
+ */
+static void mei_wdt_unregister(struct mei_wdt *wdt)
+{
+ mutex_lock(&wdt->reg_lock);
+
+ if (__mei_wdt_is_registered(wdt)) {
+ watchdog_unregister_device(&wdt->wdd);
+ watchdog_set_drvdata(&wdt->wdd, NULL);
+ memset(&wdt->wdd, 0, sizeof(wdt->wdd));
+ }
+
+ mutex_unlock(&wdt->reg_lock);
+}
+
+/**
+ * mei_wdt_register - register with the watchdog subsystem
+ *
+ * @wdt: mei watchdog device
+ *
+ * Return: 0 if success, negative errno code for failure
+ */
+static int mei_wdt_register(struct mei_wdt *wdt)
+{
+ struct device *dev;
+ int ret;
+
+ if (!wdt || !wdt->cldev)
+ return -EINVAL;
+
+ dev = &wdt->cldev->dev;
+
+ mutex_lock(&wdt->reg_lock);
+
+ if (__mei_wdt_is_registered(wdt)) {
+ ret = 0;
+ goto out;
+ }
+
+ wdt->wdd.info = &wd_info;
+ wdt->wdd.ops = &wd_ops;
+ wdt->wdd.parent = dev;
+ wdt->wdd.timeout = MEI_WDT_DEFAULT_TIMEOUT;
+ wdt->wdd.min_timeout = MEI_WDT_MIN_TIMEOUT;
+ wdt->wdd.max_timeout = MEI_WDT_MAX_TIMEOUT;
+
+ watchdog_set_drvdata(&wdt->wdd, wdt);
+ ret = watchdog_register_device(&wdt->wdd);
+ if (ret) {
+ dev_err(dev, "unable to register watchdog device = %d.\n", ret);
+ watchdog_set_drvdata(&wdt->wdd, NULL);
+ }
+
+ wdt->state = MEI_WDT_IDLE;
+
+out:
+ mutex_unlock(&wdt->reg_lock);
+ return ret;
+}
+
+static void mei_wdt_unregister_work(struct work_struct *work)
+{
+ struct mei_wdt *wdt = container_of(work, struct mei_wdt, unregister);
+
+ mei_wdt_unregister(wdt);
+}
+
+/**
+ * mei_wdt_event_rx - callback for data receive
+ *
+ * @cldev: bus device
+ */
+static void mei_wdt_event_rx(struct mei_cl_device *cldev)
+{
+ struct mei_wdt *wdt = mei_cldev_get_drvdata(cldev);
+ struct mei_wdt_start_response res;
+ const size_t res_len = sizeof(res);
+ int ret;
+
+ ret = mei_cldev_recv(wdt->cldev, (u8 *)&res, res_len);
+ if (ret < 0) {
+ dev_err(&cldev->dev, "failure in recv %d\n", ret);
+ return;
+ }
+
+ /* Empty response can be sent on stop */
+ if (ret == 0)
+ return;
+
+ if (ret < sizeof(struct mei_mc_hdr)) {
+ dev_err(&cldev->dev, "recv small data %d\n", ret);
+ return;
+ }
+
+ if (res.hdr.command != MEI_MANAGEMENT_CONTROL ||
+ res.hdr.versionnumber != MEI_MC_VERSION_NUMBER) {
+ dev_err(&cldev->dev, "wrong command received\n");
+ return;
+ }
+
+ if (res.hdr.subcommand != MEI_MC_START_WD_TIMER_RES) {
+ dev_warn(&cldev->dev, "unsupported command %d :%s[%d]\n",
+ res.hdr.subcommand,
+ mei_wdt_state_str(wdt->state),
+ wdt->state);
+ return;
+ }
+
+ /* Run the unregistration in a worker as this can be
+ * run only after ping completion, otherwise the flow will
+ * deadlock on watchdog core mutex.
+ */
+ if (wdt->state == MEI_WDT_RUNNING) {
+ if (res.wdstate & MEI_WDT_WDSTATE_NOT_REQUIRED) {
+ wdt->state = MEI_WDT_NOT_REQUIRED;
+ schedule_work(&wdt->unregister);
+ }
+ goto out;
+ }
+
+ if (wdt->state == MEI_WDT_PROBE) {
+ if (res.wdstate & MEI_WDT_WDSTATE_NOT_REQUIRED) {
+ wdt->state = MEI_WDT_NOT_REQUIRED;
+ } else {
+ /* stop the watchdog and register watchdog device */
+ mei_wdt_stop(wdt);
+ mei_wdt_register(wdt);
+ }
+ return;
+ }
+
+ dev_warn(&cldev->dev, "not in correct state %s[%d]\n",
+ mei_wdt_state_str(wdt->state), wdt->state);
+
+out:
+ if (!completion_done(&wdt->response))
+ complete(&wdt->response);
+}
+
+/*
+ * mei_wdt_notify_event - callback for event notification
+ *
+ * @cldev: bus device
+ */
+static void mei_wdt_notify_event(struct mei_cl_device *cldev)
+{
+ struct mei_wdt *wdt = mei_cldev_get_drvdata(cldev);
+
+ if (wdt->state != MEI_WDT_NOT_REQUIRED)
+ return;
+
+ mei_wdt_register(wdt);
+}
+
+/**
+ * mei_wdt_event - callback for event receive
+ *
+ * @cldev: bus device
+ * @events: event mask
+ * @context: callback context
+ */
+static void mei_wdt_event(struct mei_cl_device *cldev,
+ u32 events, void *context)
+{
+ if (events & BIT(MEI_CL_EVENT_RX))
+ mei_wdt_event_rx(cldev);
+
+ if (events & BIT(MEI_CL_EVENT_NOTIF))
+ mei_wdt_notify_event(cldev);
+}
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+
+static ssize_t mei_dbgfs_read_activation(struct file *file, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct mei_wdt *wdt = file->private_data;
+ const size_t bufsz = 32;
+ char buf[32];
+ ssize_t pos;
+
+ mutex_lock(&wdt->reg_lock);
+ pos = scnprintf(buf, bufsz, "%s\n",
+ __mei_wdt_is_registered(wdt) ? "activated" : "deactivated");
+ mutex_unlock(&wdt->reg_lock);
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
+}
+
+static const struct file_operations dbgfs_fops_activation = {
+ .open = simple_open,
+ .read = mei_dbgfs_read_activation,
+ .llseek = generic_file_llseek,
+};
+
+static ssize_t mei_dbgfs_read_state(struct file *file, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct mei_wdt *wdt = file->private_data;
+ const size_t bufsz = 32;
+ char buf[bufsz];
+ ssize_t pos;
+
+ pos = scnprintf(buf, bufsz, "state: %s\n",
+ mei_wdt_state_str(wdt->state));
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
+}
+
+static const struct file_operations dbgfs_fops_state = {
+ .open = simple_open,
+ .read = mei_dbgfs_read_state,
+ .llseek = generic_file_llseek,
+};
+
+static void dbgfs_unregister(struct mei_wdt *wdt)
+{
+ debugfs_remove_recursive(wdt->dbgfs_dir);
+ wdt->dbgfs_dir = NULL;
+}
+
+static int dbgfs_register(struct mei_wdt *wdt)
+{
+ struct dentry *dir, *f;
+
+ dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (!dir)
+ return -ENOMEM;
+
+ wdt->dbgfs_dir = dir;
+ f = debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state);
+ if (!f)
+ goto err;
+
+ f = debugfs_create_file("activation", S_IRUSR,
+ dir, wdt, &dbgfs_fops_activation);
+ if (!f)
+ goto err;
+
+ return 0;
+err:
+ dbgfs_unregister(wdt);
+ return -ENODEV;
+}
+
+#else
+
+static inline void dbgfs_unregister(struct mei_wdt *wdt) {}
+
+static inline int dbgfs_register(struct mei_wdt *wdt)
+{
+ return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static int mei_wdt_probe(struct mei_cl_device *cldev,
+ const struct mei_cl_device_id *id)
+{
+ struct mei_wdt *wdt;
+ int ret;
+
+ wdt = kzalloc(sizeof(struct mei_wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+
+ wdt->timeout = MEI_WDT_DEFAULT_TIMEOUT;
+ wdt->state = MEI_WDT_PROBE;
+ wdt->cldev = cldev;
+ wdt->resp_required = mei_cldev_ver(cldev) > 0x1;
+ mutex_init(&wdt->reg_lock);
+ init_completion(&wdt->response);
+ INIT_WORK(&wdt->unregister, mei_wdt_unregister_work);
+
+ mei_cldev_set_drvdata(cldev, wdt);
+
+ ret = mei_cldev_enable(cldev);
+ if (ret < 0) {
+ dev_err(&cldev->dev, "Could not enable cl device\n");
+ goto err_out;
+ }
+
+ ret = mei_cldev_register_event_cb(wdt->cldev,
+ BIT(MEI_CL_EVENT_RX) |
+ BIT(MEI_CL_EVENT_NOTIF),
+ mei_wdt_event, NULL);
+
+ /* on legacy devices notification is not supported
+ * this doesn't fail the registration for RX event
+ */
+ if (ret && ret != -EOPNOTSUPP) {
+ dev_err(&cldev->dev, "Could not register event ret=%d\n", ret);
+ goto err_disable;
+ }
+
+ wd_info.firmware_version = mei_cldev_ver(cldev);
+
+ if (wdt->resp_required)
+ ret = mei_wdt_ping(wdt);
+ else
+ ret = mei_wdt_register(wdt);
+
+ if (ret)
+ goto err_disable;
+
+ if (dbgfs_register(wdt))
+ dev_warn(&cldev->dev, "cannot register debugfs\n");
+
+ return 0;
+
+err_disable:
+ mei_cldev_disable(cldev);
+
+err_out:
+ kfree(wdt);
+
+ return ret;
+}
+
+static int mei_wdt_remove(struct mei_cl_device *cldev)
+{
+ struct mei_wdt *wdt = mei_cldev_get_drvdata(cldev);
+
+ /* Free the caller in case of fw initiated or unexpected reset */
+ if (!completion_done(&wdt->response))
+ complete(&wdt->response);
+
+ cancel_work_sync(&wdt->unregister);
+
+ mei_wdt_unregister(wdt);
+
+ mei_cldev_disable(cldev);
+
+ dbgfs_unregister(wdt);
+
+ kfree(wdt);
+
+ return 0;
+}
+
+#define MEI_UUID_WD UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, \
+ 0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB)
+
+static struct mei_cl_device_id mei_wdt_tbl[] = {
+ { .uuid = MEI_UUID_WD, .version = MEI_CL_VERSION_ANY },
+ /* required last entry */
+ { }
+};
+MODULE_DEVICE_TABLE(mei, mei_wdt_tbl);
+
+static struct mei_cl_driver mei_wdt_driver = {
+ .id_table = mei_wdt_tbl,
+ .name = KBUILD_MODNAME,
+
+ .probe = mei_wdt_probe,
+ .remove = mei_wdt_remove,
+};
+
+static int __init mei_wdt_init(void)
+{
+ int ret;
+
+ ret = mei_cldev_driver_register(&mei_wdt_driver);
+ if (ret) {
+ pr_err(KBUILD_MODNAME ": module registration failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void __exit mei_wdt_exit(void)
+{
+ mei_cldev_driver_unregister(&mei_wdt_driver);
+}
+
+module_init(mei_wdt_init);
+module_exit(mei_wdt_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Device driver for Intel MEI iAMT watchdog");
diff --git a/drivers/watchdog/sun4v_wdt.c b/drivers/watchdog/sun4v_wdt.c
new file mode 100644
index 000000000000..1467fe50a76f
--- /dev/null
+++ b/drivers/watchdog/sun4v_wdt.c
@@ -0,0 +1,191 @@
+/*
+ * sun4v watchdog timer
+ * (c) Copyright 2016 Oracle Corporation
+ *
+ * Implement a simple watchdog driver using the built-in sun4v hypervisor
+ * watchdog support. If time expires, the hypervisor stops or bounces
+ * the guest domain.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/watchdog.h>
+#include <asm/hypervisor.h>
+#include <asm/mdesc.h>
+
+#define WDT_TIMEOUT 60
+#define WDT_MAX_TIMEOUT 31536000
+#define WDT_MIN_TIMEOUT 1
+#define WDT_DEFAULT_RESOLUTION_MS 1000 /* 1 second */
+
+static unsigned int timeout;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
+ __MODULE_STRING(WDT_TIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, S_IRUGO);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int sun4v_wdt_stop(struct watchdog_device *wdd)
+{
+ sun4v_mach_set_watchdog(0, NULL);
+
+ return 0;
+}
+
+static int sun4v_wdt_ping(struct watchdog_device *wdd)
+{
+ int hverr;
+
+ /*
+ * HV watchdog timer will round up the timeout
+ * passed in to the nearest multiple of the
+ * watchdog resolution in milliseconds.
+ */
+ hverr = sun4v_mach_set_watchdog(wdd->timeout * 1000, NULL);
+ if (hverr == HV_EINVAL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sun4v_wdt_set_timeout(struct watchdog_device *wdd,
+ unsigned int timeout)
+{
+ wdd->timeout = timeout;
+
+ return 0;
+}
+
+static const struct watchdog_info sun4v_wdt_ident = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
+ .identity = "sun4v hypervisor watchdog",
+ .firmware_version = 0,
+};
+
+static struct watchdog_ops sun4v_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = sun4v_wdt_ping,
+ .stop = sun4v_wdt_stop,
+ .ping = sun4v_wdt_ping,
+ .set_timeout = sun4v_wdt_set_timeout,
+};
+
+static struct watchdog_device wdd = {
+ .info = &sun4v_wdt_ident,
+ .ops = &sun4v_wdt_ops,
+ .min_timeout = WDT_MIN_TIMEOUT,
+ .max_timeout = WDT_MAX_TIMEOUT,
+ .timeout = WDT_TIMEOUT,
+};
+
+static int __init sun4v_wdt_init(void)
+{
+ struct mdesc_handle *handle;
+ u64 node;
+ const u64 *value;
+ int err = 0;
+ unsigned long major = 1, minor = 1;
+
+ /*
+ * There are 2 properties that can be set from the control
+ * domain for the watchdog.
+ * watchdog-resolution
+ * watchdog-max-timeout
+ *
+ * We can expect a handle to be returned otherwise something
+ * serious is wrong. Correct to return -ENODEV here.
+ */
+
+ handle = mdesc_grab();
+ if (!handle)
+ return -ENODEV;
+
+ node = mdesc_node_by_name(handle, MDESC_NODE_NULL, "platform");
+ err = -ENODEV;
+ if (node == MDESC_NODE_NULL)
+ goto out_release;
+
+ /*
+ * This is a safe way to validate if we are on the right
+ * platform.
+ */
+ if (sun4v_hvapi_register(HV_GRP_CORE, major, &minor))
+ goto out_hv_unreg;
+
+ /* Allow value of watchdog-resolution up to 1s (default) */
+ value = mdesc_get_property(handle, node, "watchdog-resolution", NULL);
+ err = -EINVAL;
+ if (value) {
+ if (*value == 0 ||
+ *value > WDT_DEFAULT_RESOLUTION_MS)
+ goto out_hv_unreg;
+ }
+
+ value = mdesc_get_property(handle, node, "watchdog-max-timeout", NULL);
+ if (value) {
+ /*
+ * If the property value (in ms) is smaller than
+ * min_timeout, return -EINVAL.
+ */
+ if (*value < wdd.min_timeout * 1000)
+ goto out_hv_unreg;
+
+ /*
+ * If the property value is smaller than
+ * default max_timeout then set watchdog max_timeout to
+ * the value of the property in seconds.
+ */
+ if (*value < wdd.max_timeout * 1000)
+ wdd.max_timeout = *value / 1000;
+ }
+
+ watchdog_init_timeout(&wdd, timeout, NULL);
+
+ watchdog_set_nowayout(&wdd, nowayout);
+
+ err = watchdog_register_device(&wdd);
+ if (err)
+ goto out_hv_unreg;
+
+ pr_info("initialized (timeout=%ds, nowayout=%d)\n",
+ wdd.timeout, nowayout);
+
+ mdesc_release(handle);
+
+ return 0;
+
+out_hv_unreg:
+ sun4v_hvapi_unregister(HV_GRP_CORE);
+
+out_release:
+ mdesc_release(handle);
+ return err;
+}
+
+static void __exit sun4v_wdt_exit(void)
+{
+ sun4v_hvapi_unregister(HV_GRP_CORE);
+ watchdog_unregister_device(&wdd);
+}
+
+module_init(sun4v_wdt_init);
+module_exit(sun4v_wdt_exit);
+
+MODULE_AUTHOR("Wim Coekaerts <wim.coekaerts@oracle.com>");
+MODULE_DESCRIPTION("sun4v watchdog driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 73708acce3ca..979a8317204f 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -37,23 +37,30 @@ config XEN_BALLOON_MEMORY_HOTPLUG
Memory could be hotplugged in following steps:
- 1) dom0: xl mem-max <domU> <maxmem>
+ 1) target domain: ensure that memory auto online policy is in
+ effect by checking /sys/devices/system/memory/auto_online_blocks
+ file (should be 'online').
+
+ 2) control domain: xl mem-max <target-domain> <maxmem>
where <maxmem> is >= requested memory size,
- 2) dom0: xl mem-set <domU> <memory>
+ 3) control domain: xl mem-set <target-domain> <memory>
where <memory> is requested memory size; alternatively memory
could be added by writing proper value to
/sys/devices/system/xen_memory/xen_memory0/target or
- /sys/devices/system/xen_memory/xen_memory0/target_kb on dumU,
+ /sys/devices/system/xen_memory/xen_memory0/target_kb on the
+ target domain.
- 3) domU: for i in /sys/devices/system/memory/memory*/state; do \
- [ "`cat "$i"`" = offline ] && echo online > "$i"; done
+ Alternatively, if memory auto onlining was not requested at step 1
+ the newly added memory can be manually onlined in the target domain
+ by doing the following:
- Memory could be onlined automatically on domU by adding following line to udev rules:
+ for i in /sys/devices/system/memory/memory*/state; do \
+ [ "`cat "$i"`" = offline ] && echo online > "$i"; done
- SUBSYSTEM=="memory", ACTION=="add", RUN+="/bin/sh -c '[ -f /sys$devpath/state ] && echo online > /sys$devpath/state'"
+ or by adding the following line to udev rules:
- In that case step 3 should be omitted.
+ SUBSYSTEM=="memory", ACTION=="add", RUN+="/bin/sh -c '[ -f /sys$devpath/state ] && echo online > /sys$devpath/state'"
config XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
int "Hotplugged memory limit (in GiB) for a PV guest"
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 12eab503efd1..7c8a2cf16f58 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -257,7 +257,7 @@ static struct resource *additional_memory_resource(phys_addr_t size)
return NULL;
res->name = "System RAM";
- res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
ret = allocate_resource(&iomem_resource, res,
size, 0, -1,
@@ -338,7 +338,16 @@ static enum bp_state reserve_additional_memory(void)
}
#endif
- rc = add_memory_resource(nid, resource);
+ /*
+ * add_memory_resource() will call online_pages() which in its turn
+ * will call xen_online_page() callback causing deadlock if we don't
+ * release balloon_mutex here. Unlocking here is safe because the
+ * callers drop the mutex before trying again.
+ */
+ mutex_unlock(&balloon_mutex);
+ rc = add_memory_resource(nid, resource, memhp_auto_online);
+ mutex_lock(&balloon_mutex);
+
if (rc) {
pr_warn("Cannot add additional memory (%i)\n", rc);
goto err;
diff --git a/drivers/xen/events/events_2l.c b/drivers/xen/events/events_2l.c
index 7dd46312c180..403fe3955393 100644
--- a/drivers/xen/events/events_2l.c
+++ b/drivers/xen/events/events_2l.c
@@ -38,8 +38,9 @@
/* Find the first set bit in a evtchn mask */
#define EVTCHN_FIRST_BIT(w) find_first_bit(BM(&(w)), BITS_PER_EVTCHN_WORD)
-static DEFINE_PER_CPU(xen_ulong_t [EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD],
- cpu_evtchn_mask);
+#define EVTCHN_MASK_SIZE (EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD)
+
+static DEFINE_PER_CPU(xen_ulong_t [EVTCHN_MASK_SIZE], cpu_evtchn_mask);
static unsigned evtchn_2l_max_channels(void)
{
diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c
index 73dafdc494aa..fb0221434f81 100644
--- a/drivers/xen/xen-pciback/pciback_ops.c
+++ b/drivers/xen/xen-pciback/pciback_ops.c
@@ -227,8 +227,9 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev,
/*
* PCI_COMMAND_MEMORY must be enabled, otherwise we may not be able
* to access the BARs where the MSI-X entries reside.
+ * But VF devices are unique in which the PF needs to be checked.
*/
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ pci_read_config_word(pci_physfn(dev), PCI_COMMAND, &cmd);
if (dev->msi_enabled || !(cmd & PCI_COMMAND_MEMORY))
return -ENXIO;
@@ -332,6 +333,9 @@ void xen_pcibk_do_op(struct work_struct *data)
struct xen_pcibk_dev_data *dev_data = NULL;
struct xen_pci_op *op = &pdev->op;
int test_intx = 0;
+#ifdef CONFIG_PCI_MSI
+ unsigned int nr = 0;
+#endif
*op = pdev->sh_info->op;
barrier();
@@ -360,6 +364,7 @@ void xen_pcibk_do_op(struct work_struct *data)
op->err = xen_pcibk_disable_msi(pdev, dev, op);
break;
case XEN_PCI_OP_enable_msix:
+ nr = op->value;
op->err = xen_pcibk_enable_msix(pdev, dev, op);
break;
case XEN_PCI_OP_disable_msix:
@@ -382,7 +387,7 @@ void xen_pcibk_do_op(struct work_struct *data)
if (op->cmd == XEN_PCI_OP_enable_msix && op->err == 0) {
unsigned int i;
- for (i = 0; i < op->value; i++)
+ for (i = 0; i < nr; i++)
pdev->sh_info->op.msix_entries[i].vector =
op->msix_entries[i].vector;
}
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
index ad4eb1024d1f..c46ee189466f 100644
--- a/drivers/xen/xen-scsiback.c
+++ b/drivers/xen/xen-scsiback.c
@@ -849,15 +849,31 @@ static int scsiback_map(struct vscsibk_info *info)
}
/*
+ Check for a translation entry being present
+*/
+static struct v2p_entry *scsiback_chk_translation_entry(
+ struct vscsibk_info *info, struct ids_tuple *v)
+{
+ struct list_head *head = &(info->v2p_entry_lists);
+ struct v2p_entry *entry;
+
+ list_for_each_entry(entry, head, l)
+ if ((entry->v.chn == v->chn) &&
+ (entry->v.tgt == v->tgt) &&
+ (entry->v.lun == v->lun))
+ return entry;
+
+ return NULL;
+}
+
+/*
Add a new translation entry
*/
static int scsiback_add_translation_entry(struct vscsibk_info *info,
char *phy, struct ids_tuple *v)
{
int err = 0;
- struct v2p_entry *entry;
struct v2p_entry *new;
- struct list_head *head = &(info->v2p_entry_lists);
unsigned long flags;
char *lunp;
unsigned long long unpacked_lun;
@@ -917,15 +933,10 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info,
spin_lock_irqsave(&info->v2p_lock, flags);
/* Check double assignment to identical virtual ID */
- list_for_each_entry(entry, head, l) {
- if ((entry->v.chn == v->chn) &&
- (entry->v.tgt == v->tgt) &&
- (entry->v.lun == v->lun)) {
- pr_warn("Virtual ID is already used. Assignment was not performed.\n");
- err = -EEXIST;
- goto out;
- }
-
+ if (scsiback_chk_translation_entry(info, v)) {
+ pr_warn("Virtual ID is already used. Assignment was not performed.\n");
+ err = -EEXIST;
+ goto out;
}
/* Create a new translation entry and add to the list */
@@ -933,18 +944,18 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info,
new->v = *v;
new->tpg = tpg;
new->lun = unpacked_lun;
- list_add_tail(&new->l, head);
+ list_add_tail(&new->l, &info->v2p_entry_lists);
out:
spin_unlock_irqrestore(&info->v2p_lock, flags);
out_free:
- mutex_lock(&tpg->tv_tpg_mutex);
- tpg->tv_tpg_fe_count--;
- mutex_unlock(&tpg->tv_tpg_mutex);
-
- if (err)
+ if (err) {
+ mutex_lock(&tpg->tv_tpg_mutex);
+ tpg->tv_tpg_fe_count--;
+ mutex_unlock(&tpg->tv_tpg_mutex);
kfree(new);
+ }
return err;
}
@@ -956,39 +967,40 @@ static void __scsiback_del_translation_entry(struct v2p_entry *entry)
}
/*
- Delete the translation entry specfied
+ Delete the translation entry specified
*/
static int scsiback_del_translation_entry(struct vscsibk_info *info,
struct ids_tuple *v)
{
struct v2p_entry *entry;
- struct list_head *head = &(info->v2p_entry_lists);
unsigned long flags;
+ int ret = 0;
spin_lock_irqsave(&info->v2p_lock, flags);
/* Find out the translation entry specified */
- list_for_each_entry(entry, head, l) {
- if ((entry->v.chn == v->chn) &&
- (entry->v.tgt == v->tgt) &&
- (entry->v.lun == v->lun)) {
- goto found;
- }
- }
-
- spin_unlock_irqrestore(&info->v2p_lock, flags);
- return 1;
-
-found:
- /* Delete the translation entry specfied */
- __scsiback_del_translation_entry(entry);
+ entry = scsiback_chk_translation_entry(info, v);
+ if (entry)
+ __scsiback_del_translation_entry(entry);
+ else
+ ret = -ENOENT;
spin_unlock_irqrestore(&info->v2p_lock, flags);
- return 0;
+ return ret;
}
static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state,
char *phy, struct ids_tuple *vir, int try)
{
+ struct v2p_entry *entry;
+ unsigned long flags;
+
+ if (try) {
+ spin_lock_irqsave(&info->v2p_lock, flags);
+ entry = scsiback_chk_translation_entry(info, vir);
+ spin_unlock_irqrestore(&info->v2p_lock, flags);
+ if (entry)
+ return;
+ }
if (!scsiback_add_translation_entry(info, phy, vir)) {
if (xenbus_printf(XBT_NIL, info->dev->nodename, state,
"%d", XenbusStateInitialised)) {
diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c
index 9433e46518c8..912b64edb42b 100644
--- a/drivers/xen/xenbus/xenbus_dev_frontend.c
+++ b/drivers/xen/xenbus/xenbus_dev_frontend.c
@@ -188,6 +188,8 @@ static int queue_reply(struct list_head *queue, const void *data, size_t len)
if (len == 0)
return 0;
+ if (len > XENSTORE_PAYLOAD_MAX)
+ return -EINVAL;
rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL);
if (rb == NULL)
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c
index 36b210f9b6b2..9282dbf5abdb 100644
--- a/drivers/zorro/zorro-sysfs.c
+++ b/drivers/zorro/zorro-sysfs.c
@@ -65,8 +65,7 @@ static ssize_t zorro_read_config(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct zorro_dev *z = to_zorro_dev(container_of(kobj, struct device,
- kobj));
+ struct zorro_dev *z = to_zorro_dev(kobj_to_dev(kobj));
struct ConfigDev cd;
/* Construct a ConfigDev */